cc-claw 0.24.2 → 0.25.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.
- package/dist/cli.js +170 -30
- package/package.json +2 -2
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.
|
|
36
|
+
VERSION = true ? "0.25.0" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -4314,19 +4314,21 @@ function parseDbTimestamp(ts2) {
|
|
|
4314
4314
|
}
|
|
4315
4315
|
function appendToLog(chatId, userMessage, assistantResponse, backend2, model2, sessionId, messageType, toolName, toolInput, toolOutput) {
|
|
4316
4316
|
const now = Date.now();
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4317
|
+
getDb().transaction(() => {
|
|
4318
|
+
appendMessageLog(chatId, "user", userMessage, backend2 ?? null, model2 ?? null, sessionId ?? null);
|
|
4319
|
+
appendMessageLog(
|
|
4320
|
+
chatId,
|
|
4321
|
+
"assistant",
|
|
4322
|
+
assistantResponse,
|
|
4323
|
+
backend2 ?? null,
|
|
4324
|
+
model2 ?? null,
|
|
4325
|
+
sessionId ?? null,
|
|
4326
|
+
messageType ?? null,
|
|
4327
|
+
toolName ?? null,
|
|
4328
|
+
toolInput ?? null,
|
|
4329
|
+
toolOutput ?? null
|
|
4330
|
+
);
|
|
4331
|
+
})();
|
|
4330
4332
|
const existing = cache.get(chatId) ?? [];
|
|
4331
4333
|
existing.push(
|
|
4332
4334
|
{ role: "user", text: userMessage, timestamp: now },
|
|
@@ -6300,6 +6302,68 @@ var init_api_whitelist = __esm({
|
|
|
6300
6302
|
}
|
|
6301
6303
|
});
|
|
6302
6304
|
|
|
6305
|
+
// src/search/duckduckgo.ts
|
|
6306
|
+
import { search, SafeSearchType } from "duck-duck-scrape";
|
|
6307
|
+
function getCached(query) {
|
|
6308
|
+
const entry = cache3.get(query.toLowerCase().trim());
|
|
6309
|
+
if (entry && entry.expiry > Date.now()) return entry.results;
|
|
6310
|
+
if (entry) cache3.delete(query.toLowerCase().trim());
|
|
6311
|
+
return null;
|
|
6312
|
+
}
|
|
6313
|
+
function setCache(query, results) {
|
|
6314
|
+
const key = query.toLowerCase().trim();
|
|
6315
|
+
cache3.set(key, { results, expiry: Date.now() + CACHE_TTL_MS });
|
|
6316
|
+
if (cache3.size > 100) {
|
|
6317
|
+
const now = Date.now();
|
|
6318
|
+
for (const [k, v] of cache3) {
|
|
6319
|
+
if (v.expiry < now) cache3.delete(k);
|
|
6320
|
+
}
|
|
6321
|
+
if (cache3.size > 100) {
|
|
6322
|
+
const keys = [...cache3.keys()];
|
|
6323
|
+
for (let i = 0; i < keys.length - 100; i++) {
|
|
6324
|
+
cache3.delete(keys[i]);
|
|
6325
|
+
}
|
|
6326
|
+
}
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6329
|
+
async function searchWeb(query, maxResults = 5) {
|
|
6330
|
+
const effectiveMax = Math.min(Math.max(maxResults, 1), 10);
|
|
6331
|
+
const cached = getCached(query);
|
|
6332
|
+
if (cached) {
|
|
6333
|
+
log(`[search] Cache hit for: "${query.slice(0, 50)}"`);
|
|
6334
|
+
return { query, results: cached.slice(0, effectiveMax), cached: true };
|
|
6335
|
+
}
|
|
6336
|
+
log(`[search] Searching DuckDuckGo for: "${query.slice(0, 80)}"`);
|
|
6337
|
+
try {
|
|
6338
|
+
const ddgResults = await search(query, {
|
|
6339
|
+
safeSearch: SafeSearchType.MODERATE
|
|
6340
|
+
});
|
|
6341
|
+
if (ddgResults.noResults || !ddgResults.results?.length) {
|
|
6342
|
+
return { query, results: [], cached: false };
|
|
6343
|
+
}
|
|
6344
|
+
const results = ddgResults.results.slice(0, effectiveMax).map((r) => ({
|
|
6345
|
+
title: r.title,
|
|
6346
|
+
url: r.url,
|
|
6347
|
+
// strip HTML bold tags from description
|
|
6348
|
+
description: r.rawDescription?.replace(/<\/?b>/gi, "") || r.description?.replace(/<\/?b>/gi, "") || ""
|
|
6349
|
+
}));
|
|
6350
|
+
setCache(query, results);
|
|
6351
|
+
return { query, results, cached: false };
|
|
6352
|
+
} catch (err) {
|
|
6353
|
+
warn(`[search] DuckDuckGo search failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
6354
|
+
return { query, results: [], cached: false };
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
var CACHE_TTL_MS, cache3;
|
|
6358
|
+
var init_duckduckgo = __esm({
|
|
6359
|
+
"src/search/duckduckgo.ts"() {
|
|
6360
|
+
"use strict";
|
|
6361
|
+
init_log();
|
|
6362
|
+
CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
6363
|
+
cache3 = /* @__PURE__ */ new Map();
|
|
6364
|
+
}
|
|
6365
|
+
});
|
|
6366
|
+
|
|
6303
6367
|
// src/backends/api-tools.ts
|
|
6304
6368
|
import { tool } from "ai";
|
|
6305
6369
|
import { z } from "zod";
|
|
@@ -6470,10 +6534,42 @@ function createListFilesTool() {
|
|
|
6470
6534
|
}
|
|
6471
6535
|
});
|
|
6472
6536
|
}
|
|
6537
|
+
function createWebSearchTool() {
|
|
6538
|
+
return tool({
|
|
6539
|
+
description: "Search the web using DuckDuckGo for current information. Use this when you need up-to-date facts, news, documentation, or answers that may not be in your training data.",
|
|
6540
|
+
inputSchema: z.object({
|
|
6541
|
+
query: z.string().describe("The search query"),
|
|
6542
|
+
maxResults: z.number().optional().describe("Maximum results to return (default: 5, max: 10)")
|
|
6543
|
+
}),
|
|
6544
|
+
execute: async ({ query, maxResults }) => {
|
|
6545
|
+
log(`[api-tools] Web search: ${query.slice(0, 80)}`);
|
|
6546
|
+
try {
|
|
6547
|
+
const response = await searchWeb(query, maxResults ?? 5);
|
|
6548
|
+
if (response.results.length === 0) {
|
|
6549
|
+
return { query, results: [], message: "No results found." };
|
|
6550
|
+
}
|
|
6551
|
+
return {
|
|
6552
|
+
query,
|
|
6553
|
+
resultCount: response.results.length,
|
|
6554
|
+
results: response.results.map((r, i) => ({
|
|
6555
|
+
rank: i + 1,
|
|
6556
|
+
title: r.title,
|
|
6557
|
+
url: r.url,
|
|
6558
|
+
description: r.description
|
|
6559
|
+
}))
|
|
6560
|
+
};
|
|
6561
|
+
} catch (err) {
|
|
6562
|
+
return { error: `Search failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
6563
|
+
}
|
|
6564
|
+
}
|
|
6565
|
+
});
|
|
6566
|
+
}
|
|
6473
6567
|
function buildApiTools(chatId, permMode, mcpTools) {
|
|
6568
|
+
const webSearch = createWebSearchTool();
|
|
6474
6569
|
const readOnly = {
|
|
6475
6570
|
readFile: createReadFileTool(),
|
|
6476
|
-
listFiles: createListFilesTool()
|
|
6571
|
+
listFiles: createListFilesTool(),
|
|
6572
|
+
webSearch
|
|
6477
6573
|
};
|
|
6478
6574
|
const writable = {
|
|
6479
6575
|
...readOnly,
|
|
@@ -6513,6 +6609,7 @@ var init_api_tools = __esm({
|
|
|
6513
6609
|
init_paths();
|
|
6514
6610
|
init_api_whitelist();
|
|
6515
6611
|
init_log();
|
|
6612
|
+
init_duckduckgo();
|
|
6516
6613
|
execFileAsync2 = promisify2(execFile);
|
|
6517
6614
|
HOME = homedir3();
|
|
6518
6615
|
SENSITIVE_PATTERNS = [
|
|
@@ -6783,9 +6880,13 @@ var init_api_common = __esm({
|
|
|
6783
6880
|
signal,
|
|
6784
6881
|
messageHistory,
|
|
6785
6882
|
onToolAction,
|
|
6786
|
-
permMode: rawPermMode
|
|
6883
|
+
permMode: rawPermMode,
|
|
6884
|
+
thinkingLevel,
|
|
6885
|
+
onThinking
|
|
6787
6886
|
} = opts;
|
|
6788
6887
|
const permMode = rawPermMode ?? "safe";
|
|
6888
|
+
const reasoningEnabled = thinkingLevel ? !["off", "none"].includes(thinkingLevel) : false;
|
|
6889
|
+
const reasoningLevel = reasoningEnabled ? thinkingLevel === "low" ? "low" : thinkingLevel === "medium" ? "medium" : "high" : void 0;
|
|
6789
6890
|
const apiMessages = messageHistory ?? [
|
|
6790
6891
|
{ role: "user", content: prompt }
|
|
6791
6892
|
];
|
|
@@ -6815,6 +6916,8 @@ var init_api_common = __esm({
|
|
|
6815
6916
|
model: languageModel,
|
|
6816
6917
|
messages,
|
|
6817
6918
|
abortSignal,
|
|
6919
|
+
// Reasoning: pass through when enabled (model must support it)
|
|
6920
|
+
...reasoningLevel ? { reasoning: reasoningLevel } : {},
|
|
6818
6921
|
// Tool calling: provide tools and allow up to 5 steps
|
|
6819
6922
|
...hasTools ? {
|
|
6820
6923
|
tools: tools2,
|
|
@@ -6842,6 +6945,9 @@ var init_api_common = __esm({
|
|
|
6842
6945
|
if (chunk.type === "text-delta" && onStream) {
|
|
6843
6946
|
onStream(chunk.text);
|
|
6844
6947
|
}
|
|
6948
|
+
if (chunk.type === "reasoning-delta" && onThinking) {
|
|
6949
|
+
onThinking(chunk.text);
|
|
6950
|
+
}
|
|
6845
6951
|
}
|
|
6846
6952
|
});
|
|
6847
6953
|
let fullText = "";
|
|
@@ -8021,7 +8127,7 @@ var init_ollama2 = __esm({
|
|
|
8021
8127
|
const result = await this.streamDirectWithHistory(
|
|
8022
8128
|
cleanPrompt,
|
|
8023
8129
|
model2,
|
|
8024
|
-
"ollama",
|
|
8130
|
+
opts?.chatId ?? "ollama",
|
|
8025
8131
|
apiOpts
|
|
8026
8132
|
);
|
|
8027
8133
|
return {
|
|
@@ -8123,18 +8229,29 @@ var init_openrouter = __esm({
|
|
|
8123
8229
|
/**
|
|
8124
8230
|
* Execute a prompt via OpenRouter's REST API.
|
|
8125
8231
|
* Delegates to ApiBackendBase.streamDirectWithHistory() for streaming + history.
|
|
8126
|
-
* Maps
|
|
8232
|
+
* Maps StreamDirectOpts (CC-Claw standard) → ApiStreamDirectOpts (Vercel AI SDK layer),
|
|
8233
|
+
* including tool actions, permission mode, thinking tokens, and conversation history.
|
|
8127
8234
|
*/
|
|
8128
8235
|
async streamDirect(prompt, model2, opts) {
|
|
8236
|
+
const onToolAction = opts?.onToolAction ? (event) => {
|
|
8237
|
+
const input = event.input ?? {};
|
|
8238
|
+
const result2 = event.type === "tool_end" ? String(event.output ?? "") : void 0;
|
|
8239
|
+
opts.onToolAction(event.toolName, input, result2);
|
|
8240
|
+
} : void 0;
|
|
8129
8241
|
const apiOpts = {
|
|
8130
8242
|
timeoutMs: opts?.timeoutMs,
|
|
8131
8243
|
onStream: opts?.onStream,
|
|
8132
|
-
signal: opts?.signal
|
|
8244
|
+
signal: opts?.signal,
|
|
8245
|
+
messageHistory: opts?.messageHistory,
|
|
8246
|
+
onToolAction,
|
|
8247
|
+
permMode: opts?.permMode,
|
|
8248
|
+
thinkingLevel: opts?.thinkingLevel,
|
|
8249
|
+
onThinking: opts?.onThinking
|
|
8133
8250
|
};
|
|
8134
8251
|
const result = await this.streamDirectWithHistory(
|
|
8135
8252
|
prompt,
|
|
8136
8253
|
model2,
|
|
8137
|
-
"openrouter",
|
|
8254
|
+
opts?.chatId ?? "openrouter",
|
|
8138
8255
|
apiOpts
|
|
8139
8256
|
);
|
|
8140
8257
|
return {
|
|
@@ -8495,7 +8612,14 @@ function buildContextBridge(chatId, pairs = 15) {
|
|
|
8495
8612
|
const backendLabel = row.backend ?? "unknown";
|
|
8496
8613
|
const date = row.created_at.slice(0, 10);
|
|
8497
8614
|
const roleLabel = row.role === "user" ? "You" : "Assistant";
|
|
8498
|
-
|
|
8615
|
+
let line = `[${backendLabel} \xB7 ${date}] ${roleLabel}: ${row.content}`;
|
|
8616
|
+
if (row.tool_name) {
|
|
8617
|
+
const toolSummary = formatToolSummary(row.tool_name, row.tool_input, row.tool_output);
|
|
8618
|
+
if (toolSummary) {
|
|
8619
|
+
line += `
|
|
8620
|
+
${toolSummary}`;
|
|
8621
|
+
}
|
|
8622
|
+
}
|
|
8499
8623
|
if (totalChars + line.length > MAX_BRIDGE_CHARS) break;
|
|
8500
8624
|
lines.push(line);
|
|
8501
8625
|
totalChars += line.length;
|
|
@@ -8503,6 +8627,18 @@ function buildContextBridge(chatId, pairs = 15) {
|
|
|
8503
8627
|
lines.push(`[End of recent history \u2014 you are continuing this conversation]`);
|
|
8504
8628
|
return lines.join("\n");
|
|
8505
8629
|
}
|
|
8630
|
+
function formatToolSummary(toolName, toolInput, toolOutput) {
|
|
8631
|
+
const parts = [`\u{1F527} Tool: ${toolName}`];
|
|
8632
|
+
if (toolInput) {
|
|
8633
|
+
const truncInput = toolInput.length > TOOL_SUMMARY_MAX_CHARS ? toolInput.slice(0, TOOL_SUMMARY_MAX_CHARS) + "\u2026" : toolInput;
|
|
8634
|
+
parts.push(`Input: ${truncInput}`);
|
|
8635
|
+
}
|
|
8636
|
+
if (toolOutput) {
|
|
8637
|
+
const truncOutput = toolOutput.length > TOOL_SUMMARY_MAX_CHARS ? toolOutput.slice(0, TOOL_SUMMARY_MAX_CHARS) + "\u2026" : toolOutput;
|
|
8638
|
+
parts.push(`Result: ${truncOutput}`);
|
|
8639
|
+
}
|
|
8640
|
+
return parts.join(" | ");
|
|
8641
|
+
}
|
|
8506
8642
|
async function injectMemoryContext(userMessage, chatId) {
|
|
8507
8643
|
const provider = resolveProvider();
|
|
8508
8644
|
const useVectors = !!provider;
|
|
@@ -8597,7 +8733,7 @@ async function injectMemoryContext(userMessage, chatId) {
|
|
|
8597
8733
|
${lines.join("\n")}
|
|
8598
8734
|
[End memory context]`;
|
|
8599
8735
|
}
|
|
8600
|
-
var MEMORY_DECAY_RATE, SESSION_DECAY_RATE, BASE_VECTOR_TOP_K, BASE_FTS_TOP_K, FINAL_TOP_K_MEMORIES, FINAL_TOP_K_SESSIONS, MAX_MEMORY_CHARS, MAX_SESSION_CHARS, MAX_BRIDGE_CHARS, pendingContextBridges;
|
|
8736
|
+
var MEMORY_DECAY_RATE, SESSION_DECAY_RATE, BASE_VECTOR_TOP_K, BASE_FTS_TOP_K, FINAL_TOP_K_MEMORIES, FINAL_TOP_K_SESSIONS, MAX_MEMORY_CHARS, MAX_SESSION_CHARS, MAX_BRIDGE_CHARS, pendingContextBridges, TOOL_SUMMARY_MAX_CHARS;
|
|
8601
8737
|
var init_inject = __esm({
|
|
8602
8738
|
"src/memory/inject.ts"() {
|
|
8603
8739
|
"use strict";
|
|
@@ -8613,6 +8749,7 @@ var init_inject = __esm({
|
|
|
8613
8749
|
MAX_SESSION_CHARS = 800;
|
|
8614
8750
|
MAX_BRIDGE_CHARS = 48e3;
|
|
8615
8751
|
pendingContextBridges = /* @__PURE__ */ new Map();
|
|
8752
|
+
TOOL_SUMMARY_MAX_CHARS = 200;
|
|
8616
8753
|
}
|
|
8617
8754
|
});
|
|
8618
8755
|
|
|
@@ -10945,7 +11082,7 @@ function invalidateSkillCache() {
|
|
|
10945
11082
|
}
|
|
10946
11083
|
async function discoverAllSkills() {
|
|
10947
11084
|
const now = Date.now();
|
|
10948
|
-
if (cachedSkills !== null && now - cacheTimestamp <
|
|
11085
|
+
if (cachedSkills !== null && now - cacheTimestamp < CACHE_TTL_MS2) {
|
|
10949
11086
|
return cachedSkills;
|
|
10950
11087
|
}
|
|
10951
11088
|
if (pendingScan !== null) {
|
|
@@ -11129,7 +11266,7 @@ function resolveSkillForTask(skillName) {
|
|
|
11129
11266
|
}
|
|
11130
11267
|
return null;
|
|
11131
11268
|
}
|
|
11132
|
-
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS,
|
|
11269
|
+
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS, CACHE_TTL_MS2, cachedSkills, cacheTimestamp, pendingScan;
|
|
11133
11270
|
var init_discover = __esm({
|
|
11134
11271
|
"src/skills/discover.ts"() {
|
|
11135
11272
|
"use strict";
|
|
@@ -11149,7 +11286,7 @@ var init_discover = __esm({
|
|
|
11149
11286
|
join11(homedir4(), ".cursor", "skills-cursor")
|
|
11150
11287
|
]
|
|
11151
11288
|
};
|
|
11152
|
-
|
|
11289
|
+
CACHE_TTL_MS2 = 3e5;
|
|
11153
11290
|
cachedSkills = null;
|
|
11154
11291
|
cacheTimestamp = 0;
|
|
11155
11292
|
pendingScan = null;
|
|
@@ -11664,14 +11801,14 @@ function scanTemplates() {
|
|
|
11664
11801
|
}
|
|
11665
11802
|
}
|
|
11666
11803
|
function getTemplate(name) {
|
|
11667
|
-
if (Date.now() - lastScanMs >
|
|
11804
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS3) scanTemplates();
|
|
11668
11805
|
return templateCache.get(name) ?? null;
|
|
11669
11806
|
}
|
|
11670
11807
|
function listTemplates() {
|
|
11671
|
-
if (Date.now() - lastScanMs >
|
|
11808
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS3) scanTemplates();
|
|
11672
11809
|
return Array.from(templateCache.values());
|
|
11673
11810
|
}
|
|
11674
|
-
var templateCache, lastScanMs,
|
|
11811
|
+
var templateCache, lastScanMs, CACHE_TTL_MS3;
|
|
11675
11812
|
var init_loader2 = __esm({
|
|
11676
11813
|
"src/agents/templates/loader.ts"() {
|
|
11677
11814
|
"use strict";
|
|
@@ -11679,7 +11816,7 @@ var init_loader2 = __esm({
|
|
|
11679
11816
|
init_log();
|
|
11680
11817
|
templateCache = /* @__PURE__ */ new Map();
|
|
11681
11818
|
lastScanMs = 0;
|
|
11682
|
-
|
|
11819
|
+
CACHE_TTL_MS3 = 3e4;
|
|
11683
11820
|
}
|
|
11684
11821
|
});
|
|
11685
11822
|
|
|
@@ -16496,7 +16633,10 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
16496
16633
|
signal: abortController.signal,
|
|
16497
16634
|
messageHistory,
|
|
16498
16635
|
onToolAction,
|
|
16499
|
-
permMode: mode
|
|
16636
|
+
permMode: mode,
|
|
16637
|
+
thinkingLevel,
|
|
16638
|
+
onThinking,
|
|
16639
|
+
chatId
|
|
16500
16640
|
});
|
|
16501
16641
|
if (!isSyntheticChatId(chatId)) {
|
|
16502
16642
|
appendToLog(chatId, userMessage, sdResult.text, adapter.id, resolvedModel2, null);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-claw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
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",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"commander": "^14.0.3",
|
|
48
48
|
"croner": "^9.0.0",
|
|
49
49
|
"dotenv": "^16.4.7",
|
|
50
|
+
"duck-duck-scrape": "^2.2.7",
|
|
50
51
|
"grammy": "^1.35.0",
|
|
51
52
|
"js-tiktoken": "^1.0.21",
|
|
52
53
|
"marked": "^9.1.6",
|
|
@@ -60,7 +61,6 @@
|
|
|
60
61
|
},
|
|
61
62
|
"devDependencies": {
|
|
62
63
|
"@types/better-sqlite3": "^7.6.13",
|
|
63
|
-
"@types/bun": "^1.3.10",
|
|
64
64
|
"@types/marked-terminal": "^6.1.1",
|
|
65
65
|
"@types/node": "^25.3.5",
|
|
66
66
|
"@vitest/coverage-v8": "^4.0.18",
|