cc-claw 0.5.0 → 0.5.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.
Files changed (2) hide show
  1. package/dist/cli.js +302 -215
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -49,7 +49,7 @@ var VERSION;
49
49
  var init_version = __esm({
50
50
  "src/version.ts"() {
51
51
  "use strict";
52
- VERSION = true ? "0.5.0" : (() => {
52
+ VERSION = true ? "0.5.2" : (() => {
53
53
  try {
54
54
  return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
55
55
  } catch {
@@ -69,14 +69,14 @@ function ts() {
69
69
  const absM = Math.abs(offset) % 60;
70
70
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}${sign}${pad(absH)}${pad(absM)}`;
71
71
  }
72
- function log(...args2) {
73
- console.log(`[${ts()}]`, ...args2);
72
+ function log(...args) {
73
+ console.log(`[${ts()}]`, ...args);
74
74
  }
75
- function warn(...args2) {
76
- console.warn(`[${ts()}]`, ...args2);
75
+ function warn(...args) {
76
+ console.warn(`[${ts()}]`, ...args);
77
77
  }
78
- function error(...args2) {
79
- console.error(`[${ts()}]`, ...args2);
78
+ function error(...args) {
79
+ console.error(`[${ts()}]`, ...args);
80
80
  }
81
81
  function errorMessage(err) {
82
82
  return err instanceof Error ? err.message : String(err);
@@ -2639,7 +2639,7 @@ var init_claude = __esm({
2639
2639
  return { envOverrides: { MAX_THINKING_TOKENS: budgets[level] ?? "16384" } };
2640
2640
  }
2641
2641
  buildSpawnConfig(opts) {
2642
- const args2 = [
2642
+ const args = [
2643
2643
  "-p",
2644
2644
  opts.prompt,
2645
2645
  "--output-format",
@@ -2648,32 +2648,32 @@ var init_claude = __esm({
2648
2648
  "--max-turns",
2649
2649
  String(opts.maxTurns ?? 25)
2650
2650
  ];
2651
- if (opts.sessionId) args2.push("--resume", opts.sessionId);
2652
- if (opts.model) args2.push("--model", opts.model);
2651
+ if (opts.sessionId) args.push("--resume", opts.sessionId);
2652
+ if (opts.model) args.push("--model", opts.model);
2653
2653
  switch (opts.permMode) {
2654
2654
  case "plan":
2655
- args2.push("--permission-mode", "plan");
2656
- args2.push("--strict-mcp-config");
2655
+ args.push("--permission-mode", "plan");
2656
+ args.push("--strict-mcp-config");
2657
2657
  break;
2658
2658
  case "safe":
2659
- args2.push("--permission-mode", "bypassPermissions");
2659
+ args.push("--permission-mode", "bypassPermissions");
2660
2660
  if (opts.allowedTools.length > 0) {
2661
- args2.push("--tools", opts.allowedTools.join(","));
2661
+ args.push("--tools", opts.allowedTools.join(","));
2662
2662
  } else {
2663
- args2.push("--tools", "Read,Glob,Grep");
2663
+ args.push("--tools", "Read,Glob,Grep");
2664
2664
  }
2665
2665
  break;
2666
2666
  case "yolo":
2667
2667
  default:
2668
- args2.push("--permission-mode", "bypassPermissions");
2669
- args2.push("--allow-dangerously-skip-permissions");
2668
+ args.push("--permission-mode", "bypassPermissions");
2669
+ args.push("--allow-dangerously-skip-permissions");
2670
2670
  break;
2671
2671
  }
2672
2672
  const identityFile = join3(IDENTITY_PATH, "CC-CLAW.md");
2673
2673
  if (existsSync(identityFile)) {
2674
- args2.push("--append-system-prompt-file", identityFile);
2674
+ args.push("--append-system-prompt-file", identityFile);
2675
2675
  }
2676
- return { executable: this.getExecutablePath(), args: args2, cwd: opts.cwd };
2676
+ return { executable: this.getExecutablePath(), args, cwd: opts.cwd };
2677
2677
  }
2678
2678
  parseLine(raw) {
2679
2679
  if (typeof raw !== "object" || raw === null) return [];
@@ -2818,7 +2818,7 @@ var init_gemini = __esm({
2818
2818
  return {};
2819
2819
  }
2820
2820
  buildSpawnConfig(opts) {
2821
- const args2 = [
2821
+ const args = [
2822
2822
  "-p",
2823
2823
  opts.prompt,
2824
2824
  "-o",
@@ -2826,21 +2826,21 @@ var init_gemini = __esm({
2826
2826
  "--allowed-mcp-server-names=__none__"
2827
2827
  // nonexistent name = skip all user MCP servers (avoids crash/hang from broken servers)
2828
2828
  ];
2829
- if (opts.sessionId) args2.push("--resume", opts.sessionId);
2830
- if (opts.model) args2.push("-m", opts.model);
2829
+ if (opts.sessionId) args.push("--resume", opts.sessionId);
2830
+ if (opts.model) args.push("-m", opts.model);
2831
2831
  switch (opts.permMode) {
2832
2832
  case "plan":
2833
- args2.push("--approval-mode", "plan");
2833
+ args.push("--approval-mode", "plan");
2834
2834
  break;
2835
2835
  case "safe":
2836
- args2.push("--approval-mode", "plan");
2836
+ args.push("--approval-mode", "plan");
2837
2837
  break;
2838
2838
  case "yolo":
2839
2839
  default:
2840
- args2.push("--yolo");
2840
+ args.push("--yolo");
2841
2841
  break;
2842
2842
  }
2843
- return { executable: this.getExecutablePath(), args: args2, cwd: opts.cwd };
2843
+ return { executable: this.getExecutablePath(), args, cwd: opts.cwd };
2844
2844
  }
2845
2845
  parseLine(raw) {
2846
2846
  if (typeof raw !== "object" || raw === null) return [];
@@ -2975,31 +2975,31 @@ var init_codex = __esm({
2975
2975
  }
2976
2976
  buildSpawnConfig(opts) {
2977
2977
  const isResume = !!opts.sessionId;
2978
- const args2 = [];
2978
+ const args = [];
2979
2979
  if (isResume) {
2980
- args2.push("exec", "resume", opts.sessionId, opts.prompt, "--json");
2980
+ args.push("exec", "resume", opts.sessionId, opts.prompt, "--json");
2981
2981
  } else {
2982
- args2.push("exec", opts.prompt, "--json");
2982
+ args.push("exec", opts.prompt, "--json");
2983
2983
  }
2984
- if (opts.model) args2.push("-m", opts.model);
2984
+ if (opts.model) args.push("-m", opts.model);
2985
2985
  switch (opts.permMode) {
2986
2986
  case "plan":
2987
- args2.push("--sandbox", "read-only");
2987
+ args.push("--sandbox", "read-only");
2988
2988
  break;
2989
2989
  case "safe":
2990
- args2.push("--sandbox", "read-only");
2990
+ args.push("--sandbox", "read-only");
2991
2991
  break;
2992
2992
  case "yolo":
2993
2993
  default:
2994
- args2.push("--dangerously-bypass-approvals-and-sandbox");
2994
+ args.push("--dangerously-bypass-approvals-and-sandbox");
2995
2995
  break;
2996
2996
  }
2997
2997
  if (!isResume && opts.cwd) {
2998
- args2.push("-C", opts.cwd);
2998
+ args.push("-C", opts.cwd);
2999
2999
  }
3000
3000
  return {
3001
3001
  executable: this.getExecutablePath(),
3002
- args: args2,
3002
+ args,
3003
3003
  // For resume, pass cwd via spawn option since -C isn't supported
3004
3004
  cwd: isResume ? opts.cwd : void 0
3005
3005
  };
@@ -4130,8 +4130,8 @@ function spawnAgentProcess(runner, opts, callbacks) {
4130
4130
  permMode: opts.permMode,
4131
4131
  allowedTools: opts.allowedTools
4132
4132
  });
4133
- const args2 = opts.extraArgs?.length ? [...baseArgs, ...opts.extraArgs] : baseArgs;
4134
- const child = spawn2(runner.getExecutablePath(), args2, {
4133
+ const args = opts.extraArgs?.length ? [...baseArgs, ...opts.extraArgs] : baseArgs;
4134
+ const child = spawn2(runner.getExecutablePath(), args, {
4135
4135
  env: buildSpawnEnv(runner, opts.isSubAgent),
4136
4136
  cwd: opts.cwd,
4137
4137
  stdio: ["ignore", "pipe", "pipe"],
@@ -4252,8 +4252,8 @@ async function discoverExistingMcps(runner) {
4252
4252
  try {
4253
4253
  const listCmd = runner.getMcpListCommand();
4254
4254
  const exe = runner.getExecutablePath();
4255
- const args2 = listCmd.slice(1);
4256
- const result = await execFileAsync(exe, args2, {
4255
+ const args = listCmd.slice(1);
4256
+ const result = await execFileAsync(exe, args, {
4257
4257
  encoding: "utf-8",
4258
4258
  env: runner.getEnv(),
4259
4259
  cwd: homedir3(),
@@ -4301,8 +4301,8 @@ async function injectMcps(runner, mcpNames, db3, scope) {
4301
4301
  try {
4302
4302
  const config2 = defToConfig(def);
4303
4303
  const addCmd = runner.getMcpAddCommand(config2);
4304
- const args2 = addCmd.slice(1);
4305
- await execFileAsync(exe, args2, { encoding: "utf-8" });
4304
+ const args = addCmd.slice(1);
4305
+ await execFileAsync(exe, args, { encoding: "utf-8" });
4306
4306
  addPropagation(db3, name, runnerId, scope);
4307
4307
  added.push(name);
4308
4308
  } catch {
@@ -4316,8 +4316,8 @@ async function cleanupMcps(runner, mcps2, db3, scope) {
4316
4316
  for (const name of mcps2) {
4317
4317
  try {
4318
4318
  const removeCmd = runner.getMcpRemoveCommand(name);
4319
- const args2 = removeCmd.slice(1);
4320
- await execFileAsync(exe, args2, { encoding: "utf-8" });
4319
+ const args = removeCmd.slice(1);
4320
+ await execFileAsync(exe, args, { encoding: "utf-8" });
4321
4321
  } catch {
4322
4322
  }
4323
4323
  removePropagation(db3, name, runnerId, scope);
@@ -4673,8 +4673,8 @@ async function startAgent(agentId, chatId, opts) {
4673
4673
  const addCmd = runner.getMcpAddCommand(mcpConfig);
4674
4674
  const { execFileSync: execFileSync5 } = await import("child_process");
4675
4675
  const exe = addCmd[0];
4676
- const args2 = addCmd.slice(1);
4677
- execFileSync5(exe, args2, { encoding: "utf-8", timeout: 15e3, env: runner.getEnv() });
4676
+ const args = addCmd.slice(1);
4677
+ execFileSync5(exe, args, { encoding: "utf-8", timeout: 15e3, env: runner.getEnv() });
4678
4678
  });
4679
4679
  mcpsAdded = [...mcpsAdded, orchestratorMcpName];
4680
4680
  updateAgentMcpsAdded(db3, agentId, mcpsAdded);
@@ -5177,13 +5177,13 @@ __export(health_exports, {
5177
5177
  stopHealthMonitor: () => stopHealthMonitor
5178
5178
  });
5179
5179
  import { spawn as spawn3 } from "child_process";
5180
- async function checkStdioHealth(command, args2) {
5180
+ async function checkStdioHealth(command, args) {
5181
5181
  return new Promise((resolve) => {
5182
5182
  const timer = setTimeout(() => {
5183
5183
  child.kill("SIGKILL");
5184
5184
  resolve("timeout");
5185
5185
  }, CHECK_TIMEOUT_MS);
5186
- const child = spawn3(command, args2, {
5186
+ const child = spawn3(command, args, {
5187
5187
  stdio: ["pipe", "pipe", "pipe"]
5188
5188
  });
5189
5189
  let responded = false;
@@ -5238,8 +5238,8 @@ async function runHealthChecks(db3) {
5238
5238
  let status = "unhealthy";
5239
5239
  try {
5240
5240
  if (mcp.transport === "stdio" && mcp.command) {
5241
- const args2 = mcp.args ? JSON.parse(mcp.args) : [];
5242
- status = await checkStdioHealth(mcp.command, args2);
5241
+ const args = mcp.args ? JSON.parse(mcp.args) : [];
5242
+ status = await checkStdioHealth(mcp.command, args);
5243
5243
  } else if ((mcp.transport === "sse" || mcp.transport === "streamable-http") && mcp.url) {
5244
5244
  status = await checkHttpHealth(mcp.url);
5245
5245
  } else {
@@ -6480,10 +6480,10 @@ function getMcpConfigPath(chatId) {
6480
6480
  const config2 = generateOrchestratorMcpConfig({ chatId, agentId: "main", token });
6481
6481
  return writeMcpConfigFile(config2);
6482
6482
  }
6483
- function injectMcpConfig(adapterId, args2, mcpConfigPath) {
6483
+ function injectMcpConfig(adapterId, args, mcpConfigPath) {
6484
6484
  const flag = MCP_CONFIG_FLAG[adapterId];
6485
- if (!flag) return args2;
6486
- return [...args2, ...flag, mcpConfigPath];
6485
+ if (!flag) return args;
6486
+ return [...args, ...flag, mcpConfigPath];
6487
6487
  }
6488
6488
  var activeChats, chatLocks, SPAWN_TIMEOUT_MS, MCP_CONFIG_FLAG;
6489
6489
  var init_agent = __esm({
@@ -7187,17 +7187,17 @@ function wrapBackendAdapter(adapter) {
7187
7187
  if (method !== "config-file") return [];
7188
7188
  if (adapter.id === "codex") {
7189
7189
  const safeName = server.name.replace(/[^a-zA-Z0-9_-]/g, "_");
7190
- const args2 = [];
7191
- args2.push("-c", `mcp_servers.${safeName}.command="${server.command}"`);
7190
+ const args = [];
7191
+ args.push("-c", `mcp_servers.${safeName}.command="${server.command}"`);
7192
7192
  if (server.args?.length) {
7193
- args2.push("-c", `mcp_servers.${safeName}.args=${JSON.stringify(server.args)}`);
7193
+ args.push("-c", `mcp_servers.${safeName}.args=${JSON.stringify(server.args)}`);
7194
7194
  }
7195
7195
  if (server.env) {
7196
7196
  for (const [k, v] of Object.entries(server.env)) {
7197
- args2.push("-c", `mcp_servers.${safeName}.env.${k}="${v}"`);
7197
+ args.push("-c", `mcp_servers.${safeName}.env.${k}="${v}"`);
7198
7198
  }
7199
7199
  }
7200
- return args2;
7200
+ return args;
7201
7201
  }
7202
7202
  const configPath = writeMcpConfigFile(server);
7203
7203
  return ["--mcp-config", configPath];
@@ -7316,8 +7316,8 @@ function buildGenericParser(config2) {
7316
7316
  return events;
7317
7317
  };
7318
7318
  }
7319
- function templateReplace(args2, vars) {
7320
- return args2.map((a) => {
7319
+ function templateReplace(args, vars) {
7320
+ return args.map((a) => {
7321
7321
  let result = a;
7322
7322
  for (const [key, val] of Object.entries(vars)) {
7323
7323
  result = result.replace(`{${key}}`, val);
@@ -7343,23 +7343,23 @@ function configToRunner(config2) {
7343
7343
  getExecutablePath: () => exePath,
7344
7344
  getEnv: () => buildBaseEnv(config2.env),
7345
7345
  buildSpawnArgs(opts) {
7346
- const args2 = [];
7347
- if (config2.spawnPattern.extraArgs) args2.push(...config2.spawnPattern.extraArgs);
7348
- if (config2.spawnPattern.outputFormatFlag) args2.push(...config2.spawnPattern.outputFormatFlag);
7349
- args2.push(...config2.spawnPattern.promptFlag, opts.prompt);
7346
+ const args = [];
7347
+ if (config2.spawnPattern.extraArgs) args.push(...config2.spawnPattern.extraArgs);
7348
+ if (config2.spawnPattern.outputFormatFlag) args.push(...config2.spawnPattern.outputFormatFlag);
7349
+ args.push(...config2.spawnPattern.promptFlag, opts.prompt);
7350
7350
  if (opts.model && config2.spawnPattern.modelFlag) {
7351
- args2.push(...config2.spawnPattern.modelFlag, opts.model);
7351
+ args.push(...config2.spawnPattern.modelFlag, opts.model);
7352
7352
  }
7353
7353
  if (opts.cwd && config2.spawnPattern.cwdFlag) {
7354
- args2.push(...config2.spawnPattern.cwdFlag, opts.cwd);
7354
+ args.push(...config2.spawnPattern.cwdFlag, opts.cwd);
7355
7355
  }
7356
7356
  if (opts.sessionId && config2.spawnPattern.sessionResumeFlag) {
7357
- args2.push(...config2.spawnPattern.sessionResumeFlag, opts.sessionId);
7357
+ args.push(...config2.spawnPattern.sessionResumeFlag, opts.sessionId);
7358
7358
  }
7359
7359
  if (opts.permMode && config2.spawnPattern.permModes?.[opts.permMode]) {
7360
- args2.push(...config2.spawnPattern.permModes[opts.permMode]);
7360
+ args.push(...config2.spawnPattern.permModes[opts.permMode]);
7361
7361
  }
7362
- return args2;
7362
+ return args;
7363
7363
  },
7364
7364
  parseLine,
7365
7365
  shouldKillOnResult: () => config2.shouldKillOnResult,
@@ -8642,8 +8642,8 @@ function formatHeartbeatStatus(chatId) {
8642
8642
  }
8643
8643
  return lines.join("\n");
8644
8644
  }
8645
- function parseHeartbeatCommand(chatId, args2) {
8646
- const parts = args2.trim().toLowerCase().split(/\s+/);
8645
+ function parseHeartbeatCommand(chatId, args) {
8646
+ const parts = args.trim().toLowerCase().split(/\s+/);
8647
8647
  return { action: parts[0] ?? "status", value: parts.slice(1).join(" ") };
8648
8648
  }
8649
8649
  var HEARTBEAT_MD_PATH, HEARTBEAT_OK, registry2, activeTimers2;
@@ -8702,6 +8702,9 @@ var init_format_time = __esm({
8702
8702
  });
8703
8703
 
8704
8704
  // src/intent/classify.ts
8705
+ function getIntentStats() {
8706
+ return { ...intentCounts };
8707
+ }
8705
8708
  function classifyIntent(text, chatId) {
8706
8709
  const trimmed = text.trim();
8707
8710
  if (trimmed.startsWith(">>")) return "agentic";
@@ -8710,6 +8713,7 @@ function classifyIntent(text, chatId) {
8710
8713
  for (const pattern of AGENTIC_PATTERNS) {
8711
8714
  if (pattern.test(trimmed)) {
8712
8715
  log(`[intent] "${trimmed.slice(0, 30)}..." -> agentic (pattern: ${pattern})`);
8716
+ intentCounts.agentic++;
8713
8717
  return "agentic";
8714
8718
  }
8715
8719
  }
@@ -8721,6 +8725,7 @@ function classifyIntent(text, chatId) {
8721
8725
  if (elapsed < 12e4) {
8722
8726
  if (trimmed.length < 30) {
8723
8727
  log(`[intent] "${trimmed.slice(0, 30)}" -> agentic (active session, ${(elapsed / 1e3).toFixed(0)}s ago)`);
8728
+ intentCounts.agentic++;
8724
8729
  return "agentic";
8725
8730
  }
8726
8731
  }
@@ -8728,22 +8733,26 @@ function classifyIntent(text, chatId) {
8728
8733
  }
8729
8734
  if (CHAT_EXACT.has(lower)) {
8730
8735
  log(`[intent] "${lower}" -> chat (exact match)`);
8736
+ intentCounts.chat++;
8731
8737
  return "chat";
8732
8738
  }
8733
8739
  if (trimmed.length <= 4 && /^[\p{Emoji}\s]+$/u.test(trimmed)) {
8734
8740
  log(`[intent] "${trimmed}" -> chat (emoji-only)`);
8741
+ intentCounts.chat++;
8735
8742
  return "chat";
8736
8743
  }
8737
8744
  log(`[intent] "${trimmed.slice(0, 30)}..." -> agentic (default)`);
8745
+ intentCounts.agentic++;
8738
8746
  return "agentic";
8739
8747
  }
8740
- var CHAT_EXACT, AGENTIC_PATTERNS;
8748
+ var intentCounts, CHAT_EXACT, AGENTIC_PATTERNS;
8741
8749
  var init_classify = __esm({
8742
8750
  "src/intent/classify.ts"() {
8743
8751
  "use strict";
8744
8752
  init_store4();
8745
8753
  init_session_log();
8746
8754
  init_log();
8755
+ intentCounts = { chat: 0, agentic: 0 };
8747
8756
  CHAT_EXACT = /* @__PURE__ */ new Set([
8748
8757
  "hey",
8749
8758
  "hi",
@@ -9991,6 +10000,10 @@ function formatModelShort(modelId) {
9991
10000
  };
9992
10001
  return MAP[modelId] ?? modelId;
9993
10002
  }
10003
+ function buildBar(pct) {
10004
+ const filled = Math.round(Math.min(100, Math.max(0, pct)) / 100 * 8);
10005
+ return "\u2593".repeat(filled) + "\u2591".repeat(8 - filled);
10006
+ }
9994
10007
  function capitalize(s) {
9995
10008
  if (s === "extra_high") return "xHigh";
9996
10009
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -10204,32 +10217,58 @@ Tap to toggle:`,
10204
10217
  const voice2 = isVoiceEnabled(chatId);
10205
10218
  const usage2 = getUsage(chatId);
10206
10219
  const thinking2 = getThinkingLevel(chatId);
10207
- const summ = getSummarizer(chatId);
10208
- const summLabel = summ.backend === "off" ? "off" : summ.backend ? `${summ.backend}:${summ.model ?? "default"} (pinned)` : `auto (${adapter?.summarizerModel ?? "default"})`;
10220
+ const mode = getMode(chatId);
10221
+ const modelSig = getModelSignature(chatId);
10209
10222
  const contextMax = adapter?.contextWindow[model2] ?? 2e5;
10210
10223
  const contextUsed = usage2.last_input_tokens + usage2.last_cache_read_tokens;
10211
- const contextPct = contextMax > 0 ? (contextUsed / contextMax * 100).toFixed(1) : "0.0";
10224
+ const contextPct = contextMax > 0 ? contextUsed / contextMax * 100 : 0;
10225
+ const ctxBar = buildBar(contextPct);
10212
10226
  const usedK = (contextUsed / 1e3).toFixed(1);
10213
10227
  const maxK = (contextMax / 1e3).toFixed(0);
10214
- const contextLine = contextUsed > 0 ? `Context: ${usedK}K / ${maxK}K (${contextPct}%)` : `Context: ${maxK}K max (no requests yet)`;
10228
+ const bootRow = getDb().prepare("SELECT value FROM meta WHERE key = 'boot_time'").get();
10229
+ let uptimeStr = "unknown";
10230
+ if (bootRow) {
10231
+ const bootMs = (/* @__PURE__ */ new Date(bootRow.value + "Z")).getTime();
10232
+ const sec = Math.floor((Date.now() - bootMs) / 1e3);
10233
+ uptimeStr = sec < 60 ? `${sec}s` : sec < 3600 ? `${Math.floor(sec / 60)}m` : sec < 86400 ? `${Math.floor(sec / 3600)}h ${Math.floor(sec % 3600 / 60)}m` : `${Math.floor(sec / 86400)}d ${Math.floor(sec % 86400 / 3600)}h`;
10234
+ }
10235
+ let limitsLine = "";
10236
+ if (adapter) {
10237
+ const limits2 = getAllBackendLimits().filter((l) => l.backend === adapter.id);
10238
+ for (const lim of limits2) {
10239
+ if (!lim.max_input_tokens) continue;
10240
+ const u = getBackendUsageInWindow(adapter.id, lim.window);
10241
+ const pct = u.input_tokens / lim.max_input_tokens * 100;
10242
+ const remaining = Math.max(0, lim.max_input_tokens - u.input_tokens);
10243
+ const remK = (remaining / 1e3).toFixed(0);
10244
+ limitsLine += `
10245
+ \u{1F4CA} ${lim.window}: ${buildBar(pct)} ${pct.toFixed(0)}% used \xB7 ${remK}K left`;
10246
+ }
10247
+ }
10248
+ const iStats = getIntentStats();
10249
+ const iTotal = iStats.chat + iStats.agentic;
10250
+ const intentLine = iTotal > 0 ? `\u26A1 ${iStats.chat} chat \xB7 ${iStats.agentic} agentic (${(iStats.chat / iTotal * 100).toFixed(0)}% fast-path)` : `\u26A1 No messages classified yet`;
10215
10251
  const lines = [
10216
- "CC-Claw Status",
10217
- "",
10218
- `Backend: ${adapter?.displayName ?? backendId ?? "not set"}`,
10219
- `Model: ${model2}`,
10220
- `Thinking: ${thinking2}`,
10221
- `Summarizer: ${summLabel}`,
10222
- `Mode: ${getMode(chatId)}`,
10223
- contextLine,
10224
- `Session: ${sessionId ? `active (${sessionId.slice(0, 8)}...)` : "none"}`,
10225
- `CWD: ${cwd ?? "not set"}`,
10226
- `Voice: ${voice2 ? "on" : "off"}`,
10227
- "",
10228
- `Usage this chat:`,
10229
- ` Requests: ${usage2.request_count}`,
10230
- ` In tokens: ${usage2.input_tokens.toLocaleString()}`,
10231
- ` Out tokens: ${usage2.output_tokens.toLocaleString()}`,
10232
- ` Cache read: ${usage2.cache_read_tokens.toLocaleString()}`
10252
+ `\u{1F43E} CC-Claw v${VERSION}`,
10253
+ `\u23F1 Uptime: ${uptimeStr}`,
10254
+ ``,
10255
+ `\u2501\u2501 Engine \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
10256
+ `\u{1F9E0} ${adapter?.displayName ?? backendId ?? "not set"} \xB7 ${formatModelShort(model2)}`,
10257
+ `\u{1F4AD} Think: ${thinking2} \xB7 Mode: ${mode}`,
10258
+ `\u{1F507} Voice: ${voice2 ? "on" : "off"} \xB7 Sig: ${modelSig}`,
10259
+ ``,
10260
+ `\u2501\u2501 Session \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
10261
+ `\u{1F4CB} ${sessionId ? sessionId.slice(0, 12) + "..." : "no active session"}`,
10262
+ `\u{1F4C1} ${cwd ?? "default workspace"}`,
10263
+ `\u{1F4D0} Context: ${ctxBar} ${usedK}K/${maxK}K (${contextPct.toFixed(1)}%)`,
10264
+ ``,
10265
+ `\u2501\u2501 Usage \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
10266
+ `\u{1F4E8} ${usage2.request_count} requests \xB7 ${(usage2.input_tokens / 1e3).toFixed(0)}K in \xB7 ${(usage2.output_tokens / 1e3).toFixed(0)}K out`,
10267
+ `\u{1F4BE} ${(usage2.cache_read_tokens / 1e3).toFixed(0)}K cached`,
10268
+ ...limitsLine ? [limitsLine] : [],
10269
+ ``,
10270
+ `\u2501\u2501 Intelligence \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
10271
+ intentLine
10233
10272
  ];
10234
10273
  await channel.sendText(chatId, lines.join("\n"), "plain");
10235
10274
  break;
@@ -10602,13 +10641,19 @@ ${lines.join("\n")}`, "plain");
10602
10641
  }
10603
10642
  case "model_signature": {
10604
10643
  const currentSig = getModelSignature(chatId);
10605
- const newSig = currentSig === "on" ? "off" : "on";
10606
- setModelSignature(chatId, newSig);
10607
- await channel.sendText(
10608
- chatId,
10609
- newSig === "on" ? "\u{1F9E0} Model signature enabled. Each response will show the active model and thinking level." : "Model signature disabled.",
10610
- "plain"
10611
- );
10644
+ if (typeof channel.sendKeyboard === "function") {
10645
+ await channel.sendKeyboard(chatId, `Model Signature: ${currentSig === "on" ? "ON" : "OFF"}
10646
+ Appends model + thinking level to each response.`, [
10647
+ [
10648
+ { label: currentSig === "on" ? "\u2713 On" : "On", data: "model_sig:on" },
10649
+ { label: currentSig !== "on" ? "\u2713 Off" : "Off", data: "model_sig:off" }
10650
+ ]
10651
+ ]);
10652
+ } else {
10653
+ const newSig = currentSig === "on" ? "off" : "on";
10654
+ setModelSignature(chatId, newSig);
10655
+ await channel.sendText(chatId, newSig === "on" ? "Model signature enabled." : "Model signature disabled.", "plain");
10656
+ }
10612
10657
  break;
10613
10658
  }
10614
10659
  case "imagine":
@@ -11251,7 +11296,7 @@ Use /skills to see it.`, "plain");
11251
11296
  break;
11252
11297
  }
11253
11298
  case "intent": {
11254
- const testMsg = args.join(" ") || "hey";
11299
+ const testMsg = commandArgs?.trim() || "hey";
11255
11300
  const result = classifyIntent(testMsg, chatId);
11256
11301
  await channel.sendText(chatId, `Intent: ${result}
11257
11302
  Message: "${testMsg}"`, "plain");
@@ -12086,6 +12131,14 @@ ${PERM_MODES[chosen]}`,
12086
12131
  }
12087
12132
  await channel.sendText(chatId, `Response style set to: ${selectedStyle}`, "plain");
12088
12133
  }
12134
+ } else if (data.startsWith("model_sig:")) {
12135
+ const value = data.slice(10);
12136
+ setModelSignature(chatId, value);
12137
+ await channel.sendText(
12138
+ chatId,
12139
+ value === "on" ? "\u{1F9E0} Model signature enabled. Each response will show the active model and thinking level." : "Model signature disabled.",
12140
+ "plain"
12141
+ );
12089
12142
  } else if (data.startsWith("vcfg:")) {
12090
12143
  const parts = data.slice(5).split(":");
12091
12144
  const action = parts[0];
@@ -12341,6 +12394,7 @@ var init_router = __esm({
12341
12394
  init_agent();
12342
12395
  init_retry();
12343
12396
  init_classify();
12397
+ init_version();
12344
12398
  init_image_gen();
12345
12399
  init_stt();
12346
12400
  init_store4();
@@ -13312,6 +13366,106 @@ var init_index = __esm({
13312
13366
  }
13313
13367
  });
13314
13368
 
13369
+ // src/cli/api-client.ts
13370
+ var api_client_exports = {};
13371
+ __export(api_client_exports, {
13372
+ apiGet: () => apiGet,
13373
+ apiPost: () => apiPost,
13374
+ isDaemonRunning: () => isDaemonRunning
13375
+ });
13376
+ import { readFileSync as readFileSync11, existsSync as existsSync17 } from "fs";
13377
+ import { request as httpRequest } from "http";
13378
+ function getToken() {
13379
+ if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
13380
+ try {
13381
+ if (existsSync17(TOKEN_PATH)) return readFileSync11(TOKEN_PATH, "utf-8").trim();
13382
+ } catch {
13383
+ }
13384
+ return null;
13385
+ }
13386
+ async function isDaemonRunning() {
13387
+ try {
13388
+ const res = await apiGet("/api/health");
13389
+ return res.ok;
13390
+ } catch {
13391
+ return false;
13392
+ }
13393
+ }
13394
+ async function apiGet(path) {
13395
+ const token = getToken();
13396
+ return new Promise((resolve, reject) => {
13397
+ const url = new URL(path, BASE_URL);
13398
+ const req = httpRequest(url, {
13399
+ method: "GET",
13400
+ headers: token ? { "Authorization": `Bearer ${token}` } : {},
13401
+ timeout: 3e3
13402
+ }, (res) => {
13403
+ const chunks = [];
13404
+ res.on("data", (c) => chunks.push(c));
13405
+ res.on("end", () => {
13406
+ const body = Buffer.concat(chunks).toString();
13407
+ try {
13408
+ const data = JSON.parse(body);
13409
+ resolve({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
13410
+ } catch {
13411
+ resolve({ ok: false, status: res.statusCode ?? 0, data: body });
13412
+ }
13413
+ });
13414
+ });
13415
+ req.on("error", reject);
13416
+ req.on("timeout", () => {
13417
+ req.destroy();
13418
+ reject(new Error("Request timed out"));
13419
+ });
13420
+ req.end();
13421
+ });
13422
+ }
13423
+ async function apiPost(path, body) {
13424
+ const token = getToken();
13425
+ const payload = JSON.stringify(body);
13426
+ return new Promise((resolve, reject) => {
13427
+ const url = new URL(path, BASE_URL);
13428
+ const req = httpRequest(url, {
13429
+ method: "POST",
13430
+ headers: {
13431
+ "Content-Type": "application/json",
13432
+ "Content-Length": Buffer.byteLength(payload).toString(),
13433
+ ...token ? { "Authorization": `Bearer ${token}` } : {}
13434
+ },
13435
+ timeout: 3e4
13436
+ }, (res) => {
13437
+ const chunks = [];
13438
+ res.on("data", (c) => chunks.push(c));
13439
+ res.on("end", () => {
13440
+ const responseBody = Buffer.concat(chunks).toString();
13441
+ try {
13442
+ const data = JSON.parse(responseBody);
13443
+ resolve({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
13444
+ } catch {
13445
+ resolve({ ok: false, status: res.statusCode ?? 0, data: responseBody });
13446
+ }
13447
+ });
13448
+ });
13449
+ req.on("error", reject);
13450
+ req.on("timeout", () => {
13451
+ req.destroy();
13452
+ reject(new Error("Request timed out"));
13453
+ });
13454
+ req.write(payload);
13455
+ req.end();
13456
+ });
13457
+ }
13458
+ var TOKEN_PATH, DEFAULT_PORT, BASE_URL;
13459
+ var init_api_client = __esm({
13460
+ "src/cli/api-client.ts"() {
13461
+ "use strict";
13462
+ init_paths();
13463
+ TOKEN_PATH = `${DATA_PATH}/api-token`;
13464
+ DEFAULT_PORT = parseInt(process.env.DASHBOARD_PORT ?? "3141", 10);
13465
+ BASE_URL = `http://127.0.0.1:${DEFAULT_PORT}`;
13466
+ }
13467
+ });
13468
+
13315
13469
  // src/service.ts
13316
13470
  var service_exports = {};
13317
13471
  __export(service_exports, {
@@ -13319,7 +13473,7 @@ __export(service_exports, {
13319
13473
  serviceStatus: () => serviceStatus,
13320
13474
  uninstallService: () => uninstallService
13321
13475
  });
13322
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3 } from "fs";
13476
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3 } from "fs";
13323
13477
  import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
13324
13478
  import { homedir as homedir6, platform } from "os";
13325
13479
  import { join as join19, dirname as dirname3 } from "path";
@@ -13397,9 +13551,9 @@ function generatePlist() {
13397
13551
  }
13398
13552
  function installMacOS() {
13399
13553
  const agentsDir = dirname3(PLIST_PATH);
13400
- if (!existsSync17(agentsDir)) mkdirSync8(agentsDir, { recursive: true });
13401
- if (!existsSync17(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
13402
- if (existsSync17(PLIST_PATH)) {
13554
+ if (!existsSync18(agentsDir)) mkdirSync8(agentsDir, { recursive: true });
13555
+ if (!existsSync18(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
13556
+ if (existsSync18(PLIST_PATH)) {
13403
13557
  try {
13404
13558
  execFileSync2("launchctl", ["unload", PLIST_PATH]);
13405
13559
  } catch {
@@ -13411,7 +13565,7 @@ function installMacOS() {
13411
13565
  console.log(" Service loaded and starting.");
13412
13566
  }
13413
13567
  function uninstallMacOS() {
13414
- if (!existsSync17(PLIST_PATH)) {
13568
+ if (!existsSync18(PLIST_PATH)) {
13415
13569
  console.log(" No service found to uninstall.");
13416
13570
  return;
13417
13571
  }
@@ -13422,6 +13576,24 @@ function uninstallMacOS() {
13422
13576
  unlinkSync3(PLIST_PATH);
13423
13577
  console.log(" Service uninstalled.");
13424
13578
  }
13579
+ function formatUptime(seconds) {
13580
+ seconds = Math.floor(seconds);
13581
+ if (seconds < 60) return `${seconds}s`;
13582
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
13583
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
13584
+ return `${Math.floor(seconds / 86400)}d ${Math.floor(seconds % 86400 / 3600)}h`;
13585
+ }
13586
+ async function getUptimeFromDaemon() {
13587
+ try {
13588
+ const { isDaemonRunning: isDaemonRunning2, apiGet: apiGet2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
13589
+ if (!await isDaemonRunning2()) return null;
13590
+ const res = await apiGet2("/api/health");
13591
+ const sec = res.data?.uptime;
13592
+ return sec ? formatUptime(sec) : null;
13593
+ } catch {
13594
+ return null;
13595
+ }
13596
+ }
13425
13597
  function statusMacOS() {
13426
13598
  try {
13427
13599
  const out = execSync5("launchctl list | grep cc-claw", { shell: "/bin/sh", encoding: "utf-8" }).trim();
@@ -13430,7 +13602,12 @@ function statusMacOS() {
13430
13602
  const pid = parts[0];
13431
13603
  const exitCode = parts[1];
13432
13604
  if (pid !== "-") {
13433
- console.log(` Running (PID ${pid})`);
13605
+ getUptimeFromDaemon().then((uptime) => {
13606
+ const uptimeStr = uptime ? `, uptime ${uptime}` : "";
13607
+ console.log(` Running (PID ${pid}${uptimeStr})`);
13608
+ }).catch(() => {
13609
+ console.log(` Running (PID ${pid})`);
13610
+ });
13434
13611
  } else {
13435
13612
  console.log(` Not running (last exit code: ${exitCode})`);
13436
13613
  }
@@ -13462,8 +13639,8 @@ WantedBy=default.target
13462
13639
  `;
13463
13640
  }
13464
13641
  function installLinux() {
13465
- if (!existsSync17(SYSTEMD_DIR)) mkdirSync8(SYSTEMD_DIR, { recursive: true });
13466
- if (!existsSync17(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
13642
+ if (!existsSync18(SYSTEMD_DIR)) mkdirSync8(SYSTEMD_DIR, { recursive: true });
13643
+ if (!existsSync18(LOGS_PATH)) mkdirSync8(LOGS_PATH, { recursive: true });
13467
13644
  writeFileSync6(UNIT_PATH, generateUnit());
13468
13645
  console.log(` Installed: ${UNIT_PATH}`);
13469
13646
  execFileSync2("systemctl", ["--user", "daemon-reload"]);
@@ -13472,7 +13649,7 @@ function installLinux() {
13472
13649
  console.log(" Service enabled and started.");
13473
13650
  }
13474
13651
  function uninstallLinux() {
13475
- if (!existsSync17(UNIT_PATH)) {
13652
+ if (!existsSync18(UNIT_PATH)) {
13476
13653
  console.log(" No service found to uninstall.");
13477
13654
  return;
13478
13655
  }
@@ -13497,7 +13674,7 @@ function statusLinux() {
13497
13674
  }
13498
13675
  }
13499
13676
  function installService() {
13500
- if (!existsSync17(join19(CC_CLAW_HOME, ".env"))) {
13677
+ if (!existsSync18(join19(CC_CLAW_HOME, ".env"))) {
13501
13678
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
13502
13679
  console.error(" Run 'cc-claw setup' before installing the service.");
13503
13680
  process.exitCode = 1;
@@ -13695,13 +13872,13 @@ var init_daemon = __esm({
13695
13872
  });
13696
13873
 
13697
13874
  // src/cli/resolve-chat.ts
13698
- import { readFileSync as readFileSync12 } from "fs";
13875
+ import { readFileSync as readFileSync13 } from "fs";
13699
13876
  function resolveChatId(globalOpts) {
13700
13877
  const explicit = globalOpts.chat;
13701
13878
  if (explicit) return explicit;
13702
13879
  if (_cachedDefault) return _cachedDefault;
13703
13880
  try {
13704
- const content = readFileSync12(ENV_PATH, "utf-8");
13881
+ const content = readFileSync13(ENV_PATH, "utf-8");
13705
13882
  const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
13706
13883
  if (match) {
13707
13884
  _cachedDefault = match[1].split(",")[0].trim();
@@ -13720,106 +13897,6 @@ var init_resolve_chat = __esm({
13720
13897
  }
13721
13898
  });
13722
13899
 
13723
- // src/cli/api-client.ts
13724
- var api_client_exports = {};
13725
- __export(api_client_exports, {
13726
- apiGet: () => apiGet,
13727
- apiPost: () => apiPost,
13728
- isDaemonRunning: () => isDaemonRunning
13729
- });
13730
- import { readFileSync as readFileSync13, existsSync as existsSync18 } from "fs";
13731
- import { request as httpRequest } from "http";
13732
- function getToken() {
13733
- if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
13734
- try {
13735
- if (existsSync18(TOKEN_PATH)) return readFileSync13(TOKEN_PATH, "utf-8").trim();
13736
- } catch {
13737
- }
13738
- return null;
13739
- }
13740
- async function isDaemonRunning() {
13741
- try {
13742
- const res = await apiGet("/api/health");
13743
- return res.ok;
13744
- } catch {
13745
- return false;
13746
- }
13747
- }
13748
- async function apiGet(path) {
13749
- const token = getToken();
13750
- return new Promise((resolve, reject) => {
13751
- const url = new URL(path, BASE_URL);
13752
- const req = httpRequest(url, {
13753
- method: "GET",
13754
- headers: token ? { "Authorization": `Bearer ${token}` } : {},
13755
- timeout: 3e3
13756
- }, (res) => {
13757
- const chunks = [];
13758
- res.on("data", (c) => chunks.push(c));
13759
- res.on("end", () => {
13760
- const body = Buffer.concat(chunks).toString();
13761
- try {
13762
- const data = JSON.parse(body);
13763
- resolve({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
13764
- } catch {
13765
- resolve({ ok: false, status: res.statusCode ?? 0, data: body });
13766
- }
13767
- });
13768
- });
13769
- req.on("error", reject);
13770
- req.on("timeout", () => {
13771
- req.destroy();
13772
- reject(new Error("Request timed out"));
13773
- });
13774
- req.end();
13775
- });
13776
- }
13777
- async function apiPost(path, body) {
13778
- const token = getToken();
13779
- const payload = JSON.stringify(body);
13780
- return new Promise((resolve, reject) => {
13781
- const url = new URL(path, BASE_URL);
13782
- const req = httpRequest(url, {
13783
- method: "POST",
13784
- headers: {
13785
- "Content-Type": "application/json",
13786
- "Content-Length": Buffer.byteLength(payload).toString(),
13787
- ...token ? { "Authorization": `Bearer ${token}` } : {}
13788
- },
13789
- timeout: 3e4
13790
- }, (res) => {
13791
- const chunks = [];
13792
- res.on("data", (c) => chunks.push(c));
13793
- res.on("end", () => {
13794
- const responseBody = Buffer.concat(chunks).toString();
13795
- try {
13796
- const data = JSON.parse(responseBody);
13797
- resolve({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
13798
- } catch {
13799
- resolve({ ok: false, status: res.statusCode ?? 0, data: responseBody });
13800
- }
13801
- });
13802
- });
13803
- req.on("error", reject);
13804
- req.on("timeout", () => {
13805
- req.destroy();
13806
- reject(new Error("Request timed out"));
13807
- });
13808
- req.write(payload);
13809
- req.end();
13810
- });
13811
- }
13812
- var TOKEN_PATH, DEFAULT_PORT, BASE_URL;
13813
- var init_api_client = __esm({
13814
- "src/cli/api-client.ts"() {
13815
- "use strict";
13816
- init_paths();
13817
- TOKEN_PATH = `${DATA_PATH}/api-token`;
13818
- DEFAULT_PORT = parseInt(process.env.DASHBOARD_PORT ?? "3141", 10);
13819
- BASE_URL = `http://127.0.0.1:${DEFAULT_PORT}`;
13820
- }
13821
- });
13822
-
13823
13900
  // src/cli/commands/status.ts
13824
13901
  var status_exports = {};
13825
13902
  __export(status_exports, {
@@ -13917,7 +13994,7 @@ async function statusCommand(globalOpts, localOpts) {
13917
13994
  kvLine("Voice", s.voice ? success("on") : muted("off"))
13918
13995
  ];
13919
13996
  if (localOpts.deep) {
13920
- lines.push(kvLine("Daemon", s.daemon.running ? success(`running${s.daemon.uptime_seconds ? ` (uptime ${formatUptime(s.daemon.uptime_seconds)})` : ""}`) : error2("offline")));
13997
+ lines.push(kvLine("Daemon", s.daemon.running ? success(`running${s.daemon.uptime_seconds ? ` (uptime ${formatUptime2(s.daemon.uptime_seconds)})` : ""}`) : error2("offline")));
13921
13998
  }
13922
13999
  lines.push(
13923
14000
  "",
@@ -13935,7 +14012,7 @@ async function statusCommand(globalOpts, localOpts) {
13935
14012
  process.exit(1);
13936
14013
  }
13937
14014
  }
13938
- function formatUptime(seconds) {
14015
+ function formatUptime2(seconds) {
13939
14016
  if (seconds < 60) return `${seconds}s`;
13940
14017
  if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
13941
14018
  if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
@@ -14007,10 +14084,12 @@ async function doctorCommand(globalOpts, localOpts) {
14007
14084
  const { isDaemonRunning: isDaemonRunning2, apiGet: apiGet2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
14008
14085
  const running = await isDaemonRunning2();
14009
14086
  if (running) {
14010
- checks.push({ name: "Daemon", status: "ok", message: "running" });
14011
14087
  try {
14012
14088
  const health = await apiGet2("/api/health");
14013
14089
  const daemonVersion = health.data?.version;
14090
+ const uptimeSec = health.data?.uptime;
14091
+ const uptimeStr = uptimeSec ? ` (uptime ${formatUptime3(uptimeSec)})` : "";
14092
+ checks.push({ name: "Daemon", status: "ok", message: `running${uptimeStr}` });
14014
14093
  if (daemonVersion && daemonVersion !== VERSION) {
14015
14094
  checks.push({
14016
14095
  name: "Version",
@@ -14022,6 +14101,7 @@ async function doctorCommand(globalOpts, localOpts) {
14022
14101
  checks.push({ name: "Version", status: "ok", message: `v${VERSION}` });
14023
14102
  }
14024
14103
  } catch {
14104
+ checks.push({ name: "Daemon", status: "ok", message: "running" });
14025
14105
  }
14026
14106
  } else {
14027
14107
  checks.push({ name: "Daemon", status: "warning", message: "not running", fix: "cc-claw service start" });
@@ -14160,6 +14240,13 @@ async function doctorCommand(globalOpts, localOpts) {
14160
14240
  });
14161
14241
  process.exit(errors > 0 ? 1 : warnings > 0 ? 2 : 0);
14162
14242
  }
14243
+ function formatUptime3(seconds) {
14244
+ seconds = Math.floor(seconds);
14245
+ if (seconds < 60) return `${seconds}s`;
14246
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
14247
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ${Math.floor(seconds % 3600 / 60)}m`;
14248
+ return `${Math.floor(seconds / 86400)}d ${Math.floor(seconds % 86400 / 3600)}h`;
14249
+ }
14163
14250
  var init_doctor = __esm({
14164
14251
  "src/cli/commands/doctor.ts"() {
14165
14252
  "use strict";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-claw",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "CC-Claw: Personal AI assistant on Telegram — multi-backend (Claude, Gemini, Codex), sub-agent orchestration, MCP management",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",