cc-claw 0.20.11 → 0.20.13

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 +1035 -475
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ var VERSION;
33
33
  var init_version = __esm({
34
34
  "src/version.ts"() {
35
35
  "use strict";
36
- VERSION = true ? "0.20.11" : (() => {
36
+ VERSION = true ? "0.20.13" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -827,8 +827,8 @@ function cleanupBackupFiles(ccClawHome, retentionDays = 7) {
827
827
  if (!file.includes(".bak.")) continue;
828
828
  const fullPath = join3(dir, file);
829
829
  try {
830
- const stat3 = statSync(fullPath);
831
- if (stat3.mtimeMs < cutoffMs) unlinkSync(fullPath);
830
+ const stat4 = statSync(fullPath);
831
+ if (stat4.mtimeMs < cutoffMs) unlinkSync(fullPath);
832
832
  } catch {
833
833
  }
834
834
  }
@@ -2722,7 +2722,7 @@ function getSkillSuggestionsEnabled(chatId) {
2722
2722
  const row = getDb().prepare(
2723
2723
  "SELECT value FROM chat_skill_suggestions WHERE chat_id = ?"
2724
2724
  ).get(SKILL_SUGGESTIONS_GLOBAL_KEY);
2725
- return (row?.value ?? 1) === 1;
2725
+ return (row?.value ?? 0) === 1;
2726
2726
  }
2727
2727
  function setSkillSuggestionsEnabled(chatIdOrEnabled, enabled) {
2728
2728
  const value = typeof chatIdOrEnabled === "boolean" ? chatIdOrEnabled : enabled;
@@ -7501,8 +7501,21 @@ var init_loader = __esm({
7501
7501
  function appendTextChunk(accumulated, chunk) {
7502
7502
  if (!accumulated) return chunk;
7503
7503
  if (!chunk) return accumulated;
7504
- const needsSpace = !/\s$/.test(accumulated) && !/^\s/.test(chunk);
7505
- return needsSpace ? accumulated + " " + chunk : accumulated + chunk;
7504
+ if (/\s$/.test(accumulated) || /^\s/.test(chunk)) {
7505
+ return accumulated + chunk;
7506
+ }
7507
+ const tailChar = accumulated[accumulated.length - 1];
7508
+ if ("/:@.=?&#%-_~+".includes(tailChar)) {
7509
+ return accumulated + chunk;
7510
+ }
7511
+ const headChar = chunk[0];
7512
+ if (`/:@.=?&#%-_~+,;)]}>'"`.includes(headChar)) {
7513
+ return accumulated + chunk;
7514
+ }
7515
+ if (/\d$/.test(accumulated) && /^\d/.test(chunk)) {
7516
+ return accumulated + chunk;
7517
+ }
7518
+ return accumulated + " " + chunk;
7506
7519
  }
7507
7520
  var init_text_utils = __esm({
7508
7521
  "src/text-utils.ts"() {
@@ -9471,8 +9484,8 @@ function pruneAgentLogs() {
9471
9484
  mkdirSync6(AGENTS_PATH, { recursive: true });
9472
9485
  const files = readdirSync6(AGENTS_PATH).filter((f) => f.endsWith(".log")).map((f) => {
9473
9486
  const fullPath = join11(AGENTS_PATH, f);
9474
- const stat3 = statSync4(fullPath);
9475
- return { path: fullPath, mtime: stat3.mtimeMs, size: stat3.size };
9487
+ const stat4 = statSync4(fullPath);
9488
+ return { path: fullPath, mtime: stat4.mtimeMs, size: stat4.size };
9476
9489
  });
9477
9490
  const now = Date.now();
9478
9491
  const remaining = files.filter((f) => {
@@ -12720,12 +12733,12 @@ var init_evolve = __esm({
12720
12733
  const body = JSON.parse(await readBody(req));
12721
12734
  const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
12722
12735
  const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
12723
- const { join: join36 } = await import("path");
12736
+ const { join: join37 } = await import("path");
12724
12737
  const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
12725
12738
  const chatId = resolveChatId(body);
12726
12739
  if (!chatId) return jsonResponse(res, { error: "No chatId provided and ALLOWED_CHAT_ID is not set" }, 400);
12727
- const soulPath = join36(home, "identity/SOUL.md");
12728
- const userPath = join36(home, "identity/USER.md");
12740
+ const soulPath = join37(home, "identity/SOUL.md");
12741
+ const userPath = join37(home, "identity/USER.md");
12729
12742
  const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
12730
12743
  const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
12731
12744
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -12777,6 +12790,346 @@ var init_evolve = __esm({
12777
12790
  }
12778
12791
  });
12779
12792
 
12793
+ // src/dashboard/routes/files.ts
12794
+ import { createWriteStream, existsSync as existsSync14 } from "fs";
12795
+ import { readdir, stat, unlink, mkdir } from "fs/promises";
12796
+ import { join as join14, extname } from "path";
12797
+ function getUploadHtml(token, host) {
12798
+ return `<!DOCTYPE html>
12799
+ <html lang="en">
12800
+ <head>
12801
+ <meta charset="utf-8">
12802
+ <meta name="viewport" content="width=device-width, initial-scale=1">
12803
+ <title>CC-Claw File Upload</title>
12804
+ <style>
12805
+ * { margin: 0; padding: 0; box-sizing: border-box; }
12806
+ body { font-family: -apple-system, system-ui, sans-serif; background: #0d1117; color: #e6edf3; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
12807
+ .container { max-width: 520px; width: 100%; padding: 24px; }
12808
+ h1 { font-size: 1.4rem; margin-bottom: 8px; }
12809
+ .subtitle { color: #8b949e; margin-bottom: 24px; font-size: 0.9rem; }
12810
+ .drop-zone { border: 2px dashed #30363d; border-radius: 12px; padding: 48px 24px; text-align: center; cursor: pointer; transition: all 0.2s; }
12811
+ .drop-zone:hover, .drop-zone.drag-over { border-color: #58a6ff; background: rgba(88,166,255,0.05); }
12812
+ .drop-zone p { color: #8b949e; margin-top: 8px; font-size: 0.85rem; }
12813
+ .drop-zone .icon { font-size: 2.5rem; margin-bottom: 8px; }
12814
+ input[type="file"] { display: none; }
12815
+ .progress-wrap { margin-top: 16px; display: none; }
12816
+ .progress-bar { height: 6px; background: #21262d; border-radius: 3px; overflow: hidden; }
12817
+ .progress-fill { height: 100%; width: 0%; background: #58a6ff; transition: width 0.3s; }
12818
+ .progress-text { font-size: 0.8rem; color: #8b949e; margin-top: 6px; text-align: center; }
12819
+ .result { margin-top: 16px; padding: 12px; border-radius: 8px; font-size: 0.85rem; display: none; }
12820
+ .result.success { background: rgba(63,185,80,0.1); border: 1px solid #238636; color: #3fb950; }
12821
+ .result.error { background: rgba(248,81,73,0.1); border: 1px solid #da3633; color: #f85149; }
12822
+ .file-link { color: #58a6ff; text-decoration: none; word-break: break-all; }
12823
+ .file-link:hover { text-decoration: underline; }
12824
+ .files-list { margin-top: 24px; }
12825
+ .files-list h3 { font-size: 0.9rem; color: #8b949e; margin-bottom: 8px; }
12826
+ .files-list ul { list-style: none; }
12827
+ .files-list li { padding: 6px 0; border-bottom: 1px solid #21262d; font-size: 0.85rem; }
12828
+ .files-list li:last-child { border: none; }
12829
+ </style>
12830
+ </head>
12831
+ <body>
12832
+ <div class="container">
12833
+ <h1>CC-Claw Upload</h1>
12834
+ <p class="subtitle">Upload files for CC-Claw to use. Max 200MB.</p>
12835
+ <div class="drop-zone" id="dropZone">
12836
+ <div class="icon">\u{1F4C1}</div>
12837
+ <strong>Drop file here or click to browse</strong>
12838
+ <p>Videos, images, documents \u2014 anything the bot needs</p>
12839
+ </div>
12840
+ <input type="file" id="fileInput">
12841
+ <div class="progress-wrap" id="progressWrap">
12842
+ <div class="progress-bar"><div class="progress-fill" id="progressFill"></div></div>
12843
+ <div class="progress-text" id="progressText">Uploading...</div>
12844
+ </div>
12845
+ <div class="result" id="result"></div>
12846
+ <div class="files-list" id="filesList"></div>
12847
+ </div>
12848
+ <script>
12849
+ const TOKEN = "${token}";
12850
+ const HOST = "${host}";
12851
+ const dropZone = document.getElementById("dropZone");
12852
+ const fileInput = document.getElementById("fileInput");
12853
+ const progressWrap = document.getElementById("progressWrap");
12854
+ const progressFill = document.getElementById("progressFill");
12855
+ const progressText = document.getElementById("progressText");
12856
+ const resultDiv = document.getElementById("result");
12857
+
12858
+ dropZone.addEventListener("click", () => fileInput.click());
12859
+ dropZone.addEventListener("dragover", e => { e.preventDefault(); dropZone.classList.add("drag-over"); });
12860
+ dropZone.addEventListener("dragleave", () => dropZone.classList.remove("drag-over"));
12861
+ dropZone.addEventListener("drop", e => { e.preventDefault(); dropZone.classList.remove("drag-over"); if (e.dataTransfer.files.length) uploadFile(e.dataTransfer.files[0]); });
12862
+ fileInput.addEventListener("change", () => { if (fileInput.files.length) uploadFile(fileInput.files[0]); });
12863
+
12864
+ function uploadFile(file) {
12865
+ if (file.size > 200 * 1024 * 1024) { showResult("File too large (max 200MB)", true); return; }
12866
+ progressWrap.style.display = "block";
12867
+ resultDiv.style.display = "none";
12868
+ progressFill.style.width = "0%";
12869
+ progressText.textContent = "Uploading " + file.name + "...";
12870
+
12871
+ const xhr = new XMLHttpRequest();
12872
+ xhr.open("POST", HOST + "/upload");
12873
+ xhr.setRequestHeader("Authorization", "Bearer " + TOKEN);
12874
+
12875
+ xhr.upload.addEventListener("progress", e => {
12876
+ if (e.lengthComputable) {
12877
+ const pct = Math.round(e.loaded / e.total * 100);
12878
+ progressFill.style.width = pct + "%";
12879
+ progressText.textContent = pct + "% \u2014 " + (e.loaded / 1024 / 1024).toFixed(1) + " / " + (e.total / 1024 / 1024).toFixed(1) + " MB";
12880
+ }
12881
+ });
12882
+ xhr.addEventListener("load", () => {
12883
+ progressWrap.style.display = "none";
12884
+ try {
12885
+ const resp = JSON.parse(xhr.responseText);
12886
+ if (resp.ok && resp.data) {
12887
+ const link = HOST + "/files/" + resp.data.filename;
12888
+ showResult('Uploaded: <a class="file-link" href="' + link + '" target="_blank">' + resp.data.filename + '</a><br>Size: ' + resp.data.sizeMB + ' MB<br>Path: ' + resp.data.path, false);
12889
+ loadFileList();
12890
+ } else {
12891
+ showResult(resp.error || "Upload failed", true);
12892
+ }
12893
+ } catch { showResult("Upload failed: " + xhr.statusText, true); }
12894
+ });
12895
+ xhr.addEventListener("error", () => { progressWrap.style.display = "none"; showResult("Connection failed", true); });
12896
+ xhr.addEventListener("abort", () => { progressWrap.style.display = "none"; showResult("Upload cancelled", true); });
12897
+
12898
+ const formData = new FormData();
12899
+ formData.append("file", file);
12900
+ xhr.send(formData);
12901
+ }
12902
+
12903
+ function showResult(html, isError) {
12904
+ resultDiv.innerHTML = html;
12905
+ resultDiv.className = "result " + (isError ? "error" : "success");
12906
+ resultDiv.style.display = "block";
12907
+ }
12908
+
12909
+ function loadFileList() {
12910
+ fetch(HOST + "/files", { headers: { "Authorization": "Bearer " + TOKEN } })
12911
+ .then(r => r.json()).then(resp => {
12912
+ if (!resp.ok || !resp.data?.length) { document.getElementById("filesList").innerHTML = ""; return; }
12913
+ const items = resp.data.slice(0, 20).map(f =>
12914
+ '<li><a class="file-link" href="' + HOST + '/files/' + f.name + '" target="_blank">' + f.name + '</a> (' + f.sizeMB + ' MB)</li>'
12915
+ ).join("");
12916
+ document.getElementById("filesList").innerHTML = "<h3>Recent Files</h3><ul>" + items + "</ul>";
12917
+ }).catch(() => {});
12918
+ }
12919
+ loadFileList();
12920
+ </script>
12921
+ </body>
12922
+ </html>`;
12923
+ }
12924
+ function handleUploadPage(req, res, _url, token) {
12925
+ const host = `http://${req.headers.host ?? "localhost:3141"}`;
12926
+ htmlResponse(res, getUploadHtml(token, host));
12927
+ }
12928
+ async function handleUpload(req, res) {
12929
+ const contentType = req.headers["content-type"] ?? "";
12930
+ const boundaryMatch = contentType.match(/boundary=(.+?)(?:;|$)/);
12931
+ if (!boundaryMatch) {
12932
+ return jsonResponse(res, { ok: false, error: "Missing multipart boundary" }, 400);
12933
+ }
12934
+ const boundary = boundaryMatch[1];
12935
+ const contentLength = parseInt(req.headers["content-length"] ?? "0", 10);
12936
+ if (contentLength > MAX_UPLOAD_BYTES) {
12937
+ return jsonResponse(res, { ok: false, error: `File too large (max ${MAX_UPLOAD_BYTES / 1024 / 1024}MB)` }, 413);
12938
+ }
12939
+ await mkdir(INCOMING_PATH, { recursive: true });
12940
+ try {
12941
+ const result = await parseMultipartUpload(req, boundary);
12942
+ if (!result) {
12943
+ return jsonResponse(res, { ok: false, error: "No file found in upload" }, 400);
12944
+ }
12945
+ const ext = extname(result.originalName).toLowerCase();
12946
+ if (BLOCKED_EXTENSIONS.has(ext)) {
12947
+ try {
12948
+ await unlink(result.path);
12949
+ } catch {
12950
+ }
12951
+ return jsonResponse(res, { ok: false, error: `File type ${ext} is not allowed` }, 400);
12952
+ }
12953
+ const fileInfo = await stat(result.path);
12954
+ const sizeMB = (fileInfo.size / 1024 / 1024).toFixed(1);
12955
+ log(`[upload] Saved ${result.filename} (${sizeMB} MB) from ${result.originalName}`);
12956
+ return jsonResponse(res, {
12957
+ ok: true,
12958
+ data: {
12959
+ filename: result.filename,
12960
+ originalName: result.originalName,
12961
+ path: result.path,
12962
+ sizeMB
12963
+ }
12964
+ });
12965
+ } catch (err) {
12966
+ warn(`[upload] Failed: ${err.message}`);
12967
+ return jsonResponse(res, { ok: false, error: `Upload failed: ${err.message}` }, 500);
12968
+ }
12969
+ }
12970
+ async function handleFileList(req, res) {
12971
+ await mkdir(INCOMING_PATH, { recursive: true });
12972
+ try {
12973
+ const entries = await readdir(INCOMING_PATH);
12974
+ const files = [];
12975
+ for (const name of entries) {
12976
+ try {
12977
+ const s = await stat(join14(INCOMING_PATH, name));
12978
+ if (!s.isFile()) continue;
12979
+ files.push({
12980
+ name,
12981
+ sizeMB: (s.size / 1024 / 1024).toFixed(1),
12982
+ modified: s.mtime.toISOString()
12983
+ });
12984
+ } catch {
12985
+ continue;
12986
+ }
12987
+ }
12988
+ files.sort((a, b) => b.modified.localeCompare(a.modified));
12989
+ return jsonResponse(res, { ok: true, data: files });
12990
+ } catch {
12991
+ return jsonResponse(res, { ok: true, data: [] });
12992
+ }
12993
+ }
12994
+ async function handleFileServe(req, res, url) {
12995
+ const filename = decodeURIComponent(url.pathname.slice("/files/".length));
12996
+ if (filename.includes("..") || filename.includes("/") || filename.includes("\\")) {
12997
+ res.writeHead(400, { "Content-Type": "text/plain" });
12998
+ res.end("Invalid filename");
12999
+ return;
13000
+ }
13001
+ const filePath = join14(INCOMING_PATH, filename);
13002
+ if (!existsSync14(filePath)) {
13003
+ res.writeHead(404, { "Content-Type": "text/plain" });
13004
+ res.end("File not found");
13005
+ return;
13006
+ }
13007
+ const fileInfo = await stat(filePath);
13008
+ const ext = extname(filename).toLowerCase();
13009
+ const mimeTypes = {
13010
+ ".mp4": "video/mp4",
13011
+ ".mov": "video/quicktime",
13012
+ ".avi": "video/x-msvideo",
13013
+ ".webm": "video/webm",
13014
+ ".jpg": "image/jpeg",
13015
+ ".jpeg": "image/jpeg",
13016
+ ".png": "image/png",
13017
+ ".gif": "image/gif",
13018
+ ".webp": "image/webp",
13019
+ ".pdf": "application/pdf",
13020
+ ".txt": "text/plain",
13021
+ ".json": "application/json",
13022
+ ".mp3": "audio/mpeg",
13023
+ ".wav": "audio/wav",
13024
+ ".ogg": "audio/ogg"
13025
+ };
13026
+ const mime = mimeTypes[ext] ?? "application/octet-stream";
13027
+ res.writeHead(200, {
13028
+ "Content-Type": mime,
13029
+ "Content-Length": fileInfo.size,
13030
+ "Content-Disposition": `inline; filename="${filename}"`,
13031
+ "Cache-Control": "public, max-age=3600"
13032
+ });
13033
+ const { createReadStream: createReadStream2 } = await import("fs");
13034
+ const stream = createReadStream2(filePath);
13035
+ stream.pipe(res);
13036
+ stream.on("error", () => {
13037
+ if (!res.headersSent) {
13038
+ res.writeHead(500);
13039
+ }
13040
+ res.end();
13041
+ });
13042
+ }
13043
+ function parseMultipartUpload(req, boundary) {
13044
+ return new Promise((resolve, reject) => {
13045
+ const chunks = [];
13046
+ let totalBytes = 0;
13047
+ let cleanupPath = null;
13048
+ req.on("data", (chunk) => {
13049
+ totalBytes += chunk.length;
13050
+ if (totalBytes > MAX_UPLOAD_BYTES) {
13051
+ req.destroy(new Error(`Upload exceeds ${MAX_UPLOAD_BYTES / 1024 / 1024}MB limit`));
13052
+ return;
13053
+ }
13054
+ chunks.push(chunk);
13055
+ });
13056
+ req.on("error", async (err) => {
13057
+ if (cleanupPath) {
13058
+ try {
13059
+ await unlink(cleanupPath);
13060
+ } catch {
13061
+ }
13062
+ }
13063
+ reject(err);
13064
+ });
13065
+ req.on("end", async () => {
13066
+ try {
13067
+ const body = Buffer.concat(chunks);
13068
+ const boundaryBuf = Buffer.from(`--${boundary}`);
13069
+ const headerEnd = body.indexOf(Buffer.from("\r\n\r\n"));
13070
+ if (headerEnd === -1) return resolve(null);
13071
+ const headerSection = body.subarray(0, headerEnd).toString("utf-8");
13072
+ const nameMatch = headerSection.match(/filename="(.+?)"/);
13073
+ if (!nameMatch) return resolve(null);
13074
+ const originalName = nameMatch[1].replace(/[^\w.-]/g, "_");
13075
+ const ext = extname(originalName) || ".bin";
13076
+ const filename = `upload-${Date.now()}${ext}`;
13077
+ const filePath = join14(INCOMING_PATH, filename);
13078
+ cleanupPath = filePath;
13079
+ const fileStart = headerEnd + 4;
13080
+ const closingBoundary = Buffer.from(`\r
13081
+ --${boundary}`);
13082
+ let fileEnd = body.indexOf(closingBoundary, fileStart);
13083
+ if (fileEnd === -1) fileEnd = body.length;
13084
+ const fileContent = body.subarray(fileStart, fileEnd);
13085
+ const ws = createWriteStream(filePath);
13086
+ await new Promise((res, rej) => {
13087
+ ws.write(fileContent, (err) => {
13088
+ if (err) return rej(err);
13089
+ ws.end(res);
13090
+ });
13091
+ });
13092
+ cleanupPath = null;
13093
+ resolve({ filename, originalName, path: filePath });
13094
+ } catch (err) {
13095
+ if (cleanupPath) {
13096
+ try {
13097
+ await unlink(cleanupPath);
13098
+ } catch {
13099
+ }
13100
+ }
13101
+ reject(err);
13102
+ }
13103
+ });
13104
+ });
13105
+ }
13106
+ var INCOMING_PATH, MAX_UPLOAD_BYTES, BLOCKED_EXTENSIONS;
13107
+ var init_files = __esm({
13108
+ "src/dashboard/routes/files.ts"() {
13109
+ "use strict";
13110
+ init_paths();
13111
+ init_middleware();
13112
+ init_log();
13113
+ INCOMING_PATH = join14(MEDIA_PATH, "incoming");
13114
+ MAX_UPLOAD_BYTES = 200 * 1024 * 1024;
13115
+ BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
13116
+ ".exe",
13117
+ ".bat",
13118
+ ".cmd",
13119
+ ".com",
13120
+ ".scr",
13121
+ ".pif",
13122
+ ".msi",
13123
+ ".sh",
13124
+ ".bash",
13125
+ ".csh",
13126
+ ".ksh",
13127
+ ".ps1",
13128
+ ".psm1"
13129
+ ]);
13130
+ }
13131
+ });
13132
+
12780
13133
  // src/dashboard/server.ts
12781
13134
  var server_exports = {};
12782
13135
  __export(server_exports, {
@@ -12876,6 +13229,16 @@ function startDashboard() {
12876
13229
  if (url.pathname === "/api/evolve/off" && req.method === "POST") return handleEvolveOff(req, res, url);
12877
13230
  if (url.pathname === "/api/evolve/model" && req.method === "POST") return handleEvolveModel(req, res, url);
12878
13231
  if (url.pathname === "/api/evolve/settings" && req.method === "POST") return handleEvolveSettings(req, res, url);
13232
+ if (url.pathname === "/upload" && req.method === "GET") return handleUploadPage(req, res, url, getDashboardToken());
13233
+ if (url.pathname === "/upload" && req.method === "POST") {
13234
+ await handleUpload(req, res);
13235
+ return;
13236
+ }
13237
+ if (url.pathname === "/files" && req.method === "GET") return handleFileList(req, res);
13238
+ if (url.pathname.startsWith("/files/") && req.method === "GET") {
13239
+ await handleFileServe(req, res, url);
13240
+ return;
13241
+ }
12879
13242
  if (url.pathname === "/" || url.pathname === "/index.html") {
12880
13243
  return htmlResponse(res, DASHBOARD_HTML.replace("__TOKEN__", getDashboardToken()));
12881
13244
  }
@@ -12891,7 +13254,8 @@ function startDashboard() {
12891
13254
  console.error(`[api] Server error:`, err);
12892
13255
  }
12893
13256
  });
12894
- server.listen(PORT, "127.0.0.1");
13257
+ const bindHost = process.env.CC_CLAW_DASHBOARD_HOST ?? "0.0.0.0";
13258
+ server.listen(PORT, bindHost);
12895
13259
  persistToken();
12896
13260
  return server;
12897
13261
  }
@@ -12908,6 +13272,7 @@ var init_server = __esm({
12908
13272
  init_scheduler();
12909
13273
  init_config();
12910
13274
  init_evolve();
13275
+ init_files();
12911
13276
  }
12912
13277
  });
12913
13278
 
@@ -13317,9 +13682,10 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
13317
13682
  const env = opts?.envOverride ? thinkingConfig?.envOverrides ? { ...opts.envOverride, ...thinkingConfig.envOverrides } : opts.envOverride : adapter.getEnv(thinkingConfig?.envOverrides);
13318
13683
  const finalArgs = thinkingConfig?.extraArgs ? [...config2.args, ...thinkingConfig.extraArgs] : config2.args;
13319
13684
  log(`[agent:spawn] backend=${adapter.id} exe=${config2.executable} model=${model2} timeout=${effectiveTimeout / 1e3}s cwd=${config2.cwd ?? "(inherited)"}`);
13685
+ const stdinMode = adapter.id === "codex" ? "pipe" : "ignore";
13320
13686
  const proc = spawn6(config2.executable, finalArgs, {
13321
13687
  env,
13322
- stdio: ["ignore", "pipe", "pipe"],
13688
+ stdio: [stdinMode, "pipe", "pipe"],
13323
13689
  detached: true,
13324
13690
  ...config2.cwd ? { cwd: config2.cwd } : {}
13325
13691
  });
@@ -14696,6 +15062,7 @@ var init_telegram_throttle = __esm({
14696
15062
  try {
14697
15063
  const result = await this.execWithRetry(item.label, item.fn);
14698
15064
  this.recordSend(item.chatId);
15065
+ this.pauseStartedAt = 0;
14699
15066
  item.resolve(result);
14700
15067
  } catch (err) {
14701
15068
  if (is429(err)) {
@@ -14742,7 +15109,6 @@ var init_telegram_throttle = __esm({
14742
15109
  this.chatsPendingNotification.clear();
14743
15110
  if (!this.resumeNotifier) return;
14744
15111
  const pausedSec = this.pauseStartedAt > 0 ? Math.round((Date.now() - this.pauseStartedAt) / 1e3) : 0;
14745
- this.pauseStartedAt = 0;
14746
15112
  for (const chatId of chats2) {
14747
15113
  const queuedForChat = this.queue.filter((q) => q.chatId === chatId).length;
14748
15114
  if (queuedForChat === 0) continue;
@@ -14753,14 +15119,13 @@ var init_telegram_throttle = __esm({
14753
15119
  if (is429(err)) {
14754
15120
  const retrySec = err.parameters?.retry_after ?? 10;
14755
15121
  this.pausedUntil = Date.now() + retrySec * 1e3;
14756
- if (this.pauseStartedAt === 0) this.pauseStartedAt = Date.now();
14757
- for (const c of chats2) this.chatsPendingNotification.add(c);
14758
- warn(`[throttle] Resume notification hit 429, re-pausing for ${retrySec}s`);
15122
+ warn(`[throttle] Resume notification hit 429, re-pausing for ${retrySec}s (skipping further notifications)`);
14759
15123
  return;
14760
15124
  }
14761
15125
  warn(`[throttle] Resume notification failed for chat ${chatId}: ${err}`);
14762
15126
  }
14763
15127
  }
15128
+ this.pauseStartedAt = 0;
14764
15129
  }
14765
15130
  // ── Helpers ─────────────────────────────────────────────────────────
14766
15131
  recordSend(chatId) {
@@ -14779,10 +15144,10 @@ var init_telegram_throttle = __esm({
14779
15144
  });
14780
15145
 
14781
15146
  // src/health/checks.ts
14782
- import { existsSync as existsSync14, statSync as statSync6, readFileSync as readFileSync8 } from "fs";
15147
+ import { existsSync as existsSync15, statSync as statSync6, readFileSync as readFileSync8 } from "fs";
14783
15148
  import { execFileSync, execSync as execSync3 } from "child_process";
14784
15149
  function getRecentErrors() {
14785
- if (!existsSync14(ERROR_LOG_PATH)) return null;
15150
+ if (!existsSync15(ERROR_LOG_PATH)) return null;
14786
15151
  const logContent = readFileSync8(ERROR_LOG_PATH, "utf-8");
14787
15152
  const allLines = logContent.split("\n").filter(Boolean).slice(-500);
14788
15153
  const last24h = Date.now() - 864e5;
@@ -14804,7 +15169,7 @@ function getRecentErrors() {
14804
15169
  }
14805
15170
  function checkDatabase() {
14806
15171
  const checks = [];
14807
- if (existsSync14(DB_PATH)) {
15172
+ if (existsSync15(DB_PATH)) {
14808
15173
  const size = statSync6(DB_PATH).size;
14809
15174
  checks.push({ name: "Database", status: "ok", message: `${(size / 1024).toFixed(0)}KB` });
14810
15175
  } else {
@@ -14836,18 +15201,18 @@ function checkErrorLog() {
14836
15201
  return checks;
14837
15202
  }
14838
15203
  if (errors.rate429.length > 10) {
14839
- checks.push({ name: "Rate limits", status: "error", message: `${errors.rate429.length} rate-limit (429) errors in last 24h` });
15204
+ checks.push({ name: "Rate limits", status: "error", message: `${errors.rate429.length} rate-limit (429) errors in last 24h`, fix: "cc-claw doctor errors \u2014 view details; cc-claw doctor --fix \u2014 clear log" });
14840
15205
  } else if (errors.rate429.length > 0) {
14841
- checks.push({ name: "Rate limits", status: "warning", message: `${errors.rate429.length} rate-limit errors in last 24h` });
15206
+ checks.push({ name: "Rate limits", status: "warning", message: `${errors.rate429.length} rate-limit errors in last 24h`, fix: "cc-claw doctor errors \u2014 view details; cc-claw doctor --fix \u2014 clear log" });
14842
15207
  }
14843
15208
  if (errors.contentSilence.length > 0) {
14844
- checks.push({ name: "Content silence", status: "warning", message: `${errors.contentSilence.length} silence timeout(s) in last 24h` });
15209
+ checks.push({ name: "Content silence", status: "warning", message: `${errors.contentSilence.length} silence timeout(s) in last 24h`, fix: "cc-claw doctor errors \u2014 view details; cc-claw service restart \u2014 if persistent" });
14845
15210
  }
14846
15211
  if (errors.spawnTimeout.length > 0) {
14847
- checks.push({ name: "Spawn timeouts", status: "warning", message: `${errors.spawnTimeout.length} backend timeout(s) in last 24h` });
15212
+ checks.push({ name: "Spawn timeouts", status: "warning", message: `${errors.spawnTimeout.length} backend timeout(s) in last 24h`, fix: "cc-claw doctor errors \u2014 view details; cc-claw status \u2014 check backends" });
14848
15213
  }
14849
15214
  if (errors.other.length > 0) {
14850
- checks.push({ name: "Other errors", status: "warning", message: `${errors.other.length} error(s) in last 24h` });
15215
+ checks.push({ name: "Other errors", status: "warning", message: `${errors.other.length} error(s) in last 24h`, fix: "cc-claw doctor errors \u2014 view details; cc-claw doctor --fix \u2014 clear log" });
14851
15216
  }
14852
15217
  if (checks.length === 0) {
14853
15218
  checks.push({ name: "Recent errors", status: "ok", message: "none in last 24h" });
@@ -15012,8 +15377,8 @@ __export(heartbeat_exports, {
15012
15377
  stopHeartbeatForChat: () => stopHeartbeatForChat,
15013
15378
  updateHeartbeatConfig: () => updateHeartbeatConfig
15014
15379
  });
15015
- import { readFileSync as readFileSync9, existsSync as existsSync15 } from "fs";
15016
- import { join as join14 } from "path";
15380
+ import { readFileSync as readFileSync9, existsSync as existsSync16 } from "fs";
15381
+ import { join as join15 } from "path";
15017
15382
  function findHeartbeatJob() {
15018
15383
  try {
15019
15384
  const { getDb: getDb2 } = (init_store5(), __toCommonJS(store_exports5));
@@ -15144,7 +15509,7 @@ ${healthText}`);
15144
15509
  sections.push(`[Active Watches \u2014 execute these checks using your tools]
15145
15510
  ${watchLines.join("\n")}`);
15146
15511
  }
15147
- if (existsSync15(HEARTBEAT_MD_PATH)) {
15512
+ if (existsSync16(HEARTBEAT_MD_PATH)) {
15148
15513
  try {
15149
15514
  const custom = readFileSync9(HEARTBEAT_MD_PATH, "utf-8").trim();
15150
15515
  if (custom) {
@@ -15206,7 +15571,7 @@ var init_heartbeat2 = __esm({
15206
15571
  init_store5();
15207
15572
  init_checks();
15208
15573
  init_log();
15209
- HEARTBEAT_MD_PATH = join14(WORKSPACE_PATH, "HEARTBEAT.md");
15574
+ HEARTBEAT_MD_PATH = join15(WORKSPACE_PATH, "HEARTBEAT.md");
15210
15575
  HEARTBEAT_OK = "HEARTBEAT_OK";
15211
15576
  HEARTBEAT_JOB_TYPE = "heartbeat";
15212
15577
  DEFAULT_INTERVAL_MS = 30 * 60 * 1e3;
@@ -15215,8 +15580,8 @@ var init_heartbeat2 = __esm({
15215
15580
  });
15216
15581
 
15217
15582
  // src/bootstrap/profile.ts
15218
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync16 } from "fs";
15219
- import { join as join15 } from "path";
15583
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync17 } from "fs";
15584
+ import { join as join16 } from "path";
15220
15585
  function hasActiveProfile(chatId) {
15221
15586
  return activeProfiles.has(chatId);
15222
15587
  }
@@ -15345,7 +15710,7 @@ function extractUserUpdates(text) {
15345
15710
  return { cleanText, updates };
15346
15711
  }
15347
15712
  function appendToUserProfile(key, value) {
15348
- if (!existsSync16(USER_PATH2)) return;
15713
+ if (!existsSync17(USER_PATH2)) return;
15349
15714
  const content = readFileSync10(USER_PATH2, "utf-8");
15350
15715
  const line = `- **${key}**: ${value}`;
15351
15716
  if (content.includes(line)) return;
@@ -15361,7 +15726,7 @@ var init_profile = __esm({
15361
15726
  "use strict";
15362
15727
  init_paths();
15363
15728
  init_log();
15364
- USER_PATH2 = join15(IDENTITY_PATH, "USER.md");
15729
+ USER_PATH2 = join16(IDENTITY_PATH, "USER.md");
15365
15730
  activeProfiles = /* @__PURE__ */ new Map();
15366
15731
  }
15367
15732
  });
@@ -16658,8 +17023,8 @@ __export(session_log_exports2, {
16658
17023
  startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
16659
17024
  tailSessionLog: () => tailSessionLog
16660
17025
  });
16661
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync9, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
16662
- import { join as join16, basename } from "path";
17026
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync9, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
17027
+ import { join as join17, basename } from "path";
16663
17028
  import { createInterface as createInterface6 } from "readline";
16664
17029
  function getRetentionDays() {
16665
17030
  const env = process.env.SESSION_LOG_RETENTION_DAYS;
@@ -16671,13 +17036,13 @@ function getRetentionDays() {
16671
17036
  }
16672
17037
  function cleanupSessionLogs(retentionDays) {
16673
17038
  const days = retentionDays ?? getRetentionDays();
16674
- if (!existsSync17(SESSION_LOGS_PATH)) return 0;
17039
+ if (!existsSync18(SESSION_LOGS_PATH)) return 0;
16675
17040
  const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
16676
17041
  let cleaned = 0;
16677
17042
  try {
16678
17043
  for (const file of readdirSync9(SESSION_LOGS_PATH)) {
16679
17044
  if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
16680
- const filePath = join16(SESSION_LOGS_PATH, file);
17045
+ const filePath = join17(SESSION_LOGS_PATH, file);
16681
17046
  try {
16682
17047
  const { mtimeMs } = statSync7(filePath);
16683
17048
  if (mtimeMs < cutoff) {
@@ -16703,21 +17068,21 @@ function startSessionLogCleanupTimer() {
16703
17068
  return timer;
16704
17069
  }
16705
17070
  function listSessionLogs() {
16706
- if (!existsSync17(SESSION_LOGS_PATH)) return [];
17071
+ if (!existsSync18(SESSION_LOGS_PATH)) return [];
16707
17072
  const logs = [];
16708
17073
  for (const file of readdirSync9(SESSION_LOGS_PATH)) {
16709
17074
  if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
16710
- const filePath = join16(SESSION_LOGS_PATH, file);
17075
+ const filePath = join17(SESSION_LOGS_PATH, file);
16711
17076
  try {
16712
- const stat3 = statSync7(filePath);
17077
+ const stat4 = statSync7(filePath);
16713
17078
  const match = file.match(/^session-(.+?)-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})\.log$/);
16714
17079
  logs.push({
16715
17080
  filename: file,
16716
17081
  filePath,
16717
17082
  chatId: match?.[1] ?? "unknown",
16718
17083
  timestamp: match?.[2]?.replace(/-/g, (m, i) => i > 9 ? ":" : m) ?? "unknown",
16719
- sizeBytes: stat3.size,
16720
- modifiedAt: stat3.mtime
17084
+ sizeBytes: stat4.size,
17085
+ modifiedAt: stat4.mtime
16721
17086
  });
16722
17087
  } catch {
16723
17088
  }
@@ -16726,7 +17091,7 @@ function listSessionLogs() {
16726
17091
  return logs;
16727
17092
  }
16728
17093
  async function* tailSessionLog(filePath, lines = 50) {
16729
- if (!existsSync17(filePath)) {
17094
+ if (!existsSync18(filePath)) {
16730
17095
  yield `File not found: ${filePath}`;
16731
17096
  return;
16732
17097
  }
@@ -16754,12 +17119,12 @@ var init_session_log2 = __esm({
16754
17119
  constructor(chatId, backend2, model2) {
16755
17120
  this.backend = backend2;
16756
17121
  this.model = model2;
16757
- if (!existsSync17(SESSION_LOGS_PATH)) {
17122
+ if (!existsSync18(SESSION_LOGS_PATH)) {
16758
17123
  mkdirSync8(SESSION_LOGS_PATH, { recursive: true });
16759
17124
  }
16760
17125
  const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
16761
17126
  const sanitizedChatId = chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
16762
- this.filePath = join16(SESSION_LOGS_PATH, `session-${sanitizedChatId}-${ts2}.log`);
17127
+ this.filePath = join17(SESSION_LOGS_PATH, `session-${sanitizedChatId}-${ts2}.log`);
16763
17128
  const header2 = [
16764
17129
  "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
16765
17130
  `CC-Claw Agent Session \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
@@ -17162,7 +17527,7 @@ var init_gate = __esm({
17162
17527
  // src/voice/stt.ts
17163
17528
  import crypto from "crypto";
17164
17529
  import { execFile as execFile2, execFileSync as execFileSync2 } from "child_process";
17165
- import { readFile as readFile2, unlink } from "fs/promises";
17530
+ import { readFile as readFile2, unlink as unlink2 } from "fs/promises";
17166
17531
  import { promisify as promisify2 } from "util";
17167
17532
  function ensureFfmpeg() {
17168
17533
  if (ffmpegAvailable === true) return;
@@ -17316,10 +17681,10 @@ async function mp3ToOgg(mp3Buffer) {
17316
17681
  await writeFile6(tmpMp3, mp3Buffer);
17317
17682
  await execFileAsync2("ffmpeg", ["-y", "-i", tmpMp3, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
17318
17683
  const oggBuffer = await readFile2(tmpOgg);
17319
- unlink(tmpMp3).catch((err) => {
17684
+ unlink2(tmpMp3).catch((err) => {
17320
17685
  error("[tts] cleanup failed:", err);
17321
17686
  });
17322
- unlink(tmpOgg).catch((err) => {
17687
+ unlink2(tmpOgg).catch((err) => {
17323
17688
  error("[tts] cleanup failed:", err);
17324
17689
  });
17325
17690
  return oggBuffer;
@@ -17332,10 +17697,10 @@ async function macOsTts(text, voice2 = "Samantha") {
17332
17697
  await execFileAsync2("say", ["-v", voice2, "-o", tmpAiff, text]);
17333
17698
  await execFileAsync2("ffmpeg", ["-y", "-i", tmpAiff, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
17334
17699
  const oggBuffer = await readFile2(tmpOgg);
17335
- unlink(tmpAiff).catch((err) => {
17700
+ unlink2(tmpAiff).catch((err) => {
17336
17701
  error("[tts] cleanup failed:", err);
17337
17702
  });
17338
- unlink(tmpOgg).catch((err) => {
17703
+ unlink2(tmpOgg).catch((err) => {
17339
17704
  error("[tts] cleanup failed:", err);
17340
17705
  });
17341
17706
  return oggBuffer;
@@ -17367,9 +17732,9 @@ var init_stt = __esm({
17367
17732
  });
17368
17733
 
17369
17734
  // src/media/image-gen.ts
17370
- import { mkdirSync as mkdirSync9, existsSync as existsSync18, unlink as unlink2, readdir, stat } from "fs";
17735
+ import { mkdirSync as mkdirSync9, existsSync as existsSync19, unlink as unlink3, readdir as readdir2, stat as stat2 } from "fs";
17371
17736
  import { writeFile } from "fs/promises";
17372
- import { join as join17 } from "path";
17737
+ import { join as join18 } from "path";
17373
17738
  async function generateImage(prompt) {
17374
17739
  const apiKey = process.env.GEMINI_API_KEY;
17375
17740
  if (!apiKey) {
@@ -17416,12 +17781,12 @@ async function generateImage(prompt) {
17416
17781
  if (!imageData) {
17417
17782
  throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
17418
17783
  }
17419
- if (!existsSync18(IMAGE_OUTPUT_DIR)) {
17784
+ if (!existsSync19(IMAGE_OUTPUT_DIR)) {
17420
17785
  mkdirSync9(IMAGE_OUTPUT_DIR, { recursive: true });
17421
17786
  }
17422
17787
  const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
17423
17788
  const filename = `img_${Date.now()}.${ext}`;
17424
- const filePath = join17(IMAGE_OUTPUT_DIR, filename);
17789
+ const filePath = join18(IMAGE_OUTPUT_DIR, filename);
17425
17790
  const buffer = Buffer.from(imageData, "base64");
17426
17791
  await writeFile(filePath, buffer);
17427
17792
  log(`[image-gen] Saved ${buffer.length} bytes to ${filePath}`);
@@ -17431,21 +17796,21 @@ function isImageGenAvailable() {
17431
17796
  return !!process.env.GEMINI_API_KEY;
17432
17797
  }
17433
17798
  function cleanupGeneratedImage(filePath) {
17434
- unlink2(filePath, (err) => {
17799
+ unlink3(filePath, (err) => {
17435
17800
  if (err) warn(`[image-gen] cleanup failed for ${filePath}: ${err.message}`);
17436
17801
  else log(`[image-gen] cleaned up ${filePath}`);
17437
17802
  });
17438
17803
  }
17439
17804
  function pruneImageCache() {
17440
- readdir(IMAGE_OUTPUT_DIR, (err, files) => {
17805
+ readdir2(IMAGE_OUTPUT_DIR, (err, files) => {
17441
17806
  if (err || !files) return;
17442
- const imageFiles = files.filter((f) => /\.(png|jpg)$/.test(f)).map((f) => join17(IMAGE_OUTPUT_DIR, f));
17807
+ const imageFiles = files.filter((f) => /\.(png|jpg)$/.test(f)).map((f) => join18(IMAGE_OUTPUT_DIR, f));
17443
17808
  if (imageFiles.length === 0) return;
17444
17809
  const now = Date.now();
17445
17810
  let statsPending = imageFiles.length;
17446
17811
  const fileStats = [];
17447
17812
  for (const fp of imageFiles) {
17448
- stat(fp, (serr, s) => {
17813
+ stat2(fp, (serr, s) => {
17449
17814
  statsPending--;
17450
17815
  if (!serr && s) fileStats.push({ path: fp, mtime: s.mtimeMs });
17451
17816
  if (statsPending === 0) {
@@ -17454,7 +17819,7 @@ function pruneImageCache() {
17454
17819
  (f, idx) => idx >= MAX_GENERATED_IMAGES || now - f.mtime > IMAGE_MAX_AGE_MS
17455
17820
  );
17456
17821
  for (const { path } of toDelete) {
17457
- unlink2(path, (derr) => {
17822
+ unlink3(path, (derr) => {
17458
17823
  if (!derr) log(`[image-gen] pruned old image: ${path}`);
17459
17824
  });
17460
17825
  }
@@ -17471,8 +17836,8 @@ var init_image_gen = __esm({
17471
17836
  MAX_GENERATED_IMAGES = 20;
17472
17837
  IMAGE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
17473
17838
  IMAGE_MODEL = "gemini-3.1-flash-image-preview";
17474
- IMAGE_OUTPUT_DIR = join17(
17475
- process.env.CC_CLAW_HOME ?? join17(process.env.HOME ?? "/tmp", ".cc-claw"),
17839
+ IMAGE_OUTPUT_DIR = join18(
17840
+ process.env.CC_CLAW_HOME ?? join18(process.env.HOME ?? "/tmp", ".cc-claw"),
17476
17841
  "data",
17477
17842
  "images"
17478
17843
  );
@@ -17929,33 +18294,33 @@ var init_video = __esm({
17929
18294
  });
17930
18295
 
17931
18296
  // src/router/media.ts
17932
- import { join as join18 } from "path";
17933
- import { mkdir, writeFile as writeFile2, readdir as readdir2, stat as stat2, unlink as unlink3 } from "fs/promises";
18297
+ import { join as join19 } from "path";
18298
+ import { mkdir as mkdir2, writeFile as writeFile2, readdir as readdir3, stat as stat3, unlink as unlink4 } from "fs/promises";
17934
18299
  function getMediaRetentionMs() {
17935
18300
  const hours = parseInt(process.env.MEDIA_RETENTION_HOURS ?? "24", 10);
17936
18301
  return (isNaN(hours) || hours < 1 ? 24 : hours) * 60 * 60 * 1e3;
17937
18302
  }
17938
18303
  async function saveMedia(buffer, prefix, ext) {
17939
- await mkdir(MEDIA_INCOMING_PATH, { recursive: true });
18304
+ await mkdir2(MEDIA_INCOMING_PATH, { recursive: true });
17940
18305
  const filename = `${prefix}-${Date.now()}.${ext}`;
17941
- const fullPath = join18(MEDIA_INCOMING_PATH, filename);
18306
+ const fullPath = join19(MEDIA_INCOMING_PATH, filename);
17942
18307
  await writeFile2(fullPath, buffer);
17943
18308
  return fullPath;
17944
18309
  }
17945
18310
  async function cleanupOldMedia() {
17946
18311
  try {
17947
- await mkdir(MEDIA_INCOMING_PATH, { recursive: true });
18312
+ await mkdir2(MEDIA_INCOMING_PATH, { recursive: true });
17948
18313
  const retentionMs = getMediaRetentionMs();
17949
18314
  const retentionHours = Math.round(retentionMs / (60 * 60 * 1e3));
17950
- const files = await readdir2(MEDIA_INCOMING_PATH);
18315
+ const files = await readdir3(MEDIA_INCOMING_PATH);
17951
18316
  const now = Date.now();
17952
18317
  let removed = 0;
17953
18318
  for (const file of files) {
17954
18319
  try {
17955
- const filePath = join18(MEDIA_INCOMING_PATH, file);
17956
- const s = await stat2(filePath);
18320
+ const filePath = join19(MEDIA_INCOMING_PATH, file);
18321
+ const s = await stat3(filePath);
17957
18322
  if (now - s.mtimeMs > retentionMs) {
17958
- await unlink3(filePath);
18323
+ await unlink4(filePath);
17959
18324
  removed++;
17960
18325
  }
17961
18326
  } catch {
@@ -18170,7 +18535,21 @@ ${content}
18170
18535
  await sendResponse(chatId, channel, mediaResponse, msg.messageId);
18171
18536
  } catch (err) {
18172
18537
  error("[router] Media error:", err);
18173
- await channel.sendText(chatId, `Error processing file: ${errorMessage(err)}`, { parseMode: "plain" });
18538
+ const errStr = errorMessage(err);
18539
+ if (errStr.includes("file is too big") || errStr.includes("too big")) {
18540
+ const host = process.env.CC_CLAW_API_HOST ?? "192.168.68.10";
18541
+ const port = process.env.CC_CLAW_PORT ?? "3141";
18542
+ await channel.sendText(
18543
+ chatId,
18544
+ `File too large for Telegram (max 20MB via Bot API).
18545
+
18546
+ Upload directly instead:
18547
+ http://${host}:${port}/upload`,
18548
+ { parseMode: "plain" }
18549
+ );
18550
+ } else {
18551
+ await channel.sendText(chatId, `Error processing file: ${errStr}`, { parseMode: "plain" });
18552
+ }
18174
18553
  }
18175
18554
  }
18176
18555
  var MEDIA_INCOMING_PATH;
@@ -18188,7 +18567,7 @@ var init_media = __esm({
18188
18567
  init_helpers();
18189
18568
  init_response();
18190
18569
  init_live_status();
18191
- MEDIA_INCOMING_PATH = join18(MEDIA_PATH, "incoming");
18570
+ MEDIA_INCOMING_PATH = join19(MEDIA_PATH, "incoming");
18192
18571
  }
18193
18572
  });
18194
18573
 
@@ -18500,9 +18879,9 @@ var install_exports = {};
18500
18879
  __export(install_exports, {
18501
18880
  installSkillFromGitHub: () => installSkillFromGitHub
18502
18881
  });
18503
- import { mkdir as mkdir2, readdir as readdir3, readFile as readFile4, cp } from "fs/promises";
18504
- import { existsSync as existsSync19 } from "fs";
18505
- import { join as join19, basename as basename2 } from "path";
18882
+ import { mkdir as mkdir3, readdir as readdir4, readFile as readFile4, cp } from "fs/promises";
18883
+ import { existsSync as existsSync20 } from "fs";
18884
+ import { join as join20, basename as basename2 } from "path";
18506
18885
  import { execSync as execSync4 } from "child_process";
18507
18886
  async function installSkillFromGitHub(urlOrShorthand) {
18508
18887
  let repoUrl;
@@ -18513,36 +18892,36 @@ async function installSkillFromGitHub(urlOrShorthand) {
18513
18892
  }
18514
18893
  repoUrl = parsed.cloneUrl;
18515
18894
  subPath = parsed.subPath;
18516
- const tmpDir = join19("/tmp", `cc-claw-skill-${Date.now()}`);
18895
+ const tmpDir = join20("/tmp", `cc-claw-skill-${Date.now()}`);
18517
18896
  try {
18518
18897
  log(`[skill-install] Cloning ${repoUrl} to ${tmpDir}`);
18519
18898
  execSync4(`git clone --depth 1 ${repoUrl} ${tmpDir}`, {
18520
18899
  stdio: "pipe",
18521
18900
  timeout: 3e4
18522
18901
  });
18523
- if (!existsSync19(join19(tmpDir, ".git"))) {
18902
+ if (!existsSync20(join20(tmpDir, ".git"))) {
18524
18903
  return { success: false, error: "Git clone failed: no .git directory produced" };
18525
18904
  }
18526
- const searchRoot = subPath ? join19(tmpDir, subPath) : tmpDir;
18905
+ const searchRoot = subPath ? join20(tmpDir, subPath) : tmpDir;
18527
18906
  const skillDir = await findSkillDir(searchRoot);
18528
18907
  if (!skillDir) {
18529
18908
  return { success: false, error: "No SKILL.md found in the repository." };
18530
18909
  }
18531
18910
  const skillFolderName = basename2(skillDir);
18532
- const destDir = join19(SKILLS_PATH, skillFolderName);
18533
- if (existsSync19(destDir)) {
18911
+ const destDir = join20(SKILLS_PATH, skillFolderName);
18912
+ if (existsSync20(destDir)) {
18534
18913
  log(`[skill-install] Overwriting existing skill at ${destDir}`);
18535
18914
  }
18536
- await mkdir2(destDir, { recursive: true });
18915
+ await mkdir3(destDir, { recursive: true });
18537
18916
  await cp(skillDir, destDir, { recursive: true });
18538
18917
  let skillName = skillFolderName;
18539
18918
  try {
18540
- const content = await readFile4(join19(destDir, "SKILL.md"), "utf-8");
18919
+ const content = await readFile4(join20(destDir, "SKILL.md"), "utf-8");
18541
18920
  const nameMatch = content.match(/^name:\s*(.+)$/m);
18542
18921
  if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
18543
18922
  } catch {
18544
18923
  try {
18545
- const content = await readFile4(join19(destDir, "skill.md"), "utf-8");
18924
+ const content = await readFile4(join20(destDir, "skill.md"), "utf-8");
18546
18925
  const nameMatch = content.match(/^name:\s*(.+)$/m);
18547
18926
  if (nameMatch) skillName = nameMatch[1].trim().replace(/^["']|["']$/g, "");
18548
18927
  } catch {
@@ -18577,35 +18956,35 @@ function parseGitHubUrl(input) {
18577
18956
  async function findSkillDir(root) {
18578
18957
  const candidates = ["SKILL.md", "skill.md"];
18579
18958
  for (const c of candidates) {
18580
- if (existsSync19(join19(root, c))) return root;
18959
+ if (existsSync20(join20(root, c))) return root;
18581
18960
  }
18582
18961
  try {
18583
- const entries = await readdir3(root, { withFileTypes: true });
18962
+ const entries = await readdir4(root, { withFileTypes: true });
18584
18963
  for (const entry of entries) {
18585
18964
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
18586
18965
  for (const c of candidates) {
18587
- if (existsSync19(join19(root, entry.name, c))) {
18588
- return join19(root, entry.name);
18966
+ if (existsSync20(join20(root, entry.name, c))) {
18967
+ return join20(root, entry.name);
18589
18968
  }
18590
18969
  }
18591
18970
  }
18592
18971
  } catch {
18593
18972
  }
18594
18973
  try {
18595
- const entries = await readdir3(root, { withFileTypes: true });
18974
+ const entries = await readdir4(root, { withFileTypes: true });
18596
18975
  for (const entry of entries) {
18597
18976
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
18598
18977
  let subEntries;
18599
18978
  try {
18600
- subEntries = await readdir3(join19(root, entry.name), { withFileTypes: true });
18979
+ subEntries = await readdir4(join20(root, entry.name), { withFileTypes: true });
18601
18980
  } catch {
18602
18981
  continue;
18603
18982
  }
18604
18983
  for (const sub of subEntries) {
18605
18984
  if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
18606
18985
  for (const c of candidates) {
18607
- if (existsSync19(join19(root, entry.name, sub.name, c))) {
18608
- return join19(root, entry.name, sub.name);
18986
+ if (existsSync20(join20(root, entry.name, sub.name, c))) {
18987
+ return join20(root, entry.name, sub.name);
18609
18988
  }
18610
18989
  }
18611
18990
  }
@@ -18629,10 +19008,10 @@ __export(discover_exports, {
18629
19008
  invalidateSkillCache: () => invalidateSkillCache,
18630
19009
  stripFrontmatter: () => stripFrontmatter2
18631
19010
  });
18632
- import { readdir as readdir4, readFile as readFile5 } from "fs/promises";
19011
+ import { readdir as readdir5, readFile as readFile5 } from "fs/promises";
18633
19012
  import { createHash } from "crypto";
18634
19013
  import { homedir as homedir5 } from "os";
18635
- import { join as join20 } from "path";
19014
+ import { join as join21 } from "path";
18636
19015
  function invalidateSkillCache() {
18637
19016
  cachedSkills = null;
18638
19017
  cacheTimestamp = 0;
@@ -18650,7 +19029,7 @@ async function discoverAllSkills() {
18650
19029
  const rawSkills = [];
18651
19030
  rawSkills.push(...await scanSkillDir(SKILLS_PATH, "cc-claw"));
18652
19031
  for (const backendId of getAllBackendIds()) {
18653
- const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join20(homedir5(), `.${backendId}`, "skills")];
19032
+ const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join21(homedir5(), `.${backendId}`, "skills")];
18654
19033
  for (const dir of dirs) {
18655
19034
  rawSkills.push(...await scanSkillDir(dir, backendId));
18656
19035
  }
@@ -18669,7 +19048,7 @@ async function scanSkillDir(skillsDir, source) {
18669
19048
  const results = [];
18670
19049
  let entries;
18671
19050
  try {
18672
- entries = await readdir4(skillsDir, { withFileTypes: true });
19051
+ entries = await readdir5(skillsDir, { withFileTypes: true });
18673
19052
  } catch {
18674
19053
  return results;
18675
19054
  }
@@ -18678,7 +19057,7 @@ async function scanSkillDir(skillsDir, source) {
18678
19057
  let content;
18679
19058
  let resolvedPath;
18680
19059
  for (const candidate of SKILL_FILE_CANDIDATES) {
18681
- const p = join20(skillsDir, entry.name, candidate);
19060
+ const p = join21(skillsDir, entry.name, candidate);
18682
19061
  try {
18683
19062
  content = await readFile5(p, "utf-8");
18684
19063
  resolvedPath = p;
@@ -18695,9 +19074,7 @@ async function scanSkillDir(skillsDir, source) {
18695
19074
  description: frontmatter.description,
18696
19075
  filePath: resolvedPath,
18697
19076
  source,
18698
- contentHash: hash,
18699
- compatibleBackends: frontmatter.compatibleBackends,
18700
- recommendedModel: frontmatter.recommendedModel
19077
+ contentHash: hash
18701
19078
  });
18702
19079
  }
18703
19080
  return results;
@@ -18726,9 +19103,7 @@ function mergeAndDeduplicate(raw) {
18726
19103
  filePath: primary.filePath,
18727
19104
  source: primary.source,
18728
19105
  sources: [...new Set(allSources)],
18729
- contentHash: primary.contentHash,
18730
- compatibleBackends: primary.compatibleBackends,
18731
- recommendedModel: primary.recommendedModel
19106
+ contentHash: primary.contentHash
18732
19107
  });
18733
19108
  } else {
18734
19109
  for (const [hash, copies] of byHash) {
@@ -18740,9 +19115,7 @@ function mergeAndDeduplicate(raw) {
18740
19115
  filePath: primary.filePath,
18741
19116
  source: primary.source,
18742
19117
  sources: [...new Set(allSources)],
18743
- contentHash: hash,
18744
- compatibleBackends: primary.compatibleBackends,
18745
- recommendedModel: primary.recommendedModel
19118
+ contentHash: hash
18746
19119
  });
18747
19120
  }
18748
19121
  }
@@ -18762,13 +19135,9 @@ function parseFrontmatter2(content, fallbackName) {
18762
19135
  const fm = fmMatch[1];
18763
19136
  const nameMatch = fm.match(/^name:\s*(.+)$/m);
18764
19137
  const descMatch = fm.match(/^description:\s*(.+)$/m);
18765
- const compatMatch = fm.match(/^compatible_backends:\s*(.+)$/m);
18766
- const modelMatch = fm.match(/^recommended_model:\s*(.+)$/m);
18767
19138
  return {
18768
19139
  name: nameMatch?.[1]?.trim().replace(/^["']|["']$/g, "") ?? fallbackName,
18769
- description: descMatch?.[1]?.trim().replace(/^["']|["']$/g, "") ?? "",
18770
- compatibleBackends: compatMatch ? compatMatch[1].split(",").map((s) => s.trim().toLowerCase()) : void 0,
18771
- recommendedModel: modelMatch?.[1]?.trim() ?? void 0
19140
+ description: descMatch?.[1]?.trim().replace(/^["']|["']$/g, "") ?? ""
18772
19141
  };
18773
19142
  }
18774
19143
  function stripFrontmatter2(content) {
@@ -18782,15 +19151,15 @@ var init_discover = __esm({
18782
19151
  init_backends();
18783
19152
  SKILL_FILE_CANDIDATES = ["SKILL.md", "skill.md"];
18784
19153
  BACKEND_SKILL_DIRS = {
18785
- claude: [join20(homedir5(), ".claude", "skills")],
18786
- gemini: [join20(homedir5(), ".gemini", "skills")],
19154
+ claude: [join21(homedir5(), ".claude", "skills")],
19155
+ gemini: [join21(homedir5(), ".gemini", "skills")],
18787
19156
  codex: [
18788
- join20(homedir5(), ".agents", "skills"),
18789
- join20(homedir5(), ".codex", "skills")
19157
+ join21(homedir5(), ".agents", "skills"),
19158
+ join21(homedir5(), ".codex", "skills")
18790
19159
  ],
18791
19160
  cursor: [
18792
- join20(homedir5(), ".cursor", "skills"),
18793
- join20(homedir5(), ".cursor", "skills-cursor")
19161
+ join21(homedir5(), ".cursor", "skills"),
19162
+ join21(homedir5(), ".cursor", "skills-cursor")
18794
19163
  ]
18795
19164
  };
18796
19165
  CACHE_TTL_MS2 = 3e5;
@@ -20014,13 +20383,13 @@ async function handleEvolveCallback(chatId, data, channel) {
20014
20383
  const { getReflectionStatus: getReflectionStatus2, setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
20015
20384
  const current = getReflectionStatus2(getDb(), chatId);
20016
20385
  if (current === "frozen") {
20017
- const { readFileSync: readFileSync29, existsSync: existsSync57 } = await import("fs");
20018
- const { join: join36 } = await import("path");
20386
+ const { readFileSync: readFileSync29, existsSync: existsSync58 } = await import("fs");
20387
+ const { join: join37 } = await import("path");
20019
20388
  const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
20020
- const soulPath = join36(CC_CLAW_HOME3, "identity/SOUL.md");
20021
- const userPath = join36(CC_CLAW_HOME3, "identity/USER.md");
20022
- const soul = existsSync57(soulPath) ? readFileSync29(soulPath, "utf-8") : "";
20023
- const user = existsSync57(userPath) ? readFileSync29(userPath, "utf-8") : "";
20389
+ const soulPath = join37(CC_CLAW_HOME3, "identity/SOUL.md");
20390
+ const userPath = join37(CC_CLAW_HOME3, "identity/USER.md");
20391
+ const soul = existsSync58(soulPath) ? readFileSync29(soulPath, "utf-8") : "";
20392
+ const user = existsSync58(userPath) ? readFileSync29(userPath, "utf-8") : "";
20024
20393
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
20025
20394
  const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
20026
20395
  logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
@@ -20097,11 +20466,11 @@ var init_evolve2 = __esm({
20097
20466
  });
20098
20467
 
20099
20468
  // src/optimizer/identity-audit.ts
20100
- import { readFileSync as readFileSync11, existsSync as existsSync20, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
20101
- import { join as join21 } from "path";
20469
+ import { readFileSync as readFileSync11, existsSync as existsSync21, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
20470
+ import { join as join22 } from "path";
20102
20471
  function readIdentityFile2(filename) {
20103
20472
  try {
20104
- return readFileSync11(join21(IDENTITY_PATH, filename), "utf-8");
20473
+ return readFileSync11(join22(IDENTITY_PATH, filename), "utf-8");
20105
20474
  } catch {
20106
20475
  return "";
20107
20476
  }
@@ -20116,13 +20485,13 @@ function getMtime(filepath) {
20116
20485
  function findBackupFiles() {
20117
20486
  const backups = [];
20118
20487
  const dirs = [IDENTITY_PATH];
20119
- const contextDir = join21(IDENTITY_PATH, "..", "workspace", "context");
20120
- if (existsSync20(contextDir)) dirs.push(contextDir);
20488
+ const contextDir = join22(IDENTITY_PATH, "..", "workspace", "context");
20489
+ if (existsSync21(contextDir)) dirs.push(contextDir);
20121
20490
  for (const dir of dirs) {
20122
20491
  try {
20123
20492
  for (const entry of readdirSync10(dir)) {
20124
20493
  if (entry.endsWith(".bak") || /\.bak\.\d{4}-\d{2}-\d{2}/.test(entry)) {
20125
- backups.push(join21(dir, entry));
20494
+ backups.push(join22(dir, entry));
20126
20495
  }
20127
20496
  }
20128
20497
  } catch {
@@ -20143,9 +20512,9 @@ function computeIdentityStats(pendingProposals, driftPercent) {
20143
20512
  userChars,
20144
20513
  ccClawChars,
20145
20514
  boilerplateChars,
20146
- soulMtime: getMtime(join21(IDENTITY_PATH, "SOUL.md")),
20147
- userMtime: getMtime(join21(IDENTITY_PATH, "USER.md")),
20148
- ccClawMtime: getMtime(join21(IDENTITY_PATH, "CC-CLAW.md")),
20515
+ soulMtime: getMtime(join22(IDENTITY_PATH, "SOUL.md")),
20516
+ userMtime: getMtime(join22(IDENTITY_PATH, "USER.md")),
20517
+ ccClawMtime: getMtime(join22(IDENTITY_PATH, "CC-CLAW.md")),
20149
20518
  backupFiles: findBackupFiles(),
20150
20519
  estimatedTokens: Math.ceil(ccClawChars / 4),
20151
20520
  pendingEvolveProposals: pendingProposals,
@@ -20254,8 +20623,8 @@ var init_identity_audit = __esm({
20254
20623
  });
20255
20624
 
20256
20625
  // src/optimizer/skill-audit.ts
20257
- import { readFileSync as readFileSync12, existsSync as existsSync21 } from "fs";
20258
- import { join as join22, basename as basename3 } from "path";
20626
+ import { readFileSync as readFileSync12, existsSync as existsSync22 } from "fs";
20627
+ import { join as join23, basename as basename3 } from "path";
20259
20628
  function parseFrontmatter3(content) {
20260
20629
  const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
20261
20630
  if (!fmMatch) return {};
@@ -20270,10 +20639,6 @@ function parseFrontmatter3(content) {
20270
20639
  const singleDesc = fm.match(/^description:\s*(.+)/m);
20271
20640
  if (singleDesc) result.description = singleDesc[1].trim().replace(/^["']|["']$/g, "");
20272
20641
  }
20273
- const backendsMatch = fm.match(/^compatible_backends:\s*(.+)/m);
20274
- if (backendsMatch) result.compatibleBackends = backendsMatch[1].trim();
20275
- const modelMatch = fm.match(/^recommended_model:\s*(.+)/m);
20276
- if (modelMatch) result.recommendedModel = modelMatch[1].trim();
20277
20642
  return result;
20278
20643
  }
20279
20644
  function detectDependentSkills(content) {
@@ -20298,7 +20663,7 @@ function computeSkillStats(skillPath) {
20298
20663
  const content = readFileSync12(skillPath, "utf-8");
20299
20664
  const lines = content.split("\n");
20300
20665
  return {
20301
- skillName: basename3(skillPath, ".md") === "SKILL" ? basename3(join22(skillPath, "..")) : basename3(skillPath, ".md"),
20666
+ skillName: basename3(skillPath, ".md") === "SKILL" ? basename3(join23(skillPath, "..")) : basename3(skillPath, ".md"),
20302
20667
  skillPath,
20303
20668
  lineCount: lines.length,
20304
20669
  charCount: content.length,
@@ -20318,11 +20683,11 @@ function loadDependentSkillContents(depNames, ccClawSkillsDir) {
20318
20683
  const results = [];
20319
20684
  for (const name of depNames) {
20320
20685
  const candidates = [
20321
- join22(ccClawSkillsDir, name, "SKILL.md"),
20322
- join22(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
20686
+ join23(ccClawSkillsDir, name, "SKILL.md"),
20687
+ join23(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
20323
20688
  ];
20324
20689
  for (const candidate of candidates) {
20325
- if (existsSync21(candidate)) {
20690
+ if (existsSync22(candidate)) {
20326
20691
  try {
20327
20692
  const content = readFileSync12(candidate, "utf-8");
20328
20693
  results.push({
@@ -20353,8 +20718,6 @@ Lines: ${stats.lineCount} (cap: 500 \u2014 over 500 = progressive disclosure nee
20353
20718
  Chars: ${stats.charCount} (~${stats.estimatedTokens} tokens)
20354
20719
  Frontmatter name: ${stats.frontmatter.name || "(missing)"}
20355
20720
  Frontmatter description: ${stats.frontmatter.description ? stats.frontmatter.description.slice(0, 200) : "(missing)"}
20356
- Compatible backends: ${stats.frontmatter.compatibleBackends || "(not specified)"}
20357
- Recommended model: ${stats.frontmatter.recommendedModel || "(not specified)"}
20358
20721
  Referenced skills: ${stats.dependentSkills.length > 0 ? stats.dependentSkills.join(", ") : "none"}`);
20359
20722
  sections.push(`[Rubric \u2014 Evaluate Each Area]
20360
20723
 
@@ -20362,7 +20725,6 @@ Referenced skills: ${stats.dependentSkills.length > 0 ? stats.dependentSkills.jo
20362
20725
  - Is 'name' present and descriptive?
20363
20726
  - Does 'description' include BOTH what the skill does AND trigger info (when to use it)?
20364
20727
  - A good description tells the AI exactly when to activate this skill
20365
- - Should 'compatible_backends' or 'recommended_model' be specified?
20366
20728
 
20367
20729
  2. BODY STRUCTURE
20368
20730
  - Over 500 lines? \u2192 needs progressive disclosure (essentials in body, details in references/)
@@ -20439,8 +20801,8 @@ __export(analyze_exports2, {
20439
20801
  });
20440
20802
  import { spawn as spawn7 } from "child_process";
20441
20803
  import { createInterface as createInterface7 } from "readline";
20442
- import { readFileSync as readFileSync13, existsSync as existsSync22, readdirSync as readdirSync12 } from "fs";
20443
- import { join as join23 } from "path";
20804
+ import { readFileSync as readFileSync13, existsSync as existsSync23, readdirSync as readdirSync12 } from "fs";
20805
+ import { join as join24 } from "path";
20444
20806
  import { homedir as homedir7 } from "os";
20445
20807
  function parseOptimizeOutput(raw, validAreas) {
20446
20808
  if (!raw || raw.includes("NO_FINDINGS")) return [];
@@ -20570,20 +20932,20 @@ function getModelDisplayInfo(chatId) {
20570
20932
  }
20571
20933
  function readIdentityFile3(filename) {
20572
20934
  try {
20573
- return readFileSync13(join23(IDENTITY_PATH, filename), "utf-8");
20935
+ return readFileSync13(join24(IDENTITY_PATH, filename), "utf-8");
20574
20936
  } catch {
20575
20937
  return "";
20576
20938
  }
20577
20939
  }
20578
20940
  function loadContextFiles2() {
20579
- const contextDir = join23(homedir7(), ".cc-claw", "workspace", "context");
20941
+ const contextDir = join24(homedir7(), ".cc-claw", "workspace", "context");
20580
20942
  const results = [];
20581
- if (!existsSync22(contextDir)) return results;
20943
+ if (!existsSync23(contextDir)) return results;
20582
20944
  try {
20583
20945
  for (const entry of readdirSync12(contextDir)) {
20584
20946
  if (!entry.endsWith(".md")) continue;
20585
20947
  try {
20586
- const content = readFileSync13(join23(contextDir, entry), "utf-8");
20948
+ const content = readFileSync13(join24(contextDir, entry), "utf-8");
20587
20949
  results.push({ name: entry, content });
20588
20950
  } catch {
20589
20951
  }
@@ -20634,7 +20996,7 @@ async function runSkillAudit(chatId, skillPath) {
20634
20996
  const stats = computeSkillStats(skillPath);
20635
20997
  log(`[optimizer] Running skill audit on ${stats.skillName} with ${adapter.id}:${model2}`);
20636
20998
  const soulMd = readIdentityFile3("SOUL.md");
20637
- const ccClawSkillsDir = join23(homedir7(), ".cc-claw", "workspace", "skills");
20999
+ const ccClawSkillsDir = join24(homedir7(), ".cc-claw", "workspace", "skills");
20638
21000
  const skillContent = readFileSync13(skillPath, "utf-8");
20639
21001
  const prompt = buildSkillAuditPrompt(skillContent, stats, soulMd, ccClawSkillsDir);
20640
21002
  const raw = await spawnAnalysis2(adapter, model2, prompt);
@@ -20649,13 +21011,13 @@ async function runSkillAudit(chatId, skillPath) {
20649
21011
  };
20650
21012
  }
20651
21013
  function listCcClawSkills() {
20652
- const skillsDir = join23(homedir7(), ".cc-claw", "workspace", "skills");
21014
+ const skillsDir = join24(homedir7(), ".cc-claw", "workspace", "skills");
20653
21015
  const entries = [];
20654
- if (!existsSync22(skillsDir)) return entries;
21016
+ if (!existsSync23(skillsDir)) return entries;
20655
21017
  try {
20656
21018
  for (const dir of readdirSync12(skillsDir)) {
20657
- const skillFile = join23(skillsDir, dir, "SKILL.md");
20658
- if (!existsSync22(skillFile)) continue;
21019
+ const skillFile = join24(skillsDir, dir, "SKILL.md");
21020
+ if (!existsSync23(skillFile)) continue;
20659
21021
  let description = "skill";
20660
21022
  try {
20661
21023
  const content = readFileSync13(skillFile, "utf-8");
@@ -20978,8 +21340,8 @@ var init_ui2 = __esm({
20978
21340
  });
20979
21341
 
20980
21342
  // src/router/optimize.ts
20981
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as existsSync23, readdirSync as readdirSync13, unlinkSync as unlinkSync7 } from "fs";
20982
- import { join as join24, dirname as dirname4 } from "path";
21343
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as existsSync24, readdirSync as readdirSync13, unlinkSync as unlinkSync7 } from "fs";
21344
+ import { join as join25, dirname as dirname4 } from "path";
20983
21345
  import { homedir as homedir8 } from "os";
20984
21346
  async function handleOptimizeCommand(chatId, channel, _args) {
20985
21347
  const { getModelDisplayInfo: getModelDisplayInfo2 } = await Promise.resolve().then(() => (init_analyze2(), analyze_exports2));
@@ -21160,7 +21522,7 @@ async function runSkillAuditFlow(chatId, channel, skillName) {
21160
21522
  } = await Promise.resolve().then(() => (init_ui2(), ui_exports));
21161
21523
  const modelInfo = getModelDisplayInfo2(chatId);
21162
21524
  if (!modelInfo) return;
21163
- const skillPath = join24(homedir8(), ".cc-claw", "workspace", "skills", skillName, "SKILL.md");
21525
+ const skillPath = join25(homedir8(), ".cc-claw", "workspace", "skills", skillName, "SKILL.md");
21164
21526
  const progressMsgId = typeof channel.sendTextReturningId === "function" ? await channel.sendTextReturningId(
21165
21527
  chatId,
21166
21528
  buildProgressMessage2(`skill: ${skillName}`, modelInfo.backend, modelInfo.model, modelInfo.thinkingLevel),
@@ -21249,7 +21611,7 @@ async function applyFinding(chatId, channel, index) {
21249
21611
  await showFinding(chatId, channel, index + 1);
21250
21612
  return;
21251
21613
  }
21252
- if (!existsSync23(targetPath)) {
21614
+ if (!existsSync24(targetPath)) {
21253
21615
  await channel.sendText(chatId, `Target file not found: ${targetPath}`, { parseMode: "plain" });
21254
21616
  session2.skipped.push(index);
21255
21617
  await showFinding(chatId, channel, index + 1);
@@ -21331,14 +21693,14 @@ async function finishReview(chatId, channel) {
21331
21693
  activeSessions.delete(chatId);
21332
21694
  }
21333
21695
  function resolveTargetFile(location, auditTarget) {
21334
- const ccClawHome = join24(homedir8(), ".cc-claw");
21696
+ const ccClawHome = join25(homedir8(), ".cc-claw");
21335
21697
  const filePart = location.split(":")[0]?.trim();
21336
21698
  if (!filePart) return null;
21337
- if (filePart === "SOUL.md") return join24(ccClawHome, "identity", "SOUL.md");
21338
- if (filePart === "USER.md") return join24(ccClawHome, "identity", "USER.md");
21339
- if (filePart === "CC-CLAW.md") return join24(ccClawHome, "identity", "CC-CLAW.md");
21699
+ if (filePart === "SOUL.md") return join25(ccClawHome, "identity", "SOUL.md");
21700
+ if (filePart === "USER.md") return join25(ccClawHome, "identity", "USER.md");
21701
+ if (filePart === "CC-CLAW.md") return join25(ccClawHome, "identity", "CC-CLAW.md");
21340
21702
  if (filePart === "SKILL.md" && auditTarget !== "identity") {
21341
- return join24(ccClawHome, "workspace", "skills", auditTarget, "SKILL.md");
21703
+ return join25(ccClawHome, "workspace", "skills", auditTarget, "SKILL.md");
21342
21704
  }
21343
21705
  return null;
21344
21706
  }
@@ -21346,7 +21708,7 @@ function pruneBackups2(absolutePath) {
21346
21708
  const dir = dirname4(absolutePath);
21347
21709
  const baseName = absolutePath.split("/").pop() ?? "";
21348
21710
  try {
21349
- const backups = readdirSync13(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join24(dir, f));
21711
+ const backups = readdirSync13(dir).filter((f) => f.startsWith(baseName + ".bak.")).sort().map((f) => join25(dir, f));
21350
21712
  while (backups.length > 3) {
21351
21713
  const oldest = backups.shift();
21352
21714
  try {
@@ -21368,6 +21730,193 @@ var init_optimize = __esm({
21368
21730
  }
21369
21731
  });
21370
21732
 
21733
+ // src/skills/auto-create.ts
21734
+ var auto_create_exports = {};
21735
+ __export(auto_create_exports, {
21736
+ buildSessionExtractionPrompt: () => buildSessionExtractionPrompt,
21737
+ buildSkillExtractionPrompt: () => buildSkillExtractionPrompt,
21738
+ clearPendingDraft: () => clearPendingDraft,
21739
+ getPendingDraft: () => getPendingDraft,
21740
+ isSkillWorthy: () => isSkillWorthy,
21741
+ parseExtractedSkill: () => parseExtractedSkill,
21742
+ saveSkill: () => saveSkill,
21743
+ storePendingDraft: () => storePendingDraft
21744
+ });
21745
+ import { join as join26 } from "path";
21746
+ import { writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
21747
+ function isSkillWorthy(signals) {
21748
+ const { toolUseCount, tokenOutput, elapsedMs, userMessage } = signals;
21749
+ if (toolUseCount < 12) return false;
21750
+ if (elapsedMs < 3e5) return false;
21751
+ if (tokenOutput < 3e3) return false;
21752
+ const words = userMessage.split(/\s+/).length;
21753
+ if (words < 5) return false;
21754
+ const skillPatterns = /\b(use|using|run|with|the)\s+(the\s+)?[\w-]+\s+skill\b/i;
21755
+ if (skillPatterns.test(userMessage)) {
21756
+ log(`[auto-skill] Skipping \u2014 message references an existing skill`);
21757
+ return false;
21758
+ }
21759
+ log(`[auto-skill] Skill-worthy: tools=${toolUseCount}, tokens=${tokenOutput}, elapsed=${elapsedMs}ms`);
21760
+ return true;
21761
+ }
21762
+ function buildSkillExtractionPrompt(userMessage, assistantResponse) {
21763
+ const cappedResponse = assistantResponse.length > 8e3 ? assistantResponse.slice(0, 8e3) + "\n\n[...truncated...]" : assistantResponse;
21764
+ return [
21765
+ "You are a skill extraction assistant. Analyze the following completed task and create a reusable SKILL.md file.",
21766
+ "",
21767
+ "A skill is a set of instructions that an AI agent can follow to accomplish a similar task in the future.",
21768
+ "Focus on the PROCESS and APPROACH, not the specific details of this particular task.",
21769
+ "",
21770
+ "## Completed Task",
21771
+ "",
21772
+ `**User request:** ${userMessage}`,
21773
+ "",
21774
+ `**Assistant response:**`,
21775
+ cappedResponse,
21776
+ "",
21777
+ "## Output Format",
21778
+ "",
21779
+ "Output ONLY the SKILL.md content with this exact format:",
21780
+ "",
21781
+ "```",
21782
+ "---",
21783
+ 'name: "skill-name-in-kebab-case"',
21784
+ 'description: "What this skill does and when to use it"',
21785
+ "---",
21786
+ "",
21787
+ "## [Skill Title]",
21788
+ "",
21789
+ "[Step-by-step instructions for accomplishing this type of task]",
21790
+ "[Include decision points, best practices, and common pitfalls]",
21791
+ "[Keep it general enough to be reusable, specific enough to be helpful]",
21792
+ "```",
21793
+ "",
21794
+ "Rules:",
21795
+ "- The skill name should be descriptive and kebab-case",
21796
+ "- The description should explain WHAT it does AND WHEN to use it",
21797
+ "- Instructions should be general (not tied to specific file names or projects)",
21798
+ "- Include any important caveats or prerequisites",
21799
+ "- Keep it under 100 lines"
21800
+ ].join("\n");
21801
+ }
21802
+ function buildSessionExtractionPrompt(sessionMessages) {
21803
+ const transcript = [];
21804
+ let totalChars = 0;
21805
+ const CAP = 12e3;
21806
+ for (const msg of sessionMessages) {
21807
+ const prefix = msg.role === "user" ? "USER" : "ASSISTANT";
21808
+ const text = msg.text.length > 2e3 ? msg.text.slice(0, 2e3) + " [...]" : msg.text;
21809
+ if (totalChars + text.length > CAP) {
21810
+ transcript.push(`[...earlier messages truncated...]`);
21811
+ break;
21812
+ }
21813
+ transcript.push(`[${prefix}]: ${text}`);
21814
+ totalChars += text.length;
21815
+ }
21816
+ return [
21817
+ "You are a skill extraction assistant. Review the following session transcript and create a reusable SKILL.md file.",
21818
+ "",
21819
+ "A skill is a set of instructions that an AI agent can follow to accomplish a similar task in the future.",
21820
+ "Analyze the ENTIRE session to understand:",
21821
+ "- What the user was trying to accomplish",
21822
+ "- What tools and approaches the AI used",
21823
+ "- Any feedback the user gave (corrections, preferences, refinements)",
21824
+ "- The overall workflow pattern",
21825
+ "",
21826
+ "Focus on the PROCESS and APPROACH, not the specific details of this session.",
21827
+ "Incorporate user feedback as best practices or decision points in the skill.",
21828
+ "",
21829
+ "## Session Transcript",
21830
+ "",
21831
+ ...transcript,
21832
+ "",
21833
+ "## Output Format",
21834
+ "",
21835
+ "Output ONLY the SKILL.md content with this exact format:",
21836
+ "",
21837
+ "```",
21838
+ "---",
21839
+ 'name: "skill-name-in-kebab-case"',
21840
+ 'description: "What this skill does and when to use it"',
21841
+ "---",
21842
+ "",
21843
+ "## [Skill Title]",
21844
+ "",
21845
+ "[Step-by-step instructions for accomplishing this type of task]",
21846
+ "[Include decision points, best practices, and common pitfalls]",
21847
+ "[Incorporate any user preferences or corrections from the session]",
21848
+ "[Keep it general enough to be reusable, specific enough to be helpful]",
21849
+ "```",
21850
+ "",
21851
+ "Rules:",
21852
+ "- The skill name should be descriptive and kebab-case",
21853
+ "- The description should explain WHAT it does AND WHEN to use it",
21854
+ "- Instructions should be general (not tied to specific file names or projects)",
21855
+ "- If the user corrected the AI during the session, bake those corrections into the skill as best practices",
21856
+ "- Include any important caveats or prerequisites",
21857
+ "- Keep it under 100 lines"
21858
+ ].join("\n");
21859
+ }
21860
+ function parseExtractedSkill(llmResponse) {
21861
+ let content = llmResponse;
21862
+ const fenceMatch = llmResponse.match(/```(?:markdown|md)?\s*\n([\s\S]*?)```/);
21863
+ if (fenceMatch) content = fenceMatch[1].trim();
21864
+ let fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
21865
+ if (!fmMatch) {
21866
+ const greedyFence = llmResponse.match(/```(?:markdown|md)?\s*\n([\s\S]*)```/);
21867
+ if (greedyFence) {
21868
+ content = greedyFence[1].trim();
21869
+ fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
21870
+ }
21871
+ }
21872
+ if (!fmMatch) {
21873
+ fmMatch = llmResponse.match(/---\s*\n([\s\S]*?)\n---/);
21874
+ if (fmMatch) {
21875
+ const fmStart = llmResponse.indexOf(fmMatch[0]);
21876
+ content = llmResponse.slice(fmStart).replace(/```\s*$/, "").trim();
21877
+ }
21878
+ }
21879
+ if (!fmMatch) {
21880
+ warn("[auto-skill] No frontmatter found in extracted skill");
21881
+ return null;
21882
+ }
21883
+ const nameMatch = fmMatch[1].match(/^name:\s*["']?([^"'\n]+)["']?\s*$/m);
21884
+ if (!nameMatch) {
21885
+ warn("[auto-skill] No name field in skill frontmatter");
21886
+ return null;
21887
+ }
21888
+ const name = nameMatch[1].trim().toLowerCase().replace(/\s+/g, "-");
21889
+ return { name, content };
21890
+ }
21891
+ async function saveSkill(name, content) {
21892
+ const dir = join26(SKILLS_PATH, name);
21893
+ await mkdir4(dir, { recursive: true });
21894
+ const filePath = join26(dir, "SKILL.md");
21895
+ await writeFile4(filePath, content, "utf-8");
21896
+ invalidateSkillCache();
21897
+ log(`[auto-skill] Saved skill "${name}" to ${filePath}`);
21898
+ return { path: filePath };
21899
+ }
21900
+ function storePendingDraft(chatId, draft) {
21901
+ pendingDrafts.set(chatId, draft);
21902
+ }
21903
+ function getPendingDraft(chatId) {
21904
+ return pendingDrafts.get(chatId);
21905
+ }
21906
+ function clearPendingDraft(chatId) {
21907
+ pendingDrafts.delete(chatId);
21908
+ }
21909
+ var pendingDrafts;
21910
+ var init_auto_create = __esm({
21911
+ "src/skills/auto-create.ts"() {
21912
+ "use strict";
21913
+ init_paths();
21914
+ init_discover();
21915
+ init_log();
21916
+ pendingDrafts = /* @__PURE__ */ new Map();
21917
+ }
21918
+ });
21919
+
21371
21920
  // src/council/types.ts
21372
21921
  var COUNCIL_MIN_PARTICIPANTS, COUNCIL_MAX_ROUNDS, COUNCIL_WIZARD_TIMEOUT_MS;
21373
21922
  var init_types4 = __esm({
@@ -21720,6 +22269,49 @@ Use /skills to see it.`, { parseMode: "plain" });
21720
22269
  await channel.sendText(chatId, `Installation failed: ${result.error}`, { parseMode: "plain" });
21721
22270
  }
21722
22271
  }
22272
+ async function handleExtractSkillCommand(chatId, commandArgs, msg, channel) {
22273
+ const { getLog: getLog2 } = await Promise.resolve().then(() => (init_session_log(), session_log_exports));
22274
+ const sessionMessages = getLog2(chatId);
22275
+ if (sessionMessages.length < 2) {
22276
+ await channel.sendText(chatId, "No session history to extract from. Have a conversation first, then run /extract_skill.", { parseMode: "plain" });
22277
+ return;
22278
+ }
22279
+ await channel.sendText(chatId, `Reviewing session (${Math.floor(sessionMessages.length / 2)} exchanges)...`, { parseMode: "plain" });
22280
+ const { buildSessionExtractionPrompt: buildSessionExtractionPrompt2, parseExtractedSkill: parseExtractedSkill2, storePendingDraft: storePendingDraft2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
22281
+ const { askAgent: askAgent3 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
22282
+ const { getMode: getMode3 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
22283
+ const prompt = buildSessionExtractionPrompt2(sessionMessages);
22284
+ const response = await askAgent3(chatId, prompt, { permMode: getMode3(chatId) });
22285
+ const extracted = parseExtractedSkill2(response.text);
22286
+ if (!extracted) {
22287
+ await channel.sendText(chatId, "Could not extract a skill from this session. The session may be too short or unfocused.", { parseMode: "plain" });
22288
+ return;
22289
+ }
22290
+ storePendingDraft2(chatId, {
22291
+ name: extracted.name,
22292
+ content: extracted.content,
22293
+ userMessage: sessionMessages.filter((m) => m.role === "user").map((m) => m.text).join("\n"),
22294
+ assistantResponse: sessionMessages.filter((m) => m.role === "assistant").map((m) => m.text).join("\n")
22295
+ });
22296
+ const preview = extracted.content.length > 3500 ? extracted.content.slice(0, 3500) + "\n\n[...truncated...]" : extracted.content;
22297
+ if (typeof channel.sendKeyboard === "function") {
22298
+ await channel.sendText(chatId, `Extracted skill: "${extracted.name}"
22299
+
22300
+ ${preview}`, { parseMode: "plain" });
22301
+ await channel.sendKeyboard(
22302
+ chatId,
22303
+ `Save this skill?`,
22304
+ [[
22305
+ { label: "\u2705 Save Skill", data: "skill:confirm-save", style: "success" },
22306
+ { label: "\u2715 Discard", data: "skill:discard" }
22307
+ ]]
22308
+ );
22309
+ } else {
22310
+ const { saveSkill: saveSkill2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
22311
+ const result = await saveSkill2(extracted.name, extracted.content);
22312
+ await channel.sendText(chatId, `Skill "${extracted.name}" saved to ${result.path}`, { parseMode: "plain" });
22313
+ }
22314
+ }
21723
22315
  async function handleSetupProfileCommand(chatId, commandArgs, msg, channel) {
21724
22316
  await startProfileWizard(chatId, channel);
21725
22317
  }
@@ -23364,6 +23956,10 @@ async function handleCommand(msg, channel) {
23364
23956
  case "skill-install":
23365
23957
  await handleSkillInstallCommand(chatId, commandArgs, msg, channel);
23366
23958
  break;
23959
+ case "extract_skill":
23960
+ case "extractskill":
23961
+ await handleExtractSkillCommand(chatId, commandArgs, msg, channel);
23962
+ break;
23367
23963
  case "setup-profile":
23368
23964
  await handleSetupProfileCommand(chatId, commandArgs, msg, channel);
23369
23965
  break;
@@ -23450,134 +24046,6 @@ var init_commands = __esm({
23450
24046
  }
23451
24047
  });
23452
24048
 
23453
- // src/skills/auto-create.ts
23454
- var auto_create_exports = {};
23455
- __export(auto_create_exports, {
23456
- buildSkillExtractionPrompt: () => buildSkillExtractionPrompt,
23457
- clearPendingDraft: () => clearPendingDraft,
23458
- getPendingDraft: () => getPendingDraft,
23459
- isSkillWorthy: () => isSkillWorthy,
23460
- parseExtractedSkill: () => parseExtractedSkill,
23461
- saveSkill: () => saveSkill,
23462
- storePendingDraft: () => storePendingDraft
23463
- });
23464
- import { join as join25 } from "path";
23465
- import { writeFile as writeFile4, mkdir as mkdir3 } from "fs/promises";
23466
- function isSkillWorthy(signals) {
23467
- const { toolUseCount, tokenOutput, elapsedMs, userMessage } = signals;
23468
- if (toolUseCount < 8) return false;
23469
- const supplementary = [
23470
- tokenOutput >= 3e3,
23471
- // substantial output
23472
- elapsedMs >= 45e3
23473
- // took real effort (45s+)
23474
- ].filter(Boolean).length;
23475
- if (supplementary < 1) return false;
23476
- const words = userMessage.split(/\s+/).length;
23477
- if (words < 5) return false;
23478
- log(`[auto-skill] Skill-worthy: tools=${toolUseCount}, tokens=${tokenOutput}, elapsed=${elapsedMs}ms`);
23479
- return true;
23480
- }
23481
- function buildSkillExtractionPrompt(userMessage, assistantResponse) {
23482
- const cappedResponse = assistantResponse.length > 8e3 ? assistantResponse.slice(0, 8e3) + "\n\n[...truncated...]" : assistantResponse;
23483
- return [
23484
- "You are a skill extraction assistant. Analyze the following completed task and create a reusable SKILL.md file.",
23485
- "",
23486
- "A skill is a set of instructions that an AI agent can follow to accomplish a similar task in the future.",
23487
- "Focus on the PROCESS and APPROACH, not the specific details of this particular task.",
23488
- "",
23489
- "## Completed Task",
23490
- "",
23491
- `**User request:** ${userMessage}`,
23492
- "",
23493
- `**Assistant response:**`,
23494
- cappedResponse,
23495
- "",
23496
- "## Output Format",
23497
- "",
23498
- "Output ONLY the SKILL.md content with this exact format:",
23499
- "",
23500
- "```",
23501
- "---",
23502
- 'name: "skill-name-in-kebab-case"',
23503
- 'description: "What this skill does and when to use it"',
23504
- "---",
23505
- "",
23506
- "## [Skill Title]",
23507
- "",
23508
- "[Step-by-step instructions for accomplishing this type of task]",
23509
- "[Include decision points, best practices, and common pitfalls]",
23510
- "[Keep it general enough to be reusable, specific enough to be helpful]",
23511
- "```",
23512
- "",
23513
- "Rules:",
23514
- "- The skill name should be descriptive and kebab-case",
23515
- "- The description should explain WHAT it does AND WHEN to use it",
23516
- "- Instructions should be general (not tied to specific file names or projects)",
23517
- "- Include any important caveats or prerequisites",
23518
- "- Keep it under 100 lines"
23519
- ].join("\n");
23520
- }
23521
- function parseExtractedSkill(llmResponse) {
23522
- let content = llmResponse;
23523
- const fenceMatch = llmResponse.match(/```(?:markdown|md)?\s*\n([\s\S]*?)```/);
23524
- if (fenceMatch) content = fenceMatch[1].trim();
23525
- let fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
23526
- if (!fmMatch) {
23527
- const greedyFence = llmResponse.match(/```(?:markdown|md)?\s*\n([\s\S]*)```/);
23528
- if (greedyFence) {
23529
- content = greedyFence[1].trim();
23530
- fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
23531
- }
23532
- }
23533
- if (!fmMatch) {
23534
- fmMatch = llmResponse.match(/---\s*\n([\s\S]*?)\n---/);
23535
- if (fmMatch) {
23536
- const fmStart = llmResponse.indexOf(fmMatch[0]);
23537
- content = llmResponse.slice(fmStart).replace(/```\s*$/, "").trim();
23538
- }
23539
- }
23540
- if (!fmMatch) {
23541
- warn("[auto-skill] No frontmatter found in extracted skill");
23542
- return null;
23543
- }
23544
- const nameMatch = fmMatch[1].match(/^name:\s*["']?([^"'\n]+)["']?\s*$/m);
23545
- if (!nameMatch) {
23546
- warn("[auto-skill] No name field in skill frontmatter");
23547
- return null;
23548
- }
23549
- const name = nameMatch[1].trim().toLowerCase().replace(/\s+/g, "-");
23550
- return { name, content };
23551
- }
23552
- async function saveSkill(name, content) {
23553
- const dir = join25(SKILLS_PATH, name);
23554
- await mkdir3(dir, { recursive: true });
23555
- const filePath = join25(dir, "SKILL.md");
23556
- await writeFile4(filePath, content, "utf-8");
23557
- invalidateSkillCache();
23558
- log(`[auto-skill] Saved skill "${name}" to ${filePath}`);
23559
- return { path: filePath };
23560
- }
23561
- function storePendingDraft(chatId, draft) {
23562
- pendingDrafts.set(chatId, draft);
23563
- }
23564
- function getPendingDraft(chatId) {
23565
- return pendingDrafts.get(chatId);
23566
- }
23567
- function clearPendingDraft(chatId) {
23568
- pendingDrafts.delete(chatId);
23569
- }
23570
- var pendingDrafts;
23571
- var init_auto_create = __esm({
23572
- "src/skills/auto-create.ts"() {
23573
- "use strict";
23574
- init_paths();
23575
- init_discover();
23576
- init_log();
23577
- pendingDrafts = /* @__PURE__ */ new Map();
23578
- }
23579
- });
23580
-
23581
24049
  // src/router/callbacks.ts
23582
24050
  import { readFile as readFile7 } from "fs/promises";
23583
24051
  async function handleCallback(chatId, data, channel, messageId) {
@@ -23980,7 +24448,107 @@ This cannot be undone.`,
23980
24448
  }
23981
24449
  } else if (rest.startsWith("edit:")) {
23982
24450
  const id = parseInt(rest.slice(5), 10);
24451
+ const editJob = getJobById(id);
24452
+ if (!editJob) {
24453
+ await channel.sendText(chatId, `Job #${id} not found.`, { parseMode: "plain" });
24454
+ return;
24455
+ }
24456
+ if (typeof channel.sendKeyboard === "function") {
24457
+ const backendLabel = editJob.backend ? `${editJob.backend}/${editJob.model ?? "default"}` : "chat default";
24458
+ await channel.sendKeyboard(
24459
+ chatId,
24460
+ `Edit Job #${id}
24461
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
24462
+ What do you want to change?`,
24463
+ [
24464
+ [
24465
+ { label: "\u{1F4C5} Schedule", data: `job:editwiz:${id}` },
24466
+ { label: "\u{1F527} Backend/Model", data: `job:editbackend:${id}` }
24467
+ ],
24468
+ [
24469
+ { label: "\u23F1 Timeout", data: `job:edittimeout:${id}` },
24470
+ { label: "\u{1F4DD} Full Edit", data: `job:editwiz:${id}` }
24471
+ ],
24472
+ [{ label: "\u2190 Back to Job", data: `job:view:${id}` }]
24473
+ ]
24474
+ );
24475
+ } else {
24476
+ await startEditWizard(chatId, id, channel);
24477
+ }
24478
+ } else if (rest.startsWith("editwiz:")) {
24479
+ const id = parseInt(rest.slice(8), 10);
23983
24480
  await startEditWizard(chatId, id, channel);
24481
+ } else if (rest.startsWith("editbackend:")) {
24482
+ const id = parseInt(rest.slice(12), 10);
24483
+ const { getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24484
+ const adapters2 = getAllAdapters5().filter((a) => a.id !== "ollama");
24485
+ const buttons = adapters2.map((a) => ({
24486
+ label: a.displayName,
24487
+ data: `job:setbackend:${id}:${a.id}`
24488
+ }));
24489
+ const rows = [];
24490
+ for (let i = 0; i < buttons.length; i += 2) {
24491
+ rows.push(buttons.slice(i, i + 2));
24492
+ }
24493
+ rows.push([{ label: "\u2190 Back", data: `job:edit:${id}` }]);
24494
+ if (typeof channel.sendKeyboard === "function") {
24495
+ await channel.sendKeyboard(chatId, `Pick a backend for Job #${id}:`, rows);
24496
+ }
24497
+ } else if (rest.startsWith("setbackend:")) {
24498
+ const parts = rest.slice(11).split(":");
24499
+ const id = parseInt(parts[0], 10);
24500
+ const backend2 = parts[1];
24501
+ const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24502
+ const adapter = getAdapter4(backend2);
24503
+ const models = Object.entries(adapter.availableModels);
24504
+ const buttons = models.map(([modelId, info]) => ({
24505
+ label: info.label?.split("\u2014")[0]?.trim() ?? modelId,
24506
+ data: `job:setmodel:${id}:${backend2}:${modelId}`
24507
+ }));
24508
+ const rows = [];
24509
+ for (let i = 0; i < buttons.length; i += 2) {
24510
+ rows.push(buttons.slice(i, i + 2));
24511
+ }
24512
+ rows.push([{ label: "\u2190 Back", data: `job:editbackend:${id}` }]);
24513
+ if (typeof channel.sendKeyboard === "function") {
24514
+ await channel.sendKeyboard(chatId, `Pick a model for ${adapter.displayName}:`, rows);
24515
+ }
24516
+ } else if (rest.startsWith("setmodel:")) {
24517
+ const parts = rest.slice(9).split(":");
24518
+ const id = parseInt(parts[0], 10);
24519
+ const backend2 = parts[1];
24520
+ const model2 = parts.slice(2).join(":");
24521
+ const { updateJob: updateJobFields } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24522
+ updateJobFields(id, { backend: backend2, model: model2 });
24523
+ const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24524
+ const adapter = getAdapter4(backend2);
24525
+ await channel.sendText(chatId, `Job #${id} updated: ${adapter.displayName} / ${model2}`, { parseMode: "plain" });
24526
+ await sendJobDetail(chatId, id, channel);
24527
+ } else if (rest.startsWith("edittimeout:")) {
24528
+ const id = parseInt(rest.slice(12), 10);
24529
+ if (typeof channel.sendKeyboard === "function") {
24530
+ await channel.sendKeyboard(chatId, `Set timeout for Job #${id}:`, [
24531
+ [
24532
+ { label: "2 min", data: `job:settimeout:${id}:120` },
24533
+ { label: "5 min", data: `job:settimeout:${id}:300` },
24534
+ { label: "10 min", data: `job:settimeout:${id}:600` }
24535
+ ],
24536
+ [
24537
+ { label: "15 min", data: `job:settimeout:${id}:900` },
24538
+ { label: "30 min", data: `job:settimeout:${id}:1800` },
24539
+ { label: "60 min", data: `job:settimeout:${id}:3600` }
24540
+ ],
24541
+ [{ label: "\u2190 Back", data: `job:edit:${id}` }]
24542
+ ]);
24543
+ }
24544
+ } else if (rest.startsWith("settimeout:")) {
24545
+ const parts = rest.slice(11).split(":");
24546
+ const id = parseInt(parts[0], 10);
24547
+ const timeout = parseInt(parts[1], 10);
24548
+ const { updateJob: updateJobFields } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24549
+ updateJobFields(id, { timeout });
24550
+ await channel.sendText(chatId, `Job #${id} timeout updated: ${timeout}s (${Math.round(timeout / 60)} min)`, { parseMode: "plain" });
24551
+ await sendJobDetail(chatId, id, channel);
23984
24552
  } else if (rest === "back") {
23985
24553
  await sendJobsBoard(chatId, channel, 1, messageId);
23986
24554
  } else {
@@ -24786,14 +25354,6 @@ Use /skills to see all available skills.`, { parseMode: "plain" });
24786
25354
  await channel.sendText(chatId, `Skill "${skillName}" not found.`, { parseMode: "plain" });
24787
25355
  return;
24788
25356
  }
24789
- const activeBackend = getBackend(chatId) ?? "claude";
24790
- if (skill.compatibleBackends && !skill.compatibleBackends.includes(activeBackend)) {
24791
- await channel.sendText(
24792
- chatId,
24793
- `Note: "${skillName}" lists compatible backends as [${skill.compatibleBackends.join(", ")}], but active backend is ${activeBackend}. Proceeding anyway.`,
24794
- { parseMode: "plain" }
24795
- );
24796
- }
24797
25357
  const raw = await readFile7(skill.filePath, "utf-8");
24798
25358
  const skillContent = stripFrontmatter2(raw);
24799
25359
  const tags = skill.sources.join(", ");
@@ -26322,7 +26882,7 @@ var init_cron = __esm({
26322
26882
  });
26323
26883
 
26324
26884
  // src/agents/runners/wrap-backend.ts
26325
- import { join as join26 } from "path";
26885
+ import { join as join27 } from "path";
26326
26886
  function buildMcpCommands(backendId) {
26327
26887
  const exe = backendId === BACKEND.CURSOR ? "agent" : backendId;
26328
26888
  return {
@@ -26416,7 +26976,7 @@ function wrapBackendAdapter(adapter) {
26416
26976
  const configPath = writeMcpConfigFile(server);
26417
26977
  return ["--mcp-config", configPath];
26418
26978
  },
26419
- getSkillPath: () => join26(SKILLS_PATH, `agent-${adapter.id}.md`)
26979
+ getSkillPath: () => join27(SKILLS_PATH, `agent-${adapter.id}.md`)
26420
26980
  };
26421
26981
  }
26422
26982
  var BACKEND_CAPABILITIES;
@@ -26478,18 +27038,18 @@ var init_wrap_backend = __esm({
26478
27038
  });
26479
27039
 
26480
27040
  // src/agents/runners/config-loader.ts
26481
- import { readFileSync as readFileSync15, readdirSync as readdirSync14, existsSync as existsSync24, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
26482
- import { join as join27 } from "path";
27041
+ import { readFileSync as readFileSync15, readdirSync as readdirSync14, existsSync as existsSync25, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
27042
+ import { join as join28 } from "path";
26483
27043
  import { execFileSync as execFileSync3 } from "child_process";
26484
27044
  function resolveExecutable2(config2) {
26485
- if (existsSync24(config2.executable)) return config2.executable;
27045
+ if (existsSync25(config2.executable)) return config2.executable;
26486
27046
  try {
26487
27047
  return execFileSync3("which", [config2.executable], { encoding: "utf-8" }).trim();
26488
27048
  } catch {
26489
27049
  }
26490
27050
  for (const fallback of config2.executableFallbacks ?? []) {
26491
27051
  const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
26492
- if (existsSync24(resolved)) return resolved;
27052
+ if (existsSync25(resolved)) return resolved;
26493
27053
  }
26494
27054
  return config2.executable;
26495
27055
  }
@@ -26615,7 +27175,7 @@ function configToRunner(config2) {
26615
27175
  prepareMcpInjection() {
26616
27176
  return [];
26617
27177
  },
26618
- getSkillPath: () => join27(SKILLS_PATH, `agent-${config2.id}.md`)
27178
+ getSkillPath: () => join28(SKILLS_PATH, `agent-${config2.id}.md`)
26619
27179
  };
26620
27180
  }
26621
27181
  function loadRunnerConfig(filePath) {
@@ -26628,14 +27188,14 @@ function loadRunnerConfig(filePath) {
26628
27188
  }
26629
27189
  }
26630
27190
  function loadAllRunnerConfigs() {
26631
- if (!existsSync24(RUNNERS_PATH)) {
27191
+ if (!existsSync25(RUNNERS_PATH)) {
26632
27192
  mkdirSync10(RUNNERS_PATH, { recursive: true });
26633
27193
  return [];
26634
27194
  }
26635
27195
  const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
26636
27196
  const configs = [];
26637
27197
  for (const file of files) {
26638
- const config2 = loadRunnerConfig(join27(RUNNERS_PATH, file));
27198
+ const config2 = loadRunnerConfig(join28(RUNNERS_PATH, file));
26639
27199
  if (config2) configs.push(config2);
26640
27200
  }
26641
27201
  return configs;
@@ -26656,16 +27216,16 @@ function registerConfigRunners() {
26656
27216
  return count;
26657
27217
  }
26658
27218
  function watchRunnerConfigs(onChange) {
26659
- if (!existsSync24(RUNNERS_PATH)) return;
27219
+ if (!existsSync25(RUNNERS_PATH)) return;
26660
27220
  for (const prev of watchedFiles) {
26661
- if (!existsSync24(prev)) {
27221
+ if (!existsSync25(prev)) {
26662
27222
  unwatchFile(prev);
26663
27223
  watchedFiles.delete(prev);
26664
27224
  }
26665
27225
  }
26666
27226
  const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
26667
27227
  for (const file of files) {
26668
- const fullPath = join27(RUNNERS_PATH, file);
27228
+ const fullPath = join28(RUNNERS_PATH, file);
26669
27229
  if (watchedFiles.has(fullPath)) continue;
26670
27230
  watchedFiles.add(fullPath);
26671
27231
  watchFile(fullPath, { interval: 5e3 }, () => {
@@ -27731,19 +28291,19 @@ var init_telegram2 = __esm({
27731
28291
  });
27732
28292
 
27733
28293
  // src/skills/bootstrap.ts
27734
- import { existsSync as existsSync25 } from "fs";
27735
- import { readdir as readdir5, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
27736
- import { join as join28, dirname as dirname5 } from "path";
28294
+ import { existsSync as existsSync26 } from "fs";
28295
+ import { readdir as readdir6, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
28296
+ import { join as join29, dirname as dirname5 } from "path";
27737
28297
  import { fileURLToPath as fileURLToPath2 } from "url";
27738
28298
  async function copyAgentManifestSkills() {
27739
- if (!existsSync25(PKG_SKILLS)) return;
28299
+ if (!existsSync26(PKG_SKILLS)) return;
27740
28300
  try {
27741
- const entries = await readdir5(PKG_SKILLS, { withFileTypes: true });
28301
+ const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
27742
28302
  for (const entry of entries) {
27743
28303
  if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
27744
- const src = join28(PKG_SKILLS, entry.name);
27745
- const dest = join28(SKILLS_PATH, entry.name);
27746
- if (existsSync25(dest)) continue;
28304
+ const src = join29(PKG_SKILLS, entry.name);
28305
+ const dest = join29(SKILLS_PATH, entry.name);
28306
+ if (existsSync26(dest)) continue;
27747
28307
  await copyFile(src, dest);
27748
28308
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
27749
28309
  }
@@ -27753,10 +28313,10 @@ async function copyAgentManifestSkills() {
27753
28313
  }
27754
28314
  async function bootstrapSkills() {
27755
28315
  await copyAgentManifestSkills();
27756
- const usmDir = join28(SKILLS_PATH, USM_DIR_NAME);
27757
- if (existsSync25(usmDir)) return;
28316
+ const usmDir = join29(SKILLS_PATH, USM_DIR_NAME);
28317
+ if (existsSync26(usmDir)) return;
27758
28318
  try {
27759
- const entries = await readdir5(SKILLS_PATH);
28319
+ const entries = await readdir6(SKILLS_PATH);
27760
28320
  const dirs = entries.filter((e) => !e.startsWith("."));
27761
28321
  if (dirs.length > 0) return;
27762
28322
  } catch (err) {
@@ -27777,8 +28337,8 @@ async function bootstrapSkills() {
27777
28337
  }
27778
28338
  }
27779
28339
  async function patchUsmForCcClaw(usmDir) {
27780
- const skillPath = join28(usmDir, "SKILL.md");
27781
- if (!existsSync25(skillPath)) return;
28340
+ const skillPath = join29(usmDir, "SKILL.md");
28341
+ if (!existsSync26(skillPath)) return;
27782
28342
  try {
27783
28343
  let content = await readFile8(skillPath, "utf-8");
27784
28344
  let patched = false;
@@ -27823,8 +28383,8 @@ var init_bootstrap = __esm({
27823
28383
  USM_REPO = "jacob-bd/universal-skills-manager";
27824
28384
  USM_DIR_NAME = "universal-skills-manager";
27825
28385
  CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
27826
- PKG_ROOT = join28(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
27827
- PKG_SKILLS = join28(PKG_ROOT, "skills");
28386
+ PKG_ROOT = join29(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
28387
+ PKG_SKILLS = join29(PKG_ROOT, "skills");
27828
28388
  }
27829
28389
  });
27830
28390
 
@@ -28046,13 +28606,13 @@ __export(ai_skill_exports, {
28046
28606
  generateAiSkill: () => generateAiSkill,
28047
28607
  installAiSkill: () => installAiSkill
28048
28608
  });
28049
- import { existsSync as existsSync26, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
28050
- import { join as join29 } from "path";
28609
+ import { existsSync as existsSync27, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
28610
+ import { join as join30 } from "path";
28051
28611
  import { homedir as homedir9 } from "os";
28052
28612
  function generateAiSkill() {
28053
28613
  const version = VERSION;
28054
28614
  let systemState = "";
28055
- if (existsSync26(DB_PATH)) {
28615
+ if (existsSync27(DB_PATH)) {
28056
28616
  try {
28057
28617
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
28058
28618
  const readDb = openDatabaseReadOnly2();
@@ -28492,8 +29052,8 @@ function installAiSkill() {
28492
29052
  const failed = [];
28493
29053
  for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
28494
29054
  for (const dir of dirs) {
28495
- const skillDir = join29(dir, "cc-claw-cli");
28496
- const skillPath = join29(skillDir, "SKILL.md");
29055
+ const skillDir = join30(dir, "cc-claw-cli");
29056
+ const skillPath = join30(skillDir, "SKILL.md");
28497
29057
  try {
28498
29058
  mkdirSync11(skillDir, { recursive: true });
28499
29059
  writeFileSync8(skillPath, skill, "utf-8");
@@ -28512,11 +29072,11 @@ var init_ai_skill = __esm({
28512
29072
  init_paths();
28513
29073
  init_version();
28514
29074
  BACKEND_SKILL_DIRS2 = {
28515
- "cc-claw": [join29(homedir9(), ".cc-claw", "workspace", "skills")],
28516
- claude: [join29(homedir9(), ".claude", "skills")],
28517
- gemini: [join29(homedir9(), ".gemini", "skills")],
28518
- codex: [join29(homedir9(), ".agents", "skills")],
28519
- cursor: [join29(homedir9(), ".cursor", "skills"), join29(homedir9(), ".cursor", "skills-cursor")]
29075
+ "cc-claw": [join30(homedir9(), ".cc-claw", "workspace", "skills")],
29076
+ claude: [join30(homedir9(), ".claude", "skills")],
29077
+ gemini: [join30(homedir9(), ".gemini", "skills")],
29078
+ codex: [join30(homedir9(), ".agents", "skills")],
29079
+ cursor: [join30(homedir9(), ".cursor", "skills"), join30(homedir9(), ".cursor", "skills-cursor")]
28520
29080
  };
28521
29081
  }
28522
29082
  });
@@ -28526,21 +29086,21 @@ var index_exports = {};
28526
29086
  __export(index_exports, {
28527
29087
  main: () => main
28528
29088
  });
28529
- import { mkdirSync as mkdirSync12, existsSync as existsSync27, renameSync as renameSync2, statSync as statSync9, readFileSync as readFileSync17 } from "fs";
28530
- import { join as join30 } from "path";
29089
+ import { mkdirSync as mkdirSync12, existsSync as existsSync28, renameSync as renameSync2, statSync as statSync9, readFileSync as readFileSync17 } from "fs";
29090
+ import { join as join31 } from "path";
28531
29091
  import dotenv from "dotenv";
28532
29092
  function migrateLayout() {
28533
29093
  const moves = [
28534
- [join30(CC_CLAW_HOME, "cc-claw.db"), join30(DATA_PATH, "cc-claw.db")],
28535
- [join30(CC_CLAW_HOME, "cc-claw.db-shm"), join30(DATA_PATH, "cc-claw.db-shm")],
28536
- [join30(CC_CLAW_HOME, "cc-claw.db-wal"), join30(DATA_PATH, "cc-claw.db-wal")],
28537
- [join30(CC_CLAW_HOME, "cc-claw.log"), join30(LOGS_PATH, "cc-claw.log")],
28538
- [join30(CC_CLAW_HOME, "cc-claw.log.1"), join30(LOGS_PATH, "cc-claw.log.1")],
28539
- [join30(CC_CLAW_HOME, "cc-claw.error.log"), join30(LOGS_PATH, "cc-claw.error.log")],
28540
- [join30(CC_CLAW_HOME, "cc-claw.error.log.1"), join30(LOGS_PATH, "cc-claw.error.log.1")]
29094
+ [join31(CC_CLAW_HOME, "cc-claw.db"), join31(DATA_PATH, "cc-claw.db")],
29095
+ [join31(CC_CLAW_HOME, "cc-claw.db-shm"), join31(DATA_PATH, "cc-claw.db-shm")],
29096
+ [join31(CC_CLAW_HOME, "cc-claw.db-wal"), join31(DATA_PATH, "cc-claw.db-wal")],
29097
+ [join31(CC_CLAW_HOME, "cc-claw.log"), join31(LOGS_PATH, "cc-claw.log")],
29098
+ [join31(CC_CLAW_HOME, "cc-claw.log.1"), join31(LOGS_PATH, "cc-claw.log.1")],
29099
+ [join31(CC_CLAW_HOME, "cc-claw.error.log"), join31(LOGS_PATH, "cc-claw.error.log")],
29100
+ [join31(CC_CLAW_HOME, "cc-claw.error.log.1"), join31(LOGS_PATH, "cc-claw.error.log.1")]
28541
29101
  ];
28542
29102
  for (const [from, to] of moves) {
28543
- if (existsSync27(from) && !existsSync27(to)) {
29103
+ if (existsSync28(from) && !existsSync28(to)) {
28544
29104
  try {
28545
29105
  renameSync2(from, to);
28546
29106
  } catch {
@@ -28717,10 +29277,10 @@ async function main() {
28717
29277
  try {
28718
29278
  const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
28719
29279
  const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync19 } = await import("fs");
28720
- const { join: join36 } = await import("path");
28721
- const skillDir = join36(SKILLS_PATH, "cc-claw-cli");
29280
+ const { join: join37 } = await import("path");
29281
+ const skillDir = join37(SKILLS_PATH, "cc-claw-cli");
28722
29282
  mkdirSync19(skillDir, { recursive: true });
28723
- writeFileSync13(join36(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
29283
+ writeFileSync13(join37(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
28724
29284
  log("[cc-claw] AI skill updated");
28725
29285
  } catch {
28726
29286
  }
@@ -28820,10 +29380,10 @@ var init_index = __esm({
28820
29380
  init_health3();
28821
29381
  init_image_gen();
28822
29382
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
28823
- if (!existsSync27(dir)) mkdirSync12(dir, { recursive: true });
29383
+ if (!existsSync28(dir)) mkdirSync12(dir, { recursive: true });
28824
29384
  }
28825
29385
  migrateLayout();
28826
- if (existsSync27(ENV_PATH)) {
29386
+ if (existsSync28(ENV_PATH)) {
28827
29387
  dotenv.config({ path: ENV_PATH });
28828
29388
  } else {
28829
29389
  console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
@@ -28844,12 +29404,12 @@ __export(api_client_exports, {
28844
29404
  apiPost: () => apiPost,
28845
29405
  isDaemonRunning: () => isDaemonRunning
28846
29406
  });
28847
- import { readFileSync as readFileSync18, existsSync as existsSync28 } from "fs";
29407
+ import { readFileSync as readFileSync18, existsSync as existsSync29 } from "fs";
28848
29408
  import { request as httpRequest, Agent } from "http";
28849
29409
  function getToken() {
28850
29410
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
28851
29411
  try {
28852
- if (existsSync28(TOKEN_PATH)) return readFileSync18(TOKEN_PATH, "utf-8").trim();
29412
+ if (existsSync29(TOKEN_PATH)) return readFileSync18(TOKEN_PATH, "utf-8").trim();
28853
29413
  } catch {
28854
29414
  }
28855
29415
  return null;
@@ -28948,10 +29508,10 @@ __export(service_exports2, {
28948
29508
  serviceStatus: () => serviceStatus,
28949
29509
  uninstallService: () => uninstallService
28950
29510
  });
28951
- import { existsSync as existsSync29, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8 } from "fs";
29511
+ import { existsSync as existsSync30, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8 } from "fs";
28952
29512
  import { execFileSync as execFileSync4, execSync as execSync5 } from "child_process";
28953
29513
  import { homedir as homedir10, platform } from "os";
28954
- import { join as join31, dirname as dirname6 } from "path";
29514
+ import { join as join32, dirname as dirname6 } from "path";
28955
29515
  function xmlEscape(s) {
28956
29516
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
28957
29517
  }
@@ -28960,7 +29520,7 @@ function resolveExecutable3(name) {
28960
29520
  return execFileSync4("which", [name], { encoding: "utf-8" }).trim();
28961
29521
  } catch {
28962
29522
  const fallback = process.argv[1];
28963
- if (fallback && existsSync29(fallback)) return fallback;
29523
+ if (fallback && existsSync30(fallback)) return fallback;
28964
29524
  throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
28965
29525
  }
28966
29526
  }
@@ -28969,14 +29529,14 @@ function getPathDirs() {
28969
29529
  const home = homedir10();
28970
29530
  const dirs = /* @__PURE__ */ new Set([
28971
29531
  nodeBin,
28972
- join31(home, ".local", "bin"),
29532
+ join32(home, ".local", "bin"),
28973
29533
  "/usr/local/bin",
28974
29534
  "/usr/bin",
28975
29535
  "/bin"
28976
29536
  ]);
28977
29537
  try {
28978
29538
  const prefix = execSync5("npm config get prefix", { encoding: "utf-8" }).trim();
28979
- if (prefix) dirs.add(join31(prefix, "bin"));
29539
+ if (prefix) dirs.add(join32(prefix, "bin"));
28980
29540
  } catch {
28981
29541
  }
28982
29542
  return [...dirs].join(":");
@@ -29035,9 +29595,9 @@ function generatePlist() {
29035
29595
  }
29036
29596
  function installMacOS() {
29037
29597
  const agentsDir = dirname6(PLIST_PATH);
29038
- if (!existsSync29(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
29039
- if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
29040
- if (existsSync29(PLIST_PATH)) {
29598
+ if (!existsSync30(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
29599
+ if (!existsSync30(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
29600
+ if (existsSync30(PLIST_PATH)) {
29041
29601
  try {
29042
29602
  execFileSync4("launchctl", ["unload", PLIST_PATH]);
29043
29603
  } catch {
@@ -29049,7 +29609,7 @@ function installMacOS() {
29049
29609
  console.log(" Service loaded and starting.");
29050
29610
  }
29051
29611
  function uninstallMacOS() {
29052
- if (!existsSync29(PLIST_PATH)) {
29612
+ if (!existsSync30(PLIST_PATH)) {
29053
29613
  console.log(" No service found to uninstall.");
29054
29614
  return;
29055
29615
  }
@@ -29124,8 +29684,8 @@ WantedBy=default.target
29124
29684
  `;
29125
29685
  }
29126
29686
  function installLinux() {
29127
- if (!existsSync29(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
29128
- if (!existsSync29(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
29687
+ if (!existsSync30(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
29688
+ if (!existsSync30(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
29129
29689
  writeFileSync9(UNIT_PATH, generateUnit());
29130
29690
  console.log(` Installed: ${UNIT_PATH}`);
29131
29691
  execFileSync4("systemctl", ["--user", "daemon-reload"]);
@@ -29134,7 +29694,7 @@ function installLinux() {
29134
29694
  console.log(" Service enabled and started.");
29135
29695
  }
29136
29696
  function uninstallLinux() {
29137
- if (!existsSync29(UNIT_PATH)) {
29697
+ if (!existsSync30(UNIT_PATH)) {
29138
29698
  console.log(" No service found to uninstall.");
29139
29699
  return;
29140
29700
  }
@@ -29159,7 +29719,7 @@ function statusLinux() {
29159
29719
  }
29160
29720
  }
29161
29721
  function installService() {
29162
- if (!existsSync29(join31(CC_CLAW_HOME, ".env"))) {
29722
+ if (!existsSync30(join32(CC_CLAW_HOME, ".env"))) {
29163
29723
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
29164
29724
  console.error(" Run 'cc-claw setup' before installing the service.");
29165
29725
  process.exitCode = 1;
@@ -29188,9 +29748,9 @@ var init_service2 = __esm({
29188
29748
  "use strict";
29189
29749
  init_paths();
29190
29750
  PLIST_LABEL = "com.cc-claw";
29191
- PLIST_PATH = join31(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
29192
- SYSTEMD_DIR = join31(homedir10(), ".config", "systemd", "user");
29193
- UNIT_PATH = join31(SYSTEMD_DIR, "cc-claw.service");
29751
+ PLIST_PATH = join32(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
29752
+ SYSTEMD_DIR = join32(homedir10(), ".config", "systemd", "user");
29753
+ UNIT_PATH = join32(SYSTEMD_DIR, "cc-claw.service");
29194
29754
  }
29195
29755
  });
29196
29756
 
@@ -29387,7 +29947,7 @@ var status_exports = {};
29387
29947
  __export(status_exports, {
29388
29948
  statusCommand: () => statusCommand
29389
29949
  });
29390
- import { existsSync as existsSync30, statSync as statSync10 } from "fs";
29950
+ import { existsSync as existsSync31, statSync as statSync10 } from "fs";
29391
29951
  async function statusCommand(globalOpts, localOpts) {
29392
29952
  try {
29393
29953
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -29427,7 +29987,7 @@ async function statusCommand(globalOpts, localOpts) {
29427
29987
  const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
29428
29988
  const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
29429
29989
  const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
29430
- const dbStat = existsSync30(DB_PATH) ? statSync10(DB_PATH) : null;
29990
+ const dbStat = existsSync31(DB_PATH) ? statSync10(DB_PATH) : null;
29431
29991
  let daemonRunning = false;
29432
29992
  let daemonInfo = {};
29433
29993
  try {
@@ -29539,13 +30099,13 @@ __export(doctor_exports, {
29539
30099
  doctorCommand: () => doctorCommand,
29540
30100
  doctorErrors: () => doctorErrors
29541
30101
  });
29542
- import { existsSync as existsSync31, accessSync, constants } from "fs";
30102
+ import { existsSync as existsSync32, accessSync, constants } from "fs";
29543
30103
  import { execFileSync as execFileSync5 } from "child_process";
29544
30104
  async function doctorCommand(globalOpts, localOpts) {
29545
30105
  const checks = [];
29546
30106
  const dbChecks = checkDatabase();
29547
30107
  checks.push(...dbChecks);
29548
- if (existsSync31(DB_PATH)) {
30108
+ if (existsSync32(DB_PATH)) {
29549
30109
  try {
29550
30110
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29551
30111
  const readDb = openDatabaseReadOnly2();
@@ -29571,7 +30131,7 @@ async function doctorCommand(globalOpts, localOpts) {
29571
30131
  checks.push({ name: "Database health", status: "error", message: err.message });
29572
30132
  }
29573
30133
  }
29574
- if (existsSync31(ENV_PATH)) {
30134
+ if (existsSync32(ENV_PATH)) {
29575
30135
  checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
29576
30136
  } else {
29577
30137
  checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
@@ -29614,7 +30174,7 @@ async function doctorCommand(globalOpts, localOpts) {
29614
30174
  } catch {
29615
30175
  }
29616
30176
  const tokenPath = `${DATA_PATH}/api-token`;
29617
- if (existsSync31(tokenPath)) {
30177
+ if (existsSync32(tokenPath)) {
29618
30178
  try {
29619
30179
  accessSync(tokenPath, constants.R_OK);
29620
30180
  checks.push({ name: "API token", status: "ok", message: "token file readable" });
@@ -29680,7 +30240,7 @@ async function doctorCommand(globalOpts, localOpts) {
29680
30240
  const errorChecks = checks.filter(
29681
30241
  (c) => ["Rate limits", "Content silence", "Spawn timeouts", "Other errors"].includes(c.name) && c.status !== "ok"
29682
30242
  );
29683
- if (errorChecks.length > 0 && existsSync31(ERROR_LOG_PATH)) {
30243
+ if (errorChecks.length > 0 && existsSync32(ERROR_LOG_PATH)) {
29684
30244
  try {
29685
30245
  const { writeFileSync: writeFileSync13 } = await import("fs");
29686
30246
  writeFileSync13(ERROR_LOG_PATH, "");
@@ -29809,10 +30369,10 @@ var logs_exports = {};
29809
30369
  __export(logs_exports, {
29810
30370
  logsCommand: () => logsCommand
29811
30371
  });
29812
- import { existsSync as existsSync32, readFileSync as readFileSync22, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
30372
+ import { existsSync as existsSync33, readFileSync as readFileSync22, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
29813
30373
  async function logsCommand(opts) {
29814
30374
  const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
29815
- if (!existsSync32(logFile)) {
30375
+ if (!existsSync33(logFile)) {
29816
30376
  outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
29817
30377
  process.exit(1);
29818
30378
  }
@@ -29965,11 +30525,11 @@ __export(gemini_exports, {
29965
30525
  geminiReorder: () => geminiReorder,
29966
30526
  geminiRotation: () => geminiRotation
29967
30527
  });
29968
- import { existsSync as existsSync34, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync24, chmodSync } from "fs";
29969
- import { join as join32 } from "path";
30528
+ import { existsSync as existsSync35, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync24, chmodSync } from "fs";
30529
+ import { join as join33 } from "path";
29970
30530
  import { createInterface as createInterface8 } from "readline";
29971
30531
  function requireDb() {
29972
- if (!existsSync34(DB_PATH)) {
30532
+ if (!existsSync35(DB_PATH)) {
29973
30533
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
29974
30534
  process.exit(1);
29975
30535
  }
@@ -29994,8 +30554,8 @@ async function resolveSlotId(idOrLabel) {
29994
30554
  function resolveOAuthEmail(configHome) {
29995
30555
  if (!configHome) return null;
29996
30556
  try {
29997
- const accountsPath = join32(configHome, ".gemini", "google_accounts.json");
29998
- if (!existsSync34(accountsPath)) return null;
30557
+ const accountsPath = join33(configHome, ".gemini", "google_accounts.json");
30558
+ if (!existsSync35(accountsPath)) return null;
29999
30559
  const accounts = JSON.parse(readFileSync24(accountsPath, "utf-8"));
30000
30560
  return accounts.active || null;
30001
30561
  } catch {
@@ -30078,14 +30638,14 @@ async function geminiAddKey(globalOpts, opts) {
30078
30638
  }
30079
30639
  async function geminiAddAccount(globalOpts, opts) {
30080
30640
  await requireWriteDb();
30081
- const slotsDir = join32(CC_CLAW_HOME, "gemini-slots");
30082
- if (!existsSync34(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
30641
+ const slotsDir = join33(CC_CLAW_HOME, "gemini-slots");
30642
+ if (!existsSync35(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
30083
30643
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
30084
30644
  const tempId = Date.now();
30085
- const slotDir = join32(slotsDir, `slot-${tempId}`);
30645
+ const slotDir = join33(slotsDir, `slot-${tempId}`);
30086
30646
  mkdirSync14(slotDir, { recursive: true, mode: 448 });
30087
- mkdirSync14(join32(slotDir, ".gemini"), { recursive: true });
30088
- writeFileSync10(join32(slotDir, ".gemini", "settings.json"), JSON.stringify({
30647
+ mkdirSync14(join33(slotDir, ".gemini"), { recursive: true });
30648
+ writeFileSync10(join33(slotDir, ".gemini", "settings.json"), JSON.stringify({
30089
30649
  security: { auth: { selectedType: "oauth-personal" } }
30090
30650
  }, null, 2));
30091
30651
  console.log("");
@@ -30102,8 +30662,8 @@ async function geminiAddAccount(globalOpts, opts) {
30102
30662
  });
30103
30663
  } catch {
30104
30664
  }
30105
- const oauthPath = join32(slotDir, ".gemini", "oauth_creds.json");
30106
- if (!existsSync34(oauthPath)) {
30665
+ const oauthPath = join33(slotDir, ".gemini", "oauth_creds.json");
30666
+ if (!existsSync35(oauthPath)) {
30107
30667
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
30108
30668
  console.log(" The slot directory is preserved at: " + slotDir);
30109
30669
  console.log(" Re-run: cc-claw gemini add-account\n");
@@ -30111,7 +30671,7 @@ async function geminiAddAccount(globalOpts, opts) {
30111
30671
  }
30112
30672
  let accountEmail = "unknown";
30113
30673
  try {
30114
- const accounts = JSON.parse(__require("fs").readFileSync(join32(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
30674
+ const accounts = JSON.parse(__require("fs").readFileSync(join33(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
30115
30675
  accountEmail = accounts.active || accountEmail;
30116
30676
  } catch {
30117
30677
  }
@@ -30222,9 +30782,9 @@ async function geminiRelogin(globalOpts, idOrLabel) {
30222
30782
  outputError("NO_CONFIG", `Slot "${idOrLabel}" has no config directory \u2014 cannot re-login.`);
30223
30783
  return;
30224
30784
  }
30225
- const settingsPath = join32(slot.configHome, ".gemini", "settings.json");
30226
- if (!existsSync34(settingsPath)) {
30227
- mkdirSync14(join32(slot.configHome, ".gemini"), { recursive: true });
30785
+ const settingsPath = join33(slot.configHome, ".gemini", "settings.json");
30786
+ if (!existsSync35(settingsPath)) {
30787
+ mkdirSync14(join33(slot.configHome, ".gemini"), { recursive: true });
30228
30788
  writeFileSync10(settingsPath, JSON.stringify({
30229
30789
  security: { auth: { selectedType: "oauth-personal" } }
30230
30790
  }, null, 2));
@@ -30248,8 +30808,8 @@ async function geminiRelogin(globalOpts, idOrLabel) {
30248
30808
  });
30249
30809
  } catch {
30250
30810
  }
30251
- const oauthPath = join32(slot.configHome, ".gemini", "oauth_creds.json");
30252
- if (!existsSync34(oauthPath)) {
30811
+ const oauthPath = join33(slot.configHome, ".gemini", "oauth_creds.json");
30812
+ if (!existsSync35(oauthPath)) {
30253
30813
  console.log(error2("\n Re-login failed \u2014 no OAuth credentials found."));
30254
30814
  console.log(` Try again: cc-claw gemini re-login ${idOrLabel}
30255
30815
  `);
@@ -30259,7 +30819,7 @@ async function geminiRelogin(globalOpts, idOrLabel) {
30259
30819
  setGeminiSlotEnabled2(slotId, true);
30260
30820
  let accountEmail = slot.label;
30261
30821
  try {
30262
- const accounts = JSON.parse(readFileSync24(join32(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
30822
+ const accounts = JSON.parse(readFileSync24(join33(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
30263
30823
  if (accounts.active) accountEmail = accounts.active;
30264
30824
  } catch {
30265
30825
  }
@@ -30318,11 +30878,11 @@ __export(backend_cmd_factory_exports, {
30318
30878
  makeReorder: () => makeReorder,
30319
30879
  registerBackendSlotCommands: () => registerBackendSlotCommands
30320
30880
  });
30321
- import { existsSync as existsSync35, mkdirSync as mkdirSync15, readFileSync as readFileSync25 } from "fs";
30322
- import { join as join33 } from "path";
30881
+ import { existsSync as existsSync36, mkdirSync as mkdirSync15, readFileSync as readFileSync25 } from "fs";
30882
+ import { join as join34 } from "path";
30323
30883
  import { createInterface as createInterface9 } from "readline";
30324
30884
  function requireDb2() {
30325
- if (!existsSync35(DB_PATH)) {
30885
+ if (!existsSync36(DB_PATH)) {
30326
30886
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
30327
30887
  process.exit(1);
30328
30888
  }
@@ -30411,10 +30971,10 @@ function makeAddAccount(backend2, displayName) {
30411
30971
  process.exit(1);
30412
30972
  }
30413
30973
  await requireWriteDb2();
30414
- const slotsDir = join33(CC_CLAW_HOME, config2.slotsSubdir);
30415
- if (!existsSync35(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
30974
+ const slotsDir = join34(CC_CLAW_HOME, config2.slotsSubdir);
30975
+ if (!existsSync36(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
30416
30976
  const tempId = Date.now();
30417
- const slotDir = join33(slotsDir, `slot-${tempId}`);
30977
+ const slotDir = join34(slotsDir, `slot-${tempId}`);
30418
30978
  mkdirSync15(slotDir, { recursive: true, mode: 448 });
30419
30979
  if (config2.preSetup) config2.preSetup(slotDir);
30420
30980
  console.log("");
@@ -30665,12 +31225,12 @@ var init_backend_cmd_factory = __esm({
30665
31225
  envValue: (slotDir) => slotDir,
30666
31226
  envOverrides: { ANTHROPIC_API_KEY: void 0 },
30667
31227
  preSetup: (slotDir) => {
30668
- mkdirSync15(join33(slotDir, ".claude"), { recursive: true });
31228
+ mkdirSync15(join34(slotDir, ".claude"), { recursive: true });
30669
31229
  },
30670
31230
  verifyCredentials: (slotDir) => {
30671
- const claudeJson = join33(slotDir, ".claude.json");
30672
- const claudeJsonNested = join33(slotDir, ".claude", ".claude.json");
30673
- if (existsSync35(claudeJson)) {
31231
+ const claudeJson = join34(slotDir, ".claude.json");
31232
+ const claudeJsonNested = join34(slotDir, ".claude", ".claude.json");
31233
+ if (existsSync36(claudeJson)) {
30674
31234
  try {
30675
31235
  const data = JSON.parse(readFileSync25(claudeJson, "utf-8"));
30676
31236
  return Boolean(data.oauthAccount);
@@ -30678,7 +31238,7 @@ var init_backend_cmd_factory = __esm({
30678
31238
  return false;
30679
31239
  }
30680
31240
  }
30681
- if (existsSync35(claudeJsonNested)) {
31241
+ if (existsSync36(claudeJsonNested)) {
30682
31242
  try {
30683
31243
  const data = JSON.parse(readFileSync25(claudeJsonNested, "utf-8"));
30684
31244
  return Boolean(data.oauthAccount);
@@ -30701,8 +31261,8 @@ var init_backend_cmd_factory = __esm({
30701
31261
  } catch {
30702
31262
  }
30703
31263
  try {
30704
- const claudeJson = join33(slotDir, ".claude.json");
30705
- if (existsSync35(claudeJson)) {
31264
+ const claudeJson = join34(slotDir, ".claude.json");
31265
+ if (existsSync36(claudeJson)) {
30706
31266
  const data = JSON.parse(readFileSync25(claudeJson, "utf-8"));
30707
31267
  if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
30708
31268
  }
@@ -30718,11 +31278,11 @@ var init_backend_cmd_factory = __esm({
30718
31278
  envValue: (slotDir) => slotDir,
30719
31279
  envOverrides: { OPENAI_API_KEY: void 0 },
30720
31280
  verifyCredentials: (slotDir) => {
30721
- return existsSync35(join33(slotDir, "auth.json"));
31281
+ return existsSync36(join34(slotDir, "auth.json"));
30722
31282
  },
30723
31283
  extractLabel: (slotDir) => {
30724
31284
  try {
30725
- const authData = JSON.parse(readFileSync25(join33(slotDir, "auth.json"), "utf-8"));
31285
+ const authData = JSON.parse(readFileSync25(join34(slotDir, "auth.json"), "utf-8"));
30726
31286
  if (authData.email) return authData.email;
30727
31287
  if (authData.account_name) return authData.account_name;
30728
31288
  if (authData.user?.email) return authData.user.email;
@@ -30746,9 +31306,9 @@ __export(ollama_exports3, {
30746
31306
  ollamaRemove: () => ollamaRemove,
30747
31307
  ollamaTest: () => ollamaTest
30748
31308
  });
30749
- import { existsSync as existsSync36 } from "fs";
31309
+ import { existsSync as existsSync37 } from "fs";
30750
31310
  function requireDb3() {
30751
- if (!existsSync36(DB_PATH)) {
31311
+ if (!existsSync37(DB_PATH)) {
30752
31312
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
30753
31313
  process.exit(1);
30754
31314
  }
@@ -31007,12 +31567,12 @@ __export(backend_exports, {
31007
31567
  backendList: () => backendList,
31008
31568
  backendSet: () => backendSet
31009
31569
  });
31010
- import { existsSync as existsSync37 } from "fs";
31570
+ import { existsSync as existsSync38 } from "fs";
31011
31571
  async function backendList(globalOpts) {
31012
31572
  const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
31013
31573
  const chatId = resolveChatId2(globalOpts);
31014
31574
  let activeBackend = null;
31015
- if (existsSync37(DB_PATH)) {
31575
+ if (existsSync38(DB_PATH)) {
31016
31576
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
31017
31577
  const readDb = openDatabaseReadOnly2();
31018
31578
  try {
@@ -31043,7 +31603,7 @@ async function backendList(globalOpts) {
31043
31603
  }
31044
31604
  async function backendGet(globalOpts) {
31045
31605
  const chatId = resolveChatId2(globalOpts);
31046
- if (!existsSync37(DB_PATH)) {
31606
+ if (!existsSync38(DB_PATH)) {
31047
31607
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
31048
31608
  process.exit(1);
31049
31609
  }
@@ -31087,13 +31647,13 @@ __export(model_exports, {
31087
31647
  modelList: () => modelList,
31088
31648
  modelSet: () => modelSet
31089
31649
  });
31090
- import { existsSync as existsSync38 } from "fs";
31650
+ import { existsSync as existsSync39 } from "fs";
31091
31651
  async function modelList(globalOpts) {
31092
31652
  const chatId = resolveChatId2(globalOpts);
31093
31653
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
31094
31654
  const { getAdapter: getAdapter4, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
31095
31655
  let backendId = "claude";
31096
- if (existsSync38(DB_PATH)) {
31656
+ if (existsSync39(DB_PATH)) {
31097
31657
  const readDb = openDatabaseReadOnly2();
31098
31658
  try {
31099
31659
  const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
@@ -31126,7 +31686,7 @@ async function modelList(globalOpts) {
31126
31686
  }
31127
31687
  async function modelGet(globalOpts) {
31128
31688
  const chatId = resolveChatId2(globalOpts);
31129
- if (!existsSync38(DB_PATH)) {
31689
+ if (!existsSync39(DB_PATH)) {
31130
31690
  outputError("DB_NOT_FOUND", "Database not found.");
31131
31691
  process.exit(1);
31132
31692
  }
@@ -31170,9 +31730,9 @@ __export(memory_exports2, {
31170
31730
  memoryList: () => memoryList,
31171
31731
  memorySearch: () => memorySearch
31172
31732
  });
31173
- import { existsSync as existsSync39 } from "fs";
31733
+ import { existsSync as existsSync40 } from "fs";
31174
31734
  async function memoryList(globalOpts) {
31175
- if (!existsSync39(DB_PATH)) {
31735
+ if (!existsSync40(DB_PATH)) {
31176
31736
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
31177
31737
  process.exit(1);
31178
31738
  }
@@ -31196,7 +31756,7 @@ async function memoryList(globalOpts) {
31196
31756
  });
31197
31757
  }
31198
31758
  async function memorySearch(globalOpts, query) {
31199
- if (!existsSync39(DB_PATH)) {
31759
+ if (!existsSync40(DB_PATH)) {
31200
31760
  outputError("DB_NOT_FOUND", "Database not found.");
31201
31761
  process.exit(1);
31202
31762
  }
@@ -31218,7 +31778,7 @@ async function memorySearch(globalOpts, query) {
31218
31778
  });
31219
31779
  }
31220
31780
  async function memoryHistory(globalOpts, opts) {
31221
- if (!existsSync39(DB_PATH)) {
31781
+ if (!existsSync40(DB_PATH)) {
31222
31782
  outputError("DB_NOT_FOUND", "Database not found.");
31223
31783
  process.exit(1);
31224
31784
  }
@@ -31266,7 +31826,7 @@ __export(cron_exports2, {
31266
31826
  cronList: () => cronList,
31267
31827
  cronRuns: () => cronRuns
31268
31828
  });
31269
- import { existsSync as existsSync40 } from "fs";
31829
+ import { existsSync as existsSync41 } from "fs";
31270
31830
  function parseFallbacks(raw) {
31271
31831
  return raw.slice(0, 3).map((f) => {
31272
31832
  const [backend2, ...rest] = f.split(":");
@@ -31287,7 +31847,7 @@ function parseAndValidateTimeout(raw) {
31287
31847
  return val;
31288
31848
  }
31289
31849
  async function cronList(globalOpts) {
31290
- if (!existsSync40(DB_PATH)) {
31850
+ if (!existsSync41(DB_PATH)) {
31291
31851
  outputError("DB_NOT_FOUND", "Database not found.");
31292
31852
  process.exit(1);
31293
31853
  }
@@ -31325,7 +31885,7 @@ async function cronList(globalOpts) {
31325
31885
  });
31326
31886
  }
31327
31887
  async function cronHealth(globalOpts) {
31328
- if (!existsSync40(DB_PATH)) {
31888
+ if (!existsSync41(DB_PATH)) {
31329
31889
  outputError("DB_NOT_FOUND", "Database not found.");
31330
31890
  process.exit(1);
31331
31891
  }
@@ -31486,7 +32046,7 @@ async function cronEdit(globalOpts, id, opts) {
31486
32046
  }
31487
32047
  }
31488
32048
  async function cronRuns(globalOpts, jobId, opts) {
31489
- if (!existsSync40(DB_PATH)) {
32049
+ if (!existsSync41(DB_PATH)) {
31490
32050
  outputError("DB_NOT_FOUND", "Database not found.");
31491
32051
  process.exit(1);
31492
32052
  }
@@ -31533,9 +32093,9 @@ __export(agents_exports, {
31533
32093
  runnersList: () => runnersList,
31534
32094
  tasksList: () => tasksList
31535
32095
  });
31536
- import { existsSync as existsSync41 } from "fs";
32096
+ import { existsSync as existsSync42 } from "fs";
31537
32097
  async function agentsList(globalOpts) {
31538
- if (!existsSync41(DB_PATH)) {
32098
+ if (!existsSync42(DB_PATH)) {
31539
32099
  outputError("DB_NOT_FOUND", "Database not found.");
31540
32100
  process.exit(1);
31541
32101
  }
@@ -31566,7 +32126,7 @@ async function agentsList(globalOpts) {
31566
32126
  });
31567
32127
  }
31568
32128
  async function tasksList(globalOpts) {
31569
- if (!existsSync41(DB_PATH)) {
32129
+ if (!existsSync42(DB_PATH)) {
31570
32130
  outputError("DB_NOT_FOUND", "Database not found.");
31571
32131
  process.exit(1);
31572
32132
  }
@@ -31694,10 +32254,10 @@ __export(db_exports, {
31694
32254
  dbPath: () => dbPath,
31695
32255
  dbStats: () => dbStats
31696
32256
  });
31697
- import { existsSync as existsSync42, statSync as statSync11, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16 } from "fs";
32257
+ import { existsSync as existsSync43, statSync as statSync11, copyFileSync as copyFileSync3, mkdirSync as mkdirSync16 } from "fs";
31698
32258
  import { dirname as dirname7 } from "path";
31699
32259
  async function dbStats(globalOpts) {
31700
- if (!existsSync42(DB_PATH)) {
32260
+ if (!existsSync43(DB_PATH)) {
31701
32261
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
31702
32262
  process.exit(1);
31703
32263
  }
@@ -31705,7 +32265,7 @@ async function dbStats(globalOpts) {
31705
32265
  const readDb = openDatabaseReadOnly2();
31706
32266
  const mainSize = statSync11(DB_PATH).size;
31707
32267
  const walPath = DB_PATH + "-wal";
31708
- const walSize = existsSync42(walPath) ? statSync11(walPath).size : 0;
32268
+ const walSize = existsSync43(walPath) ? statSync11(walPath).size : 0;
31709
32269
  const tableNames = readDb.prepare(
31710
32270
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
31711
32271
  ).all();
@@ -31739,7 +32299,7 @@ async function dbPath(globalOpts) {
31739
32299
  output({ path: DB_PATH }, (d) => d.path);
31740
32300
  }
31741
32301
  async function dbBackup(globalOpts, destPath) {
31742
- if (!existsSync42(DB_PATH)) {
32302
+ if (!existsSync43(DB_PATH)) {
31743
32303
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
31744
32304
  process.exit(1);
31745
32305
  }
@@ -31748,7 +32308,7 @@ async function dbBackup(globalOpts, destPath) {
31748
32308
  mkdirSync16(dirname7(dest), { recursive: true });
31749
32309
  copyFileSync3(DB_PATH, dest);
31750
32310
  const walPath = DB_PATH + "-wal";
31751
- if (existsSync42(walPath)) copyFileSync3(walPath, dest + "-wal");
32311
+ if (existsSync43(walPath)) copyFileSync3(walPath, dest + "-wal");
31752
32312
  output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
31753
32313
  const b = d;
31754
32314
  return `
@@ -31777,9 +32337,9 @@ __export(usage_exports, {
31777
32337
  usageCost: () => usageCost,
31778
32338
  usageTokens: () => usageTokens
31779
32339
  });
31780
- import { existsSync as existsSync43 } from "fs";
32340
+ import { existsSync as existsSync44 } from "fs";
31781
32341
  function ensureDb() {
31782
- if (!existsSync43(DB_PATH)) {
32342
+ if (!existsSync44(DB_PATH)) {
31783
32343
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
31784
32344
  process.exit(1);
31785
32345
  }
@@ -31969,9 +32529,9 @@ __export(config_exports2, {
31969
32529
  configList: () => configList,
31970
32530
  configSet: () => configSet
31971
32531
  });
31972
- import { existsSync as existsSync44, readFileSync as readFileSync26 } from "fs";
32532
+ import { existsSync as existsSync45, readFileSync as readFileSync26 } from "fs";
31973
32533
  async function configList(globalOpts) {
31974
- if (!existsSync44(DB_PATH)) {
32534
+ if (!existsSync45(DB_PATH)) {
31975
32535
  outputError("DB_NOT_FOUND", "Database not found.");
31976
32536
  process.exit(1);
31977
32537
  }
@@ -32005,7 +32565,7 @@ async function configGet(globalOpts, key) {
32005
32565
  outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
32006
32566
  process.exit(1);
32007
32567
  }
32008
- if (!existsSync44(DB_PATH)) {
32568
+ if (!existsSync45(DB_PATH)) {
32009
32569
  outputError("DB_NOT_FOUND", "Database not found.");
32010
32570
  process.exit(1);
32011
32571
  }
@@ -32051,7 +32611,7 @@ async function configSet(globalOpts, key, value) {
32051
32611
  }
32052
32612
  }
32053
32613
  async function configEnv(_globalOpts) {
32054
- if (!existsSync44(ENV_PATH)) {
32614
+ if (!existsSync45(ENV_PATH)) {
32055
32615
  outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
32056
32616
  process.exit(1);
32057
32617
  }
@@ -32105,9 +32665,9 @@ __export(session_exports, {
32105
32665
  sessionGet: () => sessionGet,
32106
32666
  sessionNew: () => sessionNew
32107
32667
  });
32108
- import { existsSync as existsSync45 } from "fs";
32668
+ import { existsSync as existsSync46 } from "fs";
32109
32669
  async function sessionGet(globalOpts) {
32110
- if (!existsSync45(DB_PATH)) {
32670
+ if (!existsSync46(DB_PATH)) {
32111
32671
  outputError("DB_NOT_FOUND", "Database not found.");
32112
32672
  process.exit(1);
32113
32673
  }
@@ -32168,9 +32728,9 @@ __export(permissions_exports, {
32168
32728
  verboseGet: () => verboseGet,
32169
32729
  verboseSet: () => verboseSet
32170
32730
  });
32171
- import { existsSync as existsSync46 } from "fs";
32731
+ import { existsSync as existsSync47 } from "fs";
32172
32732
  function ensureDb2() {
32173
- if (!existsSync46(DB_PATH)) {
32733
+ if (!existsSync47(DB_PATH)) {
32174
32734
  outputError("DB_NOT_FOUND", "Database not found.");
32175
32735
  process.exit(1);
32176
32736
  }
@@ -32317,9 +32877,9 @@ __export(cwd_exports, {
32317
32877
  cwdGet: () => cwdGet,
32318
32878
  cwdSet: () => cwdSet
32319
32879
  });
32320
- import { existsSync as existsSync47 } from "fs";
32880
+ import { existsSync as existsSync48 } from "fs";
32321
32881
  async function cwdGet(globalOpts) {
32322
- if (!existsSync47(DB_PATH)) {
32882
+ if (!existsSync48(DB_PATH)) {
32323
32883
  outputError("DB_NOT_FOUND", "Database not found.");
32324
32884
  process.exit(1);
32325
32885
  }
@@ -32381,9 +32941,9 @@ __export(voice_exports, {
32381
32941
  voiceGet: () => voiceGet,
32382
32942
  voiceSet: () => voiceSet
32383
32943
  });
32384
- import { existsSync as existsSync48 } from "fs";
32944
+ import { existsSync as existsSync49 } from "fs";
32385
32945
  async function voiceGet(globalOpts) {
32386
- if (!existsSync48(DB_PATH)) {
32946
+ if (!existsSync49(DB_PATH)) {
32387
32947
  outputError("DB_NOT_FOUND", "Database not found.");
32388
32948
  process.exit(1);
32389
32949
  }
@@ -32432,9 +32992,9 @@ __export(heartbeat_exports2, {
32432
32992
  heartbeatGet: () => heartbeatGet,
32433
32993
  heartbeatSet: () => heartbeatSet
32434
32994
  });
32435
- import { existsSync as existsSync49 } from "fs";
32995
+ import { existsSync as existsSync50 } from "fs";
32436
32996
  async function heartbeatGet(globalOpts) {
32437
- if (!existsSync49(DB_PATH)) {
32997
+ if (!existsSync50(DB_PATH)) {
32438
32998
  outputError("DB_NOT_FOUND", "Database not found.");
32439
32999
  process.exit(1);
32440
33000
  }
@@ -32645,9 +33205,9 @@ __export(summarizer_exports, {
32645
33205
  summarizerGet: () => summarizerGet,
32646
33206
  summarizerSet: () => summarizerSet
32647
33207
  });
32648
- import { existsSync as existsSync50 } from "fs";
33208
+ import { existsSync as existsSync51 } from "fs";
32649
33209
  async function summarizerGet(globalOpts) {
32650
- if (!existsSync50(DB_PATH)) {
33210
+ if (!existsSync51(DB_PATH)) {
32651
33211
  outputError("DB_NOT_FOUND", "Database not found.");
32652
33212
  process.exit(1);
32653
33213
  }
@@ -32691,9 +33251,9 @@ __export(thinking_exports, {
32691
33251
  thinkingGet: () => thinkingGet,
32692
33252
  thinkingSet: () => thinkingSet
32693
33253
  });
32694
- import { existsSync as existsSync51 } from "fs";
33254
+ import { existsSync as existsSync52 } from "fs";
32695
33255
  async function thinkingGet(globalOpts) {
32696
- if (!existsSync51(DB_PATH)) {
33256
+ if (!existsSync52(DB_PATH)) {
32697
33257
  outputError("DB_NOT_FOUND", "Database not found.");
32698
33258
  process.exit(1);
32699
33259
  }
@@ -32737,9 +33297,9 @@ __export(chats_exports, {
32737
33297
  chatsList: () => chatsList,
32738
33298
  chatsRemoveAlias: () => chatsRemoveAlias
32739
33299
  });
32740
- import { existsSync as existsSync52 } from "fs";
33300
+ import { existsSync as existsSync53 } from "fs";
32741
33301
  async function chatsList(_globalOpts) {
32742
- if (!existsSync52(DB_PATH)) {
33302
+ if (!existsSync53(DB_PATH)) {
32743
33303
  outputError("DB_NOT_FOUND", "Database not found.");
32744
33304
  process.exit(1);
32745
33305
  }
@@ -32867,9 +33427,9 @@ var mcps_exports2 = {};
32867
33427
  __export(mcps_exports2, {
32868
33428
  mcpsList: () => mcpsList
32869
33429
  });
32870
- import { existsSync as existsSync53 } from "fs";
33430
+ import { existsSync as existsSync54 } from "fs";
32871
33431
  async function mcpsList(_globalOpts) {
32872
- if (!existsSync53(DB_PATH)) {
33432
+ if (!existsSync54(DB_PATH)) {
32873
33433
  outputError("DB_NOT_FOUND", "Database not found.");
32874
33434
  process.exit(1);
32875
33435
  }
@@ -32906,11 +33466,11 @@ __export(chat_exports2, {
32906
33466
  chatSend: () => chatSend
32907
33467
  });
32908
33468
  import { request as httpRequest2 } from "http";
32909
- import { readFileSync as readFileSync27, existsSync as existsSync54 } from "fs";
33469
+ import { readFileSync as readFileSync27, existsSync as existsSync55 } from "fs";
32910
33470
  function getToken2() {
32911
33471
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
32912
33472
  try {
32913
- if (existsSync54(TOKEN_PATH2)) return readFileSync27(TOKEN_PATH2, "utf-8").trim();
33473
+ if (existsSync55(TOKEN_PATH2)) return readFileSync27(TOKEN_PATH2, "utf-8").trim();
32914
33474
  } catch {
32915
33475
  }
32916
33476
  return null;
@@ -33398,7 +33958,7 @@ __export(completion_exports, {
33398
33958
  completionCommand: () => completionCommand
33399
33959
  });
33400
33960
  import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync17 } from "fs";
33401
- import { join as join34 } from "path";
33961
+ import { join as join35 } from "path";
33402
33962
  import { homedir as homedir11 } from "os";
33403
33963
  async function completionCommand(opts) {
33404
33964
  const shell = opts.shell ?? detectShell();
@@ -33414,10 +33974,10 @@ async function completionCommand(opts) {
33414
33974
  process.exit(1);
33415
33975
  }
33416
33976
  if (opts.install) {
33417
- const dir = join34(homedir11(), ".config", "cc-claw", "completions");
33977
+ const dir = join35(homedir11(), ".config", "cc-claw", "completions");
33418
33978
  mkdirSync17(dir, { recursive: true });
33419
33979
  const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
33420
- const filepath = join34(dir, filename);
33980
+ const filepath = join35(dir, filename);
33421
33981
  writeFileSync11(filepath, script, "utf-8");
33422
33982
  console.log(`\u2713 Completion script written to ${filepath}
33423
33983
  `);
@@ -33590,9 +34150,9 @@ __export(evolve_exports2, {
33590
34150
  evolveStatus: () => evolveStatus,
33591
34151
  evolveUndo: () => evolveUndo
33592
34152
  });
33593
- import { existsSync as existsSync55 } from "fs";
34153
+ import { existsSync as existsSync56 } from "fs";
33594
34154
  function ensureDb3() {
33595
- if (!existsSync55(DB_PATH)) {
34155
+ if (!existsSync56(DB_PATH)) {
33596
34156
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
33597
34157
  process.exit(1);
33598
34158
  }
@@ -34066,10 +34626,10 @@ var init_optimize2 = __esm({
34066
34626
 
34067
34627
  // src/setup.ts
34068
34628
  var setup_exports = {};
34069
- import { existsSync as existsSync56, writeFileSync as writeFileSync12, readFileSync as readFileSync28, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
34629
+ import { existsSync as existsSync57, writeFileSync as writeFileSync12, readFileSync as readFileSync28, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
34070
34630
  import { execFileSync as execFileSync6 } from "child_process";
34071
34631
  import { createInterface as createInterface11 } from "readline";
34072
- import { join as join35 } from "path";
34632
+ import { join as join36 } from "path";
34073
34633
  function divider2() {
34074
34634
  console.log(dim("\u2500".repeat(55)));
34075
34635
  }
@@ -34144,10 +34704,10 @@ async function setup() {
34144
34704
  }
34145
34705
  console.log("");
34146
34706
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
34147
- if (!existsSync56(dir)) mkdirSync18(dir, { recursive: true });
34707
+ if (!existsSync57(dir)) mkdirSync18(dir, { recursive: true });
34148
34708
  }
34149
34709
  const env = {};
34150
- const envSource = existsSync56(ENV_PATH) ? ENV_PATH : existsSync56(".env") ? ".env" : null;
34710
+ const envSource = existsSync57(ENV_PATH) ? ENV_PATH : existsSync57(".env") ? ".env" : null;
34151
34711
  if (envSource) {
34152
34712
  console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
34153
34713
  console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
@@ -34157,8 +34717,8 @@ async function setup() {
34157
34717
  if (match) env[match[1].trim()] = match[2].trim();
34158
34718
  }
34159
34719
  }
34160
- const cwdDb = join35(process.cwd(), "cc-claw.db");
34161
- if (existsSync56(cwdDb) && !existsSync56(DB_PATH)) {
34720
+ const cwdDb = join36(process.cwd(), "cc-claw.db");
34721
+ if (existsSync57(cwdDb) && !existsSync57(DB_PATH)) {
34162
34722
  const { size } = statSync12(cwdDb);
34163
34723
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
34164
34724
  const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);