cc-claw 0.19.3 → 0.20.0

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 +1156 -92
  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.19.3" : (() => {
36
+ VERSION = true ? "0.20.0" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -3677,6 +3677,9 @@ function setGeminiSlotEnabled(id, enabled) {
3677
3677
  function reorderGeminiSlot(id, priority) {
3678
3678
  getDb().prepare("UPDATE gemini_credentials SET priority = ? WHERE id = ?").run(priority, id);
3679
3679
  }
3680
+ function renameGeminiSlot(id, label2) {
3681
+ return getDb().prepare("UPDATE gemini_credentials SET label = ? WHERE id = ?").run(label2, id).changes > 0;
3682
+ }
3680
3683
  function getGeminiRotationMode() {
3681
3684
  const row = getDb().prepare("SELECT value FROM meta WHERE key = 'gemini_rotation_mode'").get();
3682
3685
  return row?.value ?? "all";
@@ -3775,6 +3778,9 @@ function setBackendSlotEnabled(id, enabled) {
3775
3778
  function reorderBackendSlot(id, priority) {
3776
3779
  getDb().prepare("UPDATE backend_credentials SET priority = ? WHERE id = ?").run(priority, id);
3777
3780
  }
3781
+ function renameBackendSlot(id, label2) {
3782
+ return getDb().prepare("UPDATE backend_credentials SET label = ? WHERE id = ?").run(label2, id).changes > 0;
3783
+ }
3778
3784
  function reenableBackendSlot(slotId) {
3779
3785
  getDb().prepare(`
3780
3786
  UPDATE backend_credentials
@@ -3923,6 +3929,8 @@ __export(store_exports5, {
3923
3929
  removeGeminiSlot: () => removeGeminiSlot,
3924
3930
  removeHeartbeatWatch: () => removeHeartbeatWatch,
3925
3931
  removePendingEscalation: () => removePendingEscalation,
3932
+ renameBackendSlot: () => renameBackendSlot,
3933
+ renameGeminiSlot: () => renameGeminiSlot,
3926
3934
  reorderBackendSlot: () => reorderBackendSlot,
3927
3935
  reorderGeminiSlot: () => reorderGeminiSlot,
3928
3936
  resetJobFailures: () => resetJobFailures,
@@ -6540,8 +6548,8 @@ var init_ndjson = __esm({
6540
6548
 
6541
6549
  // src/memory/inject.ts
6542
6550
  function getTopK(query) {
6543
- const wordCount = query.split(/\s+/).length;
6544
- const scale = wordCount <= 3 ? 0.5 : wordCount <= 8 ? 0.75 : 1;
6551
+ const wordCount2 = query.split(/\s+/).length;
6552
+ const scale = wordCount2 <= 3 ? 0.5 : wordCount2 <= 8 ? 0.75 : 1;
6545
6553
  return {
6546
6554
  vectorK: Math.max(5, Math.round(BASE_VECTOR_TOP_K * scale)),
6547
6555
  ftsK: Math.max(5, Math.round(BASE_FTS_TOP_K * scale))
@@ -9325,6 +9333,19 @@ var init_agent_log = __esm({
9325
9333
  });
9326
9334
 
9327
9335
  // src/agents/orchestrator.ts
9336
+ var orchestrator_exports = {};
9337
+ __export(orchestrator_exports, {
9338
+ cancelAgent: () => cancelAgent,
9339
+ cancelAllAgents: () => cancelAllAgents,
9340
+ diagnoseSpawnError: () => diagnoseSpawnError,
9341
+ getActiveProcessCount: () => getActiveProcessCount,
9342
+ getOrCreateOrchestration: () => getOrCreateOrchestration,
9343
+ getRunningAgentCount: () => getRunningAgentCount,
9344
+ initOrchestrator: () => initOrchestrator,
9345
+ setNotifyCallback: () => setNotifyCallback,
9346
+ shutdownOrchestrator: () => shutdownOrchestrator,
9347
+ spawnSubAgent: () => spawnSubAgent
9348
+ });
9328
9349
  import { existsSync as existsSync10 } from "fs";
9329
9350
  async function withRunnerLock(runnerId, fn) {
9330
9351
  const prev = runnerLocks.get(runnerId) ?? Promise.resolve();
@@ -9964,6 +9985,9 @@ function cancelAllAgents(chatId, reason = "user_cancelled") {
9964
9985
  updateOrchestrationStatus(db3, orch.id, "abandoned");
9965
9986
  return count;
9966
9987
  }
9988
+ function getActiveProcessCount() {
9989
+ return activeProcesses.size;
9990
+ }
9967
9991
  function shutdownOrchestrator() {
9968
9992
  for (const [agentId, proc] of activeProcesses) {
9969
9993
  try {
@@ -12503,12 +12527,12 @@ var init_evolve = __esm({
12503
12527
  const body = JSON.parse(await readBody(req));
12504
12528
  const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
12505
12529
  const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
12506
- const { join: join35 } = await import("path");
12530
+ const { join: join36 } = await import("path");
12507
12531
  const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
12508
12532
  const chatId = resolveChatId(body);
12509
12533
  if (!chatId) return jsonResponse(res, { error: "No chatId provided and ALLOWED_CHAT_ID is not set" }, 400);
12510
- const soulPath = join35(home, "identity/SOUL.md");
12511
- const userPath = join35(home, "identity/USER.md");
12534
+ const soulPath = join36(home, "identity/SOUL.md");
12535
+ const userPath = join36(home, "identity/USER.md");
12512
12536
  const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
12513
12537
  const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
12514
12538
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -12867,9 +12891,9 @@ function matchPatterns(message, patterns, signalType) {
12867
12891
  return matches;
12868
12892
  }
12869
12893
  function classifySignals(userMessage, _agentResponse) {
12870
- const wordCount = userMessage.trim().split(/\s+/).filter(Boolean).length;
12894
+ const wordCount2 = userMessage.trim().split(/\s+/).filter(Boolean).length;
12871
12895
  const results = [];
12872
- if (wordCount >= 3) {
12896
+ if (wordCount2 >= 3) {
12873
12897
  for (const m of matchPatterns(userMessage, CORRECTION_PATTERNS, "correction")) {
12874
12898
  results.push({ ...m, source: "auto_detect" });
12875
12899
  }
@@ -13549,7 +13573,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
13549
13573
  const adapter = backend2 ? getAdapter(backend2) : getAdapterForChat(settingsChat);
13550
13574
  const mode = permMode ?? getMode(settingsChat);
13551
13575
  const responseStyle = getResponseStyle(settingsChat);
13552
- const thinkingLevel = getThinkingLevel(settingsChat);
13576
+ const thinkingLevel = opts?.thinkingLevel ?? getThinkingLevel(settingsChat);
13553
13577
  const resolvedCwd = cwd ?? WORKSPACE_PATH;
13554
13578
  const tier = bootstrapTier ?? "full";
13555
13579
  const effectiveAgentMode = optsAgentMode ?? getAgentMode(settingsChat);
@@ -16451,8 +16475,8 @@ async function mp3ToOgg(mp3Buffer) {
16451
16475
  const id = crypto.randomUUID();
16452
16476
  const tmpMp3 = `/tmp/cc-claw-tts-${id}.mp3`;
16453
16477
  const tmpOgg = `/tmp/cc-claw-tts-${id}.ogg`;
16454
- const { writeFile: writeFile5 } = await import("fs/promises");
16455
- await writeFile5(tmpMp3, mp3Buffer);
16478
+ const { writeFile: writeFile6 } = await import("fs/promises");
16479
+ await writeFile6(tmpMp3, mp3Buffer);
16456
16480
  await execFileAsync2("ffmpeg", ["-y", "-i", tmpMp3, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
16457
16481
  const oggBuffer = await readFile2(tmpOgg);
16458
16482
  unlink(tmpMp3).catch((err) => {
@@ -19227,10 +19251,10 @@ async function handleEvolveCallback(chatId, data, channel) {
19227
19251
  const current = getReflectionStatus2(getDb(), chatId);
19228
19252
  if (current === "frozen") {
19229
19253
  const { readFileSync: readFileSync28, existsSync: existsSync56 } = await import("fs");
19230
- const { join: join35 } = await import("path");
19254
+ const { join: join36 } = await import("path");
19231
19255
  const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
19232
- const soulPath = join35(CC_CLAW_HOME3, "identity/SOUL.md");
19233
- const userPath = join35(CC_CLAW_HOME3, "identity/USER.md");
19256
+ const soulPath = join36(CC_CLAW_HOME3, "identity/SOUL.md");
19257
+ const userPath = join36(CC_CLAW_HOME3, "identity/USER.md");
19234
19258
  const soul = existsSync56(soulPath) ? readFileSync28(soulPath, "utf-8") : "";
19235
19259
  const user = existsSync56(userPath) ? readFileSync28(userPath, "utf-8") : "";
19236
19260
  setReflectionStatus2(getDb(), chatId, "active", soul, user);
@@ -20580,6 +20604,133 @@ var init_optimize = __esm({
20580
20604
  }
20581
20605
  });
20582
20606
 
20607
+ // src/council/types.ts
20608
+ var COUNCIL_MIN_PARTICIPANTS, COUNCIL_MAX_ROUNDS, COUNCIL_WIZARD_TIMEOUT_MS;
20609
+ var init_types4 = __esm({
20610
+ "src/council/types.ts"() {
20611
+ "use strict";
20612
+ COUNCIL_MIN_PARTICIPANTS = 2;
20613
+ COUNCIL_MAX_ROUNDS = 3;
20614
+ COUNCIL_WIZARD_TIMEOUT_MS = 10 * 60 * 1e3;
20615
+ }
20616
+ });
20617
+
20618
+ // src/council/wizard.ts
20619
+ var wizard_exports = {};
20620
+ __export(wizard_exports, {
20621
+ buildSelectKeyboard: () => buildSelectKeyboard,
20622
+ cancelCouncil: () => cancelCouncil,
20623
+ getCouncilState: () => getCouncilState,
20624
+ hasPendingCouncil: () => hasPendingCouncil,
20625
+ setCouncilQuestion: () => setCouncilQuestion,
20626
+ startCouncilWizard: () => startCouncilWizard,
20627
+ toggleParticipant: () => toggleParticipant
20628
+ });
20629
+ function resetCouncilTimeout(chatId) {
20630
+ const existing = councilTimers.get(chatId);
20631
+ if (existing) clearTimeout(existing);
20632
+ councilTimers.set(chatId, setTimeout(() => {
20633
+ pendingCouncils.delete(chatId);
20634
+ councilTimers.delete(chatId);
20635
+ log(`[council] Auto-cancelled stale council wizard for chat ${chatId}`);
20636
+ }, COUNCIL_WIZARD_TIMEOUT_MS));
20637
+ }
20638
+ function startCouncilWizard(chatId) {
20639
+ if (pendingCouncils.has(chatId)) {
20640
+ cancelCouncil(chatId);
20641
+ }
20642
+ pendingCouncils.set(chatId, {
20643
+ step: "select",
20644
+ selected: /* @__PURE__ */ new Map()
20645
+ });
20646
+ resetCouncilTimeout(chatId);
20647
+ }
20648
+ function hasPendingCouncil(chatId) {
20649
+ return pendingCouncils.has(chatId);
20650
+ }
20651
+ function getCouncilState(chatId) {
20652
+ return pendingCouncils.get(chatId);
20653
+ }
20654
+ function cancelCouncil(chatId) {
20655
+ pendingCouncils.delete(chatId);
20656
+ const timer = councilTimers.get(chatId);
20657
+ if (timer) {
20658
+ clearTimeout(timer);
20659
+ councilTimers.delete(chatId);
20660
+ }
20661
+ }
20662
+ function toggleParticipant(chatId, backend2, model2, label2) {
20663
+ const state = pendingCouncils.get(chatId);
20664
+ if (!state) return;
20665
+ resetCouncilTimeout(chatId);
20666
+ const key = `${backend2}:${model2}`;
20667
+ if (state.selected.has(key)) {
20668
+ state.selected.delete(key);
20669
+ } else {
20670
+ state.selected.set(key, { backend: backend2, model: model2, label: label2 });
20671
+ }
20672
+ }
20673
+ function setCouncilQuestion(chatId, question) {
20674
+ const state = pendingCouncils.get(chatId);
20675
+ if (!state) return { error: "No active council wizard." };
20676
+ resetCouncilTimeout(chatId);
20677
+ if (state.selected.size < COUNCIL_MIN_PARTICIPANTS) {
20678
+ return { error: `Select at least ${COUNCIL_MIN_PARTICIPANTS} models before starting.` };
20679
+ }
20680
+ state.question = question;
20681
+ state.step = "running";
20682
+ return {};
20683
+ }
20684
+ function buildSelectKeyboard(chatId) {
20685
+ const state = pendingCouncils.get(chatId);
20686
+ if (!state) {
20687
+ return { text: "No active council wizard.", buttons: [] };
20688
+ }
20689
+ const adapters2 = getAvailableAdapters();
20690
+ const buttons = [];
20691
+ for (const adapter of adapters2) {
20692
+ for (const [modelId, modelInfo] of Object.entries(adapter.availableModels)) {
20693
+ const key = `${adapter.id}:${modelId}`;
20694
+ const isSelected = state.selected.has(key);
20695
+ const checkmark = isSelected ? "\u2713 " : " ";
20696
+ const row = [{
20697
+ label: `${checkmark}${modelInfo.label}`,
20698
+ data: `council:toggle:${adapter.id}:${modelId}:${modelInfo.label}`,
20699
+ ...isSelected ? { style: "success" } : {}
20700
+ }];
20701
+ buttons.push(row);
20702
+ }
20703
+ }
20704
+ const count = state.selected.size;
20705
+ const canStart = count >= COUNCIL_MIN_PARTICIPANTS;
20706
+ buttons.push([
20707
+ {
20708
+ label: canStart ? `\u25B6 Start Council (${count} models)` : `\u25B6 Start Council (${count} models)`,
20709
+ data: canStart ? "council:start" : "council:noop",
20710
+ ...canStart ? {} : {}
20711
+ },
20712
+ {
20713
+ label: "\u2715 Cancel",
20714
+ data: "council:cancel"
20715
+ }
20716
+ ]);
20717
+ return {
20718
+ text: `Select models for the council debate (${count} selected):`,
20719
+ buttons
20720
+ };
20721
+ }
20722
+ var pendingCouncils, councilTimers;
20723
+ var init_wizard2 = __esm({
20724
+ "src/council/wizard.ts"() {
20725
+ "use strict";
20726
+ init_types4();
20727
+ init_backends();
20728
+ init_log();
20729
+ pendingCouncils = /* @__PURE__ */ new Map();
20730
+ councilTimers = /* @__PURE__ */ new Map();
20731
+ }
20732
+ });
20733
+
20583
20734
  // src/router/command-handlers.ts
20584
20735
  import { readFile as readFile6 } from "fs/promises";
20585
20736
  async function handleStopCommand(chatId, commandArgs, msg, channel) {
@@ -21186,6 +21337,12 @@ async function handleModelCommand(chatId, commandArgs, msg, channel) {
21186
21337
  ...id === current ? { style: "primary" } : {}
21187
21338
  }];
21188
21339
  });
21340
+ const isAuto = getModel(chatId) === "auto";
21341
+ buttons.unshift([{
21342
+ label: `${isAuto ? "\u2713 " : ""}\u{1F916} Auto (smart routing)`,
21343
+ data: "model:auto",
21344
+ ...isAuto ? { style: "primary" } : {}
21345
+ }]);
21189
21346
  await channel.sendKeyboard(chatId, `Models for ${adapter.displayName}:`, buttons);
21190
21347
  } else {
21191
21348
  const lines = Object.entries(models).map(
@@ -22095,6 +22252,20 @@ async function handleCronCommand(chatId, commandArgs, msg, channel) {
22095
22252
  await startWizard(chatId, commandArgs, channel);
22096
22253
  }
22097
22254
  }
22255
+ async function handleCouncilCommand(chatId, commandArgs, msg, channel) {
22256
+ if (process.env.DASHBOARD_ENABLED !== "1") {
22257
+ await channel.sendText(chatId, "Council requires DASHBOARD_ENABLED=1 (uses the agent orchestrator).", { parseMode: "plain" });
22258
+ return;
22259
+ }
22260
+ const { startCouncilWizard: startCouncilWizard2, buildSelectKeyboard: buildSelectKeyboard2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
22261
+ startCouncilWizard2(chatId);
22262
+ if (typeof channel.sendKeyboard === "function") {
22263
+ const { text, buttons } = buildSelectKeyboard2(chatId);
22264
+ await channel.sendKeyboard(chatId, text, buttons);
22265
+ } else {
22266
+ await channel.sendText(chatId, "Council requires Telegram (needs inline keyboards).", { parseMode: "plain" });
22267
+ }
22268
+ }
22098
22269
  var init_command_handlers = __esm({
22099
22270
  "src/router/command-handlers.ts"() {
22100
22271
  "use strict";
@@ -22303,6 +22474,10 @@ async function handleCommand(msg, channel) {
22303
22474
  case "intent":
22304
22475
  await handleIntentCommand(chatId, commandArgs, msg, channel);
22305
22476
  break;
22477
+ case "council":
22478
+ case "debate":
22479
+ await handleCouncilCommand(chatId, commandArgs, msg, channel);
22480
+ break;
22306
22481
  case "evolve":
22307
22482
  await handleEvolveCommandWrapper(chatId, commandArgs, msg, channel);
22308
22483
  break;
@@ -22345,6 +22520,118 @@ var init_commands = __esm({
22345
22520
  }
22346
22521
  });
22347
22522
 
22523
+ // src/skills/auto-create.ts
22524
+ var auto_create_exports = {};
22525
+ __export(auto_create_exports, {
22526
+ buildSkillExtractionPrompt: () => buildSkillExtractionPrompt,
22527
+ clearPendingDraft: () => clearPendingDraft,
22528
+ getPendingDraft: () => getPendingDraft,
22529
+ isSkillWorthy: () => isSkillWorthy,
22530
+ parseExtractedSkill: () => parseExtractedSkill,
22531
+ saveSkill: () => saveSkill,
22532
+ storePendingDraft: () => storePendingDraft
22533
+ });
22534
+ import { join as join25 } from "path";
22535
+ import { writeFile as writeFile4, mkdir as mkdir3 } from "fs/promises";
22536
+ function isSkillWorthy(signals) {
22537
+ const { toolUseCount, tokenOutput, elapsedMs, userMessage } = signals;
22538
+ if (toolUseCount < 3) return false;
22539
+ const supplementary = [
22540
+ tokenOutput >= 1500,
22541
+ elapsedMs >= 2e4
22542
+ ].filter(Boolean).length;
22543
+ if (supplementary < 1) return false;
22544
+ const words = userMessage.split(/\s+/).length;
22545
+ if (words < 5) return false;
22546
+ log(`[auto-skill] Skill-worthy: tools=${toolUseCount}, tokens=${tokenOutput}, elapsed=${elapsedMs}ms`);
22547
+ return true;
22548
+ }
22549
+ function buildSkillExtractionPrompt(userMessage, assistantResponse) {
22550
+ const cappedResponse = assistantResponse.length > 8e3 ? assistantResponse.slice(0, 8e3) + "\n\n[...truncated...]" : assistantResponse;
22551
+ return [
22552
+ "You are a skill extraction assistant. Analyze the following completed task and create a reusable SKILL.md file.",
22553
+ "",
22554
+ "A skill is a set of instructions that an AI agent can follow to accomplish a similar task in the future.",
22555
+ "Focus on the PROCESS and APPROACH, not the specific details of this particular task.",
22556
+ "",
22557
+ "## Completed Task",
22558
+ "",
22559
+ `**User request:** ${userMessage}`,
22560
+ "",
22561
+ `**Assistant response:**`,
22562
+ cappedResponse,
22563
+ "",
22564
+ "## Output Format",
22565
+ "",
22566
+ "Output ONLY the SKILL.md content with this exact format:",
22567
+ "",
22568
+ "```",
22569
+ "---",
22570
+ 'name: "skill-name-in-kebab-case"',
22571
+ 'description: "What this skill does and when to use it"',
22572
+ "---",
22573
+ "",
22574
+ "## [Skill Title]",
22575
+ "",
22576
+ "[Step-by-step instructions for accomplishing this type of task]",
22577
+ "[Include decision points, best practices, and common pitfalls]",
22578
+ "[Keep it general enough to be reusable, specific enough to be helpful]",
22579
+ "```",
22580
+ "",
22581
+ "Rules:",
22582
+ "- The skill name should be descriptive and kebab-case",
22583
+ "- The description should explain WHAT it does AND WHEN to use it",
22584
+ "- Instructions should be general (not tied to specific file names or projects)",
22585
+ "- Include any important caveats or prerequisites",
22586
+ "- Keep it under 100 lines"
22587
+ ].join("\n");
22588
+ }
22589
+ function parseExtractedSkill(llmResponse) {
22590
+ let content = llmResponse;
22591
+ const fenceMatch = llmResponse.match(/```(?:markdown|md)?\s*\n([\s\S]*?)```/);
22592
+ if (fenceMatch) content = fenceMatch[1].trim();
22593
+ const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
22594
+ if (!fmMatch) {
22595
+ warn("[auto-skill] No frontmatter found in extracted skill");
22596
+ return null;
22597
+ }
22598
+ const nameMatch = fmMatch[1].match(/^name:\s*["']?([^"'\n]+)["']?\s*$/m);
22599
+ if (!nameMatch) {
22600
+ warn("[auto-skill] No name field in skill frontmatter");
22601
+ return null;
22602
+ }
22603
+ const name = nameMatch[1].trim().toLowerCase().replace(/\s+/g, "-");
22604
+ return { name, content };
22605
+ }
22606
+ async function saveSkill(name, content) {
22607
+ const dir = join25(SKILLS_PATH, name);
22608
+ await mkdir3(dir, { recursive: true });
22609
+ const filePath = join25(dir, "SKILL.md");
22610
+ await writeFile4(filePath, content, "utf-8");
22611
+ invalidateSkillCache();
22612
+ log(`[auto-skill] Saved skill "${name}" to ${filePath}`);
22613
+ return { path: filePath };
22614
+ }
22615
+ function storePendingDraft(chatId, draft) {
22616
+ pendingDrafts.set(chatId, draft);
22617
+ }
22618
+ function getPendingDraft(chatId) {
22619
+ return pendingDrafts.get(chatId);
22620
+ }
22621
+ function clearPendingDraft(chatId) {
22622
+ pendingDrafts.delete(chatId);
22623
+ }
22624
+ var pendingDrafts;
22625
+ var init_auto_create = __esm({
22626
+ "src/skills/auto-create.ts"() {
22627
+ "use strict";
22628
+ init_paths();
22629
+ init_discover();
22630
+ init_log();
22631
+ pendingDrafts = /* @__PURE__ */ new Map();
22632
+ }
22633
+ });
22634
+
22348
22635
  // src/router/callbacks.ts
22349
22636
  import { readFile as readFile7 } from "fs/promises";
22350
22637
  async function handleCallback(chatId, data, channel, messageId) {
@@ -22404,6 +22691,12 @@ async function handleCallback(chatId, data, channel, messageId) {
22404
22691
  await channel.sendText(chatId, `Using ${adapter.displayName} with default model. Ready!`, { parseMode: "plain" });
22405
22692
  } else if (data.startsWith("model:")) {
22406
22693
  const chosen = data.slice(6);
22694
+ if (chosen === "auto") {
22695
+ setModel(chatId, "auto");
22696
+ clearThinkingLevel(chatId);
22697
+ await channel.sendText(chatId, "\u{1F916} Smart routing enabled \u2014 model and thinking level will be chosen per message based on complexity.", { parseMode: "plain" });
22698
+ return;
22699
+ }
22407
22700
  let adapter;
22408
22701
  try {
22409
22702
  adapter = getAdapterForChat(chatId);
@@ -23043,6 +23336,47 @@ ${rotationNote}`, { parseMode: "html" });
23043
23336
  } else if (data.startsWith("reflect:")) {
23044
23337
  await handleReflectCallback(chatId, data, channel);
23045
23338
  return;
23339
+ } else if (data.startsWith("council:")) {
23340
+ const parts = data.split(":");
23341
+ const action = parts[1];
23342
+ if (action === "toggle") {
23343
+ const backend2 = parts[2];
23344
+ const model2 = parts[3];
23345
+ const label2 = parts.slice(4).join(":");
23346
+ const { toggleParticipant: toggleParticipant2, buildSelectKeyboard: buildSelectKeyboard2, hasPendingCouncil: hasPendingCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
23347
+ if (!hasPendingCouncil2(chatId)) {
23348
+ await channel.sendText(chatId, "No council wizard active. Use /council to start.", { parseMode: "plain" });
23349
+ return;
23350
+ }
23351
+ toggleParticipant2(chatId, backend2, model2, label2);
23352
+ if (typeof channel.sendKeyboard === "function") {
23353
+ const { text, buttons } = buildSelectKeyboard2(chatId);
23354
+ await channel.sendKeyboard(chatId, text, buttons);
23355
+ }
23356
+ return;
23357
+ }
23358
+ if (action === "start") {
23359
+ const { getCouncilState: getCouncilState2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
23360
+ const state = getCouncilState2(chatId);
23361
+ if (!state || state.selected.size < 2) {
23362
+ await channel.sendText(chatId, "Select at least 2 models first.", { parseMode: "plain" });
23363
+ return;
23364
+ }
23365
+ state.step = "question";
23366
+ const names = [...state.selected.values()].map((p) => p.label).join(", ");
23367
+ await channel.sendText(chatId, `\u{1F3DB}\uFE0F Council members: ${names}
23368
+
23369
+ Now type the question you want them to debate.`, { parseMode: "plain" });
23370
+ return;
23371
+ }
23372
+ if (action === "cancel") {
23373
+ const { cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
23374
+ cancelCouncil2(chatId);
23375
+ await channel.sendText(chatId, "Council cancelled.", { parseMode: "plain" });
23376
+ return;
23377
+ }
23378
+ if (action === "noop") return;
23379
+ return;
23046
23380
  } else if (data.startsWith("opt:")) {
23047
23381
  await handleOptimizeCallback(chatId, data, channel);
23048
23382
  return;
@@ -23322,6 +23656,45 @@ Example: /limits ${bid} daily 500000`, { parseMode: "plain" });
23322
23656
  const page = parseInt(data.slice(12), 10);
23323
23657
  const skills2 = await discoverAllSkills();
23324
23658
  await sendSkillsPage(chatId, channel, skills2, page, messageId);
23659
+ } else if (data === "skill:extract") {
23660
+ const { getPendingDraft: getPendingDraft2, clearPendingDraft: clearPendingDraft2, buildSkillExtractionPrompt: buildSkillExtractionPrompt2, parseExtractedSkill: parseExtractedSkill2, saveSkill: saveSkill2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
23661
+ const draft = getPendingDraft2(chatId);
23662
+ if (!draft) {
23663
+ await channel.sendText(chatId, "No pending skill draft.", { parseMode: "plain" });
23664
+ return;
23665
+ }
23666
+ await channel.sendText(chatId, "\u{1F50D} Extracting skill from conversation...", { parseMode: "plain" });
23667
+ await channel.sendTyping?.(chatId);
23668
+ try {
23669
+ const { askAgent: askAgent3 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
23670
+ const extractionPrompt = buildSkillExtractionPrompt2(draft.userMessage, draft.assistantResponse);
23671
+ const extractionResponse = await askAgent3(chatId, extractionPrompt, {
23672
+ bootstrapTier: "slim",
23673
+ maxTurns: 1,
23674
+ timeoutMs: 3e4
23675
+ });
23676
+ const parsed = parseExtractedSkill2(extractionResponse.text);
23677
+ if (parsed) {
23678
+ const { path } = await saveSkill2(parsed.name, parsed.content);
23679
+ clearPendingDraft2(chatId);
23680
+ await channel.sendText(chatId, `\u2705 Skill "${parsed.name}" saved.
23681
+ Path: ${path}
23682
+
23683
+ Use /skills to see all available skills.`, { parseMode: "plain" });
23684
+ } else {
23685
+ clearPendingDraft2(chatId);
23686
+ await channel.sendText(chatId, "Could not extract a well-formed skill from this conversation. Try /remember to save key steps manually.", { parseMode: "plain" });
23687
+ }
23688
+ } catch (e) {
23689
+ clearPendingDraft2(chatId);
23690
+ await channel.sendText(chatId, `Skill extraction failed: ${e.message}`, { parseMode: "plain" });
23691
+ }
23692
+ return;
23693
+ } else if (data === "skill:discard") {
23694
+ const { clearPendingDraft: clearPendingDraft2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
23695
+ clearPendingDraft2(chatId);
23696
+ await channel.sendText(chatId, "Skill draft discarded.", { parseMode: "plain" });
23697
+ return;
23325
23698
  } else if (data.startsWith("skill:")) {
23326
23699
  const parts = data.slice(6).split(":");
23327
23700
  let skillName;
@@ -23396,6 +23769,399 @@ var init_callbacks = __esm({
23396
23769
  }
23397
23770
  });
23398
23771
 
23772
+ // src/channels/thread-wrapper.ts
23773
+ var thread_wrapper_exports = {};
23774
+ __export(thread_wrapper_exports, {
23775
+ withThread: () => withThread
23776
+ });
23777
+ function withThread(channel, threadId) {
23778
+ return {
23779
+ get name() {
23780
+ return channel.name;
23781
+ },
23782
+ start: channel.start.bind(channel),
23783
+ stop: channel.stop.bind(channel),
23784
+ getCapabilities: channel.getCapabilities.bind(channel),
23785
+ downloadFile: channel.downloadFile.bind(channel),
23786
+ isAuthorized: channel.isAuthorized.bind(channel),
23787
+ sendText(chatId, text, opts) {
23788
+ return channel.sendText(chatId, text, { ...opts, threadId: opts?.threadId ?? threadId });
23789
+ },
23790
+ sendVoice(chatId, audioBuffer, fileName) {
23791
+ return channel.sendVoice(chatId, audioBuffer, fileName, threadId);
23792
+ },
23793
+ sendFile(chatId, buffer, fileName, mimeType) {
23794
+ return channel.sendFile(chatId, buffer, fileName, mimeType, threadId);
23795
+ },
23796
+ sendTyping: channel.sendTyping ? (chatId) => channel.sendTyping(chatId, threadId) : void 0,
23797
+ sendKeyboard: channel.sendKeyboard ? (chatId, text, buttons) => channel.sendKeyboard(chatId, text, buttons, threadId) : void 0,
23798
+ sendTextReturningId: channel.sendTextReturningId ? (chatId, text, parseMode) => channel.sendTextReturningId(chatId, text, parseMode, threadId) : void 0,
23799
+ // These operate on existing messages — no threadId needed
23800
+ editText: channel.editText?.bind(channel),
23801
+ editKeyboard: channel.editKeyboard?.bind(channel),
23802
+ reactToMessage: channel.reactToMessage?.bind(channel)
23803
+ };
23804
+ }
23805
+ var init_thread_wrapper = __esm({
23806
+ "src/channels/thread-wrapper.ts"() {
23807
+ "use strict";
23808
+ }
23809
+ });
23810
+
23811
+ // src/intent/complexity.ts
23812
+ var complexity_exports = {};
23813
+ __export(complexity_exports, {
23814
+ classifyComplexity: () => classifyComplexity
23815
+ });
23816
+ function wordCount(text) {
23817
+ return text.trim().split(/\s+/).filter(Boolean).length;
23818
+ }
23819
+ function classifyComplexity(text) {
23820
+ const trimmed = text.trim();
23821
+ const lower = trimmed.toLowerCase();
23822
+ const words = wordCount(trimmed);
23823
+ if (TRIVIAL_EXACT.has(lower)) {
23824
+ log(`[complexity] "${lower}" -> trivial (exact match)`);
23825
+ return "trivial";
23826
+ }
23827
+ if (trimmed.length <= 4 && /^[\p{Emoji}\s]+$/u.test(trimmed)) {
23828
+ log(`[complexity] "${trimmed}" -> trivial (emoji-only)`);
23829
+ return "trivial";
23830
+ }
23831
+ if (COMPLEX_SIGNALS.test(trimmed) && (words > 15 || trimmed.length > 200)) {
23832
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> complex (signal words + length)`);
23833
+ return "complex";
23834
+ }
23835
+ if (MUTATION_VERBS.test(trimmed)) {
23836
+ const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
23837
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (mutation verb)`);
23838
+ return tier;
23839
+ }
23840
+ for (const pattern of CODE_PATTERNS) {
23841
+ if (pattern.test(trimmed)) {
23842
+ const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
23843
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (code pattern)`);
23844
+ return tier;
23845
+ }
23846
+ }
23847
+ if (trimmed.length > 200 || words > 25) {
23848
+ const tier = words > 30 || trimmed.length > 300 ? "complex" : "moderate";
23849
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> ${tier} (long message)`);
23850
+ return tier;
23851
+ }
23852
+ for (const pattern of QUESTION_PATTERNS) {
23853
+ if (pattern.test(trimmed)) {
23854
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> simple (question)`);
23855
+ return "simple";
23856
+ }
23857
+ }
23858
+ log(`[complexity] "${trimmed.slice(0, 40)}..." -> moderate (default)`);
23859
+ return "moderate";
23860
+ }
23861
+ var TRIVIAL_EXACT, COMPLEX_SIGNALS, MUTATION_VERBS, CODE_PATTERNS, QUESTION_PATTERNS;
23862
+ var init_complexity = __esm({
23863
+ "src/intent/complexity.ts"() {
23864
+ "use strict";
23865
+ init_log();
23866
+ TRIVIAL_EXACT = /* @__PURE__ */ new Set([
23867
+ "hey",
23868
+ "hi",
23869
+ "hello",
23870
+ "yo",
23871
+ "sup",
23872
+ "howdy",
23873
+ "hiya",
23874
+ "thanks",
23875
+ "thank you",
23876
+ "thx",
23877
+ "ty",
23878
+ "thank u",
23879
+ "ok",
23880
+ "okay",
23881
+ "k",
23882
+ "kk",
23883
+ "cool",
23884
+ "nice",
23885
+ "great",
23886
+ "awesome",
23887
+ "perfect",
23888
+ "good morning",
23889
+ "good night",
23890
+ "good evening",
23891
+ "gm",
23892
+ "gn",
23893
+ "bye",
23894
+ "goodbye",
23895
+ "later",
23896
+ "see ya",
23897
+ "cya",
23898
+ "lol",
23899
+ "lmao",
23900
+ "haha",
23901
+ "heh",
23902
+ "np",
23903
+ "no problem",
23904
+ "no worries",
23905
+ "nw",
23906
+ "got it",
23907
+ "understood",
23908
+ "roger",
23909
+ "copy",
23910
+ "good",
23911
+ "fine",
23912
+ "alright",
23913
+ "sure",
23914
+ "yes",
23915
+ "no",
23916
+ "yep",
23917
+ "nope",
23918
+ "yeah",
23919
+ "nah"
23920
+ ]);
23921
+ COMPLEX_SIGNALS = /\b(architect|design|research|plan|strategy|migration|microservice|distributed|end-to-end|trade-offs|pros\s+and\s+cons)\b/i;
23922
+ MUTATION_VERBS = /\b(fix|create|build|deploy|refactor|implement|write|add|update|edit|test|debug)\b/i;
23923
+ CODE_PATTERNS = [
23924
+ /```/,
23925
+ // code blocks
23926
+ /\.[a-z]{1,5}\b/,
23927
+ // file extensions (.ts, .py, .json)
23928
+ /[/\\][\w.-]+/
23929
+ // file paths (/src/foo, .\bar)
23930
+ ];
23931
+ QUESTION_PATTERNS = [
23932
+ /^(?:what|which|where|when|why|how)\b/i,
23933
+ /^(?:show|tell|list|explain)\b/i,
23934
+ /^(?:is|are)\b/i
23935
+ ];
23936
+ }
23937
+ });
23938
+
23939
+ // src/intent/auto-route.ts
23940
+ var auto_route_exports = {};
23941
+ __export(auto_route_exports, {
23942
+ resolveAutoRoute: () => resolveAutoRoute
23943
+ });
23944
+ function tieredModels(adapter) {
23945
+ const modelIds = Object.keys(adapter.availableModels);
23946
+ if (modelIds.length <= 1) {
23947
+ const only = modelIds[0] ?? adapter.defaultModel;
23948
+ return { cheap: only, mid: only, best: only };
23949
+ }
23950
+ const pricingEntries = modelIds.filter((id) => adapter.pricing[id]).map((id) => ({ id, out: adapter.pricing[id].out }));
23951
+ if (pricingEntries.length >= 2) {
23952
+ pricingEntries.sort((a, b) => a.out - b.out);
23953
+ const cheap = pricingEntries[0].id;
23954
+ const best = pricingEntries[pricingEntries.length - 1].id;
23955
+ const midIdx = Math.floor(pricingEntries.length / 2);
23956
+ const mid = pricingEntries.length === 2 ? pricingEntries[1].id : pricingEntries[midIdx].id;
23957
+ return { cheap, mid, best };
23958
+ }
23959
+ return {
23960
+ cheap: adapter.summarizerModel,
23961
+ mid: adapter.defaultModel,
23962
+ best: modelIds[0]
23963
+ };
23964
+ }
23965
+ function pickThinking(model2, adapter, desired) {
23966
+ const info = adapter.availableModels[model2];
23967
+ if (!info || info.thinking !== "adjustable") {
23968
+ return "auto";
23969
+ }
23970
+ const levels = info.thinkingLevels;
23971
+ if (!levels || levels.length === 0) {
23972
+ return "auto";
23973
+ }
23974
+ if (levels.includes(desired)) {
23975
+ return desired;
23976
+ }
23977
+ const desiredIdx = THINKING_ORDER.indexOf(desired);
23978
+ if (desiredIdx === -1) return levels[0];
23979
+ let closest = levels[0];
23980
+ let closestDist = Infinity;
23981
+ for (const lvl of levels) {
23982
+ const idx = THINKING_ORDER.indexOf(lvl);
23983
+ if (idx === -1) continue;
23984
+ const dist = Math.abs(idx - desiredIdx);
23985
+ if (dist < closestDist) {
23986
+ closestDist = dist;
23987
+ closest = lvl;
23988
+ }
23989
+ }
23990
+ return closest;
23991
+ }
23992
+ function resolveAutoRoute(tier, adapter) {
23993
+ const models = tieredModels(adapter);
23994
+ const mapping = TIER_MAP[tier];
23995
+ const model2 = models[mapping.tier];
23996
+ const thinkingLevel = pickThinking(model2, adapter, mapping.thinking);
23997
+ log(
23998
+ `[auto-route] ${tier} -> ${model2} (${mapping.tier}), thinking=${thinkingLevel} [${adapter.id}]`
23999
+ );
24000
+ return { model: model2, thinkingLevel };
24001
+ }
24002
+ var THINKING_ORDER, TIER_MAP;
24003
+ var init_auto_route = __esm({
24004
+ "src/intent/auto-route.ts"() {
24005
+ "use strict";
24006
+ init_log();
24007
+ THINKING_ORDER = ["off", "low", "medium", "high", "extra_high"];
24008
+ TIER_MAP = {
24009
+ trivial: { tier: "cheap", thinking: "off" },
24010
+ simple: { tier: "cheap", thinking: "low" },
24011
+ moderate: { tier: "mid", thinking: "medium" },
24012
+ complex: { tier: "best", thinking: "high" }
24013
+ };
24014
+ }
24015
+ });
24016
+
24017
+ // src/council/executor.ts
24018
+ var executor_exports = {};
24019
+ __export(executor_exports, {
24020
+ anonymizeSubmissions: () => anonymizeSubmissions,
24021
+ buildRoundPrompt: () => buildRoundPrompt,
24022
+ executeCouncil: () => executeCouncil,
24023
+ waitForAgent: () => waitForAgent
24024
+ });
24025
+ function anonymizeSubmissions(submissions) {
24026
+ const entries = [...submissions.entries()].map(([, response]) => response);
24027
+ for (let i = entries.length - 1; i > 0; i--) {
24028
+ const j = Math.floor(Math.random() * (i + 1));
24029
+ [entries[i], entries[j]] = [entries[j], entries[i]];
24030
+ }
24031
+ const labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
24032
+ return entries.map((response, idx) => ({
24033
+ label: `Participant ${labels[idx] ?? String(idx + 1)}`,
24034
+ response
24035
+ }));
24036
+ }
24037
+ function buildRoundPrompt(question, roundNumber, priorSubmissions) {
24038
+ if (roundNumber === 1 || !priorSubmissions?.length) {
24039
+ return [
24040
+ "You are participating in a council debate. Provide your best answer to the following question.",
24041
+ "",
24042
+ `Question: ${question}`
24043
+ ].join("\n");
24044
+ }
24045
+ const submissionBlock = priorSubmissions.map((s) => `--- ${s.label} ---
24046
+ ${s.response}`).join("\n\n");
24047
+ return [
24048
+ "You are participating in a council debate (round " + roundNumber + ").",
24049
+ "Review the positions below, address any disagreements, and refine your answer.",
24050
+ "Evaluate each position on merit only. You do NOT know which model produced which submission.",
24051
+ "",
24052
+ `Question: ${question}`,
24053
+ "",
24054
+ "Previous submissions:",
24055
+ submissionBlock
24056
+ ].join("\n");
24057
+ }
24058
+ async function waitForAgent(agentId, maxWaitMs = 3e5) {
24059
+ const { getAgent: getAgent3 } = await Promise.resolve().then(() => (init_store(), store_exports));
24060
+ const { getDb: getDb2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24061
+ const db3 = getDb2();
24062
+ const deadline = Date.now() + maxWaitMs;
24063
+ const terminalStatuses = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
24064
+ while (Date.now() < deadline) {
24065
+ const agent = getAgent3(db3, agentId);
24066
+ if (!agent) {
24067
+ return { resultSummary: null, tokenInput: 0, tokenOutput: 0, status: "not_found" };
24068
+ }
24069
+ if (terminalStatuses.has(agent.status)) {
24070
+ return {
24071
+ resultSummary: agent.resultSummary,
24072
+ tokenInput: agent.tokenInput,
24073
+ tokenOutput: agent.tokenOutput,
24074
+ status: agent.status
24075
+ };
24076
+ }
24077
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
24078
+ }
24079
+ return { resultSummary: null, tokenInput: 0, tokenOutput: 0, status: "timeout" };
24080
+ }
24081
+ function checkConvergence(submissions) {
24082
+ const wordSets = [...submissions.values()].map((text) => {
24083
+ const words = text.toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((w) => w.length > 3);
24084
+ return new Set(words);
24085
+ });
24086
+ if (wordSets.length < 2) return true;
24087
+ for (let i = 0; i < wordSets.length; i++) {
24088
+ for (let j = i + 1; j < wordSets.length; j++) {
24089
+ const a = wordSets[i];
24090
+ const b = wordSets[j];
24091
+ const intersection = new Set([...a].filter((w) => b.has(w)));
24092
+ const union = /* @__PURE__ */ new Set([...a, ...b]);
24093
+ if (union.size === 0) continue;
24094
+ const overlap = intersection.size / union.size;
24095
+ if (overlap < 0.6) return false;
24096
+ }
24097
+ }
24098
+ return true;
24099
+ }
24100
+ async function executeCouncil(chatId, participants, question, onProgress) {
24101
+ const { spawnSubAgent: spawnSubAgent2 } = await Promise.resolve().then(() => (init_orchestrator(), orchestrator_exports));
24102
+ const startTime = Date.now();
24103
+ const rounds = [];
24104
+ const totalTokens = { input: 0, output: 0 };
24105
+ let lastAnonymized = [];
24106
+ for (let round = 1; round <= COUNCIL_MAX_ROUNDS; round++) {
24107
+ onProgress?.(`Round ${round}/${COUNCIL_MAX_ROUNDS}: spawning ${participants.length} agents...`);
24108
+ const prompt = buildRoundPrompt(question, round, round > 1 ? lastAnonymized : void 0);
24109
+ const submissions = /* @__PURE__ */ new Map();
24110
+ const spawnPromises = participants.map(async (p) => {
24111
+ const key = `${p.backend}:${p.model}`;
24112
+ const { agentId } = await spawnSubAgent2(chatId, {
24113
+ runner: p.backend,
24114
+ task: prompt,
24115
+ name: `council-${p.label}-r${round}`,
24116
+ model: p.model,
24117
+ permMode: "readonly",
24118
+ role: "worker"
24119
+ });
24120
+ return { key, agentId };
24121
+ });
24122
+ const spawned = await Promise.all(spawnPromises);
24123
+ const resultPromises = spawned.map(async ({ key, agentId }) => {
24124
+ const result = await waitForAgent(agentId);
24125
+ totalTokens.input += result.tokenInput;
24126
+ totalTokens.output += result.tokenOutput;
24127
+ if (result.resultSummary) {
24128
+ submissions.set(key, result.resultSummary);
24129
+ } else {
24130
+ submissions.set(key, "(No response)");
24131
+ }
24132
+ });
24133
+ await Promise.all(resultPromises);
24134
+ rounds.push({ roundNumber: round, submissions });
24135
+ lastAnonymized = anonymizeSubmissions(submissions);
24136
+ onProgress?.(`Round ${round} complete: ${submissions.size} responses collected.`);
24137
+ if (round >= 2 && checkConvergence(submissions)) {
24138
+ log(`[council] Convergence reached after round ${round}`);
24139
+ onProgress?.(`Convergence reached after round ${round}.`);
24140
+ break;
24141
+ }
24142
+ }
24143
+ const finalParts = lastAnonymized.map(
24144
+ (s) => `### ${s.label}
24145
+ ${s.response}`
24146
+ );
24147
+ const finalAnswer = finalParts.join("\n\n");
24148
+ const elapsedMs = Date.now() - startTime;
24149
+ return {
24150
+ rounds,
24151
+ finalAnswer,
24152
+ participants,
24153
+ totalTokens,
24154
+ elapsedMs
24155
+ };
24156
+ }
24157
+ var init_executor = __esm({
24158
+ "src/council/executor.ts"() {
24159
+ "use strict";
24160
+ init_types4();
24161
+ init_log();
24162
+ }
24163
+ });
24164
+
23399
24165
  // src/router.ts
23400
24166
  var router_exports = {};
23401
24167
  __export(router_exports, {
@@ -23432,6 +24198,10 @@ __export(router_exports, {
23432
24198
  });
23433
24199
  async function handleMessage(msg, channel) {
23434
24200
  const { chatId } = msg;
24201
+ if (msg.threadId) {
24202
+ const { withThread: withThread2 } = await Promise.resolve().then(() => (init_thread_wrapper(), thread_wrapper_exports));
24203
+ channel = withThread2(channel, msg.threadId);
24204
+ }
23435
24205
  if (msg.messageId && typeof channel.reactToMessage === "function" && msg.type !== "text" && msg.type !== "command") {
23436
24206
  channel.reactToMessage(chatId, msg.messageId, pickReactionEmoji(msg)).catch(() => {
23437
24207
  });
@@ -23509,6 +24279,20 @@ async function handleText(msg, channel) {
23509
24279
  return;
23510
24280
  }
23511
24281
  const model2 = resolveModel(chatId);
24282
+ let autoRouted = false;
24283
+ let effectiveModel = model2;
24284
+ let effectiveThinking;
24285
+ if (model2 === "auto") {
24286
+ const { classifyComplexity: classifyComplexity2 } = await Promise.resolve().then(() => (init_complexity(), complexity_exports));
24287
+ const { resolveAutoRoute: resolveAutoRoute2 } = await Promise.resolve().then(() => (init_auto_route(), auto_route_exports));
24288
+ const adapter = getAdapterForChat(chatId);
24289
+ const tier = classifyComplexity2(text);
24290
+ const route = resolveAutoRoute2(tier, adapter);
24291
+ effectiveModel = route.model;
24292
+ effectiveThinking = route.thinkingLevel;
24293
+ autoRouted = true;
24294
+ log(`[router] Auto-route: "${text.slice(0, 40)}..." -> ${tier} -> model=${effectiveModel}, thinking=${effectiveThinking}`);
24295
+ }
23512
24296
  const backendId = settings.getBackend() ?? "claude";
23513
24297
  const limitMsg = checkBackendLimits(backendId);
23514
24298
  if (limitMsg) {
@@ -23632,6 +24416,43 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23632
24416
  return;
23633
24417
  }
23634
24418
  }
24419
+ {
24420
+ const { hasPendingCouncil: hasPendingCouncil2, getCouncilState: getCouncilState2, setCouncilQuestion: setCouncilQuestion2, cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
24421
+ if (hasPendingCouncil2(chatId)) {
24422
+ const state = getCouncilState2(chatId);
24423
+ if (state?.step === "question") {
24424
+ const result = setCouncilQuestion2(chatId, text);
24425
+ if (result.error) {
24426
+ await channel.sendText(chatId, result.error, { parseMode: "plain" });
24427
+ return;
24428
+ }
24429
+ const participants = [...state.selected.values()];
24430
+ const question = state.question;
24431
+ cancelCouncil2(chatId);
24432
+ await channel.sendText(chatId, `\u{1F3DB}\uFE0F Council convened \u2014 ${participants.length} models, up to 3 rounds.
24433
+
24434
+ Debating: "${question.slice(0, 100)}${question.length > 100 ? "\u2026" : ""}"`, { parseMode: "plain" });
24435
+ await channel.sendTyping?.(chatId);
24436
+ try {
24437
+ const { executeCouncil: executeCouncil2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
24438
+ const councilResult = await executeCouncil2(
24439
+ chatId,
24440
+ participants,
24441
+ question,
24442
+ (msg2) => {
24443
+ channel.sendText(chatId, msg2, { parseMode: "plain" }).catch(() => {
24444
+ });
24445
+ }
24446
+ );
24447
+ await sendResponse(chatId, channel, councilResult.finalAnswer, msg.messageId);
24448
+ } catch (e) {
24449
+ const errMsg = e.message ?? String(e);
24450
+ await channel.sendText(chatId, `Council failed: ${errMsg}`, { parseMode: "plain" });
24451
+ }
24452
+ return;
24453
+ }
24454
+ }
24455
+ }
23635
24456
  if (isChatBusy(chatId) && !bypassBusyCheck.delete(chatId)) {
23636
24457
  if (typeof channel.sendKeyboard === "function") {
23637
24458
  pendingInterrupts.set(chatId, { msg, channel });
@@ -23741,6 +24562,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23741
24562
  liveStatus = ls.liveStatus;
23742
24563
  const baseCb = tVerbose !== "off" ? ls.toolCb : void 0;
23743
24564
  tToolCb = async (toolName, input, result) => {
24565
+ if (result === void 0) toolUseCount++;
23744
24566
  if (baseCb) await baseCb(toolName, input, result);
23745
24567
  if (sessionLog) {
23746
24568
  if (result === void 0) {
@@ -23756,6 +24578,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23756
24578
  }
23757
24579
  } else if (sessionLog) {
23758
24580
  tToolCb = async (toolName, input, result) => {
24581
+ if (result === void 0) toolUseCount++;
23759
24582
  if (result === void 0) {
23760
24583
  sessionLog.logToolStart(toolName, input);
23761
24584
  } else {
@@ -23763,15 +24586,17 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23763
24586
  }
23764
24587
  };
23765
24588
  }
24589
+ let toolUseCount = 0;
23766
24590
  const sigT0 = Date.now();
23767
24591
  const response = await askAgent(chatId, cleanText || text, {
23768
24592
  cwd: settings.getCwd(),
23769
- model: model2,
24593
+ model: effectiveModel,
23770
24594
  permMode: tMode,
23771
24595
  onToolAction: tToolCb,
23772
24596
  bootstrapTier,
23773
24597
  maxTurns,
23774
24598
  agentMode: effectiveAgentMode,
24599
+ ...effectiveThinking ? { thinkingLevel: effectiveThinking } : {},
23775
24600
  onThinking: liveStatus || sessionLog ? (chunk) => {
23776
24601
  if (liveStatus) liveStatus.addThinking(chunk);
23777
24602
  if (sessionLog) sessionLog.logThinking(chunk);
@@ -23821,7 +24646,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23821
24646
  const sigEnabled = settings.getModelSignature();
23822
24647
  if (sigEnabled === "on" && responseText && !responseText.startsWith("(No response")) {
23823
24648
  const adapter2 = getAdapterForChat(chatId);
23824
- const modelId = response.resolvedModel ?? model2 ?? adapter2.defaultModel;
24649
+ const modelId = response.resolvedModel ?? effectiveModel ?? adapter2.defaultModel;
23825
24650
  const thinking2 = settings.getThinkingLevel() || "auto";
23826
24651
  const shortModel = formatModelShort(modelId);
23827
24652
  let slotTag = "";
@@ -23876,6 +24701,36 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
23876
24701
  } catch (e) {
23877
24702
  log(`[reflection] Signal detection error: ${e}`);
23878
24703
  }
24704
+ try {
24705
+ if (intent === "agentic" && toolUseCount > 0) {
24706
+ const { isSkillWorthy: isSkillWorthy2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
24707
+ const signals = {
24708
+ toolUseCount,
24709
+ tokenOutput: response.usage?.output ?? 0,
24710
+ elapsedMs,
24711
+ userMessage: cleanText || text
24712
+ };
24713
+ if (isSkillWorthy2(signals) && typeof channel.sendKeyboard === "function") {
24714
+ const { storePendingDraft: storePendingDraft2 } = await Promise.resolve().then(() => (init_auto_create(), auto_create_exports));
24715
+ storePendingDraft2(chatId, {
24716
+ name: "",
24717
+ content: "",
24718
+ userMessage: cleanText || text,
24719
+ assistantResponse: response.text
24720
+ });
24721
+ await channel.sendKeyboard(
24722
+ chatId,
24723
+ "\u{1F4A1} That looked like a reusable workflow. Want me to extract it as a skill?",
24724
+ [[
24725
+ { label: "\u2705 Extract Skill", data: "skill:extract", style: "success" },
24726
+ { label: "\u2715 No thanks", data: "skill:discard" }
24727
+ ]]
24728
+ );
24729
+ }
24730
+ }
24731
+ } catch (e) {
24732
+ log(`[auto-skill] Evaluation error: ${e}`);
24733
+ }
23879
24734
  } catch (err) {
23880
24735
  error("[router] Error:", err);
23881
24736
  const errMsg = errorMessage(err);
@@ -24368,7 +25223,7 @@ var init_cron = __esm({
24368
25223
  });
24369
25224
 
24370
25225
  // src/agents/runners/wrap-backend.ts
24371
- import { join as join25 } from "path";
25226
+ import { join as join26 } from "path";
24372
25227
  function buildMcpCommands(backendId) {
24373
25228
  const exe = backendId === BACKEND.CURSOR ? "agent" : backendId;
24374
25229
  return {
@@ -24462,7 +25317,7 @@ function wrapBackendAdapter(adapter) {
24462
25317
  const configPath = writeMcpConfigFile(server);
24463
25318
  return ["--mcp-config", configPath];
24464
25319
  },
24465
- getSkillPath: () => join25(SKILLS_PATH, `agent-${adapter.id}.md`)
25320
+ getSkillPath: () => join26(SKILLS_PATH, `agent-${adapter.id}.md`)
24466
25321
  };
24467
25322
  }
24468
25323
  var BACKEND_CAPABILITIES;
@@ -24515,7 +25370,7 @@ var init_wrap_backend = __esm({
24515
25370
 
24516
25371
  // src/agents/runners/config-loader.ts
24517
25372
  import { readFileSync as readFileSync14, readdirSync as readdirSync14, existsSync as existsSync23, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
24518
- import { join as join26 } from "path";
25373
+ import { join as join27 } from "path";
24519
25374
  import { execFileSync as execFileSync2 } from "child_process";
24520
25375
  function resolveExecutable2(config2) {
24521
25376
  if (existsSync23(config2.executable)) return config2.executable;
@@ -24651,7 +25506,7 @@ function configToRunner(config2) {
24651
25506
  prepareMcpInjection() {
24652
25507
  return [];
24653
25508
  },
24654
- getSkillPath: () => join26(SKILLS_PATH, `agent-${config2.id}.md`)
25509
+ getSkillPath: () => join27(SKILLS_PATH, `agent-${config2.id}.md`)
24655
25510
  };
24656
25511
  }
24657
25512
  function loadRunnerConfig(filePath) {
@@ -24671,7 +25526,7 @@ function loadAllRunnerConfigs() {
24671
25526
  const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
24672
25527
  const configs = [];
24673
25528
  for (const file of files) {
24674
- const config2 = loadRunnerConfig(join26(RUNNERS_PATH, file));
25529
+ const config2 = loadRunnerConfig(join27(RUNNERS_PATH, file));
24675
25530
  if (config2) configs.push(config2);
24676
25531
  }
24677
25532
  return configs;
@@ -24701,7 +25556,7 @@ function watchRunnerConfigs(onChange) {
24701
25556
  }
24702
25557
  const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
24703
25558
  for (const file of files) {
24704
- const fullPath = join26(RUNNERS_PATH, file);
25559
+ const fullPath = join27(RUNNERS_PATH, file);
24705
25560
  if (watchedFiles.has(fullPath)) continue;
24706
25561
  watchedFiles.add(fullPath);
24707
25562
  watchFile(fullPath, { interval: 5e3 }, () => {
@@ -25321,9 +26176,11 @@ var init_telegram2 = __esm({
25321
26176
  async stop() {
25322
26177
  await this.bot.stop();
25323
26178
  }
25324
- async sendTyping(chatId) {
26179
+ async sendTyping(chatId, threadId) {
25325
26180
  try {
25326
- await this.bot.api.sendChatAction(numericChatId(chatId), "typing");
26181
+ await this.bot.api.sendChatAction(numericChatId(chatId), "typing", {
26182
+ ...threadId ? { message_thread_id: threadId } : {}
26183
+ });
25327
26184
  } catch {
25328
26185
  }
25329
26186
  }
@@ -25370,21 +26227,23 @@ var init_telegram2 = __esm({
25370
26227
  }
25371
26228
  }
25372
26229
  }
25373
- async sendVoice(chatId, audioBuffer, fileName) {
26230
+ async sendVoice(chatId, audioBuffer, fileName, threadId) {
25374
26231
  await withRetry(
25375
26232
  "sendVoice",
25376
26233
  () => this.bot.api.sendVoice(
25377
26234
  numericChatId(chatId),
25378
- new InputFile(audioBuffer, fileName ?? "response.ogg")
26235
+ new InputFile(audioBuffer, fileName ?? "response.ogg"),
26236
+ { ...threadId ? { message_thread_id: threadId } : {} }
25379
26237
  )
25380
26238
  );
25381
26239
  }
25382
- async sendFile(chatId, buffer, fileName) {
26240
+ async sendFile(chatId, buffer, fileName, _mimeType, threadId) {
25383
26241
  await withRetry(
25384
26242
  "sendFile",
25385
26243
  () => this.bot.api.sendDocument(
25386
26244
  numericChatId(chatId),
25387
- new InputFile(buffer, fileName)
26245
+ new InputFile(buffer, fileName),
26246
+ { ...threadId ? { message_thread_id: threadId } : {} }
25388
26247
  )
25389
26248
  );
25390
26249
  }
@@ -25394,10 +26253,11 @@ var init_telegram2 = __esm({
25394
26253
  const response = await fetch(fileUrl);
25395
26254
  return Buffer.from(await response.arrayBuffer());
25396
26255
  }
25397
- async sendTextReturningId(chatId, text, parseMode) {
26256
+ async sendTextReturningId(chatId, text, parseMode, threadId) {
25398
26257
  try {
25399
26258
  const formatted = sanitizeForTelegram(parseMode === "html" ? text : parseMode === "plain" ? text : formatForTelegram(text));
25400
- const opts = parseMode === "plain" ? {} : { parse_mode: "HTML" };
26259
+ const threadOpts = threadId ? { message_thread_id: threadId } : {};
26260
+ const opts = parseMode === "plain" ? { ...threadOpts } : { parse_mode: "HTML", ...threadOpts };
25401
26261
  const msg = await withRetry(
25402
26262
  "sendTextReturningId",
25403
26263
  () => this.bot.api.sendMessage(numericChatId(chatId), formatted, opts)
@@ -25485,7 +26345,7 @@ var init_telegram2 = __esm({
25485
26345
  onReaction(handler) {
25486
26346
  this.reactionHandlers.push(handler);
25487
26347
  }
25488
- async sendKeyboard(chatId, text, buttons) {
26348
+ async sendKeyboard(chatId, text, buttons, threadId) {
25489
26349
  const keyboard = new InlineKeyboard();
25490
26350
  for (const row of buttons) {
25491
26351
  for (const btn of row) {
@@ -25499,12 +26359,14 @@ var init_telegram2 = __esm({
25499
26359
  const MAX_KEYBOARD_TEXT = 4e3;
25500
26360
  const safeText = text.length > MAX_KEYBOARD_TEXT ? text.slice(0, MAX_KEYBOARD_TEXT) + "\n\n\u2026(truncated)" : text;
25501
26361
  const formatted = sanitizeForTelegram(formatForTelegram(safeText));
26362
+ const threadOpts = threadId ? { message_thread_id: threadId } : {};
25502
26363
  try {
25503
26364
  const msg = await withRetry(
25504
26365
  "sendKeyboard",
25505
26366
  () => this.bot.api.sendMessage(numericChatId(chatId), formatted, {
25506
26367
  parse_mode: "HTML",
25507
- reply_markup: keyboard
26368
+ reply_markup: keyboard,
26369
+ ...threadOpts
25508
26370
  })
25509
26371
  );
25510
26372
  return msg.message_id.toString();
@@ -25519,7 +26381,8 @@ var init_telegram2 = __esm({
25519
26381
  const retryMsg = await withRetry(
25520
26382
  "sendKeyboard:plain",
25521
26383
  () => this.bot.api.sendMessage(numericChatId(chatId), escaped, {
25522
- reply_markup: keyboard
26384
+ reply_markup: keyboard,
26385
+ ...threadOpts
25523
26386
  })
25524
26387
  );
25525
26388
  return retryMsg.message_id.toString();
@@ -25532,7 +26395,7 @@ var init_telegram2 = __esm({
25532
26395
  if (plainText.trim()) {
25533
26396
  await withRetry(
25534
26397
  "sendKeyboard:text-rescue",
25535
- () => this.bot.api.sendMessage(numericChatId(chatId), plainText, {})
26398
+ () => this.bot.api.sendMessage(numericChatId(chatId), plainText, { ...threadOpts })
25536
26399
  );
25537
26400
  }
25538
26401
  } catch {
@@ -25541,7 +26404,8 @@ var init_telegram2 = __esm({
25541
26404
  const fallbackMsg = await withRetry(
25542
26405
  "sendKeyboard:fallback",
25543
26406
  () => this.bot.api.sendMessage(numericChatId(chatId), "\u2B06\uFE0F (see above for details)", {
25544
- reply_markup: keyboard
26407
+ reply_markup: keyboard,
26408
+ ...threadOpts
25545
26409
  })
25546
26410
  );
25547
26411
  return fallbackMsg.message_id.toString();
@@ -25633,6 +26497,7 @@ var init_telegram2 = __esm({
25633
26497
  const fwdOrigin = ctx.message?.forward_origin;
25634
26498
  const fwdFromChat = ctx.message?.forward_from_chat;
25635
26499
  const forwardedFrom = fwdOrigin?.chat?.title ?? fwdOrigin?.sender_chat?.title ?? fwdOrigin?.sender_user?.first_name ?? fwdOrigin?.sender_user_name ?? fwdFromChat?.title ?? void 0;
26500
+ const threadId = ctx.message?.message_thread_id;
25636
26501
  if (ctx.message?.voice) {
25637
26502
  return {
25638
26503
  chatId,
@@ -25646,6 +26511,7 @@ var init_telegram2 = __esm({
25646
26511
  chatTitle,
25647
26512
  replyToText,
25648
26513
  forwardedFrom,
26514
+ threadId,
25649
26515
  raw: ctx
25650
26516
  };
25651
26517
  }
@@ -25665,6 +26531,7 @@ var init_telegram2 = __esm({
25665
26531
  chatTitle,
25666
26532
  replyToText,
25667
26533
  forwardedFrom,
26534
+ threadId,
25668
26535
  raw: ctx
25669
26536
  };
25670
26537
  }
@@ -25682,6 +26549,7 @@ var init_telegram2 = __esm({
25682
26549
  chatTitle,
25683
26550
  replyToText,
25684
26551
  forwardedFrom,
26552
+ threadId,
25685
26553
  raw: ctx
25686
26554
  };
25687
26555
  }
@@ -25708,6 +26576,7 @@ var init_telegram2 = __esm({
25708
26576
  chatTitle,
25709
26577
  replyToText,
25710
26578
  forwardedFrom,
26579
+ threadId,
25711
26580
  raw: ctx
25712
26581
  };
25713
26582
  }
@@ -25729,6 +26598,7 @@ var init_telegram2 = __esm({
25729
26598
  chatTitle,
25730
26599
  replyToText,
25731
26600
  forwardedFrom,
26601
+ threadId,
25732
26602
  raw: ctx
25733
26603
  };
25734
26604
  }
@@ -25742,6 +26612,7 @@ var init_telegram2 = __esm({
25742
26612
  chatTitle,
25743
26613
  replyToText,
25744
26614
  forwardedFrom,
26615
+ threadId,
25745
26616
  raw: ctx
25746
26617
  };
25747
26618
  }
@@ -25753,8 +26624,8 @@ var init_telegram2 = __esm({
25753
26624
 
25754
26625
  // src/skills/bootstrap.ts
25755
26626
  import { existsSync as existsSync24 } from "fs";
25756
- import { readdir as readdir5, readFile as readFile8, writeFile as writeFile4, copyFile } from "fs/promises";
25757
- import { join as join27, dirname as dirname5 } from "path";
26627
+ import { readdir as readdir5, readFile as readFile8, writeFile as writeFile5, copyFile } from "fs/promises";
26628
+ import { join as join28, dirname as dirname5 } from "path";
25758
26629
  import { fileURLToPath as fileURLToPath2 } from "url";
25759
26630
  async function copyAgentManifestSkills() {
25760
26631
  if (!existsSync24(PKG_SKILLS)) return;
@@ -25762,8 +26633,8 @@ async function copyAgentManifestSkills() {
25762
26633
  const entries = await readdir5(PKG_SKILLS, { withFileTypes: true });
25763
26634
  for (const entry of entries) {
25764
26635
  if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
25765
- const src = join27(PKG_SKILLS, entry.name);
25766
- const dest = join27(SKILLS_PATH, entry.name);
26636
+ const src = join28(PKG_SKILLS, entry.name);
26637
+ const dest = join28(SKILLS_PATH, entry.name);
25767
26638
  if (existsSync24(dest)) continue;
25768
26639
  await copyFile(src, dest);
25769
26640
  log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
@@ -25774,7 +26645,7 @@ async function copyAgentManifestSkills() {
25774
26645
  }
25775
26646
  async function bootstrapSkills() {
25776
26647
  await copyAgentManifestSkills();
25777
- const usmDir = join27(SKILLS_PATH, USM_DIR_NAME);
26648
+ const usmDir = join28(SKILLS_PATH, USM_DIR_NAME);
25778
26649
  if (existsSync24(usmDir)) return;
25779
26650
  try {
25780
26651
  const entries = await readdir5(SKILLS_PATH);
@@ -25798,7 +26669,7 @@ async function bootstrapSkills() {
25798
26669
  }
25799
26670
  }
25800
26671
  async function patchUsmForCcClaw(usmDir) {
25801
- const skillPath = join27(usmDir, "SKILL.md");
26672
+ const skillPath = join28(usmDir, "SKILL.md");
25802
26673
  if (!existsSync24(skillPath)) return;
25803
26674
  try {
25804
26675
  let content = await readFile8(skillPath, "utf-8");
@@ -25827,7 +26698,7 @@ async function patchUsmForCcClaw(usmDir) {
25827
26698
  }
25828
26699
  }
25829
26700
  if (patched) {
25830
- await writeFile4(skillPath, content, "utf-8");
26701
+ await writeFile5(skillPath, content, "utf-8");
25831
26702
  log("[skills] Patched USM SKILL.md with CC-Claw support");
25832
26703
  }
25833
26704
  } catch (err) {
@@ -25844,8 +26715,8 @@ var init_bootstrap = __esm({
25844
26715
  USM_REPO = "jacob-bd/universal-skills-manager";
25845
26716
  USM_DIR_NAME = "universal-skills-manager";
25846
26717
  CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
25847
- PKG_ROOT = join27(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
25848
- PKG_SKILLS = join27(PKG_ROOT, "skills");
26718
+ PKG_ROOT = join28(dirname5(fileURLToPath2(import.meta.url)), "..", "..");
26719
+ PKG_SKILLS = join28(PKG_ROOT, "skills");
25849
26720
  }
25850
26721
  });
25851
26722
 
@@ -26068,7 +26939,7 @@ __export(ai_skill_exports, {
26068
26939
  installAiSkill: () => installAiSkill
26069
26940
  });
26070
26941
  import { existsSync as existsSync25, writeFileSync as writeFileSync8, mkdirSync as mkdirSync11 } from "fs";
26071
- import { join as join28 } from "path";
26942
+ import { join as join29 } from "path";
26072
26943
  import { homedir as homedir9 } from "os";
26073
26944
  function generateAiSkill() {
26074
26945
  const version = VERSION;
@@ -26488,8 +27359,8 @@ function installAiSkill() {
26488
27359
  const failed = [];
26489
27360
  for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
26490
27361
  for (const dir of dirs) {
26491
- const skillDir = join28(dir, "cc-claw-cli");
26492
- const skillPath = join28(skillDir, "SKILL.md");
27362
+ const skillDir = join29(dir, "cc-claw-cli");
27363
+ const skillPath = join29(skillDir, "SKILL.md");
26493
27364
  try {
26494
27365
  mkdirSync11(skillDir, { recursive: true });
26495
27366
  writeFileSync8(skillPath, skill, "utf-8");
@@ -26508,11 +27379,11 @@ var init_ai_skill = __esm({
26508
27379
  init_paths();
26509
27380
  init_version();
26510
27381
  BACKEND_SKILL_DIRS2 = {
26511
- "cc-claw": [join28(homedir9(), ".cc-claw", "workspace", "skills")],
26512
- claude: [join28(homedir9(), ".claude", "skills")],
26513
- gemini: [join28(homedir9(), ".gemini", "skills")],
26514
- codex: [join28(homedir9(), ".agents", "skills")],
26515
- cursor: [join28(homedir9(), ".cursor", "skills"), join28(homedir9(), ".cursor", "skills-cursor")]
27382
+ "cc-claw": [join29(homedir9(), ".cc-claw", "workspace", "skills")],
27383
+ claude: [join29(homedir9(), ".claude", "skills")],
27384
+ gemini: [join29(homedir9(), ".gemini", "skills")],
27385
+ codex: [join29(homedir9(), ".agents", "skills")],
27386
+ cursor: [join29(homedir9(), ".cursor", "skills"), join29(homedir9(), ".cursor", "skills-cursor")]
26516
27387
  };
26517
27388
  }
26518
27389
  });
@@ -26523,17 +27394,17 @@ __export(index_exports, {
26523
27394
  main: () => main
26524
27395
  });
26525
27396
  import { mkdirSync as mkdirSync12, existsSync as existsSync26, renameSync as renameSync2, statSync as statSync8, readFileSync as readFileSync16 } from "fs";
26526
- import { join as join29 } from "path";
27397
+ import { join as join30 } from "path";
26527
27398
  import dotenv from "dotenv";
26528
27399
  function migrateLayout() {
26529
27400
  const moves = [
26530
- [join29(CC_CLAW_HOME, "cc-claw.db"), join29(DATA_PATH, "cc-claw.db")],
26531
- [join29(CC_CLAW_HOME, "cc-claw.db-shm"), join29(DATA_PATH, "cc-claw.db-shm")],
26532
- [join29(CC_CLAW_HOME, "cc-claw.db-wal"), join29(DATA_PATH, "cc-claw.db-wal")],
26533
- [join29(CC_CLAW_HOME, "cc-claw.log"), join29(LOGS_PATH, "cc-claw.log")],
26534
- [join29(CC_CLAW_HOME, "cc-claw.log.1"), join29(LOGS_PATH, "cc-claw.log.1")],
26535
- [join29(CC_CLAW_HOME, "cc-claw.error.log"), join29(LOGS_PATH, "cc-claw.error.log")],
26536
- [join29(CC_CLAW_HOME, "cc-claw.error.log.1"), join29(LOGS_PATH, "cc-claw.error.log.1")]
27401
+ [join30(CC_CLAW_HOME, "cc-claw.db"), join30(DATA_PATH, "cc-claw.db")],
27402
+ [join30(CC_CLAW_HOME, "cc-claw.db-shm"), join30(DATA_PATH, "cc-claw.db-shm")],
27403
+ [join30(CC_CLAW_HOME, "cc-claw.db-wal"), join30(DATA_PATH, "cc-claw.db-wal")],
27404
+ [join30(CC_CLAW_HOME, "cc-claw.log"), join30(LOGS_PATH, "cc-claw.log")],
27405
+ [join30(CC_CLAW_HOME, "cc-claw.log.1"), join30(LOGS_PATH, "cc-claw.log.1")],
27406
+ [join30(CC_CLAW_HOME, "cc-claw.error.log"), join30(LOGS_PATH, "cc-claw.error.log")],
27407
+ [join30(CC_CLAW_HOME, "cc-claw.error.log.1"), join30(LOGS_PATH, "cc-claw.error.log.1")]
26537
27408
  ];
26538
27409
  for (const [from, to] of moves) {
26539
27410
  if (existsSync26(from) && !existsSync26(to)) {
@@ -26713,10 +27584,10 @@ async function main() {
26713
27584
  try {
26714
27585
  const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
26715
27586
  const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync19 } = await import("fs");
26716
- const { join: join35 } = await import("path");
26717
- const skillDir = join35(SKILLS_PATH, "cc-claw-cli");
27587
+ const { join: join36 } = await import("path");
27588
+ const skillDir = join36(SKILLS_PATH, "cc-claw-cli");
26718
27589
  mkdirSync19(skillDir, { recursive: true });
26719
- writeFileSync13(join35(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
27590
+ writeFileSync13(join36(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
26720
27591
  log("[cc-claw] AI skill updated");
26721
27592
  } catch {
26722
27593
  }
@@ -26947,7 +27818,7 @@ __export(service_exports2, {
26947
27818
  import { existsSync as existsSync28, mkdirSync as mkdirSync13, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8 } from "fs";
26948
27819
  import { execFileSync as execFileSync3, execSync as execSync4 } from "child_process";
26949
27820
  import { homedir as homedir10, platform } from "os";
26950
- import { join as join30, dirname as dirname6 } from "path";
27821
+ import { join as join31, dirname as dirname6 } from "path";
26951
27822
  function xmlEscape(s) {
26952
27823
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
26953
27824
  }
@@ -26965,14 +27836,14 @@ function getPathDirs() {
26965
27836
  const home = homedir10();
26966
27837
  const dirs = /* @__PURE__ */ new Set([
26967
27838
  nodeBin,
26968
- join30(home, ".local", "bin"),
27839
+ join31(home, ".local", "bin"),
26969
27840
  "/usr/local/bin",
26970
27841
  "/usr/bin",
26971
27842
  "/bin"
26972
27843
  ]);
26973
27844
  try {
26974
27845
  const prefix = execSync4("npm config get prefix", { encoding: "utf-8" }).trim();
26975
- if (prefix) dirs.add(join30(prefix, "bin"));
27846
+ if (prefix) dirs.add(join31(prefix, "bin"));
26976
27847
  } catch {
26977
27848
  }
26978
27849
  return [...dirs].join(":");
@@ -27155,7 +28026,7 @@ function statusLinux() {
27155
28026
  }
27156
28027
  }
27157
28028
  function installService() {
27158
- if (!existsSync28(join30(CC_CLAW_HOME, ".env"))) {
28029
+ if (!existsSync28(join31(CC_CLAW_HOME, ".env"))) {
27159
28030
  console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
27160
28031
  console.error(" Run 'cc-claw setup' before installing the service.");
27161
28032
  process.exitCode = 1;
@@ -27184,9 +28055,9 @@ var init_service2 = __esm({
27184
28055
  "use strict";
27185
28056
  init_paths();
27186
28057
  PLIST_LABEL = "com.cc-claw";
27187
- PLIST_PATH = join30(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
27188
- SYSTEMD_DIR = join30(homedir10(), ".config", "systemd", "user");
27189
- UNIT_PATH = join30(SYSTEMD_DIR, "cc-claw.service");
28058
+ PLIST_PATH = join31(homedir10(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
28059
+ SYSTEMD_DIR = join31(homedir10(), ".config", "systemd", "user");
28060
+ UNIT_PATH = join31(SYSTEMD_DIR, "cc-claw.service");
27190
28061
  }
27191
28062
  });
27192
28063
 
@@ -28086,12 +28957,14 @@ __export(gemini_exports, {
28086
28957
  geminiDisable: () => geminiDisable,
28087
28958
  geminiEnable: () => geminiEnable,
28088
28959
  geminiList: () => geminiList,
28960
+ geminiRelogin: () => geminiRelogin,
28089
28961
  geminiRemove: () => geminiRemove,
28962
+ geminiRename: () => geminiRename,
28090
28963
  geminiReorder: () => geminiReorder,
28091
28964
  geminiRotation: () => geminiRotation
28092
28965
  });
28093
28966
  import { existsSync as existsSync33, mkdirSync as mkdirSync14, writeFileSync as writeFileSync10, readFileSync as readFileSync23, chmodSync } from "fs";
28094
- import { join as join31 } from "path";
28967
+ import { join as join32 } from "path";
28095
28968
  import { createInterface as createInterface8 } from "readline";
28096
28969
  function requireDb() {
28097
28970
  if (!existsSync33(DB_PATH)) {
@@ -28119,7 +28992,7 @@ async function resolveSlotId(idOrLabel) {
28119
28992
  function resolveOAuthEmail(configHome) {
28120
28993
  if (!configHome) return null;
28121
28994
  try {
28122
- const accountsPath = join31(configHome, ".gemini", "google_accounts.json");
28995
+ const accountsPath = join32(configHome, ".gemini", "google_accounts.json");
28123
28996
  if (!existsSync33(accountsPath)) return null;
28124
28997
  const accounts = JSON.parse(readFileSync23(accountsPath, "utf-8"));
28125
28998
  return accounts.active || null;
@@ -28203,14 +29076,14 @@ async function geminiAddKey(globalOpts, opts) {
28203
29076
  }
28204
29077
  async function geminiAddAccount(globalOpts, opts) {
28205
29078
  await requireWriteDb();
28206
- const slotsDir = join31(CC_CLAW_HOME, "gemini-slots");
29079
+ const slotsDir = join32(CC_CLAW_HOME, "gemini-slots");
28207
29080
  if (!existsSync33(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
28208
29081
  const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
28209
29082
  const tempId = Date.now();
28210
- const slotDir = join31(slotsDir, `slot-${tempId}`);
29083
+ const slotDir = join32(slotsDir, `slot-${tempId}`);
28211
29084
  mkdirSync14(slotDir, { recursive: true, mode: 448 });
28212
- mkdirSync14(join31(slotDir, ".gemini"), { recursive: true });
28213
- writeFileSync10(join31(slotDir, ".gemini", "settings.json"), JSON.stringify({
29085
+ mkdirSync14(join32(slotDir, ".gemini"), { recursive: true });
29086
+ writeFileSync10(join32(slotDir, ".gemini", "settings.json"), JSON.stringify({
28214
29087
  security: { auth: { selectedType: "oauth-personal" } }
28215
29088
  }, null, 2));
28216
29089
  console.log("");
@@ -28227,7 +29100,7 @@ async function geminiAddAccount(globalOpts, opts) {
28227
29100
  });
28228
29101
  } catch {
28229
29102
  }
28230
- const oauthPath = join31(slotDir, ".gemini", "oauth_creds.json");
29103
+ const oauthPath = join32(slotDir, ".gemini", "oauth_creds.json");
28231
29104
  if (!existsSync33(oauthPath)) {
28232
29105
  console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
28233
29106
  console.log(" The slot directory is preserved at: " + slotDir);
@@ -28236,7 +29109,7 @@ async function geminiAddAccount(globalOpts, opts) {
28236
29109
  }
28237
29110
  let accountEmail = "unknown";
28238
29111
  try {
28239
- const accounts = JSON.parse(__require("fs").readFileSync(join31(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
29112
+ const accounts = JSON.parse(__require("fs").readFileSync(join32(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
28240
29113
  accountEmail = accounts.active || accountEmail;
28241
29114
  } catch {
28242
29115
  }
@@ -28311,6 +29184,92 @@ async function geminiReorder(globalOpts, idOrLabel, priority) {
28311
29184
  () => success(`Slot "${idOrLabel}" (#${slotId}) priority set to ${priority}`)
28312
29185
  );
28313
29186
  }
29187
+ async function geminiRename(globalOpts, idOrLabel, newLabel) {
29188
+ await requireWriteDb();
29189
+ const slotId = await resolveSlotId(idOrLabel);
29190
+ if (!slotId) {
29191
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29192
+ return;
29193
+ }
29194
+ const { renameGeminiSlot: renameGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29195
+ const updated = renameGeminiSlot2(slotId, newLabel);
29196
+ if (updated) {
29197
+ output({ id: slotId, label: newLabel }, () => success(`Renamed slot #${slotId} \u2192 "${newLabel}"`));
29198
+ } else {
29199
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29200
+ }
29201
+ }
29202
+ async function geminiRelogin(globalOpts, idOrLabel) {
29203
+ await requireWriteDb();
29204
+ const slotId = await resolveSlotId(idOrLabel);
29205
+ if (!slotId) {
29206
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29207
+ return;
29208
+ }
29209
+ const { getGeminiSlots: getGeminiSlots2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29210
+ const slot = getGeminiSlots2().find((s) => s.id === slotId);
29211
+ if (!slot) {
29212
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29213
+ return;
29214
+ }
29215
+ if (slot.slotType !== "oauth") {
29216
+ outputError("NOT_OAUTH", `Slot "${idOrLabel}" is an API key slot \u2014 re-login only works for OAuth slots.`);
29217
+ return;
29218
+ }
29219
+ if (!slot.configHome) {
29220
+ outputError("NO_CONFIG", `Slot "${idOrLabel}" has no config directory \u2014 cannot re-login.`);
29221
+ return;
29222
+ }
29223
+ const settingsPath = join32(slot.configHome, ".gemini", "settings.json");
29224
+ if (!existsSync33(settingsPath)) {
29225
+ mkdirSync14(join32(slot.configHome, ".gemini"), { recursive: true });
29226
+ writeFileSync10(settingsPath, JSON.stringify({
29227
+ security: { auth: { selectedType: "oauth-personal" } }
29228
+ }, null, 2));
29229
+ }
29230
+ console.log("");
29231
+ console.log(` Re-authenticating Gemini slot "${slot.label || `#${slot.id}`}"...`);
29232
+ console.log(" Sign in with the same Google account when prompted.");
29233
+ console.log(" After sign-in, type /quit to return here.");
29234
+ console.log("");
29235
+ const { execSync: execSync6 } = await import("child_process");
29236
+ try {
29237
+ execSync6(`gemini`, {
29238
+ stdio: "inherit",
29239
+ env: {
29240
+ ...process.env,
29241
+ GEMINI_CLI_HOME: slot.configHome,
29242
+ GEMINI_API_KEY: void 0,
29243
+ GOOGLE_API_KEY: void 0
29244
+ },
29245
+ cwd: slot.configHome
29246
+ });
29247
+ } catch {
29248
+ }
29249
+ const oauthPath = join32(slot.configHome, ".gemini", "oauth_creds.json");
29250
+ if (!existsSync33(oauthPath)) {
29251
+ console.log(error2("\n Re-login failed \u2014 no OAuth credentials found."));
29252
+ console.log(` Try again: cc-claw gemini re-login ${idOrLabel}
29253
+ `);
29254
+ process.exit(1);
29255
+ }
29256
+ const { setGeminiSlotEnabled: setGeminiSlotEnabled2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29257
+ setGeminiSlotEnabled2(slotId, true);
29258
+ let accountEmail = slot.label;
29259
+ try {
29260
+ const accounts = JSON.parse(readFileSync23(join32(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
29261
+ if (accounts.active) accountEmail = accounts.active;
29262
+ } catch {
29263
+ }
29264
+ if (accountEmail && accountEmail !== slot.label) {
29265
+ const { renameGeminiSlot: renameGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29266
+ renameGeminiSlot2(slotId, accountEmail);
29267
+ }
29268
+ output(
29269
+ { id: slotId, label: accountEmail, refreshed: true },
29270
+ () => success(`Re-authenticated Gemini slot #${slotId} (${accountEmail})`)
29271
+ );
29272
+ }
28314
29273
  async function geminiRotation(globalOpts, mode) {
28315
29274
  const validModes = ["off", "all", "accounts", "keys"];
28316
29275
  if (!mode) {
@@ -28351,12 +29310,14 @@ __export(backend_cmd_factory_exports, {
28351
29310
  makeEnable: () => makeEnable,
28352
29311
  makeList: () => makeList,
28353
29312
  makeRefresh: () => makeRefresh,
29313
+ makeRelogin: () => makeRelogin,
28354
29314
  makeRemove: () => makeRemove,
29315
+ makeRename: () => makeRename,
28355
29316
  makeReorder: () => makeReorder,
28356
29317
  registerBackendSlotCommands: () => registerBackendSlotCommands
28357
29318
  });
28358
29319
  import { existsSync as existsSync34, mkdirSync as mkdirSync15, readFileSync as readFileSync24 } from "fs";
28359
- import { join as join32 } from "path";
29320
+ import { join as join33 } from "path";
28360
29321
  import { createInterface as createInterface9 } from "readline";
28361
29322
  function requireDb2() {
28362
29323
  if (!existsSync34(DB_PATH)) {
@@ -28448,10 +29409,10 @@ function makeAddAccount(backend2, displayName) {
28448
29409
  process.exit(1);
28449
29410
  }
28450
29411
  await requireWriteDb2();
28451
- const slotsDir = join32(CC_CLAW_HOME, config2.slotsSubdir);
29412
+ const slotsDir = join33(CC_CLAW_HOME, config2.slotsSubdir);
28452
29413
  if (!existsSync34(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
28453
29414
  const tempId = Date.now();
28454
- const slotDir = join32(slotsDir, `slot-${tempId}`);
29415
+ const slotDir = join33(slotsDir, `slot-${tempId}`);
28455
29416
  mkdirSync15(slotDir, { recursive: true, mode: 448 });
28456
29417
  if (config2.preSetup) config2.preSetup(slotDir);
28457
29418
  console.log("");
@@ -28562,6 +29523,88 @@ function makeReorder(backend2, _displayName) {
28562
29523
  );
28563
29524
  };
28564
29525
  }
29526
+ function makeRename(backend2, _displayName) {
29527
+ return async function rename(_globalOpts, idOrLabel, newLabel) {
29528
+ await requireWriteDb2();
29529
+ const slotId = await resolveSlotId2(backend2, idOrLabel);
29530
+ if (!slotId) {
29531
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29532
+ return;
29533
+ }
29534
+ const { renameBackendSlot: renameBackendSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29535
+ const updated = renameBackendSlot2(slotId, newLabel);
29536
+ if (updated) {
29537
+ output({ id: slotId, label: newLabel }, () => success(`Renamed slot #${slotId} \u2192 "${newLabel}"`));
29538
+ } else {
29539
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29540
+ }
29541
+ };
29542
+ }
29543
+ function makeRelogin(backend2, displayName) {
29544
+ return async function relogin(_globalOpts, idOrLabel) {
29545
+ const config2 = ADD_ACCOUNT_CONFIGS[backend2];
29546
+ if (!config2) {
29547
+ outputError("UNSUPPORTED", `re-login is not supported for ${displayName}. Only OAuth/subscription slots can be re-logged.`);
29548
+ process.exit(1);
29549
+ }
29550
+ await requireWriteDb2();
29551
+ const slotId = await resolveSlotId2(backend2, idOrLabel);
29552
+ if (!slotId) {
29553
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29554
+ return;
29555
+ }
29556
+ const { getBackendSlots: getBackendSlots2, reenableBackendSlot: reenableBackendSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29557
+ const slot = getBackendSlots2(backend2).find((s) => s.id === slotId);
29558
+ if (!slot) {
29559
+ outputError("NOT_FOUND", `Slot "${idOrLabel}" not found.`);
29560
+ return;
29561
+ }
29562
+ if (slot.slotType !== "oauth") {
29563
+ outputError("NOT_OAUTH", `Slot "${idOrLabel}" is an API key slot \u2014 re-login only works for OAuth/subscription slots.`);
29564
+ return;
29565
+ }
29566
+ if (!slot.configHome) {
29567
+ outputError("NO_CONFIG", `Slot "${idOrLabel}" has no config directory \u2014 cannot re-login.`);
29568
+ return;
29569
+ }
29570
+ if (config2.preSetup) config2.preSetup(slot.configHome);
29571
+ console.log("");
29572
+ console.log(` Re-authenticating ${displayName} slot "${slot.label || `#${slot.id}`}"...`);
29573
+ console.log(` Sign in with the same account when the browser opens.`);
29574
+ console.log("");
29575
+ const { execSync: execSync6 } = await import("child_process");
29576
+ const loginEnv = {
29577
+ ...process.env,
29578
+ [config2.envKey]: config2.envValue(slot.configHome),
29579
+ ...config2.envOverrides
29580
+ };
29581
+ try {
29582
+ execSync6(config2.loginCommand.join(" "), {
29583
+ stdio: "inherit",
29584
+ env: loginEnv,
29585
+ cwd: slot.configHome
29586
+ });
29587
+ } catch {
29588
+ }
29589
+ if (!config2.verifyCredentials(slot.configHome)) {
29590
+ console.log(error2(`
29591
+ Re-login failed \u2014 no credentials found.`));
29592
+ console.log(` Try again: cc-claw ${backend2} re-login ${idOrLabel}
29593
+ `);
29594
+ process.exit(1);
29595
+ }
29596
+ reenableBackendSlot2(slotId);
29597
+ const newLabel = config2.extractLabel(slot.configHome);
29598
+ if (newLabel && newLabel !== slot.label && newLabel !== "subscription") {
29599
+ const { renameBackendSlot: renameBackendSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
29600
+ renameBackendSlot2(slotId, newLabel);
29601
+ }
29602
+ output(
29603
+ { id: slotId, label: newLabel || slot.label, refreshed: true },
29604
+ () => success(`Re-authenticated ${displayName} slot #${slotId} (${newLabel || slot.label})`)
29605
+ );
29606
+ };
29607
+ }
28565
29608
  function makeRefresh(backend2, displayName) {
28566
29609
  return async function refresh(_globalOpts) {
28567
29610
  await requireWriteDb2();
@@ -28620,11 +29663,11 @@ var init_backend_cmd_factory = __esm({
28620
29663
  envValue: (slotDir) => slotDir,
28621
29664
  envOverrides: { ANTHROPIC_API_KEY: void 0 },
28622
29665
  preSetup: (slotDir) => {
28623
- mkdirSync15(join32(slotDir, ".claude"), { recursive: true });
29666
+ mkdirSync15(join33(slotDir, ".claude"), { recursive: true });
28624
29667
  },
28625
29668
  verifyCredentials: (slotDir) => {
28626
- const claudeJson = join32(slotDir, ".claude.json");
28627
- const claudeJsonNested = join32(slotDir, ".claude", ".claude.json");
29669
+ const claudeJson = join33(slotDir, ".claude.json");
29670
+ const claudeJsonNested = join33(slotDir, ".claude", ".claude.json");
28628
29671
  if (existsSync34(claudeJson)) {
28629
29672
  try {
28630
29673
  const data = JSON.parse(readFileSync24(claudeJson, "utf-8"));
@@ -28656,7 +29699,7 @@ var init_backend_cmd_factory = __esm({
28656
29699
  } catch {
28657
29700
  }
28658
29701
  try {
28659
- const claudeJson = join32(slotDir, ".claude.json");
29702
+ const claudeJson = join33(slotDir, ".claude.json");
28660
29703
  if (existsSync34(claudeJson)) {
28661
29704
  const data = JSON.parse(readFileSync24(claudeJson, "utf-8"));
28662
29705
  if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
@@ -28673,11 +29716,11 @@ var init_backend_cmd_factory = __esm({
28673
29716
  envValue: (slotDir) => slotDir,
28674
29717
  envOverrides: { OPENAI_API_KEY: void 0 },
28675
29718
  verifyCredentials: (slotDir) => {
28676
- return existsSync34(join32(slotDir, "auth.json"));
29719
+ return existsSync34(join33(slotDir, "auth.json"));
28677
29720
  },
28678
29721
  extractLabel: (slotDir) => {
28679
29722
  try {
28680
- const authData = JSON.parse(readFileSync24(join32(slotDir, "auth.json"), "utf-8"));
29723
+ const authData = JSON.parse(readFileSync24(join33(slotDir, "auth.json"), "utf-8"));
28681
29724
  if (authData.email) return authData.email;
28682
29725
  if (authData.account_name) return authData.account_name;
28683
29726
  if (authData.user?.email) return authData.user.email;
@@ -31041,7 +32084,7 @@ __export(completion_exports, {
31041
32084
  completionCommand: () => completionCommand
31042
32085
  });
31043
32086
  import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync17 } from "fs";
31044
- import { join as join33 } from "path";
32087
+ import { join as join34 } from "path";
31045
32088
  import { homedir as homedir11 } from "os";
31046
32089
  async function completionCommand(opts) {
31047
32090
  const shell = opts.shell ?? detectShell();
@@ -31057,10 +32100,10 @@ async function completionCommand(opts) {
31057
32100
  process.exit(1);
31058
32101
  }
31059
32102
  if (opts.install) {
31060
- const dir = join33(homedir11(), ".config", "cc-claw", "completions");
32103
+ const dir = join34(homedir11(), ".config", "cc-claw", "completions");
31061
32104
  mkdirSync17(dir, { recursive: true });
31062
32105
  const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
31063
- const filepath = join33(dir, filename);
32106
+ const filepath = join34(dir, filename);
31064
32107
  writeFileSync11(filepath, script, "utf-8");
31065
32108
  console.log(`\u2713 Completion script written to ${filepath}
31066
32109
  `);
@@ -31710,7 +32753,7 @@ var setup_exports = {};
31710
32753
  import { existsSync as existsSync55, writeFileSync as writeFileSync12, readFileSync as readFileSync27, copyFileSync as copyFileSync4, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
31711
32754
  import { execFileSync as execFileSync5 } from "child_process";
31712
32755
  import { createInterface as createInterface11 } from "readline";
31713
- import { join as join34 } from "path";
32756
+ import { join as join35 } from "path";
31714
32757
  function divider2() {
31715
32758
  console.log(dim("\u2500".repeat(55)));
31716
32759
  }
@@ -31798,7 +32841,7 @@ async function setup() {
31798
32841
  if (match) env[match[1].trim()] = match[2].trim();
31799
32842
  }
31800
32843
  }
31801
- const cwdDb = join34(process.cwd(), "cc-claw.db");
32844
+ const cwdDb = join35(process.cwd(), "cc-claw.db");
31802
32845
  if (existsSync55(cwdDb) && !existsSync55(DB_PATH)) {
31803
32846
  const { size } = statSync12(cwdDb);
31804
32847
  console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
@@ -32188,6 +33231,14 @@ gemini.command("reorder <id-or-label> <priority>").description("Set slot priorit
32188
33231
  const { geminiReorder: geminiReorder2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
32189
33232
  await geminiReorder2(program.opts(), id, priority);
32190
33233
  });
33234
+ gemini.command("rename <id-or-label> <new-label>").description("Rename a credential slot").action(async (id, newLabel) => {
33235
+ const { geminiRename: geminiRename2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
33236
+ await geminiRename2(program.opts(), id, newLabel);
33237
+ });
33238
+ gemini.command("re-login <id-or-label>").alias("relogin").description("Re-authenticate an OAuth slot (refreshes expired token in-place)").action(async (id) => {
33239
+ const { geminiRelogin: geminiRelogin2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
33240
+ await geminiRelogin2(program.opts(), id);
33241
+ });
32191
33242
  gemini.command("rotation [mode]").description("Get or set rotation mode (off, all, accounts, keys)").action(async (mode) => {
32192
33243
  const { geminiRotation: geminiRotation2 } = await Promise.resolve().then(() => (init_gemini2(), gemini_exports));
32193
33244
  await geminiRotation2(program.opts(), mode);
@@ -32226,6 +33277,14 @@ function registerUnifiedSlotCommands(parentCmd, backendId, displayName) {
32226
33277
  const { makeRefresh: makeRefresh2 } = await Promise.resolve().then(() => (init_backend_cmd_factory(), backend_cmd_factory_exports));
32227
33278
  await makeRefresh2(backendId, displayName)(program.opts());
32228
33279
  });
33280
+ cmd.command("rename <id-or-label> <new-label>").description("Rename a credential slot").action(async (id, newLabel) => {
33281
+ const { makeRename: makeRename2 } = await Promise.resolve().then(() => (init_backend_cmd_factory(), backend_cmd_factory_exports));
33282
+ await makeRename2(backendId, displayName)(program.opts(), id, newLabel);
33283
+ });
33284
+ cmd.command("re-login <id-or-label>").alias("relogin").description("Re-authenticate an OAuth/subscription slot (refreshes expired token in-place)").action(async (id) => {
33285
+ const { makeRelogin: makeRelogin2 } = await Promise.resolve().then(() => (init_backend_cmd_factory(), backend_cmd_factory_exports));
33286
+ await makeRelogin2(backendId, displayName)(program.opts(), id);
33287
+ });
32229
33288
  }
32230
33289
  registerUnifiedSlotCommands(program, "claude", "Claude");
32231
33290
  registerUnifiedSlotCommands(program, "codex", "Codex");
@@ -32653,6 +33712,11 @@ optimize.command("skills").description("List available CC-Claw skills").action(a
32653
33712
  const { optimizeSkills: optimizeSkills2 } = await Promise.resolve().then(() => (init_optimize2(), optimize_exports));
32654
33713
  await optimizeSkills2();
32655
33714
  });
33715
+ program.command("council").alias("debate").description("Multi-model council debate (Telegram interactive)").action(async () => {
33716
+ console.log("Council is an interactive Telegram command.");
33717
+ console.log("Use /council in Telegram to start a multi-model debate wizard.");
33718
+ console.log("Select 2+ models, pose a question, and they debate anonymously for up to 3 rounds.");
33719
+ });
32656
33720
  program.command("start", { hidden: true }).description("Run the bot in the foreground (use 'service start' for background daemon)").action(async () => {
32657
33721
  await Promise.resolve().then(() => (init_index(), index_exports));
32658
33722
  });