cc-claw 0.11.1 → 0.11.3

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 +433 -253
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -72,7 +72,7 @@ var VERSION;
72
72
  var init_version = __esm({
73
73
  "src/version.ts"() {
74
74
  "use strict";
75
- VERSION = true ? "0.11.1" : (() => {
75
+ VERSION = true ? "0.11.3" : (() => {
76
76
  try {
77
77
  return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
78
78
  } catch {
@@ -1545,6 +1545,7 @@ function initDatabase() {
1545
1545
  cron TEXT,
1546
1546
  at_time TEXT,
1547
1547
  every_ms INTEGER,
1548
+ title TEXT,
1548
1549
  description TEXT NOT NULL,
1549
1550
  chat_id TEXT NOT NULL,
1550
1551
  backend TEXT,
@@ -1581,6 +1582,7 @@ function initDatabase() {
1581
1582
  cron TEXT,
1582
1583
  at_time TEXT,
1583
1584
  every_ms INTEGER,
1585
+ title TEXT,
1584
1586
  description TEXT NOT NULL,
1585
1587
  chat_id TEXT NOT NULL,
1586
1588
  backend TEXT,
@@ -1675,6 +1677,11 @@ function initDatabase() {
1675
1677
  db.exec("ALTER TABLE jobs ADD COLUMN fallbacks TEXT");
1676
1678
  } catch {
1677
1679
  }
1680
+ try {
1681
+ db.exec("ALTER TABLE jobs ADD COLUMN title TEXT");
1682
+ } catch {
1683
+ }
1684
+ backfillJobTitles(db);
1678
1685
  }
1679
1686
  } catch {
1680
1687
  }
@@ -2521,14 +2528,15 @@ function getBackendUsageInWindow(backend2, windowType) {
2521
2528
  }
2522
2529
  function insertJob(params) {
2523
2530
  const result = db.prepare(`
2524
- INSERT INTO jobs (schedule_type, cron, at_time, every_ms, description, chat_id,
2531
+ INSERT INTO jobs (schedule_type, cron, at_time, every_ms, title, description, chat_id,
2525
2532
  backend, model, thinking, timeout, fallbacks, session_type, channel, target, delivery_mode, timezone)
2526
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2533
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2527
2534
  `).run(
2528
2535
  params.scheduleType,
2529
2536
  params.cron ?? null,
2530
2537
  params.atTime ?? null,
2531
2538
  params.everyMs ?? null,
2539
+ params.title ?? null,
2532
2540
  params.description,
2533
2541
  params.chatId,
2534
2542
  params.backend ?? null,
@@ -2544,6 +2552,29 @@ function insertJob(params) {
2544
2552
  );
2545
2553
  return getJobById(Number(result.lastInsertRowid));
2546
2554
  }
2555
+ function backfillJobTitles(database) {
2556
+ const rows = database.prepare(
2557
+ "SELECT id, description FROM jobs WHERE active = 1 AND (title IS NULL OR title LIKE 'No thinking%' OR title LIKE 'You must%' OR title LIKE 'You MUST%')"
2558
+ ).all();
2559
+ if (rows.length === 0) return;
2560
+ const instructionLinePattern = /^(?:you\s+must|important|always|note|never|no\s+thinking|do\s+not|don't|remember|make\s+sure|ensure|critical|warning|before\s+you|first,?\s+you|use\s+the|call\s+the)\b[^.\n]*[.!]?\s*/i;
2561
+ for (const row of rows) {
2562
+ let text = row.description;
2563
+ let prevLen = 0;
2564
+ while (text.length !== prevLen && text.length > 0) {
2565
+ prevLen = text.length;
2566
+ text = text.replace(instructionLinePattern, "").trim();
2567
+ text = text.replace(/^\n+/, "").trim();
2568
+ }
2569
+ if (text.length < 10) text = row.description;
2570
+ text = text.replace(/https?:\/\/\S+/g, "").trim();
2571
+ text = text.replace(/\([^)]*\)\s*$/, "").trim();
2572
+ const firstLine = text.split(/\n/)[0].trim();
2573
+ const firstSentence = firstLine.match(/^.{5,55}(?:\b|[.!?])/)?.[0] ?? firstLine.slice(0, 55);
2574
+ const title = firstSentence.length > 55 ? firstSentence.slice(0, 52) + "\u2026" : firstSentence;
2575
+ database.prepare("UPDATE jobs SET title = ? WHERE id = ?").run(title, row.id);
2576
+ }
2577
+ }
2547
2578
  function mapJobRow(row) {
2548
2579
  if (!row) return void 0;
2549
2580
  row.fallbacks = row.fallbacks ? JSON.parse(row.fallbacks) : [];
@@ -2588,6 +2619,7 @@ function updateJob(id, fields) {
2588
2619
  cron: "cron",
2589
2620
  atTime: "at_time",
2590
2621
  everyMs: "every_ms",
2622
+ title: "title",
2591
2623
  description: "description",
2592
2624
  backend: "backend",
2593
2625
  model: "model",
@@ -3032,7 +3064,7 @@ var init_store5 = __esm({
3032
3064
  ALL_TOOLS = ["Read", "Glob", "Grep", "Bash", "Write", "Edit", "WebFetch", "WebSearch", "Agent", "AskUserQuestion"];
3033
3065
  JOB_SELECT = `
3034
3066
  SELECT id, schedule_type as scheduleType, cron, at_time as atTime, every_ms as everyMs,
3035
- description, chat_id as chatId, backend, model, thinking, timeout, fallbacks,
3067
+ title, description, chat_id as chatId, backend, model, thinking, timeout, fallbacks,
3036
3068
  session_type as sessionType, channel, target, delivery_mode as deliveryMode,
3037
3069
  timezone, enabled, active, created_at as createdAt, last_run_at as lastRunAt,
3038
3070
  next_run_at as nextRunAt, consecutive_failures as consecutiveFailures
@@ -6566,8 +6598,45 @@ __export(analyze_exports, {
6566
6598
  });
6567
6599
  import { spawn as spawn4 } from "child_process";
6568
6600
  import { createInterface as createInterface3 } from "readline";
6569
- import { readFileSync as readFileSync6 } from "fs";
6601
+ import { readFileSync as readFileSync6, existsSync as existsSync11, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
6570
6602
  import { join as join10 } from "path";
6603
+ import { homedir as homedir4 } from "os";
6604
+ function discoverReflectionTargets() {
6605
+ const ccClawHome = join10(homedir4(), ".cc-claw");
6606
+ const targets = [];
6607
+ try {
6608
+ const skillsDir = join10(ccClawHome, "workspace", "skills");
6609
+ if (existsSync11(skillsDir)) {
6610
+ for (const entry of readdirSync5(skillsDir)) {
6611
+ const entryPath = join10(skillsDir, entry);
6612
+ if (!statSync3(entryPath).isDirectory()) continue;
6613
+ const skillFile = join10(entryPath, "SKILL.md");
6614
+ if (!existsSync11(skillFile)) continue;
6615
+ let desc = "skill";
6616
+ try {
6617
+ const content = readFileSync6(skillFile, "utf-8").slice(0, 500);
6618
+ const descMatch = content.match(/description:\s*["']?([^"'\n]+)/);
6619
+ if (descMatch) desc = descMatch[1].trim().slice(0, 80);
6620
+ } catch {
6621
+ }
6622
+ targets.push({ path: `workspace/skills/${entry}/SKILL.md`, description: desc });
6623
+ }
6624
+ }
6625
+ } catch {
6626
+ }
6627
+ try {
6628
+ const contextDir = join10(ccClawHome, "workspace", "context");
6629
+ if (existsSync11(contextDir)) {
6630
+ for (const entry of readdirSync5(contextDir)) {
6631
+ if (!entry.endsWith(".md")) continue;
6632
+ const name = entry.replace(/\.md$/, "");
6633
+ targets.push({ path: `workspace/context/${entry}`, description: `context file: ${name}` });
6634
+ }
6635
+ }
6636
+ } catch {
6637
+ }
6638
+ return targets;
6639
+ }
6571
6640
  function buildAnalysisPrompt(params) {
6572
6641
  const {
6573
6642
  signals,
@@ -6627,7 +6696,31 @@ ${categoryList}`);
6627
6696
  sections.push(`- [#${ins.id}] (${ins.category}) ${ins.insight}`);
6628
6697
  }
6629
6698
  }
6630
- const targetOptions = codebaseEnabled ? "identity/SOUL.md | identity/USER.md | codebase" : "identity/SOUL.md | identity/USER.md";
6699
+ const { availableTargets } = params;
6700
+ const targetList = [
6701
+ "identity/SOUL.md \u2014 personality, tone, stable behavioral rules, communication style",
6702
+ "identity/USER.md \u2014 user preferences, personal info, timezone, language, profile"
6703
+ ];
6704
+ if (availableTargets) {
6705
+ for (const t of availableTargets) {
6706
+ targetList.push(`${t.path} \u2014 ${t.description}`);
6707
+ }
6708
+ }
6709
+ if (codebaseEnabled) {
6710
+ targetList.push("codebase \u2014 code-level recommendation (advisory only)");
6711
+ }
6712
+ sections.push(`[Target File Routing]
6713
+ Available targets:
6714
+ ${targetList.map((t) => `- ${t}`).join("\n")}
6715
+
6716
+ Choose the MOST SPECIFIC target for each insight:
6717
+ - Workflow or process improvements \u2192 the relevant skill file
6718
+ - Tool usage patterns or domain-specific steps \u2192 the relevant skill file
6719
+ - User preference or profile info \u2192 USER.md
6720
+ - Personality, tone, general behavior \u2192 SOUL.md
6721
+ - Domain knowledge or reference material \u2192 a context file
6722
+ - If no matching skill/context file exists, fall back to SOUL.md or USER.md`);
6723
+ const targetOptions = targetList.map((t) => t.split(" \u2014 ")[0]).join(" | ");
6631
6724
  sections.push(`[Output Format]
6632
6725
  For each insight, output EXACTLY this format. Separate multiple insights with "---" on its own line.
6633
6726
 
@@ -6823,6 +6916,7 @@ async function runAnalysis(chatId, opts = {}) {
6823
6916
  const applied = getAppliedInsights(db3, chatId);
6824
6917
  const rejected = getRejectedInsights(db3, chatId);
6825
6918
  const codebaseEnabled = process.env.REFLECTION_CODEBASE_RECOMMENDATIONS === "1";
6919
+ const availableTargets = discoverReflectionTargets();
6826
6920
  const prompt = buildAnalysisPrompt({
6827
6921
  signals: signals.map((s) => ({
6828
6922
  signalType: s.signalType,
@@ -6844,7 +6938,8 @@ async function runAnalysis(chatId, opts = {}) {
6844
6938
  insight: i.insight,
6845
6939
  category: i.category
6846
6940
  })),
6847
- codebaseEnabled
6941
+ codebaseEnabled,
6942
+ availableTargets
6848
6943
  });
6849
6944
  const resolved = resolveReflectionAdapter(chatId);
6850
6945
  if (!resolved) {
@@ -6948,7 +7043,7 @@ __export(apply_exports, {
6948
7043
  isTargetAllowed: () => isTargetAllowed,
6949
7044
  rollbackInsight: () => rollbackInsight
6950
7045
  });
6951
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync3 } from "fs";
7046
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync12, mkdirSync as mkdirSync3 } from "fs";
6952
7047
  import { join as join11, dirname as dirname2 } from "path";
6953
7048
  function isTargetAllowed(relativePath) {
6954
7049
  if (relativePath.includes("..")) return false;
@@ -7016,7 +7111,7 @@ async function applyInsight(insightId) {
7016
7111
  }
7017
7112
  const absolutePath = join11(CC_CLAW_HOME, insight.targetFile);
7018
7113
  if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
7019
- if (existsSync11(absolutePath)) {
7114
+ if (existsSync12(absolutePath)) {
7020
7115
  const currentContent = readFileSync7(absolutePath, "utf-8");
7021
7116
  const lineCount = currentContent.split("\n").length;
7022
7117
  if (lineCount >= SOUL_LINE_CAP) {
@@ -7036,7 +7131,7 @@ async function applyInsight(insightId) {
7036
7131
  };
7037
7132
  }
7038
7133
  let original = "";
7039
- if (existsSync11(absolutePath)) {
7134
+ if (existsSync12(absolutePath)) {
7040
7135
  original = readFileSync7(absolutePath, "utf-8");
7041
7136
  } else if (insight.proposedAction !== "create") {
7042
7137
  return { success: false, message: `Target file "${insight.targetFile}" does not exist` };
@@ -7045,7 +7140,7 @@ async function applyInsight(insightId) {
7045
7140
  const backupPath = absolutePath + `.bak.${timestamp}`;
7046
7141
  try {
7047
7142
  const parentDir = dirname2(absolutePath);
7048
- if (!existsSync11(parentDir)) {
7143
+ if (!existsSync12(parentDir)) {
7049
7144
  mkdirSync3(parentDir, { recursive: true });
7050
7145
  }
7051
7146
  if (original) {
@@ -7151,7 +7246,7 @@ function computeLineDrift(baseline, absolutePath) {
7151
7246
  if (!baseline) return 0;
7152
7247
  let current = "";
7153
7248
  try {
7154
- if (existsSync11(absolutePath)) {
7249
+ if (existsSync12(absolutePath)) {
7155
7250
  current = readFileSync7(absolutePath, "utf-8");
7156
7251
  }
7157
7252
  } catch {
@@ -7203,7 +7298,7 @@ __export(server_exports, {
7203
7298
  });
7204
7299
  import { createServer } from "http";
7205
7300
  import { randomBytes } from "crypto";
7206
- import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync12 } from "fs";
7301
+ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync13 } from "fs";
7207
7302
  function createSubAgentToken(agentId) {
7208
7303
  const token = `sub:${agentId.slice(0, 8)}:${randomBytes(16).toString("hex")}`;
7209
7304
  subAgentTokens.set(token, agentId);
@@ -7374,7 +7469,7 @@ function startDashboard() {
7374
7469
  if (url.pathname === "/api/orchestrator/spawn" && req.method === "POST") {
7375
7470
  try {
7376
7471
  const body = JSON.parse(await readBody(req));
7377
- if (body.cwd && !existsSync12(body.cwd)) {
7472
+ if (body.cwd && !existsSync13(body.cwd)) {
7378
7473
  return jsonResponse(res, { error: `Directory not found: ${body.cwd}` }, 400);
7379
7474
  }
7380
7475
  if (!body.permMode || body.permMode === "inherit") {
@@ -9674,18 +9769,18 @@ var init_wrap_backend = __esm({
9674
9769
  });
9675
9770
 
9676
9771
  // src/agents/runners/config-loader.ts
9677
- import { readFileSync as readFileSync8, readdirSync as readdirSync5, existsSync as existsSync13, mkdirSync as mkdirSync5, watchFile, unwatchFile } from "fs";
9772
+ import { readFileSync as readFileSync8, readdirSync as readdirSync6, existsSync as existsSync14, mkdirSync as mkdirSync5, watchFile, unwatchFile } from "fs";
9678
9773
  import { join as join13 } from "path";
9679
9774
  import { execFileSync } from "child_process";
9680
9775
  function resolveExecutable(config2) {
9681
- if (existsSync13(config2.executable)) return config2.executable;
9776
+ if (existsSync14(config2.executable)) return config2.executable;
9682
9777
  try {
9683
9778
  return execFileSync("which", [config2.executable], { encoding: "utf-8" }).trim();
9684
9779
  } catch {
9685
9780
  }
9686
9781
  for (const fallback of config2.executableFallbacks ?? []) {
9687
9782
  const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
9688
- if (existsSync13(resolved)) return resolved;
9783
+ if (existsSync14(resolved)) return resolved;
9689
9784
  }
9690
9785
  return config2.executable;
9691
9786
  }
@@ -9824,11 +9919,11 @@ function loadRunnerConfig(filePath) {
9824
9919
  }
9825
9920
  }
9826
9921
  function loadAllRunnerConfigs() {
9827
- if (!existsSync13(RUNNERS_PATH)) {
9922
+ if (!existsSync14(RUNNERS_PATH)) {
9828
9923
  mkdirSync5(RUNNERS_PATH, { recursive: true });
9829
9924
  return [];
9830
9925
  }
9831
- const files = readdirSync5(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
9926
+ const files = readdirSync6(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
9832
9927
  const configs = [];
9833
9928
  for (const file of files) {
9834
9929
  const config2 = loadRunnerConfig(join13(RUNNERS_PATH, file));
@@ -9852,14 +9947,14 @@ function registerConfigRunners() {
9852
9947
  return count;
9853
9948
  }
9854
9949
  function watchRunnerConfigs(onChange) {
9855
- if (!existsSync13(RUNNERS_PATH)) return;
9950
+ if (!existsSync14(RUNNERS_PATH)) return;
9856
9951
  for (const prev of watchedFiles) {
9857
- if (!existsSync13(prev)) {
9952
+ if (!existsSync14(prev)) {
9858
9953
  unwatchFile(prev);
9859
9954
  watchedFiles.delete(prev);
9860
9955
  }
9861
9956
  }
9862
- const files = readdirSync5(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
9957
+ const files = readdirSync6(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
9863
9958
  for (const file of files) {
9864
9959
  const fullPath = join13(RUNNERS_PATH, file);
9865
9960
  if (watchedFiles.has(fullPath)) continue;
@@ -10568,7 +10663,7 @@ __export(discover_exports, {
10568
10663
  });
10569
10664
  import { readdir, readFile as readFile2 } from "fs/promises";
10570
10665
  import { createHash } from "crypto";
10571
- import { homedir as homedir4 } from "os";
10666
+ import { homedir as homedir5 } from "os";
10572
10667
  import { join as join14 } from "path";
10573
10668
  function invalidateSkillCache() {
10574
10669
  cachedSkills = null;
@@ -10587,7 +10682,7 @@ async function discoverAllSkills() {
10587
10682
  const rawSkills = [];
10588
10683
  rawSkills.push(...await scanSkillDir(SKILLS_PATH, "cc-claw"));
10589
10684
  for (const backendId of getAllBackendIds()) {
10590
- const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join14(homedir4(), `.${backendId}`, "skills")];
10685
+ const dirs = BACKEND_SKILL_DIRS[backendId] ?? [join14(homedir5(), `.${backendId}`, "skills")];
10591
10686
  for (const dir of dirs) {
10592
10687
  rawSkills.push(...await scanSkillDir(dir, backendId));
10593
10688
  }
@@ -10718,15 +10813,15 @@ var init_discover = __esm({
10718
10813
  init_backends();
10719
10814
  SKILL_FILE_CANDIDATES = ["SKILL.md", "skill.md"];
10720
10815
  BACKEND_SKILL_DIRS = {
10721
- claude: [join14(homedir4(), ".claude", "skills")],
10722
- gemini: [join14(homedir4(), ".gemini", "skills")],
10816
+ claude: [join14(homedir5(), ".claude", "skills")],
10817
+ gemini: [join14(homedir5(), ".gemini", "skills")],
10723
10818
  codex: [
10724
- join14(homedir4(), ".agents", "skills"),
10725
- join14(homedir4(), ".codex", "skills")
10819
+ join14(homedir5(), ".agents", "skills"),
10820
+ join14(homedir5(), ".codex", "skills")
10726
10821
  ],
10727
10822
  cursor: [
10728
- join14(homedir4(), ".cursor", "skills"),
10729
- join14(homedir4(), ".cursor", "skills-cursor")
10823
+ join14(homedir5(), ".cursor", "skills"),
10824
+ join14(homedir5(), ".cursor", "skills-cursor")
10730
10825
  ]
10731
10826
  };
10732
10827
  CACHE_TTL_MS2 = 3e5;
@@ -10742,7 +10837,7 @@ __export(install_exports, {
10742
10837
  installSkillFromGitHub: () => installSkillFromGitHub
10743
10838
  });
10744
10839
  import { mkdir, readdir as readdir2, readFile as readFile3, cp } from "fs/promises";
10745
- import { existsSync as existsSync14 } from "fs";
10840
+ import { existsSync as existsSync15 } from "fs";
10746
10841
  import { join as join15, basename } from "path";
10747
10842
  import { execSync as execSync6 } from "child_process";
10748
10843
  async function installSkillFromGitHub(urlOrShorthand) {
@@ -10761,7 +10856,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
10761
10856
  stdio: "pipe",
10762
10857
  timeout: 3e4
10763
10858
  });
10764
- if (!existsSync14(join15(tmpDir, ".git"))) {
10859
+ if (!existsSync15(join15(tmpDir, ".git"))) {
10765
10860
  return { success: false, error: "Git clone failed: no .git directory produced" };
10766
10861
  }
10767
10862
  const searchRoot = subPath ? join15(tmpDir, subPath) : tmpDir;
@@ -10771,7 +10866,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
10771
10866
  }
10772
10867
  const skillFolderName = basename(skillDir);
10773
10868
  const destDir = join15(SKILLS_PATH, skillFolderName);
10774
- if (existsSync14(destDir)) {
10869
+ if (existsSync15(destDir)) {
10775
10870
  log(`[skill-install] Overwriting existing skill at ${destDir}`);
10776
10871
  }
10777
10872
  await mkdir(destDir, { recursive: true });
@@ -10818,14 +10913,14 @@ function parseGitHubUrl(input) {
10818
10913
  async function findSkillDir(root) {
10819
10914
  const candidates = ["SKILL.md", "skill.md"];
10820
10915
  for (const c of candidates) {
10821
- if (existsSync14(join15(root, c))) return root;
10916
+ if (existsSync15(join15(root, c))) return root;
10822
10917
  }
10823
10918
  try {
10824
10919
  const entries = await readdir2(root, { withFileTypes: true });
10825
10920
  for (const entry of entries) {
10826
10921
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
10827
10922
  for (const c of candidates) {
10828
- if (existsSync14(join15(root, entry.name, c))) {
10923
+ if (existsSync15(join15(root, entry.name, c))) {
10829
10924
  return join15(root, entry.name);
10830
10925
  }
10831
10926
  }
@@ -10845,7 +10940,7 @@ async function findSkillDir(root) {
10845
10940
  for (const sub of subEntries) {
10846
10941
  if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
10847
10942
  for (const c of candidates) {
10848
- if (existsSync14(join15(root, entry.name, sub.name, c))) {
10943
+ if (existsSync15(join15(root, entry.name, sub.name, c))) {
10849
10944
  return join15(root, entry.name, sub.name);
10850
10945
  }
10851
10946
  }
@@ -10864,7 +10959,7 @@ var init_install = __esm({
10864
10959
  });
10865
10960
 
10866
10961
  // src/bootstrap/profile.ts
10867
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync15 } from "fs";
10962
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync16 } from "fs";
10868
10963
  import { join as join16 } from "path";
10869
10964
  function hasActiveProfile(chatId) {
10870
10965
  return activeProfiles.has(chatId);
@@ -10994,7 +11089,7 @@ function extractUserUpdates(text) {
10994
11089
  return { cleanText, updates };
10995
11090
  }
10996
11091
  function appendToUserProfile(key, value) {
10997
- if (!existsSync15(USER_PATH2)) return;
11092
+ if (!existsSync16(USER_PATH2)) return;
10998
11093
  const content = readFileSync9(USER_PATH2, "utf-8");
10999
11094
  const line = `- **${key}**: ${value}`;
11000
11095
  if (content.includes(line)) return;
@@ -11016,7 +11111,7 @@ var init_profile = __esm({
11016
11111
  });
11017
11112
 
11018
11113
  // src/bootstrap/heartbeat.ts
11019
- import { readFileSync as readFileSync10, existsSync as existsSync16 } from "fs";
11114
+ import { readFileSync as readFileSync10, existsSync as existsSync17 } from "fs";
11020
11115
  import { join as join17 } from "path";
11021
11116
  function initHeartbeat(channelReg) {
11022
11117
  registry2 = channelReg;
@@ -11155,7 +11250,7 @@ ${healthLines.join("\n")}`);
11155
11250
  sections.push(`[Active watches]
11156
11251
  ${watchLines.join("\n")}`);
11157
11252
  }
11158
- if (existsSync16(HEARTBEAT_MD_PATH)) {
11253
+ if (existsSync17(HEARTBEAT_MD_PATH)) {
11159
11254
  try {
11160
11255
  const custom = readFileSync10(HEARTBEAT_MD_PATH, "utf-8").trim();
11161
11256
  if (custom) {
@@ -11386,7 +11481,7 @@ var init_classify = __esm({
11386
11481
  });
11387
11482
 
11388
11483
  // src/media/image-gen.ts
11389
- import { mkdirSync as mkdirSync6, existsSync as existsSync17 } from "fs";
11484
+ import { mkdirSync as mkdirSync6, existsSync as existsSync18 } from "fs";
11390
11485
  import { writeFile as writeFile2 } from "fs/promises";
11391
11486
  import { join as join18 } from "path";
11392
11487
  async function generateImage(prompt) {
@@ -11435,7 +11530,7 @@ async function generateImage(prompt) {
11435
11530
  if (!imageData) {
11436
11531
  throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
11437
11532
  }
11438
- if (!existsSync17(IMAGE_OUTPUT_DIR)) {
11533
+ if (!existsSync18(IMAGE_OUTPUT_DIR)) {
11439
11534
  mkdirSync6(IMAGE_OUTPUT_DIR, { recursive: true });
11440
11535
  }
11441
11536
  const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
@@ -12166,11 +12261,31 @@ async function finalizeJob(chatId, channel) {
12166
12261
  const pending = pendingJobs.get(chatId);
12167
12262
  if (!pending) return;
12168
12263
  const editJobId = pending._editJobId;
12264
+ let title = pending.title ?? null;
12265
+ if (!title && !editJobId) {
12266
+ try {
12267
+ const { askAgent: askAgent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
12268
+ const resp = await askAgent2(chatId, `Summarize this scheduled task in 5-8 words for a job list title. Output ONLY the title, nothing else:
12269
+
12270
+ ${pending.task}`, {
12271
+ bootstrapTier: "chat",
12272
+ maxTurns: 1,
12273
+ timeoutMs: 15e3
12274
+ });
12275
+ const generated = resp.text?.trim().replace(/^["']|["']$/g, "");
12276
+ if (generated && generated.length <= 60) title = generated;
12277
+ } catch {
12278
+ }
12279
+ if (!title) {
12280
+ title = pending.task.length > 60 ? pending.task.slice(0, 57) + "\u2026" : pending.task;
12281
+ }
12282
+ }
12169
12283
  const jobParams = {
12170
12284
  scheduleType: pending.scheduleType ?? "cron",
12171
12285
  cron: pending.cron,
12172
12286
  atTime: pending.at ?? null,
12173
12287
  everyMs: pending.everyMs ?? null,
12288
+ title,
12174
12289
  description: pending.task,
12175
12290
  backend: pending.backend ?? null,
12176
12291
  model: pending.model ?? null,
@@ -12194,6 +12309,7 @@ async function finalizeJob(chatId, channel) {
12194
12309
  chatId,
12195
12310
  `Job #${editJobId} updated!
12196
12311
 
12312
+ Title: ${jobParams.title ?? "\u2014"}
12197
12313
  Task: ${jobParams.description}
12198
12314
  Schedule: ${jobParams.cron ?? "N/A"}
12199
12315
  Timezone: ${jobParams.timezone}`,
@@ -12208,6 +12324,7 @@ Timezone: ${jobParams.timezone}`,
12208
12324
  chatId,
12209
12325
  `Job #${job.id} created!
12210
12326
 
12327
+ Title: ${job.title ?? "\u2014"}
12211
12328
  Task: ${job.description}
12212
12329
  Schedule: ${job.cron ?? "N/A"}
12213
12330
  Timezone: ${job.timezone}
@@ -12808,8 +12925,10 @@ var init_propose = __esm({
12808
12925
 
12809
12926
  // src/router.ts
12810
12927
  import { readFile as readFile5, writeFile as writeFile3, unlink as unlink2, mkdir as mkdir2, readdir as readdir3, stat } from "fs/promises";
12928
+ import { existsSync as existsSync19 } from "fs";
12811
12929
  import { randomUUID as randomUUID3 } from "crypto";
12812
12930
  import { resolve as resolvePath, join as join19 } from "path";
12931
+ import { homedir as homedir6 } from "os";
12813
12932
  function parseMcpListOutput(output2) {
12814
12933
  const results = [];
12815
12934
  const seen = /* @__PURE__ */ new Set();
@@ -14527,8 +14646,8 @@ ${agentLines.join("\n")}`, buttons);
14527
14646
  lines.push(` \u2705 <b>cc-claw</b> <i>Agent orchestrator (spawn, tasks, inbox)</i>`);
14528
14647
  }
14529
14648
  const { execFile: execFile5 } = await import("child_process");
14530
- const { homedir: homedir7 } = await import("os");
14531
- const discoveryCwd = homedir7();
14649
+ const { homedir: homedir9 } = await import("os");
14650
+ const discoveryCwd = homedir9();
14532
14651
  const runnerResults = await Promise.allSettled(
14533
14652
  getAllRunners().map((runner) => {
14534
14653
  const listCmd = runner.getMcpListCommand();
@@ -14911,26 +15030,6 @@ async function handleText(msg, channel) {
14911
15030
  await handleWizardText(chatId, text, channel);
14912
15031
  return;
14913
15032
  }
14914
- const discussingInsightId = activeProposalDiscussion.get(chatId);
14915
- if (discussingInsightId !== void 0) {
14916
- if (text.toLowerCase() === "done") {
14917
- activeProposalDiscussion.delete(chatId);
14918
- const { getInsightById: getInsightById2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
14919
- const { formatProposalCard: formatProposalCard2, buildProposalKeyboard: buildProposalKeyboard2 } = await Promise.resolve().then(() => (init_propose(), propose_exports));
14920
- const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
14921
- const insight = getInsightById2(getDb2(), discussingInsightId);
14922
- if (insight && insight.status === "pending") {
14923
- const card = formatProposalCard2(insight);
14924
- const kb = buildProposalKeyboard2(insight.id, insight.category);
14925
- await channel.sendKeyboard(chatId, "Discussion complete. Updated proposal:\n\n" + card, kb);
14926
- } else {
14927
- await channel.sendText(chatId, "Discussion ended.", { parseMode: "plain" });
14928
- }
14929
- return;
14930
- }
14931
- await handleProposalDiscussion(chatId, discussingInsightId, text, channel);
14932
- return;
14933
- }
14934
15033
  const rememberMatch = text.match(/^remember\s+(?:that\s+)?(.+)/i);
14935
15034
  if (rememberMatch) {
14936
15035
  const content = rememberMatch[1];
@@ -15158,65 +15257,6 @@ After installing, restart the service: cc-claw service restart`;
15158
15257
  }
15159
15258
  return `Error: ${msg}`;
15160
15259
  }
15161
- async function handleProposalDiscussion(chatId, insightId, userQuestion, channel) {
15162
- const { getInsightById: getInsightById2, updateInsightProposal: updateInsightProposal2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
15163
- const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
15164
- const insight = getInsightById2(getDb2(), insightId);
15165
- if (!insight) {
15166
- activeProposalDiscussion.delete(chatId);
15167
- await channel.sendText(chatId, "Proposal not found. Discussion ended.", { parseMode: "plain" });
15168
- return;
15169
- }
15170
- const prompt = [
15171
- `You are reviewing a self-learning proposal with the user. They want to discuss it before deciding whether to apply, modify, or reject it.`,
15172
- ``,
15173
- `Current proposal:`,
15174
- `- Category: ${insight.category}`,
15175
- `- Insight: ${insight.insight}`,
15176
- `- Why: ${insight.why ?? "not specified"}`,
15177
- `- Target file: ${insight.targetFile ?? "not specified"}`,
15178
- `- Proposed action: ${insight.proposedAction ?? "not specified"}`,
15179
- `- Proposed diff: ${insight.proposedDiff ?? "none"}`,
15180
- `- Confidence: ${Math.round(insight.confidence * 100)}%`,
15181
- ``,
15182
- `The user asks: "${userQuestion}"`,
15183
- ``,
15184
- `Answer their question honestly. If they suggest retargeting to a different file or modifying the proposal, agree if it makes sense and output one of these markers:`,
15185
- `- [RETARGET:filepath] \u2014 to change the target file (e.g., [RETARGET:skills/newsroom/SKILL.md])`,
15186
- `- [REVISE_DIFF:new diff text] \u2014 to update the proposed change`,
15187
- `- [REVISE_ACTION:action] \u2014 to change the action type (append/replace/etc.)`,
15188
- ``,
15189
- `Only output markers when the user explicitly asks for a change. Otherwise just discuss.`,
15190
- `Keep responses concise \u2014 this is a quick review conversation, not an essay.`
15191
- ].join("\n");
15192
- try {
15193
- await channel.sendTyping?.(chatId);
15194
- const response = await askAgent(chatId, prompt, {
15195
- bootstrapTier: "chat",
15196
- maxTurns: 1,
15197
- timeoutMs: 6e4
15198
- });
15199
- const responseText = response.text ?? "";
15200
- const retargetMatch = responseText.match(/\[RETARGET:([^\]]+)\]/);
15201
- const reviseDiffMatch = responseText.match(/\[REVISE_DIFF:([^\]]+)\]/);
15202
- const reviseActionMatch = responseText.match(/\[REVISE_ACTION:([^\]]+)\]/);
15203
- if (retargetMatch || reviseDiffMatch || reviseActionMatch) {
15204
- const newTarget = retargetMatch?.[1]?.trim() ?? insight.targetFile ?? "";
15205
- const newDiff = reviseDiffMatch?.[1]?.trim() ?? insight.proposedDiff ?? null;
15206
- const newAction = reviseActionMatch?.[1]?.trim() ?? insight.proposedAction ?? null;
15207
- updateInsightProposal2(getDb2(), insightId, newTarget, newDiff, newAction);
15208
- }
15209
- const cleanText = responseText.replace(/\[RETARGET:[^\]]+\]/g, "").replace(/\[REVISE_DIFF:[^\]]+\]/g, "").replace(/\[REVISE_ACTION:[^\]]+\]/g, "").trim();
15210
- if (cleanText) {
15211
- await channel.sendText(chatId, cleanText);
15212
- }
15213
- await channel.sendKeyboard(chatId, "Continue discussing, or type 'done' to finish.", [
15214
- [{ label: "Done \u2014 show updated proposal", data: `evolve:discuss-done:${insightId}` }]
15215
- ]);
15216
- } catch (err) {
15217
- await channel.sendText(chatId, `Discussion error: ${err.message}`, { parseMode: "plain" });
15218
- }
15219
- }
15220
15260
  async function handleSideQuest(parentChatId, msg, channel) {
15221
15261
  const sqId = `sq:${parentChatId}:${randomUUID3()}`;
15222
15262
  const active = activeSideQuests.get(parentChatId) ?? /* @__PURE__ */ new Set();
@@ -15791,7 +15831,7 @@ async function sendJobsBoard(chatId, channel, page) {
15791
15831
  pageSize: 10,
15792
15832
  callbackPrefix: "job:",
15793
15833
  renderItem: (j) => ({
15794
- label: `#${j.id}: ${j.description.slice(0, 30)}`,
15834
+ label: `#${j.id}: ${(j.title ?? j.description).slice(0, 30)}`,
15795
15835
  data: `job:view:${j.id}`,
15796
15836
  style: "primary"
15797
15837
  }),
@@ -15801,7 +15841,7 @@ async function sendJobsBoard(chatId, channel, page) {
15801
15841
  for (const j of pageJobs) {
15802
15842
  const emoji = getJobStatusEmoji(j);
15803
15843
  const schedule2 = getJobScheduleText(j);
15804
- const desc = j.description.length > 24 ? j.description.slice(0, 24) + "\u2026" : j.description;
15844
+ const desc = j.title ?? (j.description.length > 24 ? j.description.slice(0, 24) + "\u2026" : j.description);
15805
15845
  lines.push(`${emoji} ${desc} \xB7 ${schedule2}`);
15806
15846
  }
15807
15847
  lines.push("");
@@ -15836,8 +15876,9 @@ async function sendJobDetail(chatId, jobId, channel) {
15836
15876
  const runs = getJobRuns(jobId, 1);
15837
15877
  const lastRunStatus = runs.length > 0 ? runs[0].status : null;
15838
15878
  const lines = [
15839
- `Job #${job.id}: ${job.description}`,
15879
+ `Job #${job.id}: ${job.title ?? job.description}`,
15840
15880
  buildSectionHeader("", 22),
15881
+ ...job.title ? [`Task: ${job.description}`] : [],
15841
15882
  `Runs: ${schedule2}${tz}`,
15842
15883
  `Backend: ${backend2} | Model: ${model2}`,
15843
15884
  `Last run: ${lastRun}${lastRunStatus ? ` (${lastRunStatus})` : ""}`,
@@ -15944,7 +15985,7 @@ async function sendJobPicker(chatId, channel, action) {
15944
15985
  const actionLabel = action.charAt(0).toUpperCase() + action.slice(1);
15945
15986
  const style = action === "run" ? "success" : action === "cancel" ? "danger" : void 0;
15946
15987
  const buttons = jobs.map((j) => [{
15947
- label: `#${j.id}: ${j.description.slice(0, 30)}`,
15988
+ label: `#${j.id}: ${(j.title ?? j.description).slice(0, 30)}`,
15948
15989
  data: action === "cancel" ? `job:cancel:${j.id}` : `job:${action}:${j.id}`,
15949
15990
  ...style ? { style } : {}
15950
15991
  }]);
@@ -16602,24 +16643,159 @@ Result: ${task.result.slice(0, 500)}` : ""
16602
16643
  }
16603
16644
  case "discuss": {
16604
16645
  const insId = parseInt(idStr, 10);
16605
- activeProposalDiscussion.set(chatId, insId);
16606
- await channel.sendKeyboard(chatId, `Discussing proposal #${insId}. Send your questions \u2014 type "done" when finished.`, [
16607
- [{ label: "Done", data: `evolve:discuss-done:${insId}` }]
16646
+ await channel.sendKeyboard(chatId, [
16647
+ "What would you like to do with this proposal?",
16648
+ "",
16649
+ "Why this file? \u2014 ask the AI to explain its reasoning",
16650
+ "Retarget \u2014 move this change to a different file (e.g., a skill instead of SOUL.md)",
16651
+ "Revise \u2014 ask the AI to rewrite the proposed change"
16652
+ ].join("\n"), [
16653
+ [
16654
+ { label: "Why this file?", data: `evolve:discuss-why:${insId}`, style: "primary" },
16655
+ { label: "Retarget", data: `evolve:discuss-retarget:${insId}` }
16656
+ ],
16657
+ [
16658
+ { label: "Revise the change", data: `evolve:discuss-revise:${insId}` },
16659
+ { label: "Back", data: `evolve:discuss-back:${insId}` }
16660
+ ]
16608
16661
  ]);
16609
16662
  break;
16610
16663
  }
16611
- case "discuss-done": {
16612
- activeProposalDiscussion.delete(chatId);
16613
- const { getInsightById: getIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16614
- const { formatProposalCard: fmtCard, buildProposalKeyboard: buildKb } = await Promise.resolve().then(() => (init_propose(), propose_exports));
16615
- const { getDb: getDatabase } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16616
- const ins = getIns(getDatabase(), parseInt(idStr, 10));
16617
- if (ins && ins.status === "pending") {
16618
- const card = fmtCard(ins);
16619
- const kb = buildKb(ins.id, ins.category);
16620
- await channel.sendKeyboard(chatId, "Updated proposal:\n\n" + card, kb);
16621
- } else {
16622
- await channel.sendText(chatId, "Discussion ended.", { parseMode: "plain" });
16664
+ case "discuss-why": {
16665
+ const { getInsightById: gwIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16666
+ const { getDb: gwDb } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16667
+ const gwInsight = gwIns(gwDb(), parseInt(idStr, 10));
16668
+ if (!gwInsight) {
16669
+ await channel.sendText(chatId, "Proposal not found.", { parseMode: "plain" });
16670
+ break;
16671
+ }
16672
+ await channel.sendTyping?.(chatId);
16673
+ const whyPrompt = [
16674
+ `Explain in 2-3 sentences why you chose "${gwInsight.targetFile}" as the target file for this insight:`,
16675
+ `"${gwInsight.insight}"`,
16676
+ `Consider what other files could work (skills, context files, USER.md) and explain your reasoning.`
16677
+ ].join("\n");
16678
+ try {
16679
+ const whyResp = await askAgent(chatId, whyPrompt, { bootstrapTier: "chat", maxTurns: 1, timeoutMs: 6e4 });
16680
+ await channel.sendText(chatId, whyResp.text ?? "No response.");
16681
+ } catch (e) {
16682
+ await channel.sendText(chatId, `Error: ${e.message}`, { parseMode: "plain" });
16683
+ }
16684
+ await channel.sendKeyboard(chatId, "What next?", [
16685
+ [
16686
+ { label: "OK, Apply", data: `evolve:apply:${idStr}`, style: "success" },
16687
+ { label: "Retarget instead", data: `evolve:discuss-retarget:${idStr}` }
16688
+ ],
16689
+ [
16690
+ { label: "Reject", data: `evolve:reject:${idStr}`, style: "danger" },
16691
+ { label: "Back", data: `evolve:discuss-back:${idStr}` }
16692
+ ]
16693
+ ]);
16694
+ break;
16695
+ }
16696
+ case "discuss-retarget": {
16697
+ const { getInsightById: rtIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16698
+ const { getDb: rtDb } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16699
+ const rtInsight = rtIns(rtDb(), parseInt(idStr, 10));
16700
+ if (!rtInsight) {
16701
+ await channel.sendText(chatId, "Proposal not found.", { parseMode: "plain" });
16702
+ break;
16703
+ }
16704
+ const currentTarget = rtInsight.targetFile ?? "unknown";
16705
+ const targets = [
16706
+ { label: "SOUL.md", path: "identity/SOUL.md" },
16707
+ { label: "USER.md", path: "identity/USER.md" }
16708
+ ];
16709
+ const skillDirs = [
16710
+ join19(homedir6(), ".cc-claw", "workspace", "skills")
16711
+ ];
16712
+ try {
16713
+ const { readdirSync: readdirSync7, statSync: statSync9 } = await import("fs");
16714
+ for (const dir of skillDirs) {
16715
+ if (!existsSync19(dir)) continue;
16716
+ for (const entry of readdirSync7(dir)) {
16717
+ if (statSync9(join19(dir, entry)).isDirectory()) {
16718
+ targets.push({ label: `skills/${entry}`, path: `workspace/skills/${entry}/SKILL.md` });
16719
+ }
16720
+ }
16721
+ }
16722
+ } catch {
16723
+ }
16724
+ const rows = targets.filter((t) => t.path !== currentTarget).map((t) => [{ label: t.label, data: `evolve:discuss-retarget-to:${idStr}:${t.path}` }]);
16725
+ rows.push([{ label: "Cancel", data: `evolve:discuss-back:${idStr}` }]);
16726
+ await channel.sendKeyboard(chatId, `Current target: ${currentTarget}
16727
+
16728
+ Pick a different file for this change. Identity files (SOUL/USER) shape personality; skills teach specific workflows.`, rows);
16729
+ break;
16730
+ }
16731
+ case "discuss-retarget-to": {
16732
+ const retargetParts = data.split(":");
16733
+ const rtId = parseInt(retargetParts[2], 10);
16734
+ const newPath = retargetParts.slice(3).join(":");
16735
+ const { getInsightById: rt2Ins, updateInsightProposal: rt2Update } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16736
+ const { formatProposalCard: rt2Card, buildProposalKeyboard: rt2Kb } = await Promise.resolve().then(() => (init_propose(), propose_exports));
16737
+ const { getDb: rt2Db } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16738
+ const rt2Insight = rt2Ins(rt2Db(), rtId);
16739
+ if (!rt2Insight) {
16740
+ await channel.sendText(chatId, "Proposal not found.", { parseMode: "plain" });
16741
+ break;
16742
+ }
16743
+ rt2Update(rt2Db(), rtId, newPath, rt2Insight.proposedDiff, rt2Insight.proposedAction);
16744
+ const updatedIns = rt2Ins(rt2Db(), rtId);
16745
+ if (updatedIns) {
16746
+ const card = rt2Card(updatedIns);
16747
+ const kb = rt2Kb(updatedIns.id, updatedIns.category);
16748
+ await channel.sendKeyboard(chatId, `Retargeted to ${newPath}. Updated proposal:
16749
+
16750
+ ` + card, kb);
16751
+ }
16752
+ break;
16753
+ }
16754
+ case "discuss-revise": {
16755
+ const { getInsightById: rvIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16756
+ const { getDb: rvDb } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16757
+ const rvInsight = rvIns(rvDb(), parseInt(idStr, 10));
16758
+ if (!rvInsight) {
16759
+ await channel.sendText(chatId, "Proposal not found.", { parseMode: "plain" });
16760
+ break;
16761
+ }
16762
+ await channel.sendTyping?.(chatId);
16763
+ const revisePrompt = [
16764
+ `Revise this proposed change to be more specific and actionable:`,
16765
+ `Current insight: "${rvInsight.insight}"`,
16766
+ `Current diff: ${rvInsight.proposedDiff ?? "none"}`,
16767
+ `Target: ${rvInsight.targetFile}`,
16768
+ ``,
16769
+ `Output ONLY the revised diff lines (starting with + for additions, - for removals). No explanation.`
16770
+ ].join("\n");
16771
+ try {
16772
+ const rvResp = await askAgent(chatId, revisePrompt, { bootstrapTier: "chat", maxTurns: 1, timeoutMs: 6e4 });
16773
+ const newDiff = rvResp.text?.trim() ?? rvInsight.proposedDiff;
16774
+ if (newDiff) {
16775
+ const { updateInsightProposal: rvUpdate } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16776
+ rvUpdate(rvDb(), parseInt(idStr, 10), rvInsight.targetFile ?? "", newDiff, rvInsight.proposedAction);
16777
+ }
16778
+ const updatedRv = rvIns(rvDb(), parseInt(idStr, 10));
16779
+ if (updatedRv) {
16780
+ const { formatProposalCard: rvCard, buildProposalKeyboard: rvKb } = await Promise.resolve().then(() => (init_propose(), propose_exports));
16781
+ const card = rvCard(updatedRv);
16782
+ const kb = rvKb(updatedRv.id, updatedRv.category);
16783
+ await channel.sendKeyboard(chatId, "Revised proposal:\n\n" + card, kb);
16784
+ }
16785
+ } catch (e) {
16786
+ await channel.sendText(chatId, `Revision error: ${e.message}`, { parseMode: "plain" });
16787
+ }
16788
+ break;
16789
+ }
16790
+ case "discuss-back": {
16791
+ const { getInsightById: bkIns } = await Promise.resolve().then(() => (init_store4(), store_exports4));
16792
+ const { formatProposalCard: bkCard, buildProposalKeyboard: bkKb } = await Promise.resolve().then(() => (init_propose(), propose_exports));
16793
+ const { getDb: bkDb } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16794
+ const bkInsight = bkIns(bkDb(), parseInt(idStr, 10));
16795
+ if (bkInsight && bkInsight.status === "pending") {
16796
+ const card = bkCard(bkInsight);
16797
+ const kb = bkKb(bkInsight.id, bkInsight.category);
16798
+ await channel.sendKeyboard(chatId, card, kb);
16623
16799
  }
16624
16800
  break;
16625
16801
  }
@@ -16681,13 +16857,13 @@ Result: ${task.result.slice(0, 500)}` : ""
16681
16857
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
16682
16858
  const current = getReflectionStatus2(getDb2(), chatId);
16683
16859
  if (current === "frozen") {
16684
- const { readFileSync: readFileSync21, existsSync: existsSync45 } = await import("fs");
16860
+ const { readFileSync: readFileSync21, existsSync: existsSync47 } = await import("fs");
16685
16861
  const { join: join26 } = await import("path");
16686
16862
  const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
16687
16863
  const soulPath = join26(CC_CLAW_HOME3, "identity/SOUL.md");
16688
16864
  const userPath = join26(CC_CLAW_HOME3, "identity/USER.md");
16689
- const soul = existsSync45(soulPath) ? readFileSync21(soulPath, "utf-8") : "";
16690
- const user = existsSync45(userPath) ? readFileSync21(userPath, "utf-8") : "";
16865
+ const soul = existsSync47(soulPath) ? readFileSync21(soulPath, "utf-8") : "";
16866
+ const user = existsSync47(userPath) ? readFileSync21(userPath, "utf-8") : "";
16691
16867
  setReflectionStatus2(getDb2(), chatId, "active", soul, user);
16692
16868
  const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
16693
16869
  logActivity2(getDb2(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
@@ -17281,7 +17457,7 @@ Use /skills <page> to navigate (e.g. /skills 2)` : "";
17281
17457
  const header2 = totalPages > 1 ? `${skills2.length} skills (page ${safePage}/${totalPages}). Select one to invoke:` : `${skills2.length} skills available. Select one to invoke:`;
17282
17458
  await channel.sendKeyboard(chatId, header2, buttons);
17283
17459
  }
17284
- var PERM_MODES, VERBOSE_LEVELS, HELP_CATEGORIES, USAGE_WINDOW_MAP, MEDIA_INCOMING_PATH, TONE_PATTERNS, pendingInterrupts, bypassBusyCheck, activeSideQuests, MAX_SIDE_QUESTS, activeProposalDiscussion, pendingFallbackMessages, dashboardClawWarnings, pendingSummaryUndo, pendingNewchatUndo, CLI_INSTALL_HINTS, BLOCKED_PATH_PATTERNS2, ALLOWED_REACTION_EMOJIS, SKILLS_PER_PAGE;
17460
+ var PERM_MODES, VERBOSE_LEVELS, HELP_CATEGORIES, USAGE_WINDOW_MAP, MEDIA_INCOMING_PATH, TONE_PATTERNS, pendingInterrupts, bypassBusyCheck, activeSideQuests, MAX_SIDE_QUESTS, pendingFallbackMessages, dashboardClawWarnings, pendingSummaryUndo, pendingNewchatUndo, CLI_INSTALL_HINTS, BLOCKED_PATH_PATTERNS2, ALLOWED_REACTION_EMOJIS, SKILLS_PER_PAGE;
17285
17461
  var init_router = __esm({
17286
17462
  "src/router.ts"() {
17287
17463
  "use strict";
@@ -17422,7 +17598,6 @@ var init_router = __esm({
17422
17598
  bypassBusyCheck = /* @__PURE__ */ new Set();
17423
17599
  activeSideQuests = /* @__PURE__ */ new Map();
17424
17600
  MAX_SIDE_QUESTS = 2;
17425
- activeProposalDiscussion = /* @__PURE__ */ new Map();
17426
17601
  pendingFallbackMessages = /* @__PURE__ */ new Map();
17427
17602
  dashboardClawWarnings = /* @__PURE__ */ new Map();
17428
17603
  pendingSummaryUndo = /* @__PURE__ */ new Map();
@@ -17522,19 +17697,19 @@ var init_router = __esm({
17522
17697
  });
17523
17698
 
17524
17699
  // src/skills/bootstrap.ts
17525
- import { existsSync as existsSync18 } from "fs";
17700
+ import { existsSync as existsSync20 } from "fs";
17526
17701
  import { readdir as readdir4, readFile as readFile6, writeFile as writeFile4, copyFile } from "fs/promises";
17527
17702
  import { join as join20, dirname as dirname3 } from "path";
17528
17703
  import { fileURLToPath as fileURLToPath2 } from "url";
17529
17704
  async function copyAgentManifestSkills() {
17530
- if (!existsSync18(PKG_SKILLS)) return;
17705
+ if (!existsSync20(PKG_SKILLS)) return;
17531
17706
  try {
17532
17707
  const entries = await readdir4(PKG_SKILLS, { withFileTypes: true });
17533
17708
  for (const entry of entries) {
17534
17709
  if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
17535
17710
  const src = join20(PKG_SKILLS, entry.name);
17536
17711
  const dest = join20(SKILLS_PATH, entry.name);
17537
- if (existsSync18(dest)) continue;
17712
+ if (existsSync20(dest)) continue;
17538
17713
  await copyFile(src, dest);
17539
17714
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
17540
17715
  }
@@ -17545,7 +17720,7 @@ async function copyAgentManifestSkills() {
17545
17720
  async function bootstrapSkills() {
17546
17721
  await copyAgentManifestSkills();
17547
17722
  const usmDir = join20(SKILLS_PATH, USM_DIR_NAME);
17548
- if (existsSync18(usmDir)) return;
17723
+ if (existsSync20(usmDir)) return;
17549
17724
  try {
17550
17725
  const entries = await readdir4(SKILLS_PATH);
17551
17726
  const dirs = entries.filter((e) => !e.startsWith("."));
@@ -17568,7 +17743,7 @@ async function bootstrapSkills() {
17568
17743
  }
17569
17744
  async function patchUsmForCcClaw(usmDir) {
17570
17745
  const skillPath = join20(usmDir, "SKILL.md");
17571
- if (!existsSync18(skillPath)) return;
17746
+ if (!existsSync20(skillPath)) return;
17572
17747
  try {
17573
17748
  let content = await readFile6(skillPath, "utf-8");
17574
17749
  let patched = false;
@@ -17828,13 +18003,13 @@ __export(ai_skill_exports, {
17828
18003
  generateAiSkill: () => generateAiSkill,
17829
18004
  installAiSkill: () => installAiSkill
17830
18005
  });
17831
- import { existsSync as existsSync19, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7 } from "fs";
18006
+ import { existsSync as existsSync21, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7 } from "fs";
17832
18007
  import { join as join21 } from "path";
17833
- import { homedir as homedir5 } from "os";
18008
+ import { homedir as homedir7 } from "os";
17834
18009
  function generateAiSkill() {
17835
18010
  const version = VERSION;
17836
18011
  let systemState = "";
17837
- if (existsSync19(DB_PATH)) {
18012
+ if (existsSync21(DB_PATH)) {
17838
18013
  try {
17839
18014
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
17840
18015
  const readDb = openDatabaseReadOnly2();
@@ -18250,11 +18425,11 @@ var init_ai_skill = __esm({
18250
18425
  init_paths();
18251
18426
  init_version();
18252
18427
  BACKEND_SKILL_DIRS2 = {
18253
- "cc-claw": [join21(homedir5(), ".cc-claw", "workspace", "skills")],
18254
- claude: [join21(homedir5(), ".claude", "skills")],
18255
- gemini: [join21(homedir5(), ".gemini", "skills")],
18256
- codex: [join21(homedir5(), ".agents", "skills")],
18257
- cursor: [join21(homedir5(), ".cursor", "skills"), join21(homedir5(), ".cursor", "skills-cursor")]
18428
+ "cc-claw": [join21(homedir7(), ".cc-claw", "workspace", "skills")],
18429
+ claude: [join21(homedir7(), ".claude", "skills")],
18430
+ gemini: [join21(homedir7(), ".gemini", "skills")],
18431
+ codex: [join21(homedir7(), ".agents", "skills")],
18432
+ cursor: [join21(homedir7(), ".cursor", "skills"), join21(homedir7(), ".cursor", "skills-cursor")]
18258
18433
  };
18259
18434
  }
18260
18435
  });
@@ -18264,7 +18439,7 @@ var index_exports = {};
18264
18439
  __export(index_exports, {
18265
18440
  main: () => main
18266
18441
  });
18267
- import { mkdirSync as mkdirSync8, existsSync as existsSync20, renameSync, statSync as statSync3, readFileSync as readFileSync12 } from "fs";
18442
+ import { mkdirSync as mkdirSync8, existsSync as existsSync22, renameSync, statSync as statSync4, readFileSync as readFileSync12 } from "fs";
18268
18443
  import { join as join22 } from "path";
18269
18444
  import dotenv from "dotenv";
18270
18445
  function migrateLayout() {
@@ -18278,7 +18453,7 @@ function migrateLayout() {
18278
18453
  [join22(CC_CLAW_HOME, "cc-claw.error.log.1"), join22(LOGS_PATH, "cc-claw.error.log.1")]
18279
18454
  ];
18280
18455
  for (const [from, to] of moves) {
18281
- if (existsSync20(from) && !existsSync20(to)) {
18456
+ if (existsSync22(from) && !existsSync22(to)) {
18282
18457
  try {
18283
18458
  renameSync(from, to);
18284
18459
  } catch {
@@ -18289,7 +18464,7 @@ function migrateLayout() {
18289
18464
  function rotateLogs() {
18290
18465
  for (const file of [LOG_PATH, ERROR_LOG_PATH]) {
18291
18466
  try {
18292
- const { size } = statSync3(file);
18467
+ const { size } = statSync4(file);
18293
18468
  if (size > LOG_MAX_BYTES) {
18294
18469
  const archivePath = `${file}.1`;
18295
18470
  try {
@@ -18485,10 +18660,10 @@ var init_index = __esm({
18485
18660
  init_bootstrap2();
18486
18661
  init_health3();
18487
18662
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
18488
- if (!existsSync20(dir)) mkdirSync8(dir, { recursive: true });
18663
+ if (!existsSync22(dir)) mkdirSync8(dir, { recursive: true });
18489
18664
  }
18490
18665
  migrateLayout();
18491
- if (existsSync20(ENV_PATH)) {
18666
+ if (existsSync22(ENV_PATH)) {
18492
18667
  dotenv.config({ path: ENV_PATH });
18493
18668
  } else {
18494
18669
  console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
@@ -18509,12 +18684,12 @@ __export(api_client_exports, {
18509
18684
  apiPost: () => apiPost,
18510
18685
  isDaemonRunning: () => isDaemonRunning
18511
18686
  });
18512
- import { readFileSync as readFileSync13, existsSync as existsSync21 } from "fs";
18687
+ import { readFileSync as readFileSync13, existsSync as existsSync23 } from "fs";
18513
18688
  import { request as httpRequest } from "http";
18514
18689
  function getToken() {
18515
18690
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
18516
18691
  try {
18517
- if (existsSync21(TOKEN_PATH)) return readFileSync13(TOKEN_PATH, "utf-8").trim();
18692
+ if (existsSync23(TOKEN_PATH)) return readFileSync13(TOKEN_PATH, "utf-8").trim();
18518
18693
  } catch {
18519
18694
  }
18520
18695
  return null;
@@ -18609,9 +18784,9 @@ __export(service_exports, {
18609
18784
  serviceStatus: () => serviceStatus,
18610
18785
  uninstallService: () => uninstallService
18611
18786
  });
18612
- import { existsSync as existsSync22, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4 } from "fs";
18787
+ import { existsSync as existsSync24, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7, unlinkSync as unlinkSync4 } from "fs";
18613
18788
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
18614
- import { homedir as homedir6, platform } from "os";
18789
+ import { homedir as homedir8, platform } from "os";
18615
18790
  import { join as join23, dirname as dirname4 } from "path";
18616
18791
  function resolveExecutable2(name) {
18617
18792
  try {
@@ -18622,7 +18797,7 @@ function resolveExecutable2(name) {
18622
18797
  }
18623
18798
  function getPathDirs() {
18624
18799
  const nodeBin = dirname4(process.execPath);
18625
- const home = homedir6();
18800
+ const home = homedir8();
18626
18801
  const dirs = /* @__PURE__ */ new Set([
18627
18802
  nodeBin,
18628
18803
  join23(home, ".local", "bin"),
@@ -18640,7 +18815,7 @@ function getPathDirs() {
18640
18815
  function generatePlist() {
18641
18816
  const ccClawBin = resolveExecutable2("cc-claw");
18642
18817
  const pathDirs = getPathDirs();
18643
- const home = homedir6();
18818
+ const home = homedir8();
18644
18819
  return `<?xml version="1.0" encoding="UTF-8"?>
18645
18820
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
18646
18821
  <plist version="1.0">
@@ -18684,9 +18859,9 @@ function generatePlist() {
18684
18859
  }
18685
18860
  function installMacOS() {
18686
18861
  const agentsDir = dirname4(PLIST_PATH);
18687
- if (!existsSync22(agentsDir)) mkdirSync9(agentsDir, { recursive: true });
18688
- if (!existsSync22(LOGS_PATH)) mkdirSync9(LOGS_PATH, { recursive: true });
18689
- if (existsSync22(PLIST_PATH)) {
18862
+ if (!existsSync24(agentsDir)) mkdirSync9(agentsDir, { recursive: true });
18863
+ if (!existsSync24(LOGS_PATH)) mkdirSync9(LOGS_PATH, { recursive: true });
18864
+ if (existsSync24(PLIST_PATH)) {
18690
18865
  try {
18691
18866
  execFileSync2("launchctl", ["unload", PLIST_PATH]);
18692
18867
  } catch {
@@ -18698,7 +18873,7 @@ function installMacOS() {
18698
18873
  console.log(" Service loaded and starting.");
18699
18874
  }
18700
18875
  function uninstallMacOS() {
18701
- if (!existsSync22(PLIST_PATH)) {
18876
+ if (!existsSync24(PLIST_PATH)) {
18702
18877
  console.log(" No service found to uninstall.");
18703
18878
  return;
18704
18879
  }
@@ -18765,15 +18940,15 @@ Restart=on-failure
18765
18940
  RestartSec=10
18766
18941
  WorkingDirectory=${CC_CLAW_HOME}
18767
18942
  Environment=PATH=${pathDirs}
18768
- Environment=HOME=${homedir6()}
18943
+ Environment=HOME=${homedir8()}
18769
18944
 
18770
18945
  [Install]
18771
18946
  WantedBy=default.target
18772
18947
  `;
18773
18948
  }
18774
18949
  function installLinux() {
18775
- if (!existsSync22(SYSTEMD_DIR)) mkdirSync9(SYSTEMD_DIR, { recursive: true });
18776
- if (!existsSync22(LOGS_PATH)) mkdirSync9(LOGS_PATH, { recursive: true });
18950
+ if (!existsSync24(SYSTEMD_DIR)) mkdirSync9(SYSTEMD_DIR, { recursive: true });
18951
+ if (!existsSync24(LOGS_PATH)) mkdirSync9(LOGS_PATH, { recursive: true });
18777
18952
  writeFileSync7(UNIT_PATH, generateUnit());
18778
18953
  console.log(` Installed: ${UNIT_PATH}`);
18779
18954
  execFileSync2("systemctl", ["--user", "daemon-reload"]);
@@ -18782,7 +18957,7 @@ function installLinux() {
18782
18957
  console.log(" Service enabled and started.");
18783
18958
  }
18784
18959
  function uninstallLinux() {
18785
- if (!existsSync22(UNIT_PATH)) {
18960
+ if (!existsSync24(UNIT_PATH)) {
18786
18961
  console.log(" No service found to uninstall.");
18787
18962
  return;
18788
18963
  }
@@ -18807,7 +18982,7 @@ function statusLinux() {
18807
18982
  }
18808
18983
  }
18809
18984
  function installService() {
18810
- if (!existsSync22(join23(CC_CLAW_HOME, ".env"))) {
18985
+ if (!existsSync24(join23(CC_CLAW_HOME, ".env"))) {
18811
18986
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
18812
18987
  console.error(" Run 'cc-claw setup' before installing the service.");
18813
18988
  process.exitCode = 1;
@@ -18836,8 +19011,8 @@ var init_service = __esm({
18836
19011
  "use strict";
18837
19012
  init_paths();
18838
19013
  PLIST_LABEL = "com.cc-claw";
18839
- PLIST_PATH = join23(homedir6(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
18840
- SYSTEMD_DIR = join23(homedir6(), ".config", "systemd", "user");
19014
+ PLIST_PATH = join23(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
19015
+ SYSTEMD_DIR = join23(homedir8(), ".config", "systemd", "user");
18841
19016
  UNIT_PATH = join23(SYSTEMD_DIR, "cc-claw.service");
18842
19017
  }
18843
19018
  });
@@ -19035,7 +19210,7 @@ var status_exports = {};
19035
19210
  __export(status_exports, {
19036
19211
  statusCommand: () => statusCommand
19037
19212
  });
19038
- import { existsSync as existsSync23, statSync as statSync4 } from "fs";
19213
+ import { existsSync as existsSync25, statSync as statSync5 } from "fs";
19039
19214
  async function statusCommand(globalOpts, localOpts) {
19040
19215
  try {
19041
19216
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -19075,7 +19250,7 @@ async function statusCommand(globalOpts, localOpts) {
19075
19250
  const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
19076
19251
  const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
19077
19252
  const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
19078
- const dbStat = existsSync23(DB_PATH) ? statSync4(DB_PATH) : null;
19253
+ const dbStat = existsSync25(DB_PATH) ? statSync5(DB_PATH) : null;
19079
19254
  let daemonRunning = false;
19080
19255
  let daemonInfo = {};
19081
19256
  if (localOpts.deep) {
@@ -19166,12 +19341,12 @@ var doctor_exports = {};
19166
19341
  __export(doctor_exports, {
19167
19342
  doctorCommand: () => doctorCommand
19168
19343
  });
19169
- import { existsSync as existsSync24, statSync as statSync5, accessSync, constants } from "fs";
19344
+ import { existsSync as existsSync26, statSync as statSync6, accessSync, constants } from "fs";
19170
19345
  import { execFileSync as execFileSync3 } from "child_process";
19171
19346
  async function doctorCommand(globalOpts, localOpts) {
19172
19347
  const checks = [];
19173
- if (existsSync24(DB_PATH)) {
19174
- const size = statSync5(DB_PATH).size;
19348
+ if (existsSync26(DB_PATH)) {
19349
+ const size = statSync6(DB_PATH).size;
19175
19350
  checks.push({ name: "Database", status: "ok", message: `${DB_PATH} (${(size / 1024).toFixed(0)}KB)` });
19176
19351
  try {
19177
19352
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
@@ -19200,7 +19375,7 @@ async function doctorCommand(globalOpts, localOpts) {
19200
19375
  } else {
19201
19376
  checks.push({ name: "Database", status: "error", message: `Not found at ${DB_PATH}`, fix: "cc-claw setup" });
19202
19377
  }
19203
- if (existsSync24(ENV_PATH)) {
19378
+ if (existsSync26(ENV_PATH)) {
19204
19379
  checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
19205
19380
  } else {
19206
19381
  checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
@@ -19244,7 +19419,7 @@ async function doctorCommand(globalOpts, localOpts) {
19244
19419
  checks.push({ name: "Daemon", status: "warning", message: "could not probe" });
19245
19420
  }
19246
19421
  const tokenPath = `${DATA_PATH}/api-token`;
19247
- if (existsSync24(tokenPath)) {
19422
+ if (existsSync26(tokenPath)) {
19248
19423
  try {
19249
19424
  accessSync(tokenPath, constants.R_OK);
19250
19425
  checks.push({ name: "API token", status: "ok", message: "token file readable" });
@@ -19269,7 +19444,7 @@ async function doctorCommand(globalOpts, localOpts) {
19269
19444
  }
19270
19445
  } catch {
19271
19446
  }
19272
- if (existsSync24(ERROR_LOG_PATH)) {
19447
+ if (existsSync26(ERROR_LOG_PATH)) {
19273
19448
  try {
19274
19449
  const { readFileSync: readFileSync21 } = await import("fs");
19275
19450
  const logContent = readFileSync21(ERROR_LOG_PATH, "utf-8");
@@ -19395,10 +19570,10 @@ var logs_exports = {};
19395
19570
  __export(logs_exports, {
19396
19571
  logsCommand: () => logsCommand
19397
19572
  });
19398
- import { existsSync as existsSync25, readFileSync as readFileSync16, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
19573
+ import { existsSync as existsSync27, readFileSync as readFileSync16, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
19399
19574
  async function logsCommand(opts) {
19400
19575
  const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
19401
- if (!existsSync25(logFile)) {
19576
+ if (!existsSync27(logFile)) {
19402
19577
  outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
19403
19578
  process.exit(1);
19404
19579
  }
@@ -19450,11 +19625,11 @@ __export(gemini_exports, {
19450
19625
  geminiReorder: () => geminiReorder,
19451
19626
  geminiRotation: () => geminiRotation
19452
19627
  });
19453
- import { existsSync as existsSync26, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync17, chmodSync } from "fs";
19628
+ import { existsSync as existsSync28, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync17, chmodSync } from "fs";
19454
19629
  import { join as join24 } from "path";
19455
19630
  import { createInterface as createInterface5 } from "readline";
19456
19631
  function requireDb() {
19457
- if (!existsSync26(DB_PATH)) {
19632
+ if (!existsSync28(DB_PATH)) {
19458
19633
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
19459
19634
  process.exit(1);
19460
19635
  }
@@ -19480,7 +19655,7 @@ function resolveOAuthEmail(configHome) {
19480
19655
  if (!configHome) return null;
19481
19656
  try {
19482
19657
  const accountsPath = join24(configHome, ".gemini", "google_accounts.json");
19483
- if (!existsSync26(accountsPath)) return null;
19658
+ if (!existsSync28(accountsPath)) return null;
19484
19659
  const accounts = JSON.parse(readFileSync17(accountsPath, "utf-8"));
19485
19660
  return accounts.active || null;
19486
19661
  } catch {
@@ -19564,7 +19739,7 @@ async function geminiAddKey(globalOpts, opts) {
19564
19739
  async function geminiAddAccount(globalOpts, opts) {
19565
19740
  await requireWriteDb();
19566
19741
  const slotsDir = join24(CC_CLAW_HOME, "gemini-slots");
19567
- if (!existsSync26(slotsDir)) mkdirSync10(slotsDir, { recursive: true });
19742
+ if (!existsSync28(slotsDir)) mkdirSync10(slotsDir, { recursive: true });
19568
19743
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
19569
19744
  const tempId = Date.now();
19570
19745
  const slotDir = join24(slotsDir, `slot-${tempId}`);
@@ -19588,7 +19763,7 @@ async function geminiAddAccount(globalOpts, opts) {
19588
19763
  } catch {
19589
19764
  }
19590
19765
  const oauthPath = join24(slotDir, ".gemini", "oauth_creds.json");
19591
- if (!existsSync26(oauthPath)) {
19766
+ if (!existsSync28(oauthPath)) {
19592
19767
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
19593
19768
  console.log(" The slot directory is preserved at: " + slotDir);
19594
19769
  console.log(" Re-run: cc-claw gemini add-account\n");
@@ -19702,12 +19877,12 @@ __export(backend_exports, {
19702
19877
  backendList: () => backendList,
19703
19878
  backendSet: () => backendSet
19704
19879
  });
19705
- import { existsSync as existsSync27 } from "fs";
19880
+ import { existsSync as existsSync29 } from "fs";
19706
19881
  async function backendList(globalOpts) {
19707
19882
  const { getAvailableAdapters: getAvailableAdapters2 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
19708
19883
  const chatId = resolveChatId(globalOpts);
19709
19884
  let activeBackend = null;
19710
- if (existsSync27(DB_PATH)) {
19885
+ if (existsSync29(DB_PATH)) {
19711
19886
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
19712
19887
  const readDb = openDatabaseReadOnly2();
19713
19888
  try {
@@ -19738,7 +19913,7 @@ async function backendList(globalOpts) {
19738
19913
  }
19739
19914
  async function backendGet(globalOpts) {
19740
19915
  const chatId = resolveChatId(globalOpts);
19741
- if (!existsSync27(DB_PATH)) {
19916
+ if (!existsSync29(DB_PATH)) {
19742
19917
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
19743
19918
  process.exit(1);
19744
19919
  }
@@ -19782,13 +19957,13 @@ __export(model_exports, {
19782
19957
  modelList: () => modelList,
19783
19958
  modelSet: () => modelSet
19784
19959
  });
19785
- import { existsSync as existsSync28 } from "fs";
19960
+ import { existsSync as existsSync30 } from "fs";
19786
19961
  async function modelList(globalOpts) {
19787
19962
  const chatId = resolveChatId(globalOpts);
19788
19963
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
19789
19964
  const { getAdapter: getAdapter2, getAllAdapters: getAllAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
19790
19965
  let backendId = "claude";
19791
- if (existsSync28(DB_PATH)) {
19966
+ if (existsSync30(DB_PATH)) {
19792
19967
  const readDb = openDatabaseReadOnly2();
19793
19968
  try {
19794
19969
  const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
@@ -19821,7 +19996,7 @@ async function modelList(globalOpts) {
19821
19996
  }
19822
19997
  async function modelGet(globalOpts) {
19823
19998
  const chatId = resolveChatId(globalOpts);
19824
- if (!existsSync28(DB_PATH)) {
19999
+ if (!existsSync30(DB_PATH)) {
19825
20000
  outputError("DB_NOT_FOUND", "Database not found.");
19826
20001
  process.exit(1);
19827
20002
  }
@@ -19865,9 +20040,9 @@ __export(memory_exports, {
19865
20040
  memoryList: () => memoryList,
19866
20041
  memorySearch: () => memorySearch
19867
20042
  });
19868
- import { existsSync as existsSync29 } from "fs";
20043
+ import { existsSync as existsSync31 } from "fs";
19869
20044
  async function memoryList(globalOpts) {
19870
- if (!existsSync29(DB_PATH)) {
20045
+ if (!existsSync31(DB_PATH)) {
19871
20046
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
19872
20047
  process.exit(1);
19873
20048
  }
@@ -19891,7 +20066,7 @@ async function memoryList(globalOpts) {
19891
20066
  });
19892
20067
  }
19893
20068
  async function memorySearch(globalOpts, query) {
19894
- if (!existsSync29(DB_PATH)) {
20069
+ if (!existsSync31(DB_PATH)) {
19895
20070
  outputError("DB_NOT_FOUND", "Database not found.");
19896
20071
  process.exit(1);
19897
20072
  }
@@ -19913,7 +20088,7 @@ async function memorySearch(globalOpts, query) {
19913
20088
  });
19914
20089
  }
19915
20090
  async function memoryHistory(globalOpts, opts) {
19916
- if (!existsSync29(DB_PATH)) {
20091
+ if (!existsSync31(DB_PATH)) {
19917
20092
  outputError("DB_NOT_FOUND", "Database not found.");
19918
20093
  process.exit(1);
19919
20094
  }
@@ -19961,7 +20136,7 @@ __export(cron_exports2, {
19961
20136
  cronList: () => cronList,
19962
20137
  cronRuns: () => cronRuns
19963
20138
  });
19964
- import { existsSync as existsSync30 } from "fs";
20139
+ import { existsSync as existsSync32 } from "fs";
19965
20140
  function parseFallbacks(raw) {
19966
20141
  return raw.slice(0, 3).map((f) => {
19967
20142
  const [backend2, ...rest] = f.split(":");
@@ -19982,7 +20157,7 @@ function parseAndValidateTimeout(raw) {
19982
20157
  return val;
19983
20158
  }
19984
20159
  async function cronList(globalOpts) {
19985
- if (!existsSync30(DB_PATH)) {
20160
+ if (!existsSync32(DB_PATH)) {
19986
20161
  outputError("DB_NOT_FOUND", "Database not found.");
19987
20162
  process.exit(1);
19988
20163
  }
@@ -20001,7 +20176,7 @@ async function cronList(globalOpts) {
20001
20176
  const schedule2 = j.cron ?? (j.at_time ? `at ${j.at_time}` : j.every_ms ? `every ${j.every_ms / 1e3}s` : "?");
20002
20177
  const tz = j.timezone !== "UTC" ? ` (${j.timezone})` : "";
20003
20178
  lines.push(` ${statusDot(status)} #${j.id} [${status}] ${schedule2}${tz}`);
20004
- lines.push(` ${j.description}`);
20179
+ lines.push(` ${j.title ?? j.description}`);
20005
20180
  if (j.backend) lines.push(` Backend: ${j.backend}${j.model ? ` / ${j.model}` : ""}`);
20006
20181
  if (j.fallbacks) {
20007
20182
  try {
@@ -20020,7 +20195,7 @@ async function cronList(globalOpts) {
20020
20195
  });
20021
20196
  }
20022
20197
  async function cronHealth(globalOpts) {
20023
- if (!existsSync30(DB_PATH)) {
20198
+ if (!existsSync32(DB_PATH)) {
20024
20199
  outputError("DB_NOT_FOUND", "Database not found.");
20025
20200
  process.exit(1);
20026
20201
  }
@@ -20080,6 +20255,7 @@ async function cronCreate(globalOpts, opts) {
20080
20255
  cron: opts.cron ?? null,
20081
20256
  atTime: opts.at ?? null,
20082
20257
  everyMs,
20258
+ title: opts.title ?? null,
20083
20259
  description: opts.description,
20084
20260
  chatId,
20085
20261
  backend: opts.backend ?? null,
@@ -20134,6 +20310,10 @@ async function cronEdit(globalOpts, id, opts) {
20134
20310
  const db3 = getDb2();
20135
20311
  const updates = [];
20136
20312
  const values = [];
20313
+ if (opts.title) {
20314
+ updates.push("title = ?");
20315
+ values.push(opts.title);
20316
+ }
20137
20317
  if (opts.description) {
20138
20318
  updates.push("description = ?");
20139
20319
  values.push(opts.description);
@@ -20200,7 +20380,7 @@ async function cronEdit(globalOpts, id, opts) {
20200
20380
  }
20201
20381
  }
20202
20382
  async function cronRuns(globalOpts, jobId, opts) {
20203
- if (!existsSync30(DB_PATH)) {
20383
+ if (!existsSync32(DB_PATH)) {
20204
20384
  outputError("DB_NOT_FOUND", "Database not found.");
20205
20385
  process.exit(1);
20206
20386
  }
@@ -20247,9 +20427,9 @@ __export(agents_exports, {
20247
20427
  runnersList: () => runnersList,
20248
20428
  tasksList: () => tasksList
20249
20429
  });
20250
- import { existsSync as existsSync31 } from "fs";
20430
+ import { existsSync as existsSync33 } from "fs";
20251
20431
  async function agentsList(globalOpts) {
20252
- if (!existsSync31(DB_PATH)) {
20432
+ if (!existsSync33(DB_PATH)) {
20253
20433
  outputError("DB_NOT_FOUND", "Database not found.");
20254
20434
  process.exit(1);
20255
20435
  }
@@ -20280,7 +20460,7 @@ async function agentsList(globalOpts) {
20280
20460
  });
20281
20461
  }
20282
20462
  async function tasksList(globalOpts) {
20283
- if (!existsSync31(DB_PATH)) {
20463
+ if (!existsSync33(DB_PATH)) {
20284
20464
  outputError("DB_NOT_FOUND", "Database not found.");
20285
20465
  process.exit(1);
20286
20466
  }
@@ -20408,18 +20588,18 @@ __export(db_exports, {
20408
20588
  dbPath: () => dbPath,
20409
20589
  dbStats: () => dbStats
20410
20590
  });
20411
- import { existsSync as existsSync32, statSync as statSync6, copyFileSync as copyFileSync2, mkdirSync as mkdirSync11 } from "fs";
20591
+ import { existsSync as existsSync34, statSync as statSync7, copyFileSync as copyFileSync2, mkdirSync as mkdirSync11 } from "fs";
20412
20592
  import { dirname as dirname5 } from "path";
20413
20593
  async function dbStats(globalOpts) {
20414
- if (!existsSync32(DB_PATH)) {
20594
+ if (!existsSync34(DB_PATH)) {
20415
20595
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
20416
20596
  process.exit(1);
20417
20597
  }
20418
20598
  const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
20419
20599
  const readDb = openDatabaseReadOnly2();
20420
- const mainSize = statSync6(DB_PATH).size;
20600
+ const mainSize = statSync7(DB_PATH).size;
20421
20601
  const walPath = DB_PATH + "-wal";
20422
- const walSize = existsSync32(walPath) ? statSync6(walPath).size : 0;
20602
+ const walSize = existsSync34(walPath) ? statSync7(walPath).size : 0;
20423
20603
  const tableNames = readDb.prepare(
20424
20604
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
20425
20605
  ).all();
@@ -20453,7 +20633,7 @@ async function dbPath(globalOpts) {
20453
20633
  output({ path: DB_PATH }, (d) => d.path);
20454
20634
  }
20455
20635
  async function dbBackup(globalOpts, destPath) {
20456
- if (!existsSync32(DB_PATH)) {
20636
+ if (!existsSync34(DB_PATH)) {
20457
20637
  outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
20458
20638
  process.exit(1);
20459
20639
  }
@@ -20462,8 +20642,8 @@ async function dbBackup(globalOpts, destPath) {
20462
20642
  mkdirSync11(dirname5(dest), { recursive: true });
20463
20643
  copyFileSync2(DB_PATH, dest);
20464
20644
  const walPath = DB_PATH + "-wal";
20465
- if (existsSync32(walPath)) copyFileSync2(walPath, dest + "-wal");
20466
- output({ path: dest, sizeBytes: statSync6(dest).size }, (d) => {
20645
+ if (existsSync34(walPath)) copyFileSync2(walPath, dest + "-wal");
20646
+ output({ path: dest, sizeBytes: statSync7(dest).size }, (d) => {
20467
20647
  const b = d;
20468
20648
  return `
20469
20649
  ${success("Backup created:")} ${b.path} (${(b.sizeBytes / 1024).toFixed(0)}KB)
@@ -20491,9 +20671,9 @@ __export(usage_exports, {
20491
20671
  usageCost: () => usageCost,
20492
20672
  usageTokens: () => usageTokens
20493
20673
  });
20494
- import { existsSync as existsSync33 } from "fs";
20674
+ import { existsSync as existsSync35 } from "fs";
20495
20675
  function ensureDb() {
20496
- if (!existsSync33(DB_PATH)) {
20676
+ if (!existsSync35(DB_PATH)) {
20497
20677
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
20498
20678
  process.exit(1);
20499
20679
  }
@@ -20683,9 +20863,9 @@ __export(config_exports, {
20683
20863
  configList: () => configList,
20684
20864
  configSet: () => configSet
20685
20865
  });
20686
- import { existsSync as existsSync34, readFileSync as readFileSync18 } from "fs";
20866
+ import { existsSync as existsSync36, readFileSync as readFileSync18 } from "fs";
20687
20867
  async function configList(globalOpts) {
20688
- if (!existsSync34(DB_PATH)) {
20868
+ if (!existsSync36(DB_PATH)) {
20689
20869
  outputError("DB_NOT_FOUND", "Database not found.");
20690
20870
  process.exit(1);
20691
20871
  }
@@ -20719,7 +20899,7 @@ async function configGet(globalOpts, key) {
20719
20899
  outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
20720
20900
  process.exit(1);
20721
20901
  }
20722
- if (!existsSync34(DB_PATH)) {
20902
+ if (!existsSync36(DB_PATH)) {
20723
20903
  outputError("DB_NOT_FOUND", "Database not found.");
20724
20904
  process.exit(1);
20725
20905
  }
@@ -20765,7 +20945,7 @@ async function configSet(globalOpts, key, value) {
20765
20945
  }
20766
20946
  }
20767
20947
  async function configEnv(_globalOpts) {
20768
- if (!existsSync34(ENV_PATH)) {
20948
+ if (!existsSync36(ENV_PATH)) {
20769
20949
  outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
20770
20950
  process.exit(1);
20771
20951
  }
@@ -20819,9 +20999,9 @@ __export(session_exports, {
20819
20999
  sessionGet: () => sessionGet,
20820
21000
  sessionNew: () => sessionNew
20821
21001
  });
20822
- import { existsSync as existsSync35 } from "fs";
21002
+ import { existsSync as existsSync37 } from "fs";
20823
21003
  async function sessionGet(globalOpts) {
20824
- if (!existsSync35(DB_PATH)) {
21004
+ if (!existsSync37(DB_PATH)) {
20825
21005
  outputError("DB_NOT_FOUND", "Database not found.");
20826
21006
  process.exit(1);
20827
21007
  }
@@ -20882,9 +21062,9 @@ __export(permissions_exports, {
20882
21062
  verboseGet: () => verboseGet,
20883
21063
  verboseSet: () => verboseSet
20884
21064
  });
20885
- import { existsSync as existsSync36 } from "fs";
21065
+ import { existsSync as existsSync38 } from "fs";
20886
21066
  function ensureDb2() {
20887
- if (!existsSync36(DB_PATH)) {
21067
+ if (!existsSync38(DB_PATH)) {
20888
21068
  outputError("DB_NOT_FOUND", "Database not found.");
20889
21069
  process.exit(1);
20890
21070
  }
@@ -21031,9 +21211,9 @@ __export(cwd_exports, {
21031
21211
  cwdGet: () => cwdGet,
21032
21212
  cwdSet: () => cwdSet
21033
21213
  });
21034
- import { existsSync as existsSync37 } from "fs";
21214
+ import { existsSync as existsSync39 } from "fs";
21035
21215
  async function cwdGet(globalOpts) {
21036
- if (!existsSync37(DB_PATH)) {
21216
+ if (!existsSync39(DB_PATH)) {
21037
21217
  outputError("DB_NOT_FOUND", "Database not found.");
21038
21218
  process.exit(1);
21039
21219
  }
@@ -21095,9 +21275,9 @@ __export(voice_exports, {
21095
21275
  voiceGet: () => voiceGet,
21096
21276
  voiceSet: () => voiceSet
21097
21277
  });
21098
- import { existsSync as existsSync38 } from "fs";
21278
+ import { existsSync as existsSync40 } from "fs";
21099
21279
  async function voiceGet(globalOpts) {
21100
- if (!existsSync38(DB_PATH)) {
21280
+ if (!existsSync40(DB_PATH)) {
21101
21281
  outputError("DB_NOT_FOUND", "Database not found.");
21102
21282
  process.exit(1);
21103
21283
  }
@@ -21146,9 +21326,9 @@ __export(heartbeat_exports, {
21146
21326
  heartbeatGet: () => heartbeatGet,
21147
21327
  heartbeatSet: () => heartbeatSet
21148
21328
  });
21149
- import { existsSync as existsSync39 } from "fs";
21329
+ import { existsSync as existsSync41 } from "fs";
21150
21330
  async function heartbeatGet(globalOpts) {
21151
- if (!existsSync39(DB_PATH)) {
21331
+ if (!existsSync41(DB_PATH)) {
21152
21332
  outputError("DB_NOT_FOUND", "Database not found.");
21153
21333
  process.exit(1);
21154
21334
  }
@@ -21258,9 +21438,9 @@ __export(chats_exports, {
21258
21438
  chatsList: () => chatsList,
21259
21439
  chatsRemoveAlias: () => chatsRemoveAlias
21260
21440
  });
21261
- import { existsSync as existsSync40 } from "fs";
21441
+ import { existsSync as existsSync42 } from "fs";
21262
21442
  async function chatsList(_globalOpts) {
21263
- if (!existsSync40(DB_PATH)) {
21443
+ if (!existsSync42(DB_PATH)) {
21264
21444
  outputError("DB_NOT_FOUND", "Database not found.");
21265
21445
  process.exit(1);
21266
21446
  }
@@ -21388,9 +21568,9 @@ var mcps_exports = {};
21388
21568
  __export(mcps_exports, {
21389
21569
  mcpsList: () => mcpsList
21390
21570
  });
21391
- import { existsSync as existsSync41 } from "fs";
21571
+ import { existsSync as existsSync43 } from "fs";
21392
21572
  async function mcpsList(_globalOpts) {
21393
- if (!existsSync41(DB_PATH)) {
21573
+ if (!existsSync43(DB_PATH)) {
21394
21574
  outputError("DB_NOT_FOUND", "Database not found.");
21395
21575
  process.exit(1);
21396
21576
  }
@@ -21427,11 +21607,11 @@ __export(chat_exports, {
21427
21607
  chatSend: () => chatSend
21428
21608
  });
21429
21609
  import { request as httpRequest2 } from "http";
21430
- import { readFileSync as readFileSync19, existsSync as existsSync42 } from "fs";
21610
+ import { readFileSync as readFileSync19, existsSync as existsSync44 } from "fs";
21431
21611
  function getToken2() {
21432
21612
  if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
21433
21613
  try {
21434
- if (existsSync42(TOKEN_PATH2)) return readFileSync19(TOKEN_PATH2, "utf-8").trim();
21614
+ if (existsSync44(TOKEN_PATH2)) return readFileSync19(TOKEN_PATH2, "utf-8").trim();
21435
21615
  } catch {
21436
21616
  }
21437
21617
  return null;
@@ -21871,9 +22051,9 @@ __export(evolve_exports, {
21871
22051
  evolveStatus: () => evolveStatus,
21872
22052
  evolveUndo: () => evolveUndo
21873
22053
  });
21874
- import { existsSync as existsSync43 } from "fs";
22054
+ import { existsSync as existsSync45 } from "fs";
21875
22055
  function ensureDb3() {
21876
- if (!existsSync43(DB_PATH)) {
22056
+ if (!existsSync45(DB_PATH)) {
21877
22057
  outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
21878
22058
  process.exit(1);
21879
22059
  }
@@ -22235,7 +22415,7 @@ var init_evolve = __esm({
22235
22415
 
22236
22416
  // src/setup.ts
22237
22417
  var setup_exports = {};
22238
- import { existsSync as existsSync44, writeFileSync as writeFileSync9, readFileSync as readFileSync20, copyFileSync as copyFileSync3, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
22418
+ import { existsSync as existsSync46, writeFileSync as writeFileSync9, readFileSync as readFileSync20, copyFileSync as copyFileSync3, mkdirSync as mkdirSync12, statSync as statSync8 } from "fs";
22239
22419
  import { execFileSync as execFileSync4 } from "child_process";
22240
22420
  import { createInterface as createInterface7 } from "readline";
22241
22421
  import { join as join25 } from "path";
@@ -22313,10 +22493,10 @@ async function setup() {
22313
22493
  }
22314
22494
  console.log("");
22315
22495
  for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
22316
- if (!existsSync44(dir)) mkdirSync12(dir, { recursive: true });
22496
+ if (!existsSync46(dir)) mkdirSync12(dir, { recursive: true });
22317
22497
  }
22318
22498
  const env = {};
22319
- const envSource = existsSync44(ENV_PATH) ? ENV_PATH : existsSync44(".env") ? ".env" : null;
22499
+ const envSource = existsSync46(ENV_PATH) ? ENV_PATH : existsSync46(".env") ? ".env" : null;
22320
22500
  if (envSource) {
22321
22501
  console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
22322
22502
  console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
@@ -22327,8 +22507,8 @@ async function setup() {
22327
22507
  }
22328
22508
  }
22329
22509
  const cwdDb = join25(process.cwd(), "cc-claw.db");
22330
- if (existsSync44(cwdDb) && !existsSync44(DB_PATH)) {
22331
- const { size } = statSync7(cwdDb);
22510
+ if (existsSync46(cwdDb) && !existsSync46(DB_PATH)) {
22511
+ const { size } = statSync8(cwdDb);
22332
22512
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
22333
22513
  const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
22334
22514
  if (migrate) {
@@ -22747,7 +22927,7 @@ function registerCronCommands(cmd) {
22747
22927
  const { cronList: cronList2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
22748
22928
  await cronList2(program.opts());
22749
22929
  });
22750
- cmd.command("create").description("Create a scheduled job").requiredOption("--description <text>", "Job description").option("--prompt <text>", "Agent prompt (defaults to description)").option("--cron <expr>", "Cron expression (e.g. '0 9 * * *')").option("--at <iso8601>", "One-shot time").option("--every <interval>", "Repeat interval (e.g. 30m, 1h)").option("--backend <name>", "Backend for this job").option("--model <name>", "Model for this job").option("--thinking <level>", "Thinking level").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--fallback <backend:model>", "Fallback backend:model (repeatable, max 3)", (val, prev) => [...prev, val], []).option("--timezone <tz>", "IANA timezone", "UTC").option("--session-type <type>", "Session type (isolated/main)", "isolated").option("--delivery <mode>", "Delivery mode (announce/webhook/none)", "announce").option("--channel <name>", "Delivery channel").option("--target <id>", "Delivery target").option("--cwd <path>", "Working directory").action(async (opts) => {
22930
+ cmd.command("create").description("Create a scheduled job").requiredOption("--description <text>", "Job description").option("--title <text>", "Short title for job list (auto-generated if omitted)").option("--prompt <text>", "Agent prompt (defaults to description)").option("--cron <expr>", "Cron expression (e.g. '0 9 * * *')").option("--at <iso8601>", "One-shot time").option("--every <interval>", "Repeat interval (e.g. 30m, 1h)").option("--backend <name>", "Backend for this job").option("--model <name>", "Model for this job").option("--thinking <level>", "Thinking level").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--fallback <backend:model>", "Fallback backend:model (repeatable, max 3)", (val, prev) => [...prev, val], []).option("--timezone <tz>", "IANA timezone", "UTC").option("--session-type <type>", "Session type (isolated/main)", "isolated").option("--delivery <mode>", "Delivery mode (announce/webhook/none)", "announce").option("--channel <name>", "Delivery channel").option("--target <id>", "Delivery target").option("--cwd <path>", "Working directory").action(async (opts) => {
22751
22931
  const { cronCreate: cronCreate2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
22752
22932
  await cronCreate2(program.opts(), opts);
22753
22933
  });
@@ -22767,7 +22947,7 @@ function registerCronCommands(cmd) {
22767
22947
  const { cronAction: cronAction2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
22768
22948
  await cronAction2(program.opts(), "run", id);
22769
22949
  });
22770
- cmd.command("edit <id>").description("Edit a job (same flags as create)").option("--description <text>").option("--cron <expr>").option("--at <iso8601>").option("--every <interval>").option("--backend <name>").option("--model <name>").option("--thinking <level>").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--fallback <backend:model>", "Fallback backend:model (repeatable, max 3)", (val, prev) => [...prev, val], []).option("--timezone <tz>").action(async (id, opts) => {
22950
+ cmd.command("edit <id>").description("Edit a job (same flags as create)").option("--title <text>", "Short title for job list").option("--description <text>").option("--cron <expr>").option("--at <iso8601>").option("--every <interval>").option("--backend <name>").option("--model <name>").option("--thinking <level>").option("--timeout <seconds>", "Job timeout in seconds (30-3600)").option("--fallback <backend:model>", "Fallback backend:model (repeatable, max 3)", (val, prev) => [...prev, val], []).option("--timezone <tz>").action(async (id, opts) => {
22771
22951
  const { cronEdit: cronEdit2 } = await Promise.resolve().then(() => (init_cron2(), cron_exports2));
22772
22952
  await cronEdit2(program.opts(), id, opts);
22773
22953
  });