cc-claw 0.20.15 → 0.20.17

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 +151 -10
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ var VERSION;
33
33
  var init_version = __esm({
34
34
  "src/version.ts"() {
35
35
  "use strict";
36
- VERSION = true ? "0.20.15" : (() => {
36
+ VERSION = true ? "0.20.17" : (() => {
37
37
  try {
38
38
  return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
39
39
  } catch {
@@ -4150,6 +4150,11 @@ var init_store5 = __esm({
4150
4150
  });
4151
4151
 
4152
4152
  // src/backends/types.ts
4153
+ var types_exports = {};
4154
+ __export(types_exports, {
4155
+ BACKEND: () => BACKEND,
4156
+ isBackendId: () => isBackendId
4157
+ });
4153
4158
  function isBackendId(value) {
4154
4159
  return Object.values(BACKEND).includes(value);
4155
4160
  }
@@ -13710,6 +13715,9 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
13710
13715
  ...config2.cwd ? { cwd: config2.cwd } : {}
13711
13716
  });
13712
13717
  proc.unref();
13718
+ if (proc.stdin) {
13719
+ proc.stdin.end();
13720
+ }
13713
13721
  cancelState.process = proc;
13714
13722
  const timeoutState = { firstResponse: false, contentSilence: false };
13715
13723
  let timedOut = false;
@@ -16087,6 +16095,17 @@ var init_types3 = __esm({
16087
16095
  });
16088
16096
 
16089
16097
  // src/scheduler/wizard.ts
16098
+ var wizard_exports = {};
16099
+ __export(wizard_exports, {
16100
+ cancelWizard: () => cancelWizard,
16101
+ getPendingJob: () => getPendingJob,
16102
+ handleWizardCallback: () => handleWizardCallback,
16103
+ handleWizardText: () => handleWizardText,
16104
+ hasPendingWizard: () => hasPendingWizard,
16105
+ resolveSlotLabel: () => resolveSlotLabel,
16106
+ startEditWizard: () => startEditWizard,
16107
+ startWizard: () => startWizard
16108
+ });
16090
16109
  function hasPendingWizard(chatId) {
16091
16110
  return pendingJobs.has(chatId);
16092
16111
  }
@@ -16107,6 +16126,9 @@ function resetWizardTimeout(chatId) {
16107
16126
  log(`[wizard] Auto-cancelled stale wizard for chat ${chatId}`);
16108
16127
  }, WIZARD_TIMEOUT_MS));
16109
16128
  }
16129
+ function getPendingJob(chatId) {
16130
+ return pendingJobs.get(chatId);
16131
+ }
16110
16132
  function parseNaturalLanguage(input) {
16111
16133
  const lower = input.toLowerCase();
16112
16134
  const minMatch = lower.match(/every\s+(\d+)\s+min/);
@@ -20100,6 +20122,7 @@ async function sendJobDetail(chatId, jobId, channel, messageId) {
20100
20122
  }
20101
20123
  actionRow1.push({ label: "Edit", data: `job:edit:${job.id}` });
20102
20124
  const actionRow2 = [
20125
+ { label: "\u{1F9EA} Test Model", data: `job:test:${job.id}` },
20103
20126
  { label: "View Runs", data: `job:runs:${job.id}`, style: "primary" }
20104
20127
  ];
20105
20128
  if (job.active) {
@@ -22159,8 +22182,8 @@ var init_types4 = __esm({
22159
22182
  });
22160
22183
 
22161
22184
  // src/council/wizard.ts
22162
- var wizard_exports = {};
22163
- __export(wizard_exports, {
22185
+ var wizard_exports2 = {};
22186
+ __export(wizard_exports2, {
22164
22187
  buildSelectKeyboard: () => buildSelectKeyboard,
22165
22188
  cancelCouncil: () => cancelCouncil,
22166
22189
  getCouncilState: () => getCouncilState,
@@ -24003,7 +24026,7 @@ async function handleCouncilCommand(chatId, commandArgs, msg, channel) {
24003
24026
  await channel.sendText(chatId, "Council requires DASHBOARD_ENABLED=1 (uses the agent orchestrator).", { parseMode: "plain" });
24004
24027
  return;
24005
24028
  }
24006
- const { startCouncilWizard: startCouncilWizard2, buildSelectKeyboard: buildSelectKeyboard2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
24029
+ const { startCouncilWizard: startCouncilWizard2, buildSelectKeyboard: buildSelectKeyboard2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports2));
24007
24030
  startCouncilWizard2(chatId);
24008
24031
  if (typeof channel.sendKeyboard === "function") {
24009
24032
  const { text, buttons } = buildSelectKeyboard2(chatId);
@@ -24604,12 +24627,99 @@ ${plan.originalMessage}`;
24604
24627
  } else if (data.startsWith("sched:")) {
24605
24628
  await handleWizardCallback(chatId, data, channel);
24606
24629
  } else if (data.startsWith("job:")) {
24630
+ async function showJobAccountPicker(cid, jobId, backend2, model2, thinking2, ch) {
24631
+ const isGemini = backend2 === "gemini";
24632
+ const slots = isGemini ? getGeminiSlots() : getBackendSlots(backend2);
24633
+ const enabledSlots = slots.filter((s) => s.enabled);
24634
+ if (enabledSlots.length === 0 || typeof ch.sendKeyboard !== "function") {
24635
+ const { updateJob: updateJobFields } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24636
+ updateJobFields(jobId, { backend: backend2, model: model2, thinking: thinking2, credentialSlotId: null });
24637
+ const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24638
+ const adapter = getAdapter4(backend2);
24639
+ await ch.sendText(cid, `Job #${jobId} updated: ${adapter.displayName} / ${model2} / ${thinking2}`, { parseMode: "plain" });
24640
+ await sendJobDetail(cid, jobId, ch);
24641
+ return;
24642
+ }
24643
+ const rows = [
24644
+ [{ label: "\u{1F504} Auto (rotate)", data: `job:setaccount:${jobId}:${backend2}:${model2}:${thinking2}:auto` }]
24645
+ ];
24646
+ for (const slot of enabledSlots) {
24647
+ const s = slot;
24648
+ const icon = s.slotType === "api_key" ? "\u{1F511}" : "\u{1F4E7}";
24649
+ const label2 = s.label || s.email || `Slot #${s.id}`;
24650
+ const type = s.slotType === "api_key" ? "API key" : "OAuth";
24651
+ rows.push([{ label: `${icon} ${label2} (${type})`, data: `job:setaccount:${jobId}:${backend2}:${model2}:${thinking2}:${s.id}` }]);
24652
+ }
24653
+ rows.push([{ label: "\u2190 Back", data: `job:editbackend:${jobId}` }]);
24654
+ await ch.sendKeyboard(cid, `Which account for Job #${jobId}?`, rows);
24655
+ }
24607
24656
  const rest = data.slice(4);
24608
24657
  if (rest === "back") {
24609
24658
  await sendJobsBoard(chatId, channel, 1);
24610
24659
  } else if (rest.startsWith("view:")) {
24611
24660
  const id = parseInt(rest.slice(5), 10);
24612
24661
  await sendJobDetail(chatId, id, channel, messageId);
24662
+ } else if (rest.startsWith("test:")) {
24663
+ const id = parseInt(rest.slice(5), 10);
24664
+ const { getJobById: getJob } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24665
+ const testJob = getJob(id);
24666
+ if (!testJob) {
24667
+ await channel.sendText(chatId, `Job #${id} not found.`, { parseMode: "plain" });
24668
+ } else {
24669
+ await channel.sendText(chatId, `\u{1F9EA} Testing model: ${testJob.backend ?? "default"}/${testJob.model ?? "default"}...`, { parseMode: "plain" });
24670
+ try {
24671
+ const { askAgent: askAgent3 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
24672
+ const { BACKEND: BACKEND2 } = await Promise.resolve().then(() => (init_types(), types_exports));
24673
+ const { pinChatGeminiSlot: pinChatGeminiSlot4, pinChatBackendSlot: pinChatBackendSlot3 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24674
+ const testChatId = `cron:test:${id}:${Date.now()}`;
24675
+ const backend2 = testJob.backend ?? "claude";
24676
+ if (testJob.credentialSlotId) {
24677
+ if (backend2 === BACKEND2.GEMINI) {
24678
+ pinChatGeminiSlot4(testChatId, testJob.credentialSlotId);
24679
+ } else {
24680
+ pinChatBackendSlot3(testChatId, backend2, testJob.credentialSlotId);
24681
+ }
24682
+ }
24683
+ const t0 = Date.now();
24684
+ const resp = await askAgent3(testChatId, 'Reply with exactly: "pong"', {
24685
+ backend: backend2,
24686
+ model: testJob.model ?? void 0,
24687
+ bootstrapTier: "chat",
24688
+ maxTurns: 1,
24689
+ timeoutMs: 3e4,
24690
+ permMode: "yolo"
24691
+ });
24692
+ const elapsed = ((Date.now() - t0) / 1e3).toFixed(1);
24693
+ const got = resp.text?.trim().slice(0, 100) || "(empty)";
24694
+ const { resolveSlotLabel: resolveSlotLabel2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
24695
+ const acct = resolveSlotLabel2(backend2, testJob.credentialSlotId);
24696
+ if (typeof channel.sendKeyboard === "function") {
24697
+ await channel.sendKeyboard(
24698
+ chatId,
24699
+ `\u2705 Model test passed (${elapsed}s)
24700
+
24701
+ Backend: ${backend2}
24702
+ Model: ${testJob.model ?? "default"}
24703
+ Account: ${acct}
24704
+ Response: "${got}"`,
24705
+ [[{ label: "\u2190 Back to Job", data: `job:view:${id}` }]]
24706
+ );
24707
+ }
24708
+ } catch (err) {
24709
+ const msg = err instanceof Error ? err.message : String(err);
24710
+ if (typeof channel.sendKeyboard === "function") {
24711
+ await channel.sendKeyboard(
24712
+ chatId,
24713
+ `\u274C Model test failed
24714
+
24715
+ ${msg.slice(0, 500)}`,
24716
+ [[{ label: "\u2190 Back to Job", data: `job:view:${id}` }]]
24717
+ );
24718
+ } else {
24719
+ await channel.sendText(chatId, `\u274C Model test failed: ${msg.slice(0, 300)}`, { parseMode: "plain" });
24720
+ }
24721
+ }
24722
+ }
24613
24723
  } else if (rest.startsWith("run:")) {
24614
24724
  const id = parseInt(rest.slice(4), 10);
24615
24725
  await channel.sendText(chatId, `Triggering job #${id}...`, { parseMode: "plain" });
@@ -24748,11 +24858,42 @@ What do you want to change?`,
24748
24858
  const id = parseInt(parts[0], 10);
24749
24859
  const backend2 = parts[1];
24750
24860
  const model2 = parts.slice(2).join(":");
24861
+ const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24862
+ const adapter = getAdapter4(backend2);
24863
+ const modelInfo = adapter.availableModels[model2];
24864
+ if (modelInfo?.thinking === "adjustable" && modelInfo.thinkingLevels && typeof channel.sendKeyboard === "function") {
24865
+ const rows = modelInfo.thinkingLevels.map((level) => [{
24866
+ label: level === "auto" ? "Auto (default)" : level.replace("_", " ").replace(/\b\w/g, (c) => c.toUpperCase()),
24867
+ data: `job:setthinking:${id}:${backend2}:${model2}:${level}`
24868
+ }]);
24869
+ rows.push([{ label: "\u2190 Back", data: `job:setbackend:${id}:${backend2}` }]);
24870
+ await channel.sendKeyboard(chatId, `Thinking level for Job #${id}?`, rows);
24871
+ } else {
24872
+ await showJobAccountPicker(chatId, id, backend2, model2, "auto", channel);
24873
+ }
24874
+ } else if (rest.startsWith("setthinking:")) {
24875
+ const parts = rest.slice(12).split(":");
24876
+ const id = parseInt(parts[0], 10);
24877
+ const backend2 = parts[1];
24878
+ const model2 = parts[2];
24879
+ const thinking2 = parts[3] ?? "auto";
24880
+ await showJobAccountPicker(chatId, id, backend2, model2, thinking2, channel);
24881
+ } else if (rest.startsWith("setaccount:")) {
24882
+ const parts = rest.slice(11).split(":");
24883
+ const id = parseInt(parts[0], 10);
24884
+ const backend2 = parts[1];
24885
+ const model2 = parts[2];
24886
+ const thinking2 = parts[3];
24887
+ const slotVal = parts[4];
24888
+ const credentialSlotId = slotVal === "auto" ? null : parseInt(slotVal, 10);
24751
24889
  const { updateJob: updateJobFields } = await Promise.resolve().then(() => (init_store5(), store_exports5));
24752
- updateJobFields(id, { backend: backend2, model: model2 });
24890
+ updateJobFields(id, { backend: backend2, model: model2, thinking: thinking2, credentialSlotId });
24753
24891
  const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
24754
24892
  const adapter = getAdapter4(backend2);
24755
- await channel.sendText(chatId, `Job #${id} updated: ${adapter.displayName} / ${model2}`, { parseMode: "plain" });
24893
+ const { resolveSlotLabel: resolveSlotLabel2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
24894
+ const accountLabel = resolveSlotLabel2(backend2, credentialSlotId);
24895
+ await channel.sendText(chatId, `Job #${id} updated: ${adapter.displayName} / ${model2} / ${thinking2}
24896
+ Account: ${accountLabel}`, { parseMode: "plain" });
24756
24897
  await sendJobDetail(chatId, id, channel);
24757
24898
  } else if (rest.startsWith("edittimeout:")) {
24758
24899
  const id = parseInt(rest.slice(12), 10);
@@ -25089,7 +25230,7 @@ ${rotationNote}`, { parseMode: "html" });
25089
25230
  const { getAdapter: getAdapter4 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
25090
25231
  const toggleAdapter = getAdapter4(backend2);
25091
25232
  const label2 = toggleAdapter.availableModels[model2]?.label ?? model2;
25092
- const { toggleParticipant: toggleParticipant2, buildSelectKeyboard: buildSelectKeyboard2, hasPendingCouncil: hasPendingCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
25233
+ const { toggleParticipant: toggleParticipant2, buildSelectKeyboard: buildSelectKeyboard2, hasPendingCouncil: hasPendingCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports2));
25093
25234
  if (!hasPendingCouncil2(chatId)) {
25094
25235
  await channel.sendText(chatId, "No council wizard active. Use /council to start.", { parseMode: "plain" });
25095
25236
  return;
@@ -25102,7 +25243,7 @@ ${rotationNote}`, { parseMode: "html" });
25102
25243
  return;
25103
25244
  }
25104
25245
  if (action === "start") {
25105
- const { getCouncilState: getCouncilState2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
25246
+ const { getCouncilState: getCouncilState2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports2));
25106
25247
  const state = getCouncilState2(chatId);
25107
25248
  if (!state || state.selected.size < 2) {
25108
25249
  await channel.sendText(chatId, "Select at least 2 models first.", { parseMode: "plain" });
@@ -25116,7 +25257,7 @@ Now type the question you want them to debate.`, { parseMode: "plain" });
25116
25257
  return;
25117
25258
  }
25118
25259
  if (action === "cancel") {
25119
- const { cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
25260
+ const { cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports2));
25120
25261
  cancelCouncil2(chatId);
25121
25262
  await channel.sendText(chatId, "Council cancelled.", { parseMode: "plain" });
25122
25263
  return;
@@ -26282,7 +26423,7 @@ You're still in discussion mode \u2014 try again or click a button to exit.`, {
26282
26423
  }
26283
26424
  }
26284
26425
  {
26285
- const { hasPendingCouncil: hasPendingCouncil2, getCouncilState: getCouncilState2, setCouncilQuestion: setCouncilQuestion2, cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports));
26426
+ const { hasPendingCouncil: hasPendingCouncil2, getCouncilState: getCouncilState2, setCouncilQuestion: setCouncilQuestion2, cancelCouncil: cancelCouncil2 } = await Promise.resolve().then(() => (init_wizard2(), wizard_exports2));
26286
26427
  if (hasPendingCouncil2(chatId)) {
26287
26428
  const state = getCouncilState2(chatId);
26288
26429
  if (state?.step === "question") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-claw",
3
- "version": "0.20.15",
3
+ "version": "0.20.17",
4
4
  "description": "CC-Claw: Personal AI assistant on Telegram — multi-backend (Claude, Gemini, Codex, Cursor), sub-agent orchestration, MCP management",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",