cc-claw 0.26.0 → 0.27.1
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 +1635 -1007
- 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.
|
|
36
|
+
VERSION = true ? "0.27.1" : (() => {
|
|
37
37
|
try {
|
|
38
38
|
return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
39
39
|
} catch {
|
|
@@ -417,8 +417,8 @@ function updateAgentResult(db3, id, opts) {
|
|
|
417
417
|
id
|
|
418
418
|
);
|
|
419
419
|
}
|
|
420
|
-
function updateAgentMcpsAdded(db3, id,
|
|
421
|
-
db3.prepare("UPDATE agents SET mcpsAdded = ? WHERE id = ?").run(JSON.stringify(
|
|
420
|
+
function updateAgentMcpsAdded(db3, id, mcps) {
|
|
421
|
+
db3.prepare("UPDATE agents SET mcpsAdded = ? WHERE id = ?").run(JSON.stringify(mcps), id);
|
|
422
422
|
}
|
|
423
423
|
function createTask(db3, opts) {
|
|
424
424
|
const result = db3.prepare(`
|
|
@@ -535,6 +535,7 @@ var store_exports2 = {};
|
|
|
535
535
|
__export(store_exports2, {
|
|
536
536
|
addMcpServer: () => addMcpServer,
|
|
537
537
|
addPropagation: () => addPropagation,
|
|
538
|
+
getEnabledMcps: () => getEnabledMcps,
|
|
538
539
|
getMcpServer: () => getMcpServer,
|
|
539
540
|
getPropagationsForRunner: () => getPropagationsForRunner,
|
|
540
541
|
initMcpTables: () => initMcpTables,
|
|
@@ -637,6 +638,11 @@ function getMcpServer(db3, name) {
|
|
|
637
638
|
function listMcpServers(db3) {
|
|
638
639
|
return db3.prepare("SELECT * FROM mcp_servers ORDER BY name").all();
|
|
639
640
|
}
|
|
641
|
+
function getEnabledMcps(db3) {
|
|
642
|
+
return db3.prepare(
|
|
643
|
+
"SELECT * FROM mcp_servers WHERE enabledByDefault = 1 ORDER BY name"
|
|
644
|
+
).all();
|
|
645
|
+
}
|
|
640
646
|
function addPropagation(db3, mcpName, runnerId, scope) {
|
|
641
647
|
db3.prepare(`
|
|
642
648
|
INSERT OR IGNORE INTO mcp_propagation (mcpName, runnerId, scope, addedAt) VALUES (?, ?, ?, datetime('now'))
|
|
@@ -1770,6 +1776,12 @@ function initSchema(db3) {
|
|
|
1770
1776
|
whitelist TEXT
|
|
1771
1777
|
);
|
|
1772
1778
|
`);
|
|
1779
|
+
db3.exec(`
|
|
1780
|
+
CREATE TABLE IF NOT EXISTS chat_api_web_search (
|
|
1781
|
+
chat_id TEXT PRIMARY KEY,
|
|
1782
|
+
enabled INTEGER DEFAULT 1
|
|
1783
|
+
);
|
|
1784
|
+
`);
|
|
1773
1785
|
db3.exec(`
|
|
1774
1786
|
CREATE TABLE IF NOT EXISTS api_backend_models (
|
|
1775
1787
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -5174,7 +5186,6 @@ var init_claude = __esm({
|
|
|
5174
5186
|
switch (opts.permMode) {
|
|
5175
5187
|
case "plan":
|
|
5176
5188
|
args.push("--permission-mode", "plan");
|
|
5177
|
-
args.push("--strict-mcp-config");
|
|
5178
5189
|
break;
|
|
5179
5190
|
case "safe":
|
|
5180
5191
|
args.push("--permission-mode", "bypassPermissions");
|
|
@@ -6276,8 +6287,11 @@ __export(api_whitelist_exports, {
|
|
|
6276
6287
|
addCliToWhitelist: () => addCliToWhitelist,
|
|
6277
6288
|
clearApiCliWhitelist: () => clearApiCliWhitelist,
|
|
6278
6289
|
getApiCliWhitelist: () => getApiCliWhitelist,
|
|
6290
|
+
getApiWebSearchEnabled: () => getApiWebSearchEnabled,
|
|
6279
6291
|
removeCliFromWhitelist: () => removeCliFromWhitelist,
|
|
6280
6292
|
setApiCliWhitelist: () => setApiCliWhitelist,
|
|
6293
|
+
setApiWebSearchEnabled: () => setApiWebSearchEnabled,
|
|
6294
|
+
toggleApiWebSearchEnabled: () => toggleApiWebSearchEnabled,
|
|
6281
6295
|
updateCliCapabilities: () => updateCliCapabilities
|
|
6282
6296
|
});
|
|
6283
6297
|
function getApiCliWhitelist(chatId) {
|
|
@@ -6328,6 +6342,28 @@ function updateCliCapabilities(chatId, cli, capabilities) {
|
|
|
6328
6342
|
function clearApiCliWhitelist(chatId) {
|
|
6329
6343
|
getDb().prepare("DELETE FROM chat_api_cli_whitelist WHERE chat_id = ?").run(chatId);
|
|
6330
6344
|
}
|
|
6345
|
+
function getApiWebSearchEnabled(chatId) {
|
|
6346
|
+
try {
|
|
6347
|
+
const row = getDb().prepare(
|
|
6348
|
+
"SELECT enabled FROM chat_api_web_search WHERE chat_id = ?"
|
|
6349
|
+
).get(chatId);
|
|
6350
|
+
return row ? row.enabled !== 0 : true;
|
|
6351
|
+
} catch {
|
|
6352
|
+
return true;
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
function setApiWebSearchEnabled(chatId, enabled) {
|
|
6356
|
+
getDb().prepare(`
|
|
6357
|
+
INSERT INTO chat_api_web_search (chat_id, enabled)
|
|
6358
|
+
VALUES (?, ?)
|
|
6359
|
+
ON CONFLICT(chat_id) DO UPDATE SET enabled = ?
|
|
6360
|
+
`).run(chatId, enabled ? 1 : 0, enabled ? 1 : 0);
|
|
6361
|
+
}
|
|
6362
|
+
function toggleApiWebSearchEnabled(chatId) {
|
|
6363
|
+
const next = !getApiWebSearchEnabled(chatId);
|
|
6364
|
+
setApiWebSearchEnabled(chatId, next);
|
|
6365
|
+
return next;
|
|
6366
|
+
}
|
|
6331
6367
|
var init_api_whitelist = __esm({
|
|
6332
6368
|
"src/memory/api-whitelist.ts"() {
|
|
6333
6369
|
"use strict";
|
|
@@ -6410,29 +6446,32 @@ function isSensitivePath(filePath) {
|
|
|
6410
6446
|
if (SENSITIVE_EXACT.has(normalized)) return true;
|
|
6411
6447
|
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
6412
6448
|
}
|
|
6413
|
-
function createRestrictedBashTool(chatId) {
|
|
6449
|
+
function createRestrictedBashTool(chatId, permMode, whitelist) {
|
|
6450
|
+
const isYolo = permMode === "yolo";
|
|
6414
6451
|
return tool({
|
|
6415
|
-
description:
|
|
6452
|
+
description: isYolo ? `Run any shell command. Use this for ALL external CLI tools. No restrictions. Format: restrictedBash({command: 'gsearch "query" --type news'})` : "Run a whitelisted shell command. Use this for ANY external CLI tool \u2014 do NOT call CLIs as separate tools by name, always route them through restrictedBash. Format: restrictedBash({command: 'toolname args...'})",
|
|
6416
6453
|
inputSchema: z.object({
|
|
6417
6454
|
command: z.string().describe("The shell command to run")
|
|
6418
6455
|
}),
|
|
6419
6456
|
execute: async ({ command }) => {
|
|
6420
|
-
const whitelist = getApiCliWhitelist(chatId);
|
|
6421
6457
|
const trimmed = command.trim();
|
|
6422
6458
|
const firstWord = trimmed.split(/\s+/)[0];
|
|
6423
6459
|
if (!firstWord) {
|
|
6424
6460
|
return { error: "Empty command" };
|
|
6425
6461
|
}
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
const
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6462
|
+
if (!isYolo) {
|
|
6463
|
+
const list = whitelist ?? getApiCliWhitelist(chatId);
|
|
6464
|
+
const entry = list.find((w) => w.cli === firstWord);
|
|
6465
|
+
if (!entry) {
|
|
6466
|
+
const allowed = list.map((w) => w.cli).join(", ") || "(none)";
|
|
6467
|
+
return {
|
|
6468
|
+
error: `Command "${firstWord}" is not whitelisted. Allowed commands: ${allowed}. IMPORTANT: Stop retrying. Tell the user exactly this: "I tried to run '${firstWord}' but it's not in your approved tools list. Go to /tools \u2192 Add Command \u2192 type '${firstWord}' to allow it, then ask me again."`
|
|
6469
|
+
};
|
|
6470
|
+
}
|
|
6471
|
+
const dangerousPatterns = /[;|&`$(){}]|>>|<<|\n/;
|
|
6472
|
+
if (dangerousPatterns.test(trimmed.slice(firstWord.length))) {
|
|
6473
|
+
return { output: `Error: Command contains disallowed shell operators. Only simple arguments are allowed with whitelisted commands.`, exitCode: 1 };
|
|
6474
|
+
}
|
|
6436
6475
|
}
|
|
6437
6476
|
log(`[api-tools] Executing whitelisted command: ${trimmed.slice(0, 100)}`);
|
|
6438
6477
|
try {
|
|
@@ -6569,13 +6608,19 @@ function createListFilesTool() {
|
|
|
6569
6608
|
}
|
|
6570
6609
|
function createWebSearchTool() {
|
|
6571
6610
|
return tool({
|
|
6572
|
-
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.",
|
|
6611
|
+
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. If whitelisted search CLIs (pwm, gemcli) are available, prefer those instead.",
|
|
6573
6612
|
inputSchema: z.object({
|
|
6574
6613
|
query: z.string().describe("The search query"),
|
|
6575
6614
|
maxResults: z.number().optional().describe("Maximum results to return (default: 5, max: 10)")
|
|
6576
6615
|
}),
|
|
6577
6616
|
execute: async ({ query, maxResults }) => {
|
|
6578
6617
|
log(`[api-tools] Web search: ${query.slice(0, 80)}`);
|
|
6618
|
+
const now = Date.now();
|
|
6619
|
+
const gap = now - lastDdgSearchAt;
|
|
6620
|
+
if (gap < DDG_MIN_GAP_MS) {
|
|
6621
|
+
await new Promise((r) => setTimeout(r, DDG_MIN_GAP_MS - gap));
|
|
6622
|
+
}
|
|
6623
|
+
lastDdgSearchAt = Date.now();
|
|
6579
6624
|
try {
|
|
6580
6625
|
const response = await searchWeb(query, maxResults ?? 5);
|
|
6581
6626
|
if (response.results.length === 0) {
|
|
@@ -6597,27 +6642,26 @@ function createWebSearchTool() {
|
|
|
6597
6642
|
}
|
|
6598
6643
|
});
|
|
6599
6644
|
}
|
|
6600
|
-
function buildApiTools(chatId, permMode, mcpTools) {
|
|
6601
|
-
const
|
|
6645
|
+
function buildApiTools(chatId, permMode, mcpTools, webSearchEnabled) {
|
|
6646
|
+
const searchEnabled = webSearchEnabled ?? getApiWebSearchEnabled(chatId);
|
|
6602
6647
|
const readOnly = {
|
|
6603
6648
|
readFile: createReadFileTool(),
|
|
6604
6649
|
listFiles: createListFilesTool(),
|
|
6605
|
-
webSearch
|
|
6606
|
-
};
|
|
6607
|
-
const writable = {
|
|
6608
|
-
...readOnly,
|
|
6609
|
-
restrictedBash: createRestrictedBashTool(chatId)
|
|
6650
|
+
...searchEnabled ? { webSearch: createWebSearchTool() } : {}
|
|
6610
6651
|
};
|
|
6611
6652
|
if (mcpTools) {
|
|
6612
|
-
Object.assign(writable, mcpTools);
|
|
6613
6653
|
Object.assign(readOnly, filterReadOnlyMcpTools(mcpTools));
|
|
6614
6654
|
}
|
|
6615
6655
|
switch (permMode) {
|
|
6616
|
-
case "yolo":
|
|
6617
|
-
|
|
6656
|
+
case "yolo": {
|
|
6657
|
+
const all = { ...readOnly, ...mcpTools ?? {}, restrictedBash: createRestrictedBashTool(chatId, permMode) };
|
|
6658
|
+
return all;
|
|
6659
|
+
}
|
|
6618
6660
|
case "safe": {
|
|
6619
6661
|
const whitelist = getApiCliWhitelist(chatId);
|
|
6620
|
-
|
|
6662
|
+
const base = { ...readOnly, ...mcpTools ?? {} };
|
|
6663
|
+
if (whitelist.length === 0) return base;
|
|
6664
|
+
return { ...base, restrictedBash: createRestrictedBashTool(chatId, permMode, whitelist) };
|
|
6621
6665
|
}
|
|
6622
6666
|
case "plan":
|
|
6623
6667
|
return readOnly;
|
|
@@ -6635,7 +6679,7 @@ function filterReadOnlyMcpTools(mcpTools) {
|
|
|
6635
6679
|
}
|
|
6636
6680
|
return filtered;
|
|
6637
6681
|
}
|
|
6638
|
-
var execFileAsync2, HOME, SENSITIVE_PATTERNS, SENSITIVE_EXACT, MAX_READ_BYTES;
|
|
6682
|
+
var execFileAsync2, HOME, SENSITIVE_PATTERNS, SENSITIVE_EXACT, MAX_READ_BYTES, lastDdgSearchAt, DDG_MIN_GAP_MS;
|
|
6639
6683
|
var init_api_tools = __esm({
|
|
6640
6684
|
"src/backends/api-tools.ts"() {
|
|
6641
6685
|
"use strict";
|
|
@@ -6667,6 +6711,151 @@ var init_api_tools = __esm({
|
|
|
6667
6711
|
normalize(resolve(CC_CLAW_HOME, ".env"))
|
|
6668
6712
|
]);
|
|
6669
6713
|
MAX_READ_BYTES = 1e5;
|
|
6714
|
+
lastDdgSearchAt = 0;
|
|
6715
|
+
DDG_MIN_GAP_MS = 3e3;
|
|
6716
|
+
}
|
|
6717
|
+
});
|
|
6718
|
+
|
|
6719
|
+
// src/mcps/pool.ts
|
|
6720
|
+
var pool_exports = {};
|
|
6721
|
+
__export(pool_exports, {
|
|
6722
|
+
McpConnectionPool: () => McpConnectionPool,
|
|
6723
|
+
getMcpPool: () => getMcpPool,
|
|
6724
|
+
shutdownMcpPool: () => shutdownMcpPool
|
|
6725
|
+
});
|
|
6726
|
+
import { createMCPClient } from "@ai-sdk/mcp";
|
|
6727
|
+
import { Experimental_StdioMCPTransport } from "@ai-sdk/mcp/mcp-stdio";
|
|
6728
|
+
function getMcpPool() {
|
|
6729
|
+
if (!poolInstance) poolInstance = new McpConnectionPool();
|
|
6730
|
+
return poolInstance;
|
|
6731
|
+
}
|
|
6732
|
+
async function shutdownMcpPool() {
|
|
6733
|
+
if (poolInstance) {
|
|
6734
|
+
await poolInstance.shutdown();
|
|
6735
|
+
poolInstance = null;
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
var MAX_RETRIES, BASE_BACKOFF_MS, MAX_BACKOFF_MS, McpConnectionPool, poolInstance;
|
|
6739
|
+
var init_pool = __esm({
|
|
6740
|
+
"src/mcps/pool.ts"() {
|
|
6741
|
+
"use strict";
|
|
6742
|
+
init_env();
|
|
6743
|
+
init_log();
|
|
6744
|
+
MAX_RETRIES = 5;
|
|
6745
|
+
BASE_BACKOFF_MS = 2e3;
|
|
6746
|
+
MAX_BACKOFF_MS = 6e4;
|
|
6747
|
+
McpConnectionPool = class {
|
|
6748
|
+
connections = /* @__PURE__ */ new Map();
|
|
6749
|
+
connecting = /* @__PURE__ */ new Map();
|
|
6750
|
+
/** Cached merged tool set — invalidated on connect/disconnect. */
|
|
6751
|
+
cachedAllTools = null;
|
|
6752
|
+
/**
|
|
6753
|
+
* Connect to an MCP server and cache the connection.
|
|
6754
|
+
* Returns the tool set. Reuses existing connection if already connected.
|
|
6755
|
+
*/
|
|
6756
|
+
async connect(name, config2) {
|
|
6757
|
+
const existing = this.connections.get(name);
|
|
6758
|
+
if (existing) {
|
|
6759
|
+
existing.lastUsedAt = Date.now();
|
|
6760
|
+
return existing.tools;
|
|
6761
|
+
}
|
|
6762
|
+
const inflight = this.connecting.get(name);
|
|
6763
|
+
if (inflight) {
|
|
6764
|
+
const conn = await inflight;
|
|
6765
|
+
return conn?.tools ?? {};
|
|
6766
|
+
}
|
|
6767
|
+
const promise = this.doConnect(name, config2);
|
|
6768
|
+
this.connecting.set(name, promise);
|
|
6769
|
+
try {
|
|
6770
|
+
const conn = await promise;
|
|
6771
|
+
return conn?.tools ?? {};
|
|
6772
|
+
} finally {
|
|
6773
|
+
this.connecting.delete(name);
|
|
6774
|
+
}
|
|
6775
|
+
}
|
|
6776
|
+
async doConnect(name, config2, retryCount = 0) {
|
|
6777
|
+
try {
|
|
6778
|
+
const transport = new Experimental_StdioMCPTransport({
|
|
6779
|
+
command: config2.command,
|
|
6780
|
+
args: config2.args,
|
|
6781
|
+
env: buildBaseEnv(config2.env)
|
|
6782
|
+
});
|
|
6783
|
+
const client = await createMCPClient({ transport });
|
|
6784
|
+
const tools2 = await client.tools();
|
|
6785
|
+
const conn = {
|
|
6786
|
+
name,
|
|
6787
|
+
client,
|
|
6788
|
+
tools: tools2,
|
|
6789
|
+
config: config2,
|
|
6790
|
+
connectedAt: Date.now(),
|
|
6791
|
+
lastUsedAt: Date.now()
|
|
6792
|
+
};
|
|
6793
|
+
this.connections.set(name, conn);
|
|
6794
|
+
this.cachedAllTools = null;
|
|
6795
|
+
log(`[mcp-pool] Connected to ${name} (${Object.keys(tools2).length} tools)`);
|
|
6796
|
+
return conn;
|
|
6797
|
+
} catch (err) {
|
|
6798
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
6799
|
+
warn(`[mcp-pool] Failed to connect to ${name}: ${msg}`);
|
|
6800
|
+
if (retryCount < MAX_RETRIES) {
|
|
6801
|
+
const backoff = Math.min(BASE_BACKOFF_MS * 2 ** retryCount, MAX_BACKOFF_MS);
|
|
6802
|
+
log(`[mcp-pool] Retrying ${name} in ${backoff}ms (attempt ${retryCount + 1}/${MAX_RETRIES})`);
|
|
6803
|
+
await new Promise((r) => setTimeout(r, backoff));
|
|
6804
|
+
return this.doConnect(name, config2, retryCount + 1);
|
|
6805
|
+
}
|
|
6806
|
+
warn(`[mcp-pool] Giving up on ${name} after ${MAX_RETRIES} retries`);
|
|
6807
|
+
return null;
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
/** Get tools for a specific MCP. Returns empty object if not connected. */
|
|
6811
|
+
async getTools(name) {
|
|
6812
|
+
const conn = this.connections.get(name);
|
|
6813
|
+
if (conn) {
|
|
6814
|
+
conn.lastUsedAt = Date.now();
|
|
6815
|
+
return conn.tools;
|
|
6816
|
+
}
|
|
6817
|
+
return {};
|
|
6818
|
+
}
|
|
6819
|
+
/** Get aggregated tools from ALL connected MCPs. Result is cached until a connect/disconnect. */
|
|
6820
|
+
async getAllTools() {
|
|
6821
|
+
if (this.cachedAllTools) return this.cachedAllTools;
|
|
6822
|
+
const all = {};
|
|
6823
|
+
for (const conn of this.connections.values()) {
|
|
6824
|
+
conn.lastUsedAt = Date.now();
|
|
6825
|
+
Object.assign(all, conn.tools);
|
|
6826
|
+
}
|
|
6827
|
+
this.cachedAllTools = all;
|
|
6828
|
+
return all;
|
|
6829
|
+
}
|
|
6830
|
+
/** Disconnect a specific MCP and remove from pool. */
|
|
6831
|
+
async disconnect(name) {
|
|
6832
|
+
const conn = this.connections.get(name);
|
|
6833
|
+
if (!conn) return;
|
|
6834
|
+
try {
|
|
6835
|
+
await conn.client.close();
|
|
6836
|
+
} catch (err) {
|
|
6837
|
+
warn(`[mcp-pool] Error closing ${name}: ${err instanceof Error ? err.message : err}`);
|
|
6838
|
+
}
|
|
6839
|
+
this.connections.delete(name);
|
|
6840
|
+
this.cachedAllTools = null;
|
|
6841
|
+
log(`[mcp-pool] Disconnected ${name}`);
|
|
6842
|
+
}
|
|
6843
|
+
/** Close all connections. Called on SIGTERM. */
|
|
6844
|
+
async shutdown() {
|
|
6845
|
+
const names = [...this.connections.keys()];
|
|
6846
|
+
await Promise.allSettled(names.map((n) => this.disconnect(n)));
|
|
6847
|
+
log(`[mcp-pool] Shutdown complete (${names.length} connection(s) closed)`);
|
|
6848
|
+
}
|
|
6849
|
+
/** Check if a specific MCP is currently connected. */
|
|
6850
|
+
isConnected(name) {
|
|
6851
|
+
return this.connections.has(name);
|
|
6852
|
+
}
|
|
6853
|
+
/** List names of all connected MCPs. */
|
|
6854
|
+
listConnected() {
|
|
6855
|
+
return [...this.connections.keys()];
|
|
6856
|
+
}
|
|
6857
|
+
};
|
|
6858
|
+
poolInstance = null;
|
|
6670
6859
|
}
|
|
6671
6860
|
});
|
|
6672
6861
|
|
|
@@ -6714,6 +6903,17 @@ function writeMcpConfigFile(config2) {
|
|
|
6714
6903
|
}
|
|
6715
6904
|
return configPath;
|
|
6716
6905
|
}
|
|
6906
|
+
function writeUnifiedMcpConfigFile(config2) {
|
|
6907
|
+
const filePath = join8(MCP_CONFIG_DIR, "mcp-unified.json");
|
|
6908
|
+
const content = JSON.stringify(config2, null, 2);
|
|
6909
|
+
if (lastWrittenConfig.get(filePath) === content) return filePath;
|
|
6910
|
+
if (!existsSync9(MCP_CONFIG_DIR)) {
|
|
6911
|
+
mkdirSync3(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
6912
|
+
}
|
|
6913
|
+
writeFileSync2(filePath, content, { mode: 384 });
|
|
6914
|
+
lastWrittenConfig.set(filePath, content);
|
|
6915
|
+
return filePath;
|
|
6916
|
+
}
|
|
6717
6917
|
function deleteMcpConfigFile(mcpName) {
|
|
6718
6918
|
const safeName = mcpName.replace(/[^a-zA-Z0-9-]/g, "_");
|
|
6719
6919
|
const configPath = join8(MCP_CONFIG_DIR, `mcp-${safeName}.json`);
|
|
@@ -6751,35 +6951,27 @@ var init_mcp_config = __esm({
|
|
|
6751
6951
|
});
|
|
6752
6952
|
|
|
6753
6953
|
// src/backends/api-mcp.ts
|
|
6754
|
-
|
|
6755
|
-
import { Experimental_StdioMCPTransport } from "@ai-sdk/mcp/mcp-stdio";
|
|
6756
|
-
var ALLOWED_MCP_TOOL_PREFIXES, McpClientManager;
|
|
6954
|
+
var McpClientManager;
|
|
6757
6955
|
var init_api_mcp = __esm({
|
|
6758
6956
|
"src/backends/api-mcp.ts"() {
|
|
6759
6957
|
"use strict";
|
|
6958
|
+
init_pool();
|
|
6959
|
+
init_store2();
|
|
6960
|
+
init_store5();
|
|
6760
6961
|
init_mcp_config();
|
|
6761
6962
|
init_paths();
|
|
6762
6963
|
init_log();
|
|
6763
|
-
ALLOWED_MCP_TOOL_PREFIXES = [
|
|
6764
|
-
"cc_claw_memory",
|
|
6765
|
-
"cc_claw_schedule",
|
|
6766
|
-
"cc_claw_comms"
|
|
6767
|
-
];
|
|
6768
6964
|
McpClientManager = class {
|
|
6769
6965
|
constructor(chatId, port) {
|
|
6770
6966
|
this.chatId = chatId;
|
|
6771
6967
|
this.port = port;
|
|
6772
6968
|
}
|
|
6773
|
-
client = null;
|
|
6774
|
-
/**
|
|
6775
|
-
* Check if the dashboard (and thus MCP server) is available.
|
|
6776
|
-
* The dashboard must be running for the MCP server to work.
|
|
6777
|
-
*/
|
|
6778
6969
|
isDashboardAvailable() {
|
|
6779
6970
|
return process.env.DASHBOARD_ENABLED === "1";
|
|
6780
6971
|
}
|
|
6781
6972
|
/**
|
|
6782
|
-
*
|
|
6973
|
+
* Get all MCP tools from the connection pool.
|
|
6974
|
+
* Lazily connects MCPs not yet in the pool.
|
|
6783
6975
|
* Returns empty object if dashboard is unavailable.
|
|
6784
6976
|
*/
|
|
6785
6977
|
async getTools() {
|
|
@@ -6788,79 +6980,69 @@ var init_api_mcp = __esm({
|
|
|
6788
6980
|
return {};
|
|
6789
6981
|
}
|
|
6790
6982
|
try {
|
|
6983
|
+
const pool = getMcpPool();
|
|
6984
|
+
const db3 = getDb();
|
|
6791
6985
|
const token = readApiToken();
|
|
6792
6986
|
if (!token) {
|
|
6793
|
-
warn("[api-mcp] No API token
|
|
6794
|
-
return {};
|
|
6987
|
+
warn("[api-mcp] No API token \u2014 orchestrator MCP unavailable");
|
|
6795
6988
|
}
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6989
|
+
if (token) {
|
|
6990
|
+
const orchConfig = generateOrchestratorMcpConfig({
|
|
6991
|
+
chatId: this.chatId,
|
|
6992
|
+
agentId: "api-backend",
|
|
6993
|
+
token,
|
|
6994
|
+
port: this.port ?? process.env.DASHBOARD_PORT ?? "3141"
|
|
6995
|
+
});
|
|
6996
|
+
if (!pool.isConnected(orchConfig.name)) {
|
|
6997
|
+
await pool.connect(orchConfig.name, {
|
|
6998
|
+
command: orchConfig.command,
|
|
6999
|
+
args: orchConfig.args ?? [],
|
|
7000
|
+
env: orchConfig.env ?? {}
|
|
7001
|
+
});
|
|
7002
|
+
}
|
|
6805
7003
|
}
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
7004
|
+
const mcps = getEnabledMcps(db3);
|
|
7005
|
+
for (const mcp2 of mcps) {
|
|
7006
|
+
if (mcp2.transport !== "stdio" || !mcp2.command) continue;
|
|
7007
|
+
if (pool.isConnected(mcp2.name)) continue;
|
|
7008
|
+
let args = [];
|
|
7009
|
+
let env = {};
|
|
7010
|
+
try {
|
|
7011
|
+
args = mcp2.args ? JSON.parse(mcp2.args) : [];
|
|
7012
|
+
env = mcp2.env ? JSON.parse(mcp2.env) : {};
|
|
7013
|
+
} catch {
|
|
7014
|
+
warn(`[api-mcp] Skipping ${mcp2.name}: malformed args/env JSON in DB`);
|
|
7015
|
+
continue;
|
|
7016
|
+
}
|
|
7017
|
+
const config2 = {
|
|
7018
|
+
command: mcp2.command,
|
|
7019
|
+
args,
|
|
7020
|
+
env
|
|
7021
|
+
};
|
|
7022
|
+
pool.connect(mcp2.name, config2).catch((err) => {
|
|
7023
|
+
warn(`[api-mcp] Failed to connect ${mcp2.name}: ${err instanceof Error ? err.message : err}`);
|
|
7024
|
+
});
|
|
6810
7025
|
}
|
|
6811
|
-
const
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
env: cleanEnv
|
|
6815
|
-
});
|
|
6816
|
-
this.client = await createMCPClient({ transport });
|
|
6817
|
-
const allTools = await this.client.tools();
|
|
6818
|
-
return this.filterTools(allTools);
|
|
7026
|
+
const tools2 = await pool.getAllTools();
|
|
7027
|
+
log(`[api-mcp] Loaded ${Object.keys(tools2).length} tool(s) from pool`);
|
|
7028
|
+
return tools2;
|
|
6819
7029
|
} catch (err) {
|
|
6820
|
-
warn(
|
|
6821
|
-
"[api-mcp] Failed to connect to MCP server:",
|
|
6822
|
-
err instanceof Error ? err.message : String(err)
|
|
6823
|
-
);
|
|
7030
|
+
warn("[api-mcp] Failed to get tools from pool:", err instanceof Error ? err.message : String(err));
|
|
6824
7031
|
return {};
|
|
6825
7032
|
}
|
|
6826
7033
|
}
|
|
6827
7034
|
/**
|
|
6828
|
-
*
|
|
6829
|
-
*
|
|
7035
|
+
* No-op — pool connections are persistent, managed by the pool lifecycle.
|
|
7036
|
+
* close() is called by api-common.ts in a finally block; keeping it safe to call.
|
|
6830
7037
|
*/
|
|
6831
7038
|
async close() {
|
|
6832
|
-
if (this.client) {
|
|
6833
|
-
try {
|
|
6834
|
-
await this.client.close();
|
|
6835
|
-
} catch (err) {
|
|
6836
|
-
warn(
|
|
6837
|
-
"[api-mcp] Error closing MCP client:",
|
|
6838
|
-
err instanceof Error ? err.message : String(err)
|
|
6839
|
-
);
|
|
6840
|
-
}
|
|
6841
|
-
this.client = null;
|
|
6842
|
-
}
|
|
6843
|
-
}
|
|
6844
|
-
/**
|
|
6845
|
-
* Filter MCP tools to only allowed prefixes.
|
|
6846
|
-
* Excludes agent orchestration tools that don't work with API backends.
|
|
6847
|
-
*/
|
|
6848
|
-
filterTools(allTools) {
|
|
6849
|
-
const filtered = {};
|
|
6850
|
-
for (const [name, t] of Object.entries(allTools)) {
|
|
6851
|
-
if (ALLOWED_MCP_TOOL_PREFIXES.some((prefix) => name.startsWith(prefix))) {
|
|
6852
|
-
filtered[name] = t;
|
|
6853
|
-
}
|
|
6854
|
-
}
|
|
6855
|
-
log(`[api-mcp] Loaded ${Object.keys(filtered).length} MCP tools (of ${Object.keys(allTools).length} total)`);
|
|
6856
|
-
return filtered;
|
|
6857
7039
|
}
|
|
6858
7040
|
};
|
|
6859
7041
|
}
|
|
6860
7042
|
});
|
|
6861
7043
|
|
|
6862
7044
|
// src/backends/api-common.ts
|
|
6863
|
-
import { streamText, stepCountIs } from "ai";
|
|
7045
|
+
import { streamText, stepCountIs, NoOutputGeneratedError } from "ai";
|
|
6864
7046
|
function toModelMessage(msg) {
|
|
6865
7047
|
switch (msg.role) {
|
|
6866
7048
|
case "system":
|
|
@@ -6883,6 +7065,7 @@ var init_api_common = __esm({
|
|
|
6883
7065
|
"use strict";
|
|
6884
7066
|
init_api_context();
|
|
6885
7067
|
init_api_tools();
|
|
7068
|
+
init_api_whitelist();
|
|
6886
7069
|
init_api_mcp();
|
|
6887
7070
|
init_log();
|
|
6888
7071
|
ApiBackendBase = class {
|
|
@@ -6933,7 +7116,7 @@ var init_api_common = __esm({
|
|
|
6933
7116
|
} catch (err) {
|
|
6934
7117
|
log(`[api-common] MCP tools unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
6935
7118
|
}
|
|
6936
|
-
const tools2 = buildApiTools(chatId, permMode, mcpTools);
|
|
7119
|
+
const tools2 = buildApiTools(chatId, permMode, mcpTools, getApiWebSearchEnabled(chatId));
|
|
6937
7120
|
const hasTools = Object.keys(tools2).length > 0;
|
|
6938
7121
|
let abortSignal = signal;
|
|
6939
7122
|
let timeoutHandle;
|
|
@@ -6957,7 +7140,7 @@ var init_api_common = __esm({
|
|
|
6957
7140
|
// Tool calling: provide tools and allow up to 5 steps
|
|
6958
7141
|
...hasTools ? {
|
|
6959
7142
|
tools: tools2,
|
|
6960
|
-
stopWhen: stepCountIs(
|
|
7143
|
+
stopWhen: stepCountIs(15),
|
|
6961
7144
|
onStepFinish: ({ toolCalls, toolResults }) => {
|
|
6962
7145
|
if (onToolAction && toolCalls.length > 0) {
|
|
6963
7146
|
for (const tc of toolCalls) {
|
|
@@ -7005,6 +7188,9 @@ var init_api_common = __esm({
|
|
|
7005
7188
|
if (abortSignal?.aborted || signal?.aborted || err instanceof Error && (err.name === "AbortError" || err.message.toLowerCase().includes("abort") || err.message.toLowerCase().includes("cancel"))) {
|
|
7006
7189
|
return { text: "", cost: null };
|
|
7007
7190
|
}
|
|
7191
|
+
if (NoOutputGeneratedError.isInstance(err)) {
|
|
7192
|
+
return { text: "", cost: null };
|
|
7193
|
+
}
|
|
7008
7194
|
throw err;
|
|
7009
7195
|
} finally {
|
|
7010
7196
|
if (timeoutHandle !== void 0) clearTimeout(timeoutHandle);
|
|
@@ -8281,7 +8467,7 @@ var init_ollama2 = __esm({
|
|
|
8281
8467
|
});
|
|
8282
8468
|
|
|
8283
8469
|
// src/backends/openrouter.ts
|
|
8284
|
-
import {
|
|
8470
|
+
import { createOpenAICompatible as createOpenAICompatible2 } from "@ai-sdk/openai-compatible";
|
|
8285
8471
|
var OPENROUTER_HTTP_SENTINEL, DEFAULT_FREE_MODEL, OpenRouterAdapter;
|
|
8286
8472
|
var init_openrouter = __esm({
|
|
8287
8473
|
"src/backends/openrouter.ts"() {
|
|
@@ -8336,7 +8522,8 @@ var init_openrouter = __esm({
|
|
|
8336
8522
|
*/
|
|
8337
8523
|
createProvider(model2) {
|
|
8338
8524
|
const apiKey = this.getApiKey();
|
|
8339
|
-
const openrouterProvider =
|
|
8525
|
+
const openrouterProvider = createOpenAICompatible2({
|
|
8526
|
+
name: "openrouter",
|
|
8340
8527
|
baseURL: "https://openrouter.ai/api/v1",
|
|
8341
8528
|
apiKey: apiKey || "sk-or-no-key",
|
|
8342
8529
|
headers: {
|
|
@@ -8356,7 +8543,7 @@ var init_openrouter = __esm({
|
|
|
8356
8543
|
async streamDirect(prompt, model2, opts) {
|
|
8357
8544
|
const onToolAction = opts?.onToolAction ? (event) => {
|
|
8358
8545
|
const input = event.input ?? {};
|
|
8359
|
-
const result2 = event.type === "tool_end" ?
|
|
8546
|
+
const result2 = event.type === "tool_end" ? typeof event.output === "string" ? event.output : JSON.stringify(event.output ?? "") : void 0;
|
|
8360
8547
|
opts.onToolAction(event.toolName, input, result2);
|
|
8361
8548
|
} : void 0;
|
|
8362
8549
|
const apiOpts = {
|
|
@@ -9630,58 +9817,73 @@ var init_init = __esm({
|
|
|
9630
9817
|
});
|
|
9631
9818
|
|
|
9632
9819
|
// src/bootstrap/loader.ts
|
|
9633
|
-
import { readFileSync as readFileSync7,
|
|
9820
|
+
import { readFileSync as readFileSync7, readdirSync as readdirSync4 } from "fs";
|
|
9634
9821
|
import { join as join10 } from "path";
|
|
9635
|
-
function
|
|
9636
|
-
|
|
9637
|
-
|
|
9822
|
+
function tokenize(text) {
|
|
9823
|
+
return new Set(
|
|
9824
|
+
text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 3)
|
|
9825
|
+
);
|
|
9826
|
+
}
|
|
9827
|
+
function stripFrontmatter(content) {
|
|
9828
|
+
if (!content.startsWith("---")) return content;
|
|
9829
|
+
const end = content.indexOf("---", 3);
|
|
9830
|
+
return end === -1 ? content : content.slice(end + 3).trim();
|
|
9831
|
+
}
|
|
9832
|
+
function loadMarkdownDir(dir, cacheRef, wordSource = (c) => c) {
|
|
9833
|
+
if (cacheRef.v && Date.now() - cacheRef.v.timestamp < CACHE_TTL_MS2) {
|
|
9834
|
+
return cacheRef.v.files;
|
|
9638
9835
|
}
|
|
9639
9836
|
const files = /* @__PURE__ */ new Map();
|
|
9640
9837
|
try {
|
|
9641
|
-
const
|
|
9642
|
-
|
|
9838
|
+
for (const entry of readdirSync4(dir)) {
|
|
9839
|
+
if (!entry.endsWith(".md")) continue;
|
|
9643
9840
|
try {
|
|
9644
|
-
const content = readFileSync7(join10(
|
|
9645
|
-
if (content) files.set(entry, content);
|
|
9841
|
+
const content = readFileSync7(join10(dir, entry), "utf-8").trim();
|
|
9842
|
+
if (content) files.set(entry, { content, words: tokenize(wordSource(content)) });
|
|
9646
9843
|
} catch {
|
|
9647
9844
|
continue;
|
|
9648
9845
|
}
|
|
9649
9846
|
}
|
|
9650
|
-
} catch
|
|
9651
|
-
warn("[bootstrap] Failed to load context directory:", err instanceof Error ? err.message : err);
|
|
9847
|
+
} catch {
|
|
9652
9848
|
}
|
|
9653
|
-
|
|
9849
|
+
cacheRef.v = { files, timestamp: Date.now() };
|
|
9654
9850
|
return files;
|
|
9655
9851
|
}
|
|
9656
|
-
function
|
|
9657
|
-
|
|
9658
|
-
const msgWords = new Set(
|
|
9659
|
-
userMessage.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 3)
|
|
9660
|
-
);
|
|
9852
|
+
function findBestMatch(userMessage, files, opts) {
|
|
9853
|
+
const msgWords = tokenize(userMessage);
|
|
9661
9854
|
if (msgWords.size === 0) return null;
|
|
9662
|
-
let
|
|
9663
|
-
const
|
|
9664
|
-
|
|
9665
|
-
const fileWords = new Set(
|
|
9666
|
-
content.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 3)
|
|
9667
|
-
);
|
|
9855
|
+
let best = null;
|
|
9856
|
+
for (const entry of files.values()) {
|
|
9857
|
+
if (opts.filter && !opts.filter(entry)) continue;
|
|
9668
9858
|
let score = 0;
|
|
9669
9859
|
for (const word of msgWords) {
|
|
9670
|
-
if (
|
|
9860
|
+
if (entry.words.has(word)) score++;
|
|
9671
9861
|
}
|
|
9672
|
-
if (score
|
|
9673
|
-
|
|
9862
|
+
if (score >= 2 && (!best || score > best.score)) {
|
|
9863
|
+
best = { score, content: entry.content };
|
|
9674
9864
|
}
|
|
9675
9865
|
}
|
|
9676
|
-
if (
|
|
9677
|
-
|
|
9678
|
-
|
|
9866
|
+
if (!best) return null;
|
|
9867
|
+
return best.content.length > opts.maxChars ? best.content.slice(0, opts.maxChars) + "\n\u2026(truncated)" : best.content;
|
|
9868
|
+
}
|
|
9869
|
+
function searchContext(userMessage) {
|
|
9870
|
+
return findBestMatch(
|
|
9871
|
+
userMessage,
|
|
9872
|
+
loadMarkdownDir(CONTEXT_DIR2, contextCacheRef),
|
|
9873
|
+
{ maxChars: MAX_CONTEXT_CHARS }
|
|
9874
|
+
);
|
|
9875
|
+
}
|
|
9876
|
+
function searchSkill(userMessage) {
|
|
9877
|
+
return findBestMatch(
|
|
9878
|
+
userMessage,
|
|
9879
|
+
loadMarkdownDir(SKILLS_DIR, skillCacheRef, stripFrontmatter),
|
|
9880
|
+
{
|
|
9881
|
+
maxChars: MAX_SKILL_CHARS,
|
|
9882
|
+
filter: ({ content }) => content.includes("status: approved") || content.includes("status: imported")
|
|
9679
9883
|
}
|
|
9680
|
-
|
|
9681
|
-
}
|
|
9682
|
-
return null;
|
|
9884
|
+
);
|
|
9683
9885
|
}
|
|
9684
|
-
async function assembleBootstrapPrompt(userMessage, entityType = "main", profile = "interactive", chatId, permMode, responseStyle, agentMode, sideQuestContext, planningDirective, chatContext) {
|
|
9886
|
+
async function assembleBootstrapPrompt(userMessage, entityType = "main", profile = "interactive", chatId, permMode, responseStyle, agentMode, sideQuestContext, planningDirective, chatContext, backendType) {
|
|
9685
9887
|
const sections = [];
|
|
9686
9888
|
if (planningDirective) {
|
|
9687
9889
|
sections.push(planningDirective);
|
|
@@ -9693,6 +9895,15 @@ async function assembleBootstrapPrompt(userMessage, entityType = "main", profile
|
|
|
9693
9895
|
if (permMode && permMode !== "yolo") {
|
|
9694
9896
|
sections.push(buildPermissionNotice(permMode));
|
|
9695
9897
|
}
|
|
9898
|
+
if (backendType === "api" && profile !== "minimal") {
|
|
9899
|
+
sections.push(`[API Backend \u2014 Tool Usage]
|
|
9900
|
+
You are operating as a direct API model (not a CLI like Claude Code or Gemini CLI).
|
|
9901
|
+
External tools (gsearch, pwm, gws, gemcli, nlm, curl, python3, etc.) are accessed ONLY via the \`restrictedBash\` tool.
|
|
9902
|
+
NEVER call external CLIs as direct tools by name \u2014 they are not registered as native tools.
|
|
9903
|
+
Correct: restrictedBash({"command": "gsearch \\"query\\" --type news"})
|
|
9904
|
+
Incorrect: gsearch({"query": "..."}) \u2190 this will fail silently
|
|
9905
|
+
If a skill or instruction says to use a CLI tool, always route it through restrictedBash.`);
|
|
9906
|
+
}
|
|
9696
9907
|
if (responseStyle) {
|
|
9697
9908
|
if (responseStyle === "concise") {
|
|
9698
9909
|
sections.push("[Response Style]\nYou must be as concise and direct as possible. Avoid unnecessary verbosity, pleasantries, or long explanations.");
|
|
@@ -9720,6 +9931,13 @@ ${parts.join("\n")}`);
|
|
|
9720
9931
|
${ctx}`);
|
|
9721
9932
|
}
|
|
9722
9933
|
}
|
|
9934
|
+
if (profile === "interactive" || profile === "chat") {
|
|
9935
|
+
const skill = searchSkill(userMessage);
|
|
9936
|
+
if (skill) {
|
|
9937
|
+
sections.push(`[Relevant skill]
|
|
9938
|
+
${skill}`);
|
|
9939
|
+
}
|
|
9940
|
+
}
|
|
9723
9941
|
if (chatId && profile !== "minimal" && profile !== "chat") {
|
|
9724
9942
|
if (sideQuestContext) {
|
|
9725
9943
|
const bridge = buildContextBridge(sideQuestContext.parentChatId, 15);
|
|
@@ -9879,7 +10097,7 @@ ${parts.join("\n")}${MEMORY_DISCIPLINE}`;
|
|
|
9879
10097
|
}
|
|
9880
10098
|
return null;
|
|
9881
10099
|
}
|
|
9882
|
-
var lastSyncMs, CONTEXT_DIR2, MAX_CONTEXT_CHARS,
|
|
10100
|
+
var lastSyncMs, CONTEXT_DIR2, SKILLS_DIR, MAX_CONTEXT_CHARS, MAX_SKILL_CHARS, CACHE_TTL_MS2, contextCacheRef, skillCacheRef, ACTIVITY_TOKEN_BUDGET, INBOX_TOKEN_BUDGET, WHITEBOARD_TOKEN_BUDGET;
|
|
9883
10101
|
var init_loader = __esm({
|
|
9884
10102
|
"src/bootstrap/loader.ts"() {
|
|
9885
10103
|
"use strict";
|
|
@@ -9893,9 +10111,12 @@ var init_loader = __esm({
|
|
|
9893
10111
|
init_backends();
|
|
9894
10112
|
lastSyncMs = 0;
|
|
9895
10113
|
CONTEXT_DIR2 = join10(WORKSPACE_PATH, "context");
|
|
10114
|
+
SKILLS_DIR = join10(WORKSPACE_PATH, "skills");
|
|
9896
10115
|
MAX_CONTEXT_CHARS = 4e3;
|
|
9897
|
-
|
|
9898
|
-
|
|
10116
|
+
MAX_SKILL_CHARS = 6e3;
|
|
10117
|
+
CACHE_TTL_MS2 = 3e4;
|
|
10118
|
+
contextCacheRef = { v: null };
|
|
10119
|
+
skillCacheRef = { v: null };
|
|
9899
10120
|
ACTIVITY_TOKEN_BUDGET = 1500;
|
|
9900
10121
|
INBOX_TOKEN_BUDGET = 2e3;
|
|
9901
10122
|
WHITEBOARD_TOKEN_BUDGET = 500;
|
|
@@ -10192,7 +10413,7 @@ async function summarizeWithFallbackChain(chatId, targetBackendId, excludeBacken
|
|
|
10192
10413
|
const key = `${targetAdapter.id}:${model2}`;
|
|
10193
10414
|
if (!tried.has(key)) {
|
|
10194
10415
|
tried.add(key);
|
|
10195
|
-
const result = await attemptSummarize(chatId, targetAdapter, model2, entries);
|
|
10416
|
+
const result = targetAdapter.streamDirect ? await attemptSummarizeDirect(chatId, (p) => targetAdapter.streamDirect(p, model2), targetAdapter.id, model2, entries, getTranscriptCap(model2)) : await attemptSummarize(chatId, targetAdapter, model2, entries);
|
|
10196
10417
|
if (result.success) {
|
|
10197
10418
|
await extractAndLogSignals(result.rawText, chatId, targetAdapter.id, model2);
|
|
10198
10419
|
if (clearLogAfter) clearLog(chatId);
|
|
@@ -10210,7 +10431,7 @@ async function summarizeWithFallbackChain(chatId, targetBackendId, excludeBacken
|
|
|
10210
10431
|
const key = `${adapter.id}:${model2}`;
|
|
10211
10432
|
if (!tried.has(key)) {
|
|
10212
10433
|
tried.add(key);
|
|
10213
|
-
const result = await attemptSummarize(chatId, adapter, model2, entries);
|
|
10434
|
+
const result = adapter.streamDirect ? await attemptSummarizeDirect(chatId, (p) => adapter.streamDirect(p, model2), adapter.id, model2, entries, adapter.id === "ollama" ? getOllamaTranscriptCap(model2) : getTranscriptCap(model2)) : await attemptSummarize(chatId, adapter, model2, entries);
|
|
10214
10435
|
if (result.success) {
|
|
10215
10436
|
await extractAndLogSignals(result.rawText, chatId, adapter.id, model2);
|
|
10216
10437
|
if (clearLogAfter) clearLog(chatId);
|
|
@@ -11199,7 +11420,7 @@ __export(discover_exports, {
|
|
|
11199
11420
|
discoverAllSkills: () => discoverAllSkills,
|
|
11200
11421
|
invalidateSkillCache: () => invalidateSkillCache,
|
|
11201
11422
|
resolveSkillForTask: () => resolveSkillForTask,
|
|
11202
|
-
stripFrontmatter: () =>
|
|
11423
|
+
stripFrontmatter: () => stripFrontmatter2
|
|
11203
11424
|
});
|
|
11204
11425
|
import { readdir, readFile } from "fs/promises";
|
|
11205
11426
|
import { createHash } from "crypto";
|
|
@@ -11211,7 +11432,7 @@ function invalidateSkillCache() {
|
|
|
11211
11432
|
}
|
|
11212
11433
|
async function discoverAllSkills() {
|
|
11213
11434
|
const now = Date.now();
|
|
11214
|
-
if (cachedSkills !== null && now - cacheTimestamp <
|
|
11435
|
+
if (cachedSkills !== null && now - cacheTimestamp < CACHE_TTL_MS3) {
|
|
11215
11436
|
return cachedSkills;
|
|
11216
11437
|
}
|
|
11217
11438
|
if (pendingScan !== null) {
|
|
@@ -11371,7 +11592,7 @@ function parseFrontmatter(content, fallbackName, source) {
|
|
|
11371
11592
|
requires
|
|
11372
11593
|
};
|
|
11373
11594
|
}
|
|
11374
|
-
function
|
|
11595
|
+
function stripFrontmatter2(content) {
|
|
11375
11596
|
return content.replace(/^---\s*\n[\s\S]*?\n---\s*\n?/, "").trim();
|
|
11376
11597
|
}
|
|
11377
11598
|
function resolveSkillForTask(skillName) {
|
|
@@ -11379,15 +11600,15 @@ function resolveSkillForTask(skillName) {
|
|
|
11379
11600
|
for (const candidate of SKILL_FILE_CANDIDATES3) {
|
|
11380
11601
|
const skillPath = join11(SKILLS_PATH, skillName, candidate);
|
|
11381
11602
|
try {
|
|
11382
|
-
const { readFileSync:
|
|
11383
|
-
if (!
|
|
11384
|
-
const raw =
|
|
11603
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = __require("fs");
|
|
11604
|
+
if (!existsSync62(skillPath)) continue;
|
|
11605
|
+
const raw = readFileSync35(skillPath, "utf-8");
|
|
11385
11606
|
const fm = parseFrontmatter(raw, skillName, "cc-claw");
|
|
11386
11607
|
if (fm.status !== "approved") {
|
|
11387
11608
|
log(`[skills] Skill "${skillName}" has status "${fm.status}" \u2014 only approved skills can be used as task worker identity`);
|
|
11388
11609
|
return null;
|
|
11389
11610
|
}
|
|
11390
|
-
const content =
|
|
11611
|
+
const content = stripFrontmatter2(raw);
|
|
11391
11612
|
return { content, requires: fm.requires };
|
|
11392
11613
|
} catch {
|
|
11393
11614
|
continue;
|
|
@@ -11395,7 +11616,7 @@ function resolveSkillForTask(skillName) {
|
|
|
11395
11616
|
}
|
|
11396
11617
|
return null;
|
|
11397
11618
|
}
|
|
11398
|
-
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS,
|
|
11619
|
+
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS, CACHE_TTL_MS3, cachedSkills, cacheTimestamp, pendingScan;
|
|
11399
11620
|
var init_discover = __esm({
|
|
11400
11621
|
"src/skills/discover.ts"() {
|
|
11401
11622
|
"use strict";
|
|
@@ -11415,7 +11636,7 @@ var init_discover = __esm({
|
|
|
11415
11636
|
join11(homedir4(), ".cursor", "skills-cursor")
|
|
11416
11637
|
]
|
|
11417
11638
|
};
|
|
11418
|
-
|
|
11639
|
+
CACHE_TTL_MS3 = 3e5;
|
|
11419
11640
|
cachedSkills = null;
|
|
11420
11641
|
cacheTimestamp = 0;
|
|
11421
11642
|
pendingScan = null;
|
|
@@ -11425,9 +11646,9 @@ var init_discover = __esm({
|
|
|
11425
11646
|
// src/agents/spawn.ts
|
|
11426
11647
|
import { spawn as spawn2 } from "child_process";
|
|
11427
11648
|
import { createInterface as createInterface2 } from "readline";
|
|
11428
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
11649
|
+
import { readFileSync as readFileSync8, existsSync as existsSync12 } from "fs";
|
|
11429
11650
|
import { join as join12 } from "path";
|
|
11430
|
-
function
|
|
11651
|
+
function stripFrontmatter3(text) {
|
|
11431
11652
|
const lines = text.split("\n");
|
|
11432
11653
|
if (lines.length < 2 || lines[0].trim() !== "---") return text;
|
|
11433
11654
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -11442,10 +11663,10 @@ function resolveSkillContent(skillName) {
|
|
|
11442
11663
|
const SKILL_FILE_CANDIDATES3 = ["SKILL.md", "skill.md"];
|
|
11443
11664
|
for (const candidate of SKILL_FILE_CANDIDATES3) {
|
|
11444
11665
|
const skillPath = join12(SKILLS_PATH, skillName, candidate);
|
|
11445
|
-
if (
|
|
11666
|
+
if (existsSync12(skillPath)) {
|
|
11446
11667
|
try {
|
|
11447
11668
|
const raw = readFileSync8(skillPath, "utf-8");
|
|
11448
|
-
return
|
|
11669
|
+
return stripFrontmatter3(raw).trim();
|
|
11449
11670
|
} catch {
|
|
11450
11671
|
return null;
|
|
11451
11672
|
}
|
|
@@ -11501,7 +11722,7 @@ function buildAgentPrompt(opts, runnerSkillPath) {
|
|
|
11501
11722
|
if (runnerSkillPath) {
|
|
11502
11723
|
try {
|
|
11503
11724
|
const raw = readFileSync8(runnerSkillPath, "utf-8");
|
|
11504
|
-
const content =
|
|
11725
|
+
const content = stripFrontmatter3(raw).trim();
|
|
11505
11726
|
if (content) parts.push(content, "");
|
|
11506
11727
|
} catch {
|
|
11507
11728
|
}
|
|
@@ -11512,7 +11733,7 @@ function buildAgentPrompt(opts, runnerSkillPath) {
|
|
|
11512
11733
|
if (runnerSkillPath) {
|
|
11513
11734
|
try {
|
|
11514
11735
|
const raw = readFileSync8(runnerSkillPath, "utf-8");
|
|
11515
|
-
const content =
|
|
11736
|
+
const content = stripFrontmatter3(raw).trim();
|
|
11516
11737
|
if (content) parts.push(content);
|
|
11517
11738
|
parts.push("");
|
|
11518
11739
|
} catch {
|
|
@@ -11697,8 +11918,15 @@ var init_cost = __esm({
|
|
|
11697
11918
|
});
|
|
11698
11919
|
|
|
11699
11920
|
// src/mcps/propagate.ts
|
|
11921
|
+
var propagate_exports = {};
|
|
11922
|
+
__export(propagate_exports, {
|
|
11923
|
+
cleanupMcps: () => cleanupMcps,
|
|
11924
|
+
diffMcps: () => diffMcps,
|
|
11925
|
+
discoverExistingMcps: () => discoverExistingMcps,
|
|
11926
|
+
injectMcps: () => injectMcps
|
|
11927
|
+
});
|
|
11700
11928
|
import { execFile as execFile2 } from "child_process";
|
|
11701
|
-
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as
|
|
11929
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync13 } from "fs";
|
|
11702
11930
|
import { promisify as promisify3 } from "util";
|
|
11703
11931
|
import { homedir as homedir5 } from "os";
|
|
11704
11932
|
import { join as join13 } from "path";
|
|
@@ -11777,7 +12005,7 @@ function injectMcpToCursorConfig(config2) {
|
|
|
11777
12005
|
const configPath = join13(homedir5(), ".cursor", "mcp.json");
|
|
11778
12006
|
let existing = {};
|
|
11779
12007
|
try {
|
|
11780
|
-
if (
|
|
12008
|
+
if (existsSync13(configPath)) {
|
|
11781
12009
|
existing = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
11782
12010
|
}
|
|
11783
12011
|
} catch {
|
|
@@ -11830,10 +12058,10 @@ async function injectMcps(runner, mcpNames, db3, scope) {
|
|
|
11830
12058
|
}
|
|
11831
12059
|
return added;
|
|
11832
12060
|
}
|
|
11833
|
-
async function cleanupMcps(runner,
|
|
12061
|
+
async function cleanupMcps(runner, mcps, db3, scope) {
|
|
11834
12062
|
const exe = runner.getExecutablePath();
|
|
11835
12063
|
const runnerId = runner.id;
|
|
11836
|
-
for (const name of
|
|
12064
|
+
for (const name of mcps) {
|
|
11837
12065
|
try {
|
|
11838
12066
|
const removeCmd = runner.getMcpRemoveCommand(name);
|
|
11839
12067
|
const args = removeCmd.slice(1);
|
|
@@ -11930,14 +12158,14 @@ function scanTemplates() {
|
|
|
11930
12158
|
}
|
|
11931
12159
|
}
|
|
11932
12160
|
function getTemplate(name) {
|
|
11933
|
-
if (Date.now() - lastScanMs >
|
|
12161
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS4) scanTemplates();
|
|
11934
12162
|
return templateCache.get(name) ?? null;
|
|
11935
12163
|
}
|
|
11936
12164
|
function listTemplates() {
|
|
11937
|
-
if (Date.now() - lastScanMs >
|
|
12165
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS4) scanTemplates();
|
|
11938
12166
|
return Array.from(templateCache.values());
|
|
11939
12167
|
}
|
|
11940
|
-
var templateCache, lastScanMs,
|
|
12168
|
+
var templateCache, lastScanMs, CACHE_TTL_MS4;
|
|
11941
12169
|
var init_loader2 = __esm({
|
|
11942
12170
|
"src/agents/templates/loader.ts"() {
|
|
11943
12171
|
"use strict";
|
|
@@ -11945,7 +12173,7 @@ var init_loader2 = __esm({
|
|
|
11945
12173
|
init_log();
|
|
11946
12174
|
templateCache = /* @__PURE__ */ new Map();
|
|
11947
12175
|
lastScanMs = 0;
|
|
11948
|
-
|
|
12176
|
+
CACHE_TTL_MS4 = 3e4;
|
|
11949
12177
|
}
|
|
11950
12178
|
});
|
|
11951
12179
|
|
|
@@ -12062,7 +12290,7 @@ __export(orchestrator_exports, {
|
|
|
12062
12290
|
spawnSubAgent: () => spawnSubAgent,
|
|
12063
12291
|
suppressNotifications: () => suppressNotifications
|
|
12064
12292
|
});
|
|
12065
|
-
import { existsSync as
|
|
12293
|
+
import { existsSync as existsSync14 } from "fs";
|
|
12066
12294
|
async function withRunnerLock(runnerId, fn) {
|
|
12067
12295
|
const prev = runnerLocks.get(runnerId) ?? Promise.resolve();
|
|
12068
12296
|
const next = prev.then(fn, () => fn());
|
|
@@ -12194,7 +12422,7 @@ async function spawnSubAgent(chatId, opts) {
|
|
|
12194
12422
|
async function startAgent(agentId, chatId, opts) {
|
|
12195
12423
|
const db3 = getDb();
|
|
12196
12424
|
const runner = getRunner(opts.runner);
|
|
12197
|
-
if (opts.cwd && !
|
|
12425
|
+
if (opts.cwd && !existsSync14(opts.cwd)) {
|
|
12198
12426
|
const msg = `Directory not found: ${opts.cwd}`;
|
|
12199
12427
|
error(`[orchestrator] Agent ${agentId}: ${msg}`);
|
|
12200
12428
|
updateAgentStatus(db3, agentId, "failed");
|
|
@@ -12216,7 +12444,7 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
12216
12444
|
return;
|
|
12217
12445
|
}
|
|
12218
12446
|
const exePath = runner.getExecutablePath();
|
|
12219
|
-
if (exePath.startsWith("/") && !
|
|
12447
|
+
if (exePath.startsWith("/") && !existsSync14(exePath)) {
|
|
12220
12448
|
const msg = `Executable not found: ${exePath}`;
|
|
12221
12449
|
error(`[orchestrator] Agent ${agentId}: ${msg}`);
|
|
12222
12450
|
updateAgentStatus(db3, agentId, "failed");
|
|
@@ -12503,10 +12731,10 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
12503
12731
|
function diagnoseSpawnError(err, exePath, cwd) {
|
|
12504
12732
|
const nodeErr = err;
|
|
12505
12733
|
if (nodeErr.code === "ENOENT") {
|
|
12506
|
-
if (cwd && !
|
|
12734
|
+
if (cwd && !existsSync14(cwd)) {
|
|
12507
12735
|
return `Directory not found: ${cwd}`;
|
|
12508
12736
|
}
|
|
12509
|
-
if (exePath.startsWith("/") && !
|
|
12737
|
+
if (exePath.startsWith("/") && !existsSync14(exePath)) {
|
|
12510
12738
|
return `Executable not found: ${exePath}`;
|
|
12511
12739
|
}
|
|
12512
12740
|
return `ENOENT spawning ${exePath} (cwd: ${cwd ?? "inherited"}) \u2014 check that both the binary and directory exist`;
|
|
@@ -12905,7 +13133,7 @@ var init_registry2 = __esm({
|
|
|
12905
13133
|
});
|
|
12906
13134
|
|
|
12907
13135
|
// src/dashboard/routes/orchestrator.ts
|
|
12908
|
-
import { existsSync as
|
|
13136
|
+
import { existsSync as existsSync15 } from "fs";
|
|
12909
13137
|
var handleSpawn, handleCancel, handleCancelAll, handleCreateTask, handleUpdateTask, handleSendMessage, handleReadInbox, handleSetState, handleGetState, handleListState, handleBroadcast, handleListRunners, handleListMcps, handleListTemplates, handleCheckAgent;
|
|
12910
13138
|
var init_orchestrator2 = __esm({
|
|
12911
13139
|
"src/dashboard/routes/orchestrator.ts"() {
|
|
@@ -12921,7 +13149,7 @@ var init_orchestrator2 = __esm({
|
|
|
12921
13149
|
handleSpawn = async (req, res) => {
|
|
12922
13150
|
try {
|
|
12923
13151
|
const body = JSON.parse(await readBody(req));
|
|
12924
|
-
if (body.cwd && !
|
|
13152
|
+
if (body.cwd && !existsSync15(body.cwd)) {
|
|
12925
13153
|
return jsonResponse(res, { error: `Directory not found: ${body.cwd}` }, 400);
|
|
12926
13154
|
}
|
|
12927
13155
|
if (!body.permMode || body.permMode === "inherit") {
|
|
@@ -13163,28 +13391,28 @@ async function checkHttpHealth(url) {
|
|
|
13163
13391
|
}
|
|
13164
13392
|
}
|
|
13165
13393
|
async function runHealthChecks(db3) {
|
|
13166
|
-
const
|
|
13167
|
-
const sorted =
|
|
13394
|
+
const mcps = listMcpServers(db3);
|
|
13395
|
+
const sorted = mcps.sort((a, b) => {
|
|
13168
13396
|
const aTime = a.lastHealthCheck ?? "0";
|
|
13169
13397
|
const bTime = b.lastHealthCheck ?? "0";
|
|
13170
13398
|
return aTime < bTime ? -1 : aTime > bTime ? 1 : 0;
|
|
13171
13399
|
});
|
|
13172
13400
|
const batch = sorted.slice(0, MAX_CHECKS_PER_CYCLE);
|
|
13173
|
-
for (const
|
|
13401
|
+
for (const mcp2 of batch) {
|
|
13174
13402
|
let status = "unhealthy";
|
|
13175
13403
|
try {
|
|
13176
|
-
if (
|
|
13177
|
-
const args =
|
|
13178
|
-
status = await checkStdioHealth(
|
|
13179
|
-
} else if ((
|
|
13180
|
-
status = await checkHttpHealth(
|
|
13404
|
+
if (mcp2.transport === "stdio" && mcp2.command) {
|
|
13405
|
+
const args = mcp2.args ? JSON.parse(mcp2.args) : [];
|
|
13406
|
+
status = await checkStdioHealth(mcp2.command, args);
|
|
13407
|
+
} else if ((mcp2.transport === "sse" || mcp2.transport === "streamable-http") && mcp2.url) {
|
|
13408
|
+
status = await checkHttpHealth(mcp2.url);
|
|
13181
13409
|
} else {
|
|
13182
13410
|
status = "unknown";
|
|
13183
13411
|
}
|
|
13184
13412
|
} catch {
|
|
13185
13413
|
status = "unhealthy";
|
|
13186
13414
|
}
|
|
13187
|
-
updateMcpHealth(db3,
|
|
13415
|
+
updateMcpHealth(db3, mcp2.name, status);
|
|
13188
13416
|
}
|
|
13189
13417
|
}
|
|
13190
13418
|
function startHealthMonitor(db3) {
|
|
@@ -13252,8 +13480,8 @@ var init_mcps = __esm({
|
|
|
13252
13480
|
try {
|
|
13253
13481
|
const { runHealthChecks: runHealthChecks2 } = await Promise.resolve().then(() => (init_health(), health_exports));
|
|
13254
13482
|
await runHealthChecks2(getDb());
|
|
13255
|
-
const
|
|
13256
|
-
jsonResponse(res,
|
|
13483
|
+
const mcps = listMcpServers(getDb());
|
|
13484
|
+
jsonResponse(res, mcps);
|
|
13257
13485
|
} catch (err) {
|
|
13258
13486
|
jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
13259
13487
|
}
|
|
@@ -14293,7 +14521,7 @@ __export(stt_exports, {
|
|
|
14293
14521
|
import crypto from "crypto";
|
|
14294
14522
|
import { execFile as execFile3, execFileSync } from "child_process";
|
|
14295
14523
|
import { readFile as readFile2, unlink, writeFile } from "fs/promises";
|
|
14296
|
-
import { existsSync as
|
|
14524
|
+
import { existsSync as existsSync16 } from "fs";
|
|
14297
14525
|
import { join as join16, sep } from "path";
|
|
14298
14526
|
import { promisify as promisify4 } from "util";
|
|
14299
14527
|
import { createRequire } from "module";
|
|
@@ -14394,13 +14622,13 @@ function isWhisperModelDownloaded(model2) {
|
|
|
14394
14622
|
if (idx >= 0) {
|
|
14395
14623
|
const pkgRoot = hfMain.slice(0, idx + marker.length - 1);
|
|
14396
14624
|
const v4CacheDir = join16(pkgRoot, ".cache", org, modelName);
|
|
14397
|
-
if (
|
|
14625
|
+
if (existsSync16(v4CacheDir)) return true;
|
|
14398
14626
|
}
|
|
14399
14627
|
} catch {
|
|
14400
14628
|
}
|
|
14401
14629
|
const home = process.env.HOME ?? "/tmp";
|
|
14402
14630
|
const hubCacheDir = join16(home, ".cache", "huggingface", "hub", `models--${hfId.replace("/", "--")}`);
|
|
14403
|
-
return
|
|
14631
|
+
return existsSync16(hubCacheDir);
|
|
14404
14632
|
}
|
|
14405
14633
|
async function downloadWhisperModel(model2, onProgress) {
|
|
14406
14634
|
const info = LOCAL_WHISPER_MODELS[model2];
|
|
@@ -14583,8 +14811,8 @@ async function mp3ToOgg(mp3Buffer) {
|
|
|
14583
14811
|
const id = crypto.randomUUID();
|
|
14584
14812
|
const tmpMp3 = `/tmp/cc-claw-tts-${id}.mp3`;
|
|
14585
14813
|
const tmpOgg = `/tmp/cc-claw-tts-${id}.ogg`;
|
|
14586
|
-
const { writeFile:
|
|
14587
|
-
await
|
|
14814
|
+
const { writeFile: writeFile6 } = await import("fs/promises");
|
|
14815
|
+
await writeFile6(tmpMp3, mp3Buffer);
|
|
14588
14816
|
await execFileAsync4("ffmpeg", ["-y", "-i", tmpMp3, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
|
|
14589
14817
|
const oggBuffer = await readFile2(tmpOgg);
|
|
14590
14818
|
unlink(tmpMp3).catch((err) => {
|
|
@@ -14762,7 +14990,7 @@ function is429(err) {
|
|
|
14762
14990
|
function sleep(ms) {
|
|
14763
14991
|
return new Promise((r) => setTimeout(r, ms));
|
|
14764
14992
|
}
|
|
14765
|
-
var PER_DM_INTERVAL_MS, PER_GROUP_INTERVAL_MS, GLOBAL_INTERVAL_MS,
|
|
14993
|
+
var PER_DM_INTERVAL_MS, PER_GROUP_INTERVAL_MS, GLOBAL_INTERVAL_MS, MAX_RETRIES2, RETRY_DELAY_MS, MAX_QUEUE_SIZE, MAX_TOTAL_PAUSE_MS, _activeThrottle, TelegramThrottle;
|
|
14766
14994
|
var init_telegram_throttle = __esm({
|
|
14767
14995
|
"src/channels/telegram-throttle.ts"() {
|
|
14768
14996
|
"use strict";
|
|
@@ -14770,7 +14998,7 @@ var init_telegram_throttle = __esm({
|
|
|
14770
14998
|
PER_DM_INTERVAL_MS = 1e3;
|
|
14771
14999
|
PER_GROUP_INTERVAL_MS = 3500;
|
|
14772
15000
|
GLOBAL_INTERVAL_MS = 100;
|
|
14773
|
-
|
|
15001
|
+
MAX_RETRIES2 = 2;
|
|
14774
15002
|
RETRY_DELAY_MS = 1e3;
|
|
14775
15003
|
MAX_QUEUE_SIZE = 100;
|
|
14776
15004
|
MAX_TOTAL_PAUSE_MS = 30 * 60 * 1e3;
|
|
@@ -14903,13 +15131,13 @@ var init_telegram_throttle = __esm({
|
|
|
14903
15131
|
}
|
|
14904
15132
|
// ── Retry logic (non-429 errors only) ───────────────────────────────
|
|
14905
15133
|
async execWithRetry(label2, fn) {
|
|
14906
|
-
for (let attempt = 0; attempt <=
|
|
15134
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
14907
15135
|
try {
|
|
14908
15136
|
return await fn();
|
|
14909
15137
|
} catch (err) {
|
|
14910
15138
|
if (is429(err)) throw err;
|
|
14911
|
-
if (attempt <
|
|
14912
|
-
warn(`[throttle] ${label2} attempt ${attempt + 1}/${
|
|
15139
|
+
if (attempt < MAX_RETRIES2 && err instanceof GrammyError) {
|
|
15140
|
+
warn(`[throttle] ${label2} attempt ${attempt + 1}/${MAX_RETRIES2} failed (${err.error_code}), retrying`);
|
|
14913
15141
|
await sleep(RETRY_DELAY_MS);
|
|
14914
15142
|
continue;
|
|
14915
15143
|
}
|
|
@@ -14969,10 +15197,10 @@ var init_telegram_throttle = __esm({
|
|
|
14969
15197
|
});
|
|
14970
15198
|
|
|
14971
15199
|
// src/health/checks.ts
|
|
14972
|
-
import { existsSync as
|
|
15200
|
+
import { existsSync as existsSync17, statSync as statSync5, readFileSync as readFileSync11 } from "fs";
|
|
14973
15201
|
import { execFileSync as execFileSync2, execSync as execSync3 } from "child_process";
|
|
14974
15202
|
function getRecentErrors() {
|
|
14975
|
-
if (!
|
|
15203
|
+
if (!existsSync17(ERROR_LOG_PATH)) return null;
|
|
14976
15204
|
const logContent = readFileSync11(ERROR_LOG_PATH, "utf-8");
|
|
14977
15205
|
const allLines = logContent.split("\n").filter(Boolean).slice(-500);
|
|
14978
15206
|
const last24h = Date.now() - 864e5;
|
|
@@ -14994,7 +15222,7 @@ function getRecentErrors() {
|
|
|
14994
15222
|
}
|
|
14995
15223
|
function checkDatabase() {
|
|
14996
15224
|
const checks = [];
|
|
14997
|
-
if (
|
|
15225
|
+
if (existsSync17(DB_PATH)) {
|
|
14998
15226
|
const size = statSync5(DB_PATH).size;
|
|
14999
15227
|
checks.push({ name: "Database", status: "ok", message: `${(size / 1024).toFixed(0)}KB` });
|
|
15000
15228
|
} else {
|
|
@@ -15202,7 +15430,7 @@ __export(heartbeat_exports, {
|
|
|
15202
15430
|
stopHeartbeatForChat: () => stopHeartbeatForChat,
|
|
15203
15431
|
updateHeartbeatConfig: () => updateHeartbeatConfig
|
|
15204
15432
|
});
|
|
15205
|
-
import { readFileSync as readFileSync12, existsSync as
|
|
15433
|
+
import { readFileSync as readFileSync12, existsSync as existsSync18 } from "fs";
|
|
15206
15434
|
import { join as join17 } from "path";
|
|
15207
15435
|
function findHeartbeatJob() {
|
|
15208
15436
|
try {
|
|
@@ -15382,7 +15610,7 @@ ${healthText}`);
|
|
|
15382
15610
|
sections.push(`[Active Watches \u2014 execute these checks using your tools]
|
|
15383
15611
|
${watchLines.join("\n")}`);
|
|
15384
15612
|
}
|
|
15385
|
-
if (
|
|
15613
|
+
if (existsSync18(HEARTBEAT_MD_PATH)) {
|
|
15386
15614
|
try {
|
|
15387
15615
|
const custom = readFileSync12(HEARTBEAT_MD_PATH, "utf-8").trim();
|
|
15388
15616
|
if (custom) {
|
|
@@ -15646,7 +15874,6 @@ __export(ui_exports, {
|
|
|
15646
15874
|
sendBackendThinkingPicker: () => sendBackendThinkingPicker,
|
|
15647
15875
|
sendCouncilResults: () => sendCouncilResults,
|
|
15648
15876
|
sendCurrentProposal: () => sendCurrentProposal,
|
|
15649
|
-
sendEscalationKeyboard: () => sendEscalationKeyboard,
|
|
15650
15877
|
sendForgetPicker: () => sendForgetPicker,
|
|
15651
15878
|
sendHeartbeatEngine: () => sendHeartbeatEngine,
|
|
15652
15879
|
sendHeartbeatFallbacks: () => sendHeartbeatFallbacks,
|
|
@@ -17285,45 +17512,18 @@ async function doBackendSwitch(chatId, backendId, channel, opts) {
|
|
|
17285
17512
|
}
|
|
17286
17513
|
}
|
|
17287
17514
|
}
|
|
17288
|
-
async function sendEscalationKeyboard(chatId, channel, currentBackendId, messageId) {
|
|
17289
|
-
if (typeof channel.sendKeyboard !== "function") return void 0;
|
|
17290
|
-
const cliBackends = getAvailableChatBackendIds().filter((id) => {
|
|
17291
|
-
try {
|
|
17292
|
-
return getAdapter(id).type === "cli";
|
|
17293
|
-
} catch {
|
|
17294
|
-
return false;
|
|
17295
|
-
}
|
|
17296
|
-
});
|
|
17297
|
-
const text = [
|
|
17298
|
-
"\u{1F504} This looks like an agentic task (code changes, file ops, etc.).",
|
|
17299
|
-
"",
|
|
17300
|
-
`Your current backend (${currentBackendId}) uses the API with limited tools.`,
|
|
17301
|
-
"For full capabilities, switch to a CLI backend:"
|
|
17302
|
-
].join("\n");
|
|
17303
|
-
const buttons = [];
|
|
17304
|
-
for (const id of cliBackends) {
|
|
17305
|
-
const adapter = getAdapter(id);
|
|
17306
|
-
buttons.push([{
|
|
17307
|
-
label: `Switch to ${adapter.displayName}`,
|
|
17308
|
-
data: `escalate:switch:${id}`,
|
|
17309
|
-
style: "primary"
|
|
17310
|
-
}]);
|
|
17311
|
-
}
|
|
17312
|
-
buttons.push([
|
|
17313
|
-
{ label: "\u26A1 Bypass (30 min)", data: "escalate:bypass" },
|
|
17314
|
-
{ label: "\u2192 Proceed anyway", data: "escalate:proceed" }
|
|
17315
|
-
]);
|
|
17316
|
-
return sendOrEditKeyboard(chatId, channel, messageId, text, buttons);
|
|
17317
|
-
}
|
|
17318
17515
|
async function sendApiToolsKeyboard(chatId, channel, messageId) {
|
|
17319
|
-
const { getApiCliWhitelist: getApiCliWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
17516
|
+
const { getApiCliWhitelist: getApiCliWhitelist2, getApiWebSearchEnabled: getApiWebSearchEnabled2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
17320
17517
|
const entries = getApiCliWhitelist2(chatId);
|
|
17321
17518
|
const whitelist = entries.map((e) => e.cli);
|
|
17519
|
+
const webSearchEnabled = getApiWebSearchEnabled2(chatId);
|
|
17322
17520
|
const lines = [
|
|
17323
|
-
"\u{1F527} API Backend \u2014
|
|
17521
|
+
"\u{1F527} API Backend \u2014 Tools",
|
|
17324
17522
|
buildSectionHeader("", 26),
|
|
17325
17523
|
"",
|
|
17326
|
-
|
|
17524
|
+
`\u{1F50D} Built-in web search (DuckDuckGo): ${webSearchEnabled ? "\u{1F7E2} On" : "\u26AB Off"}`,
|
|
17525
|
+
"",
|
|
17526
|
+
"CLI Whitelist \u2014 commands the AI can run:",
|
|
17327
17527
|
""
|
|
17328
17528
|
];
|
|
17329
17529
|
if (whitelist.length > 0) {
|
|
@@ -17336,6 +17536,11 @@ async function sendApiToolsKeyboard(chatId, channel, messageId) {
|
|
|
17336
17536
|
lines.push("");
|
|
17337
17537
|
lines.push("Tap \u2795 to add a command pattern.");
|
|
17338
17538
|
const buttons = [];
|
|
17539
|
+
buttons.push([{
|
|
17540
|
+
label: webSearchEnabled ? "\u{1F50D} Disable Web Search" : "\u{1F50D} Enable Web Search",
|
|
17541
|
+
data: "apitools:toggle-web-search",
|
|
17542
|
+
style: webSearchEnabled ? "danger" : "success"
|
|
17543
|
+
}]);
|
|
17339
17544
|
for (const cmd of whitelist.slice(0, 10)) {
|
|
17340
17545
|
buttons.push([{
|
|
17341
17546
|
label: `\u2715 ${cmd.length > 25 ? cmd.slice(0, 25) + "\u2026" : cmd}`,
|
|
@@ -18721,7 +18926,7 @@ __export(analyze_exports, {
|
|
|
18721
18926
|
});
|
|
18722
18927
|
import { spawn as spawn4 } from "child_process";
|
|
18723
18928
|
import { createInterface as createInterface3 } from "readline";
|
|
18724
|
-
import { readFileSync as readFileSync13, existsSync as
|
|
18929
|
+
import { readFileSync as readFileSync13, existsSync as existsSync19, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
|
|
18725
18930
|
import { join as join18 } from "path";
|
|
18726
18931
|
import { homedir as homedir6 } from "os";
|
|
18727
18932
|
function applySignalDecay(confidence, createdAt) {
|
|
@@ -18735,12 +18940,12 @@ function discoverReflectionTargets() {
|
|
|
18735
18940
|
const targets = [];
|
|
18736
18941
|
try {
|
|
18737
18942
|
const skillsDir = join18(ccClawHome, "workspace", "skills");
|
|
18738
|
-
if (
|
|
18943
|
+
if (existsSync19(skillsDir)) {
|
|
18739
18944
|
for (const entry of readdirSync7(skillsDir)) {
|
|
18740
18945
|
const entryPath = join18(skillsDir, entry);
|
|
18741
18946
|
if (!statSync6(entryPath).isDirectory()) continue;
|
|
18742
18947
|
const skillFile = join18(entryPath, "SKILL.md");
|
|
18743
|
-
if (!
|
|
18948
|
+
if (!existsSync19(skillFile)) continue;
|
|
18744
18949
|
let desc = "skill";
|
|
18745
18950
|
try {
|
|
18746
18951
|
const content = readFileSync13(skillFile, "utf-8");
|
|
@@ -18755,7 +18960,7 @@ function discoverReflectionTargets() {
|
|
|
18755
18960
|
}
|
|
18756
18961
|
try {
|
|
18757
18962
|
const contextDir = join18(ccClawHome, "workspace", "context");
|
|
18758
|
-
if (
|
|
18963
|
+
if (existsSync19(contextDir)) {
|
|
18759
18964
|
for (const entry of readdirSync7(contextDir)) {
|
|
18760
18965
|
if (!entry.endsWith(".md")) continue;
|
|
18761
18966
|
const name = entry.replace(/\.md$/, "");
|
|
@@ -19110,7 +19315,7 @@ async function runAnalysisImpl(chatId, opts) {
|
|
|
19110
19315
|
if (!isRelevant) continue;
|
|
19111
19316
|
try {
|
|
19112
19317
|
const fullPath = join18(ccClawHome, target.path);
|
|
19113
|
-
if (
|
|
19318
|
+
if (existsSync19(fullPath)) {
|
|
19114
19319
|
const content = readFileSync13(fullPath, "utf-8");
|
|
19115
19320
|
if (totalSkillChars + content.length > SKILL_CONTENT_CAP) break;
|
|
19116
19321
|
skillContents.push({ path: target.path, content });
|
|
@@ -19491,7 +19696,7 @@ __export(apply_exports, {
|
|
|
19491
19696
|
isTargetAllowed: () => isTargetAllowed,
|
|
19492
19697
|
rollbackInsight: () => rollbackInsight
|
|
19493
19698
|
});
|
|
19494
|
-
import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as
|
|
19699
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as existsSync20, mkdirSync as mkdirSync7, readdirSync as readdirSync8, unlinkSync as unlinkSync5 } from "fs";
|
|
19495
19700
|
import { join as join19, dirname as dirname4 } from "path";
|
|
19496
19701
|
function isTargetAllowed(relativePath) {
|
|
19497
19702
|
if (relativePath.includes("..")) return false;
|
|
@@ -19578,7 +19783,7 @@ async function applyInsight(insightId) {
|
|
|
19578
19783
|
}
|
|
19579
19784
|
const absolutePath = join19(CC_CLAW_HOME, insight.targetFile);
|
|
19580
19785
|
if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
|
|
19581
|
-
if (
|
|
19786
|
+
if (existsSync20(absolutePath)) {
|
|
19582
19787
|
const currentContent = readFileSync14(absolutePath, "utf-8");
|
|
19583
19788
|
const lineCount = currentContent.split("\n").length;
|
|
19584
19789
|
if (lineCount >= SOUL_LINE_CAP) {
|
|
@@ -19600,7 +19805,7 @@ async function applyInsight(insightId) {
|
|
|
19600
19805
|
};
|
|
19601
19806
|
}
|
|
19602
19807
|
let original = "";
|
|
19603
|
-
if (
|
|
19808
|
+
if (existsSync20(absolutePath)) {
|
|
19604
19809
|
original = readFileSync14(absolutePath, "utf-8");
|
|
19605
19810
|
} else if (insight.proposedAction !== "create") {
|
|
19606
19811
|
return { success: false, message: `Target file "${insight.targetFile}" does not exist` };
|
|
@@ -19609,7 +19814,7 @@ async function applyInsight(insightId) {
|
|
|
19609
19814
|
const backupPath = absolutePath + `.bak.${timestamp}`;
|
|
19610
19815
|
try {
|
|
19611
19816
|
const parentDir = dirname4(absolutePath);
|
|
19612
|
-
if (!
|
|
19817
|
+
if (!existsSync20(parentDir)) {
|
|
19613
19818
|
mkdirSync7(parentDir, { recursive: true });
|
|
19614
19819
|
}
|
|
19615
19820
|
if (original) {
|
|
@@ -19741,7 +19946,7 @@ function computeLineDrift(baseline, absolutePath) {
|
|
|
19741
19946
|
if (!baseline) return 0;
|
|
19742
19947
|
let current = "";
|
|
19743
19948
|
try {
|
|
19744
|
-
if (
|
|
19949
|
+
if (existsSync20(absolutePath)) {
|
|
19745
19950
|
current = readFileSync14(absolutePath, "utf-8");
|
|
19746
19951
|
}
|
|
19747
19952
|
} catch {
|
|
@@ -19841,12 +20046,12 @@ var init_evolve = __esm({
|
|
|
19841
20046
|
const body = JSON.parse(await readBody(req));
|
|
19842
20047
|
const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
19843
20048
|
const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
|
|
19844
|
-
const { join:
|
|
20049
|
+
const { join: join42 } = await import("path");
|
|
19845
20050
|
const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
19846
20051
|
const chatId = resolveChatId(body);
|
|
19847
20052
|
if (!chatId) return jsonResponse(res, { error: "No chatId provided and ALLOWED_CHAT_ID is not set" }, 400);
|
|
19848
|
-
const soulPath =
|
|
19849
|
-
const userPath =
|
|
20053
|
+
const soulPath = join42(home, "identity/SOUL.md");
|
|
20054
|
+
const userPath = join42(home, "identity/USER.md");
|
|
19850
20055
|
const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
|
|
19851
20056
|
const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
|
|
19852
20057
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
@@ -19899,7 +20104,7 @@ var init_evolve = __esm({
|
|
|
19899
20104
|
});
|
|
19900
20105
|
|
|
19901
20106
|
// src/dashboard/routes/files.ts
|
|
19902
|
-
import { createWriteStream, existsSync as
|
|
20107
|
+
import { createWriteStream, existsSync as existsSync21 } from "fs";
|
|
19903
20108
|
import { readdir as readdir2, stat, unlink as unlink2, mkdir } from "fs/promises";
|
|
19904
20109
|
import { join as join20, extname } from "path";
|
|
19905
20110
|
function getUploadHtml(token, host) {
|
|
@@ -20107,7 +20312,7 @@ async function handleFileServe(req, res, url) {
|
|
|
20107
20312
|
return;
|
|
20108
20313
|
}
|
|
20109
20314
|
const filePath = join20(INCOMING_PATH, filename);
|
|
20110
|
-
if (!
|
|
20315
|
+
if (!existsSync21(filePath)) {
|
|
20111
20316
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
20112
20317
|
res.end("File not found");
|
|
20113
20318
|
return;
|
|
@@ -20533,6 +20738,36 @@ var init_detect_subagent = __esm({
|
|
|
20533
20738
|
}
|
|
20534
20739
|
});
|
|
20535
20740
|
|
|
20741
|
+
// src/mcps/unified-config.ts
|
|
20742
|
+
function buildUnifiedMcpConfig(orchestratorOpts) {
|
|
20743
|
+
const orchestrator = generateOrchestratorMcpConfig(orchestratorOpts);
|
|
20744
|
+
const servers = {};
|
|
20745
|
+
servers[orchestrator.name] = {
|
|
20746
|
+
command: orchestrator.command,
|
|
20747
|
+
args: orchestrator.args,
|
|
20748
|
+
env: orchestrator.env
|
|
20749
|
+
};
|
|
20750
|
+
const db3 = getDb();
|
|
20751
|
+
const mcps = getEnabledMcps(db3);
|
|
20752
|
+
for (const mcp2 of mcps) {
|
|
20753
|
+
if (mcp2.transport !== "stdio") continue;
|
|
20754
|
+
servers[mcp2.name] = {
|
|
20755
|
+
command: mcp2.command ?? void 0,
|
|
20756
|
+
args: mcp2.args ? JSON.parse(mcp2.args) : void 0,
|
|
20757
|
+
env: mcp2.env ? JSON.parse(mcp2.env) : void 0
|
|
20758
|
+
};
|
|
20759
|
+
}
|
|
20760
|
+
return { mcpServers: servers };
|
|
20761
|
+
}
|
|
20762
|
+
var init_unified_config = __esm({
|
|
20763
|
+
"src/mcps/unified-config.ts"() {
|
|
20764
|
+
"use strict";
|
|
20765
|
+
init_store5();
|
|
20766
|
+
init_store2();
|
|
20767
|
+
init_mcp_config();
|
|
20768
|
+
}
|
|
20769
|
+
});
|
|
20770
|
+
|
|
20536
20771
|
// src/reflection/detect.ts
|
|
20537
20772
|
var detect_exports = {};
|
|
20538
20773
|
__export(detect_exports, {
|
|
@@ -21288,7 +21523,7 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
21288
21523
|
const { entityType, bootstrapProfile: profile } = optsEntityType && optsProfile ? { entityType: optsEntityType, bootstrapProfile: optsProfile } : resolveFromLegacyTier(bootstrapTier ?? "full");
|
|
21289
21524
|
const effectiveAgentMode = optsAgentMode ?? getAgentMode(settingsChat);
|
|
21290
21525
|
const sideQuestCtx = settingsSourceChatId ? { parentChatId: settingsSourceChatId, actualChatId: chatId } : void 0;
|
|
21291
|
-
const fullPrompt = await assembleBootstrapPrompt(userMessage, entityType, profile, settingsChat, mode, responseStyle, effectiveAgentMode, sideQuestCtx, planningDirective, opts?.chatContext);
|
|
21526
|
+
const fullPrompt = await assembleBootstrapPrompt(userMessage, entityType, profile, settingsChat, mode, responseStyle, effectiveAgentMode, sideQuestCtx, planningDirective, opts?.chatContext, adapter.type);
|
|
21292
21527
|
if (adapter.streamDirect) {
|
|
21293
21528
|
const resolvedModel2 = model2 ?? adapter.defaultModel;
|
|
21294
21529
|
const abortController = new AbortController();
|
|
@@ -21334,8 +21569,9 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
21334
21569
|
if (cancelState2.cancelled) {
|
|
21335
21570
|
return { text: "Stopped.", usage: { input: sdUsage.input, output: sdUsage.output, cacheRead: 0 } };
|
|
21336
21571
|
}
|
|
21572
|
+
const fallbackText = adapter.type === "api" ? `I wasn't able to complete that request. This can happen when a required tool is blocked or unavailable. Check /tools to see what commands are whitelisted, then try again.` : `(No response from ${adapter.displayName})`;
|
|
21337
21573
|
return {
|
|
21338
|
-
text: sdResult.text ||
|
|
21574
|
+
text: sdResult.text || fallbackText,
|
|
21339
21575
|
usage: { input: sdUsage.input, output: sdUsage.output, cacheRead: 0 },
|
|
21340
21576
|
resolvedModel: resolvedModel2
|
|
21341
21577
|
};
|
|
@@ -21655,13 +21891,19 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
21655
21891
|
function getMcpConfigPath(chatId) {
|
|
21656
21892
|
if (process.env.DASHBOARD_ENABLED !== "1") return null;
|
|
21657
21893
|
const token = getDashboardToken();
|
|
21658
|
-
|
|
21659
|
-
|
|
21894
|
+
if (!token) return null;
|
|
21895
|
+
const config2 = buildUnifiedMcpConfig({
|
|
21896
|
+
chatId,
|
|
21897
|
+
agentId: "main",
|
|
21898
|
+
token,
|
|
21899
|
+
port: process.env.DASHBOARD_PORT ?? "3141"
|
|
21900
|
+
});
|
|
21901
|
+
return writeUnifiedMcpConfigFile(config2);
|
|
21660
21902
|
}
|
|
21661
21903
|
function injectMcpConfig(adapterId, args, mcpConfigPath) {
|
|
21662
21904
|
const flag = MCP_CONFIG_FLAG[adapterId];
|
|
21663
21905
|
if (!flag) return args;
|
|
21664
|
-
return [...args, ...flag, mcpConfigPath];
|
|
21906
|
+
return [...args, ...flag, mcpConfigPath, "--strict-mcp-config"];
|
|
21665
21907
|
}
|
|
21666
21908
|
var activeChats, staleSweepTimer, chatLocks, SPAWN_TIMEOUT_MS, FIRST_RESPONSE_TIMEOUT_MS, CONTENT_SILENCE_TIMEOUT_MS, CONTENT_SILENCE_TIMEOUT_ERROR, FIRST_RESPONSE_TIMEOUT_ERROR, FREE_SLOTS_EXHAUSTED, GEMINI_FALLBACK_CHAIN, GEMINI_DOWNGRADE_MODELS, MCP_CONFIG_FLAG;
|
|
21667
21909
|
var init_agent = __esm({
|
|
@@ -21686,9 +21928,10 @@ var init_agent = __esm({
|
|
|
21686
21928
|
init_store5();
|
|
21687
21929
|
init_store5();
|
|
21688
21930
|
init_server();
|
|
21689
|
-
init_mcp_config();
|
|
21690
21931
|
init_store5();
|
|
21691
21932
|
init_detect_subagent();
|
|
21933
|
+
init_unified_config();
|
|
21934
|
+
init_mcp_config();
|
|
21692
21935
|
activeChats = /* @__PURE__ */ new Map();
|
|
21693
21936
|
chatLocks = /* @__PURE__ */ new Map();
|
|
21694
21937
|
SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
@@ -21925,7 +22168,7 @@ function getBackoffMs(retryCount) {
|
|
|
21925
22168
|
const jitter = Math.floor(base * 0.2 * (Math.random() * 2 - 1));
|
|
21926
22169
|
return base + jitter;
|
|
21927
22170
|
}
|
|
21928
|
-
var EXHAUSTED_PATTERNS, TRANSIENT_PATTERNS, PERMANENT_PATTERNS, BACKOFF_MS,
|
|
22171
|
+
var EXHAUSTED_PATTERNS, TRANSIENT_PATTERNS, PERMANENT_PATTERNS, BACKOFF_MS, MAX_RETRIES3, AUTO_PAUSE_THRESHOLD;
|
|
21929
22172
|
var init_retry = __esm({
|
|
21930
22173
|
"src/scheduler/retry.ts"() {
|
|
21931
22174
|
"use strict";
|
|
@@ -21975,13 +22218,13 @@ var init_retry = __esm({
|
|
|
21975
22218
|
/subscription.*expired/i
|
|
21976
22219
|
];
|
|
21977
22220
|
BACKOFF_MS = [3e4, 6e4, 3e5];
|
|
21978
|
-
|
|
22221
|
+
MAX_RETRIES3 = 3;
|
|
21979
22222
|
AUTO_PAUSE_THRESHOLD = 5;
|
|
21980
22223
|
}
|
|
21981
22224
|
});
|
|
21982
22225
|
|
|
21983
22226
|
// src/bootstrap/profile.ts
|
|
21984
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, existsSync as
|
|
22227
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, existsSync as existsSync22 } from "fs";
|
|
21985
22228
|
import { join as join21 } from "path";
|
|
21986
22229
|
function hasActiveProfile(chatId) {
|
|
21987
22230
|
return activeProfiles.has(chatId);
|
|
@@ -22111,7 +22354,7 @@ function extractUserUpdates(text) {
|
|
|
22111
22354
|
return { cleanText, updates };
|
|
22112
22355
|
}
|
|
22113
22356
|
function appendToUserProfile(key, value) {
|
|
22114
|
-
if (!
|
|
22357
|
+
if (!existsSync22(USER_PATH2)) return;
|
|
22115
22358
|
const content = readFileSync15(USER_PATH2, "utf-8");
|
|
22116
22359
|
const line = `- **${key}**: ${value}`;
|
|
22117
22360
|
if (content.includes(line)) return;
|
|
@@ -22132,203 +22375,13 @@ var init_profile = __esm({
|
|
|
22132
22375
|
}
|
|
22133
22376
|
});
|
|
22134
22377
|
|
|
22135
|
-
// src/router/state.ts
|
|
22136
|
-
var state_exports = {};
|
|
22137
|
-
__export(state_exports, {
|
|
22138
|
-
activeSideQuests: () => activeSideQuests,
|
|
22139
|
-
bypassBusyCheck: () => bypassBusyCheck,
|
|
22140
|
-
clearEscalationBypass: () => clearEscalationBypass,
|
|
22141
|
-
clearHistoryFilter: () => clearHistoryFilter,
|
|
22142
|
-
clearPendingCliAddition: () => clearPendingCliAddition,
|
|
22143
|
-
clearPendingModelResults: () => clearPendingModelResults,
|
|
22144
|
-
clearPendingModelSearch: () => clearPendingModelSearch,
|
|
22145
|
-
consumeAgenticBypass: () => consumeAgenticBypass,
|
|
22146
|
-
councilResults: () => councilResults,
|
|
22147
|
-
dashboardClawWarnings: () => dashboardClawWarnings,
|
|
22148
|
-
getActiveSideQuestCount: () => getActiveSideQuestCount,
|
|
22149
|
-
hasEscalationBypass: () => hasEscalationBypass,
|
|
22150
|
-
historyFilters: () => historyFilters,
|
|
22151
|
-
parseSideQuestPrefix: () => parseSideQuestPrefix,
|
|
22152
|
-
pendingCliAdditions: () => pendingCliAdditions,
|
|
22153
|
-
pendingInterrupts: () => pendingInterrupts,
|
|
22154
|
-
pendingModelResults: () => pendingModelResults,
|
|
22155
|
-
pendingModelSearch: () => pendingModelSearch,
|
|
22156
|
-
pendingNewchatUndo: () => pendingNewchatUndo,
|
|
22157
|
-
pendingSummaryUndo: () => pendingSummaryUndo,
|
|
22158
|
-
setAgenticBypass: () => setAgenticBypass,
|
|
22159
|
-
setCouncilResult: () => setCouncilResult,
|
|
22160
|
-
setEscalationBypass: () => setEscalationBypass,
|
|
22161
|
-
setHistoryFilter: () => setHistoryFilter,
|
|
22162
|
-
setPendingCliAddition: () => setPendingCliAddition,
|
|
22163
|
-
setPendingModelResults: () => setPendingModelResults,
|
|
22164
|
-
setPendingModelSearch: () => setPendingModelSearch,
|
|
22165
|
-
startStateSweep: () => startStateSweep,
|
|
22166
|
-
stopAllSideQuests: () => stopAllSideQuests,
|
|
22167
|
-
stopStateSweep: () => stopStateSweep
|
|
22168
|
-
});
|
|
22169
|
-
function setHistoryFilter(chatId, filter) {
|
|
22170
|
-
historyFilters.set(chatId, filter);
|
|
22171
|
-
historyFilterTimestamps.set(chatId, Date.now());
|
|
22172
|
-
}
|
|
22173
|
-
function clearHistoryFilter(chatId) {
|
|
22174
|
-
historyFilters.delete(chatId);
|
|
22175
|
-
historyFilterTimestamps.delete(chatId);
|
|
22176
|
-
}
|
|
22177
|
-
function setCouncilResult(chatId, result) {
|
|
22178
|
-
councilResults.set(chatId, result);
|
|
22179
|
-
councilResultTimestamps.set(chatId, Date.now());
|
|
22180
|
-
}
|
|
22181
|
-
function setPendingModelSearch(chatId, state) {
|
|
22182
|
-
pendingModelSearch.set(chatId, state);
|
|
22183
|
-
pendingModelSearchTimestamps.set(chatId, Date.now());
|
|
22184
|
-
}
|
|
22185
|
-
function clearPendingModelSearch(chatId) {
|
|
22186
|
-
pendingModelSearch.delete(chatId);
|
|
22187
|
-
pendingModelSearchTimestamps.delete(chatId);
|
|
22188
|
-
}
|
|
22189
|
-
function setPendingModelResults(chatId, results) {
|
|
22190
|
-
pendingModelResults.set(chatId, results);
|
|
22191
|
-
}
|
|
22192
|
-
function clearPendingModelResults(chatId) {
|
|
22193
|
-
pendingModelResults.delete(chatId);
|
|
22194
|
-
}
|
|
22195
|
-
function parseSideQuestPrefix(text) {
|
|
22196
|
-
const match = text.match(/^(?:sq|btw):\s*/i);
|
|
22197
|
-
if (match) return { isSideQuest: true, cleanText: text.slice(match[0].length) };
|
|
22198
|
-
return { isSideQuest: false, cleanText: text };
|
|
22199
|
-
}
|
|
22200
|
-
function getActiveSideQuestCount(chatId) {
|
|
22201
|
-
return activeSideQuests.get(chatId)?.size ?? 0;
|
|
22202
|
-
}
|
|
22203
|
-
function stopAllSideQuests(chatId) {
|
|
22204
|
-
const active = activeSideQuests.get(chatId);
|
|
22205
|
-
if (active) {
|
|
22206
|
-
for (const sqId of active) {
|
|
22207
|
-
stopAgent(sqId);
|
|
22208
|
-
}
|
|
22209
|
-
}
|
|
22210
|
-
}
|
|
22211
|
-
function startStateSweep() {
|
|
22212
|
-
if (sweepTimer) return;
|
|
22213
|
-
sweepTimer = setInterval(() => {
|
|
22214
|
-
const now = Date.now();
|
|
22215
|
-
for (const [chatId, ts2] of dashboardClawWarnings) {
|
|
22216
|
-
if (now - ts2 > STALE_THRESHOLD_MS) dashboardClawWarnings.delete(chatId);
|
|
22217
|
-
}
|
|
22218
|
-
for (const [cid, ts2] of historyFilterTimestamps) {
|
|
22219
|
-
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
22220
|
-
historyFilters.delete(cid);
|
|
22221
|
-
historyFilterTimestamps.delete(cid);
|
|
22222
|
-
}
|
|
22223
|
-
}
|
|
22224
|
-
for (const [cid, ts2] of councilResultTimestamps) {
|
|
22225
|
-
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
22226
|
-
councilResults.delete(cid);
|
|
22227
|
-
councilResultTimestamps.delete(cid);
|
|
22228
|
-
}
|
|
22229
|
-
}
|
|
22230
|
-
for (const [cid, ts2] of pendingModelSearchTimestamps) {
|
|
22231
|
-
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
22232
|
-
pendingModelSearch.delete(cid);
|
|
22233
|
-
pendingModelSearchTimestamps.delete(cid);
|
|
22234
|
-
}
|
|
22235
|
-
}
|
|
22236
|
-
for (const chatId of pendingInterrupts.keys()) {
|
|
22237
|
-
if (!_interruptSeen.has(chatId)) {
|
|
22238
|
-
_interruptSeen.add(chatId);
|
|
22239
|
-
} else {
|
|
22240
|
-
pendingInterrupts.delete(chatId);
|
|
22241
|
-
_interruptSeen.delete(chatId);
|
|
22242
|
-
}
|
|
22243
|
-
}
|
|
22244
|
-
for (const chatId of _interruptSeen) {
|
|
22245
|
-
if (!pendingInterrupts.has(chatId)) _interruptSeen.delete(chatId);
|
|
22246
|
-
}
|
|
22247
|
-
for (const [chatId, expiry] of escalationBypasses) {
|
|
22248
|
-
if (now > expiry) escalationBypasses.delete(chatId);
|
|
22249
|
-
}
|
|
22250
|
-
for (const [cid, ts2] of pendingCliTimestamps) {
|
|
22251
|
-
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
22252
|
-
pendingCliAdditions.delete(cid);
|
|
22253
|
-
pendingCliTimestamps.delete(cid);
|
|
22254
|
-
}
|
|
22255
|
-
}
|
|
22256
|
-
}, SWEEP_INTERVAL_MS);
|
|
22257
|
-
sweepTimer.unref();
|
|
22258
|
-
}
|
|
22259
|
-
function stopStateSweep() {
|
|
22260
|
-
if (sweepTimer) {
|
|
22261
|
-
clearInterval(sweepTimer);
|
|
22262
|
-
sweepTimer = null;
|
|
22263
|
-
}
|
|
22264
|
-
}
|
|
22265
|
-
function setEscalationBypass(chatId) {
|
|
22266
|
-
escalationBypasses.set(chatId, Date.now() + ESCALATION_BYPASS_MS);
|
|
22267
|
-
}
|
|
22268
|
-
function hasEscalationBypass(chatId) {
|
|
22269
|
-
const expiry = escalationBypasses.get(chatId);
|
|
22270
|
-
if (!expiry) return false;
|
|
22271
|
-
if (Date.now() > expiry) {
|
|
22272
|
-
escalationBypasses.delete(chatId);
|
|
22273
|
-
return false;
|
|
22274
|
-
}
|
|
22275
|
-
return true;
|
|
22276
|
-
}
|
|
22277
|
-
function clearEscalationBypass(chatId) {
|
|
22278
|
-
escalationBypasses.delete(chatId);
|
|
22279
|
-
}
|
|
22280
|
-
function setAgenticBypass(chatId) {
|
|
22281
|
-
agenticBypass.add(chatId);
|
|
22282
|
-
}
|
|
22283
|
-
function consumeAgenticBypass(chatId) {
|
|
22284
|
-
return agenticBypass.delete(chatId);
|
|
22285
|
-
}
|
|
22286
|
-
function setPendingCliAddition(chatId, messageId) {
|
|
22287
|
-
pendingCliAdditions.set(chatId, messageId);
|
|
22288
|
-
pendingCliTimestamps.set(chatId, Date.now());
|
|
22289
|
-
}
|
|
22290
|
-
function clearPendingCliAddition(chatId) {
|
|
22291
|
-
pendingCliAdditions.delete(chatId);
|
|
22292
|
-
pendingCliTimestamps.delete(chatId);
|
|
22293
|
-
}
|
|
22294
|
-
var pendingInterrupts, bypassBusyCheck, activeSideQuests, dashboardClawWarnings, pendingSummaryUndo, pendingNewchatUndo, historyFilters, historyFilterTimestamps, councilResults, councilResultTimestamps, pendingModelSearch, pendingModelSearchTimestamps, pendingModelResults, SWEEP_INTERVAL_MS, STALE_THRESHOLD_MS, sweepTimer, _interruptSeen, ESCALATION_BYPASS_MS, escalationBypasses, agenticBypass, pendingCliAdditions, pendingCliTimestamps;
|
|
22295
|
-
var init_state = __esm({
|
|
22296
|
-
"src/router/state.ts"() {
|
|
22297
|
-
"use strict";
|
|
22298
|
-
init_agent();
|
|
22299
|
-
pendingInterrupts = /* @__PURE__ */ new Map();
|
|
22300
|
-
bypassBusyCheck = /* @__PURE__ */ new Set();
|
|
22301
|
-
activeSideQuests = /* @__PURE__ */ new Map();
|
|
22302
|
-
dashboardClawWarnings = /* @__PURE__ */ new Map();
|
|
22303
|
-
pendingSummaryUndo = /* @__PURE__ */ new Map();
|
|
22304
|
-
pendingNewchatUndo = /* @__PURE__ */ new Map();
|
|
22305
|
-
historyFilters = /* @__PURE__ */ new Map();
|
|
22306
|
-
historyFilterTimestamps = /* @__PURE__ */ new Map();
|
|
22307
|
-
councilResults = /* @__PURE__ */ new Map();
|
|
22308
|
-
councilResultTimestamps = /* @__PURE__ */ new Map();
|
|
22309
|
-
pendingModelSearch = /* @__PURE__ */ new Map();
|
|
22310
|
-
pendingModelSearchTimestamps = /* @__PURE__ */ new Map();
|
|
22311
|
-
pendingModelResults = /* @__PURE__ */ new Map();
|
|
22312
|
-
SWEEP_INTERVAL_MS = 30 * 60 * 1e3;
|
|
22313
|
-
STALE_THRESHOLD_MS = 30 * 60 * 1e3;
|
|
22314
|
-
sweepTimer = null;
|
|
22315
|
-
_interruptSeen = /* @__PURE__ */ new Set();
|
|
22316
|
-
ESCALATION_BYPASS_MS = 30 * 60 * 1e3;
|
|
22317
|
-
escalationBypasses = /* @__PURE__ */ new Map();
|
|
22318
|
-
agenticBypass = /* @__PURE__ */ new Set();
|
|
22319
|
-
pendingCliAdditions = /* @__PURE__ */ new Map();
|
|
22320
|
-
pendingCliTimestamps = /* @__PURE__ */ new Map();
|
|
22321
|
-
}
|
|
22322
|
-
});
|
|
22323
|
-
|
|
22324
22378
|
// src/intent/classify.ts
|
|
22325
22379
|
var classify_exports = {};
|
|
22326
22380
|
__export(classify_exports, {
|
|
22327
22381
|
classifyIntent: () => classifyIntent,
|
|
22328
22382
|
classifyIntentAsync: () => classifyIntentAsync,
|
|
22329
22383
|
getIntentStats: () => getIntentStats,
|
|
22330
|
-
resetIntentStats: () => resetIntentStats
|
|
22331
|
-
shouldEscalate: () => shouldEscalate
|
|
22384
|
+
resetIntentStats: () => resetIntentStats
|
|
22332
22385
|
});
|
|
22333
22386
|
function getIntentStats() {
|
|
22334
22387
|
return { ...intentCounts };
|
|
@@ -22338,7 +22391,6 @@ function resetIntentStats() {
|
|
|
22338
22391
|
intentCounts.agentic = 0;
|
|
22339
22392
|
}
|
|
22340
22393
|
function classifyIntentFast(text, chatId) {
|
|
22341
|
-
if (consumeAgenticBypass(chatId)) return "agentic";
|
|
22342
22394
|
const trimmed = text.trim();
|
|
22343
22395
|
if (trimmed.startsWith(">>")) return "agentic";
|
|
22344
22396
|
if (trimmed.startsWith("/")) return "agentic";
|
|
@@ -22508,16 +22560,12 @@ async function classifyIntentAsync(text, chatId) {
|
|
|
22508
22560
|
intentCounts.agentic++;
|
|
22509
22561
|
return "agentic";
|
|
22510
22562
|
}
|
|
22511
|
-
function shouldEscalate(backendType, intent) {
|
|
22512
|
-
return backendType === "api" && intent === "agentic";
|
|
22513
|
-
}
|
|
22514
22563
|
var intentCounts, CHAT_EXACT, MUTATION_PATTERNS, CHAT_QUESTION_PATTERNS, STRUCTURAL_PATTERNS, LLM_CLASSIFY_PROMPT, LLM_CLASSIFY_TIMEOUT_MS;
|
|
22515
22564
|
var init_classify = __esm({
|
|
22516
22565
|
"src/intent/classify.ts"() {
|
|
22517
22566
|
"use strict";
|
|
22518
22567
|
init_store5();
|
|
22519
22568
|
init_session_log();
|
|
22520
|
-
init_state();
|
|
22521
22569
|
init_log();
|
|
22522
22570
|
intentCounts = { chat: 0, agentic: 0 };
|
|
22523
22571
|
CHAT_EXACT = /* @__PURE__ */ new Set([
|
|
@@ -23305,7 +23353,7 @@ __export(session_log_exports2, {
|
|
|
23305
23353
|
startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
|
|
23306
23354
|
tailSessionLog: () => tailSessionLog
|
|
23307
23355
|
});
|
|
23308
|
-
import { existsSync as
|
|
23356
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync9, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
|
|
23309
23357
|
import { join as join22, basename } from "path";
|
|
23310
23358
|
import { createInterface as createInterface6 } from "readline";
|
|
23311
23359
|
function getRetentionDays() {
|
|
@@ -23318,7 +23366,7 @@ function getRetentionDays() {
|
|
|
23318
23366
|
}
|
|
23319
23367
|
function cleanupSessionLogs(retentionDays) {
|
|
23320
23368
|
const days = retentionDays ?? getRetentionDays();
|
|
23321
|
-
if (!
|
|
23369
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return 0;
|
|
23322
23370
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
23323
23371
|
let cleaned = 0;
|
|
23324
23372
|
try {
|
|
@@ -23350,7 +23398,7 @@ function startSessionLogCleanupTimer() {
|
|
|
23350
23398
|
return timer;
|
|
23351
23399
|
}
|
|
23352
23400
|
function listSessionLogs() {
|
|
23353
|
-
if (!
|
|
23401
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return [];
|
|
23354
23402
|
const logs = [];
|
|
23355
23403
|
for (const file of readdirSync9(SESSION_LOGS_PATH)) {
|
|
23356
23404
|
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
@@ -23373,7 +23421,7 @@ function listSessionLogs() {
|
|
|
23373
23421
|
return logs;
|
|
23374
23422
|
}
|
|
23375
23423
|
async function* tailSessionLog(filePath, lines = 50) {
|
|
23376
|
-
if (!
|
|
23424
|
+
if (!existsSync23(filePath)) {
|
|
23377
23425
|
yield `File not found: ${filePath}`;
|
|
23378
23426
|
return;
|
|
23379
23427
|
}
|
|
@@ -23401,7 +23449,7 @@ var init_session_log2 = __esm({
|
|
|
23401
23449
|
constructor(chatId, backend2, model2) {
|
|
23402
23450
|
this.backend = backend2;
|
|
23403
23451
|
this.model = model2;
|
|
23404
|
-
if (!
|
|
23452
|
+
if (!existsSync23(SESSION_LOGS_PATH)) {
|
|
23405
23453
|
mkdirSync8(SESSION_LOGS_PATH, { recursive: true });
|
|
23406
23454
|
}
|
|
23407
23455
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
@@ -23887,7 +23935,7 @@ var init_gate = __esm({
|
|
|
23887
23935
|
});
|
|
23888
23936
|
|
|
23889
23937
|
// src/media/image-gen.ts
|
|
23890
|
-
import { mkdirSync as mkdirSync9, existsSync as
|
|
23938
|
+
import { mkdirSync as mkdirSync9, existsSync as existsSync24, unlink as unlink3, readdir as readdir3, stat as stat2 } from "fs";
|
|
23891
23939
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
23892
23940
|
import { join as join23 } from "path";
|
|
23893
23941
|
async function generateImage(prompt) {
|
|
@@ -23936,7 +23984,7 @@ async function generateImage(prompt) {
|
|
|
23936
23984
|
if (!imageData) {
|
|
23937
23985
|
throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
|
|
23938
23986
|
}
|
|
23939
|
-
if (!
|
|
23987
|
+
if (!existsSync24(IMAGE_OUTPUT_DIR)) {
|
|
23940
23988
|
mkdirSync9(IMAGE_OUTPUT_DIR, { recursive: true });
|
|
23941
23989
|
}
|
|
23942
23990
|
const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
|
|
@@ -24765,6 +24813,168 @@ var init_media = __esm({
|
|
|
24765
24813
|
}
|
|
24766
24814
|
});
|
|
24767
24815
|
|
|
24816
|
+
// src/router/state.ts
|
|
24817
|
+
var state_exports = {};
|
|
24818
|
+
__export(state_exports, {
|
|
24819
|
+
activeSideQuests: () => activeSideQuests,
|
|
24820
|
+
bypassBusyCheck: () => bypassBusyCheck,
|
|
24821
|
+
clearHistoryFilter: () => clearHistoryFilter,
|
|
24822
|
+
clearPendingCliAddition: () => clearPendingCliAddition,
|
|
24823
|
+
clearPendingModelResults: () => clearPendingModelResults,
|
|
24824
|
+
clearPendingModelSearch: () => clearPendingModelSearch,
|
|
24825
|
+
councilResults: () => councilResults,
|
|
24826
|
+
dashboardClawWarnings: () => dashboardClawWarnings,
|
|
24827
|
+
getActiveSideQuestCount: () => getActiveSideQuestCount,
|
|
24828
|
+
historyFilters: () => historyFilters,
|
|
24829
|
+
parseSideQuestPrefix: () => parseSideQuestPrefix,
|
|
24830
|
+
pendingCliAdditions: () => pendingCliAdditions,
|
|
24831
|
+
pendingInterrupts: () => pendingInterrupts,
|
|
24832
|
+
pendingMcpImports: () => pendingMcpImports,
|
|
24833
|
+
pendingModelResults: () => pendingModelResults,
|
|
24834
|
+
pendingModelSearch: () => pendingModelSearch,
|
|
24835
|
+
pendingNewchatUndo: () => pendingNewchatUndo,
|
|
24836
|
+
pendingSummaryUndo: () => pendingSummaryUndo,
|
|
24837
|
+
setCouncilResult: () => setCouncilResult,
|
|
24838
|
+
setHistoryFilter: () => setHistoryFilter,
|
|
24839
|
+
setPendingCliAddition: () => setPendingCliAddition,
|
|
24840
|
+
setPendingModelResults: () => setPendingModelResults,
|
|
24841
|
+
setPendingModelSearch: () => setPendingModelSearch,
|
|
24842
|
+
startStateSweep: () => startStateSweep,
|
|
24843
|
+
stopAllSideQuests: () => stopAllSideQuests,
|
|
24844
|
+
stopStateSweep: () => stopStateSweep
|
|
24845
|
+
});
|
|
24846
|
+
function setHistoryFilter(chatId, filter) {
|
|
24847
|
+
historyFilters.set(chatId, filter);
|
|
24848
|
+
historyFilterTimestamps.set(chatId, Date.now());
|
|
24849
|
+
}
|
|
24850
|
+
function clearHistoryFilter(chatId) {
|
|
24851
|
+
historyFilters.delete(chatId);
|
|
24852
|
+
historyFilterTimestamps.delete(chatId);
|
|
24853
|
+
}
|
|
24854
|
+
function setCouncilResult(chatId, result) {
|
|
24855
|
+
councilResults.set(chatId, result);
|
|
24856
|
+
councilResultTimestamps.set(chatId, Date.now());
|
|
24857
|
+
}
|
|
24858
|
+
function setPendingModelSearch(chatId, state) {
|
|
24859
|
+
pendingModelSearch.set(chatId, state);
|
|
24860
|
+
pendingModelSearchTimestamps.set(chatId, Date.now());
|
|
24861
|
+
}
|
|
24862
|
+
function clearPendingModelSearch(chatId) {
|
|
24863
|
+
pendingModelSearch.delete(chatId);
|
|
24864
|
+
pendingModelSearchTimestamps.delete(chatId);
|
|
24865
|
+
}
|
|
24866
|
+
function setPendingModelResults(chatId, results) {
|
|
24867
|
+
pendingModelResults.set(chatId, results);
|
|
24868
|
+
}
|
|
24869
|
+
function clearPendingModelResults(chatId) {
|
|
24870
|
+
pendingModelResults.delete(chatId);
|
|
24871
|
+
}
|
|
24872
|
+
function parseSideQuestPrefix(text) {
|
|
24873
|
+
const match = text.match(/^(?:sq|btw):\s*/i);
|
|
24874
|
+
if (match) return { isSideQuest: true, cleanText: text.slice(match[0].length) };
|
|
24875
|
+
return { isSideQuest: false, cleanText: text };
|
|
24876
|
+
}
|
|
24877
|
+
function getActiveSideQuestCount(chatId) {
|
|
24878
|
+
return activeSideQuests.get(chatId)?.size ?? 0;
|
|
24879
|
+
}
|
|
24880
|
+
function stopAllSideQuests(chatId) {
|
|
24881
|
+
const active = activeSideQuests.get(chatId);
|
|
24882
|
+
if (active) {
|
|
24883
|
+
for (const sqId of active) {
|
|
24884
|
+
stopAgent(sqId);
|
|
24885
|
+
}
|
|
24886
|
+
}
|
|
24887
|
+
}
|
|
24888
|
+
function startStateSweep() {
|
|
24889
|
+
if (sweepTimer) return;
|
|
24890
|
+
sweepTimer = setInterval(() => {
|
|
24891
|
+
const now = Date.now();
|
|
24892
|
+
for (const [chatId, ts2] of dashboardClawWarnings) {
|
|
24893
|
+
if (now - ts2 > STALE_THRESHOLD_MS) dashboardClawWarnings.delete(chatId);
|
|
24894
|
+
}
|
|
24895
|
+
for (const [cid, ts2] of historyFilterTimestamps) {
|
|
24896
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24897
|
+
historyFilters.delete(cid);
|
|
24898
|
+
historyFilterTimestamps.delete(cid);
|
|
24899
|
+
}
|
|
24900
|
+
}
|
|
24901
|
+
for (const [cid, ts2] of councilResultTimestamps) {
|
|
24902
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24903
|
+
councilResults.delete(cid);
|
|
24904
|
+
councilResultTimestamps.delete(cid);
|
|
24905
|
+
}
|
|
24906
|
+
}
|
|
24907
|
+
for (const [cid, ts2] of pendingModelSearchTimestamps) {
|
|
24908
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24909
|
+
pendingModelSearch.delete(cid);
|
|
24910
|
+
pendingModelSearchTimestamps.delete(cid);
|
|
24911
|
+
}
|
|
24912
|
+
}
|
|
24913
|
+
for (const chatId of pendingInterrupts.keys()) {
|
|
24914
|
+
if (!_interruptSeen.has(chatId)) {
|
|
24915
|
+
_interruptSeen.add(chatId);
|
|
24916
|
+
} else {
|
|
24917
|
+
pendingInterrupts.delete(chatId);
|
|
24918
|
+
_interruptSeen.delete(chatId);
|
|
24919
|
+
}
|
|
24920
|
+
}
|
|
24921
|
+
for (const chatId of _interruptSeen) {
|
|
24922
|
+
if (!pendingInterrupts.has(chatId)) _interruptSeen.delete(chatId);
|
|
24923
|
+
}
|
|
24924
|
+
for (const [cid, ts2] of pendingCliTimestamps) {
|
|
24925
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24926
|
+
pendingCliAdditions.delete(cid);
|
|
24927
|
+
pendingCliTimestamps.delete(cid);
|
|
24928
|
+
}
|
|
24929
|
+
}
|
|
24930
|
+
for (const [cid, state] of pendingMcpImports) {
|
|
24931
|
+
if (now - state.startedAt > STALE_THRESHOLD_MS) pendingMcpImports.delete(cid);
|
|
24932
|
+
}
|
|
24933
|
+
}, SWEEP_INTERVAL_MS);
|
|
24934
|
+
sweepTimer.unref();
|
|
24935
|
+
}
|
|
24936
|
+
function stopStateSweep() {
|
|
24937
|
+
if (sweepTimer) {
|
|
24938
|
+
clearInterval(sweepTimer);
|
|
24939
|
+
sweepTimer = null;
|
|
24940
|
+
}
|
|
24941
|
+
}
|
|
24942
|
+
function setPendingCliAddition(chatId, messageId) {
|
|
24943
|
+
pendingCliAdditions.set(chatId, messageId);
|
|
24944
|
+
pendingCliTimestamps.set(chatId, Date.now());
|
|
24945
|
+
}
|
|
24946
|
+
function clearPendingCliAddition(chatId) {
|
|
24947
|
+
pendingCliAdditions.delete(chatId);
|
|
24948
|
+
pendingCliTimestamps.delete(chatId);
|
|
24949
|
+
}
|
|
24950
|
+
var pendingInterrupts, bypassBusyCheck, activeSideQuests, dashboardClawWarnings, pendingSummaryUndo, pendingNewchatUndo, historyFilters, historyFilterTimestamps, councilResults, councilResultTimestamps, pendingModelSearch, pendingModelSearchTimestamps, pendingModelResults, SWEEP_INTERVAL_MS, STALE_THRESHOLD_MS, sweepTimer, _interruptSeen, pendingMcpImports, pendingCliAdditions, pendingCliTimestamps;
|
|
24951
|
+
var init_state = __esm({
|
|
24952
|
+
"src/router/state.ts"() {
|
|
24953
|
+
"use strict";
|
|
24954
|
+
init_agent();
|
|
24955
|
+
pendingInterrupts = /* @__PURE__ */ new Map();
|
|
24956
|
+
bypassBusyCheck = /* @__PURE__ */ new Set();
|
|
24957
|
+
activeSideQuests = /* @__PURE__ */ new Map();
|
|
24958
|
+
dashboardClawWarnings = /* @__PURE__ */ new Map();
|
|
24959
|
+
pendingSummaryUndo = /* @__PURE__ */ new Map();
|
|
24960
|
+
pendingNewchatUndo = /* @__PURE__ */ new Map();
|
|
24961
|
+
historyFilters = /* @__PURE__ */ new Map();
|
|
24962
|
+
historyFilterTimestamps = /* @__PURE__ */ new Map();
|
|
24963
|
+
councilResults = /* @__PURE__ */ new Map();
|
|
24964
|
+
councilResultTimestamps = /* @__PURE__ */ new Map();
|
|
24965
|
+
pendingModelSearch = /* @__PURE__ */ new Map();
|
|
24966
|
+
pendingModelSearchTimestamps = /* @__PURE__ */ new Map();
|
|
24967
|
+
pendingModelResults = /* @__PURE__ */ new Map();
|
|
24968
|
+
SWEEP_INTERVAL_MS = 30 * 60 * 1e3;
|
|
24969
|
+
STALE_THRESHOLD_MS = 30 * 60 * 1e3;
|
|
24970
|
+
sweepTimer = null;
|
|
24971
|
+
_interruptSeen = /* @__PURE__ */ new Set();
|
|
24972
|
+
pendingMcpImports = /* @__PURE__ */ new Map();
|
|
24973
|
+
pendingCliAdditions = /* @__PURE__ */ new Map();
|
|
24974
|
+
pendingCliTimestamps = /* @__PURE__ */ new Map();
|
|
24975
|
+
}
|
|
24976
|
+
});
|
|
24977
|
+
|
|
24768
24978
|
// src/router/sidequest.ts
|
|
24769
24979
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
24770
24980
|
async function handleSideQuest(parentChatId, msg, channel) {
|
|
@@ -24954,7 +25164,7 @@ __export(install_exports, {
|
|
|
24954
25164
|
installSkillFromGitHub: () => installSkillFromGitHub
|
|
24955
25165
|
});
|
|
24956
25166
|
import { mkdir as mkdir3, readdir as readdir5, readFile as readFile5, cp } from "fs/promises";
|
|
24957
|
-
import { existsSync as
|
|
25167
|
+
import { existsSync as existsSync25 } from "fs";
|
|
24958
25168
|
import { join as join25, basename as basename2 } from "path";
|
|
24959
25169
|
import { execSync as execSync4 } from "child_process";
|
|
24960
25170
|
async function installSkillFromGitHub(urlOrShorthand) {
|
|
@@ -24973,7 +25183,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
24973
25183
|
stdio: "pipe",
|
|
24974
25184
|
timeout: 3e4
|
|
24975
25185
|
});
|
|
24976
|
-
if (!
|
|
25186
|
+
if (!existsSync25(join25(tmpDir, ".git"))) {
|
|
24977
25187
|
return { success: false, error: "Git clone failed: no .git directory produced" };
|
|
24978
25188
|
}
|
|
24979
25189
|
const searchRoot = subPath ? join25(tmpDir, subPath) : tmpDir;
|
|
@@ -24983,7 +25193,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
24983
25193
|
}
|
|
24984
25194
|
const skillFolderName = basename2(skillDir);
|
|
24985
25195
|
const destDir = join25(SKILLS_PATH, skillFolderName);
|
|
24986
|
-
if (
|
|
25196
|
+
if (existsSync25(destDir)) {
|
|
24987
25197
|
log(`[skill-install] Overwriting existing skill at ${destDir}`);
|
|
24988
25198
|
}
|
|
24989
25199
|
await mkdir3(destDir, { recursive: true });
|
|
@@ -25030,14 +25240,14 @@ function parseGitHubUrl(input) {
|
|
|
25030
25240
|
async function findSkillDir(root) {
|
|
25031
25241
|
const candidates = ["SKILL.md", "skill.md"];
|
|
25032
25242
|
for (const c of candidates) {
|
|
25033
|
-
if (
|
|
25243
|
+
if (existsSync25(join25(root, c))) return root;
|
|
25034
25244
|
}
|
|
25035
25245
|
try {
|
|
25036
25246
|
const entries = await readdir5(root, { withFileTypes: true });
|
|
25037
25247
|
for (const entry of entries) {
|
|
25038
25248
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
25039
25249
|
for (const c of candidates) {
|
|
25040
|
-
if (
|
|
25250
|
+
if (existsSync25(join25(root, entry.name, c))) {
|
|
25041
25251
|
return join25(root, entry.name);
|
|
25042
25252
|
}
|
|
25043
25253
|
}
|
|
@@ -25057,7 +25267,7 @@ async function findSkillDir(root) {
|
|
|
25057
25267
|
for (const sub of subEntries) {
|
|
25058
25268
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
25059
25269
|
for (const c of candidates) {
|
|
25060
|
-
if (
|
|
25270
|
+
if (existsSync25(join25(root, entry.name, sub.name, c))) {
|
|
25061
25271
|
return join25(root, entry.name, sub.name);
|
|
25062
25272
|
}
|
|
25063
25273
|
}
|
|
@@ -25348,12 +25558,12 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
25348
25558
|
);
|
|
25349
25559
|
break;
|
|
25350
25560
|
}
|
|
25351
|
-
const { readFileSync:
|
|
25352
|
-
const { join:
|
|
25353
|
-
const targetPath =
|
|
25561
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = await import("fs");
|
|
25562
|
+
const { join: join42 } = await import("path");
|
|
25563
|
+
const targetPath = join42(homedir7(), ".cc-claw", insight.targetFile);
|
|
25354
25564
|
let previewText;
|
|
25355
|
-
if (
|
|
25356
|
-
const current =
|
|
25565
|
+
if (existsSync62(targetPath)) {
|
|
25566
|
+
const current = readFileSync35(targetPath, "utf-8");
|
|
25357
25567
|
const diffLines = insight.proposedDiff.split("\n");
|
|
25358
25568
|
const additions = diffLines.filter((l) => l.startsWith("+")).map((l) => ` + ${l.slice(1).trim()}`);
|
|
25359
25569
|
const removals = diffLines.filter((l) => l.startsWith("-")).map((l) => ` - ${l.slice(1).trim()}`);
|
|
@@ -25425,13 +25635,13 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
25425
25635
|
const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
|
|
25426
25636
|
const current = getReflectionStatus2(getDb(), chatId);
|
|
25427
25637
|
if (current === "frozen") {
|
|
25428
|
-
const { readFileSync:
|
|
25429
|
-
const { join:
|
|
25638
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = await import("fs");
|
|
25639
|
+
const { join: join42 } = await import("path");
|
|
25430
25640
|
const { CC_CLAW_HOME: CC_CLAW_HOME3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
25431
|
-
const soulPath =
|
|
25432
|
-
const userPath =
|
|
25433
|
-
const soul =
|
|
25434
|
-
const user =
|
|
25641
|
+
const soulPath = join42(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
25642
|
+
const userPath = join42(CC_CLAW_HOME3, "identity/USER.md");
|
|
25643
|
+
const soul = existsSync62(soulPath) ? readFileSync35(soulPath, "utf-8") : "";
|
|
25644
|
+
const user = existsSync62(userPath) ? readFileSync35(userPath, "utf-8") : "";
|
|
25435
25645
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
25436
25646
|
logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
|
|
25437
25647
|
await sendEvolveDashboard(chatId, reflChatId, channel, messageId);
|
|
@@ -25568,7 +25778,7 @@ var init_evolve2 = __esm({
|
|
|
25568
25778
|
});
|
|
25569
25779
|
|
|
25570
25780
|
// src/optimizer/identity-audit.ts
|
|
25571
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
25781
|
+
import { readFileSync as readFileSync16, existsSync as existsSync26, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
|
|
25572
25782
|
import { join as join26 } from "path";
|
|
25573
25783
|
function readIdentityFile2(filename) {
|
|
25574
25784
|
try {
|
|
@@ -25588,7 +25798,7 @@ function findBackupFiles() {
|
|
|
25588
25798
|
const backups = [];
|
|
25589
25799
|
const dirs = [IDENTITY_PATH];
|
|
25590
25800
|
const contextDir = join26(IDENTITY_PATH, "..", "workspace", "context");
|
|
25591
|
-
if (
|
|
25801
|
+
if (existsSync26(contextDir)) dirs.push(contextDir);
|
|
25592
25802
|
for (const dir of dirs) {
|
|
25593
25803
|
try {
|
|
25594
25804
|
for (const entry of readdirSync10(dir)) {
|
|
@@ -25725,7 +25935,7 @@ var init_identity_audit = __esm({
|
|
|
25725
25935
|
});
|
|
25726
25936
|
|
|
25727
25937
|
// src/optimizer/skill-audit.ts
|
|
25728
|
-
import { readFileSync as readFileSync17, existsSync as
|
|
25938
|
+
import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
|
|
25729
25939
|
import { join as join27, basename as basename3 } from "path";
|
|
25730
25940
|
function parseFrontmatter3(content) {
|
|
25731
25941
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -25798,7 +26008,7 @@ function loadDependentSkillContents(depNames, ccClawSkillsDir) {
|
|
|
25798
26008
|
join27(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
|
|
25799
26009
|
];
|
|
25800
26010
|
for (const candidate of candidates) {
|
|
25801
|
-
if (
|
|
26011
|
+
if (existsSync27(candidate)) {
|
|
25802
26012
|
try {
|
|
25803
26013
|
const content = readFileSync17(candidate, "utf-8");
|
|
25804
26014
|
results.push({
|
|
@@ -25944,7 +26154,7 @@ __export(analyze_exports2, {
|
|
|
25944
26154
|
});
|
|
25945
26155
|
import { spawn as spawn7 } from "child_process";
|
|
25946
26156
|
import { createInterface as createInterface7 } from "readline";
|
|
25947
|
-
import { readFileSync as readFileSync18, existsSync as
|
|
26157
|
+
import { readFileSync as readFileSync18, existsSync as existsSync28, readdirSync as readdirSync12 } from "fs";
|
|
25948
26158
|
import { join as join28 } from "path";
|
|
25949
26159
|
import { homedir as homedir8 } from "os";
|
|
25950
26160
|
function parseOptimizeOutput(raw, validAreas) {
|
|
@@ -26080,10 +26290,10 @@ function readIdentityFile3(filename) {
|
|
|
26080
26290
|
return "";
|
|
26081
26291
|
}
|
|
26082
26292
|
}
|
|
26083
|
-
function
|
|
26293
|
+
function loadContextFiles() {
|
|
26084
26294
|
const contextDir = join28(homedir8(), ".cc-claw", "workspace", "context");
|
|
26085
26295
|
const results = [];
|
|
26086
|
-
if (!
|
|
26296
|
+
if (!existsSync28(contextDir)) return results;
|
|
26087
26297
|
try {
|
|
26088
26298
|
for (const entry of readdirSync12(contextDir)) {
|
|
26089
26299
|
if (!entry.endsWith(".md")) continue;
|
|
@@ -26119,7 +26329,7 @@ async function runIdentityAudit(chatId) {
|
|
|
26119
26329
|
const soulMd = readIdentityFile3("SOUL.md");
|
|
26120
26330
|
const userMd = readIdentityFile3("USER.md");
|
|
26121
26331
|
const ccClawMd = readIdentityFile3("CC-CLAW.md");
|
|
26122
|
-
const contextFiles =
|
|
26332
|
+
const contextFiles = loadContextFiles();
|
|
26123
26333
|
const prompt = buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles);
|
|
26124
26334
|
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
26125
26335
|
const findings = parseOptimizeOutput(raw, VALID_IDENTITY_AREAS);
|
|
@@ -26156,11 +26366,11 @@ async function runSkillAudit(chatId, skillPath) {
|
|
|
26156
26366
|
function listCcClawSkills() {
|
|
26157
26367
|
const skillsDir = join28(homedir8(), ".cc-claw", "workspace", "skills");
|
|
26158
26368
|
const entries = [];
|
|
26159
|
-
if (!
|
|
26369
|
+
if (!existsSync28(skillsDir)) return entries;
|
|
26160
26370
|
try {
|
|
26161
26371
|
for (const dir of readdirSync12(skillsDir)) {
|
|
26162
26372
|
const skillFile = join28(skillsDir, dir, "SKILL.md");
|
|
26163
|
-
if (!
|
|
26373
|
+
if (!existsSync28(skillFile)) continue;
|
|
26164
26374
|
let description = "skill";
|
|
26165
26375
|
try {
|
|
26166
26376
|
const content = readFileSync18(skillFile, "utf-8");
|
|
@@ -26490,7 +26700,7 @@ __export(optimize_exports2, {
|
|
|
26490
26700
|
handleOptimizeCallback: () => handleOptimizeCallback,
|
|
26491
26701
|
handleOptimizeCommand: () => handleOptimizeCommand
|
|
26492
26702
|
});
|
|
26493
|
-
import { readFileSync as readFileSync19, writeFileSync as writeFileSync9, existsSync as
|
|
26703
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync9, existsSync as existsSync29, readdirSync as readdirSync13, unlinkSync as unlinkSync7 } from "fs";
|
|
26494
26704
|
import { join as join29, dirname as dirname5 } from "path";
|
|
26495
26705
|
import { homedir as homedir9 } from "os";
|
|
26496
26706
|
async function handleOptimizeCommand(chatId, channel, _args, messageId) {
|
|
@@ -26715,7 +26925,7 @@ async function applyFinding(chatId, channel, index, messageId) {
|
|
|
26715
26925
|
}
|
|
26716
26926
|
try {
|
|
26717
26927
|
const targetPath = resolveTargetFile(finding.location, session2.result.target);
|
|
26718
|
-
if (!targetPath || !
|
|
26928
|
+
if (!targetPath || !existsSync29(targetPath)) {
|
|
26719
26929
|
session2.skipped.push(index);
|
|
26720
26930
|
await showFinding(chatId, channel, index + 1, effectiveMsgId);
|
|
26721
26931
|
return;
|
|
@@ -29188,73 +29398,6 @@ ${agentLines.join("\n")}`, buttons);
|
|
|
29188
29398
|
const ok = cancelAgent(match.id);
|
|
29189
29399
|
await channel.sendText(chatId, ok ? `Agent ${match.id.slice(0, 8)} cancelled.` : "Could not cancel agent.", { parseMode: "plain" });
|
|
29190
29400
|
}
|
|
29191
|
-
async function handleMcpCommand(chatId, commandArgs, msg, channel) {
|
|
29192
|
-
const db3 = getDb();
|
|
29193
|
-
const lines = ["<b>\u{1F50C} MCP Servers</b>"];
|
|
29194
|
-
let totalCount = 0;
|
|
29195
|
-
let connectedCount = 0;
|
|
29196
|
-
const centralMcps = listRegisteredMcps(db3);
|
|
29197
|
-
if (centralMcps.length > 0) {
|
|
29198
|
-
lines.push("", "\u2501\u2501 <b>CC-Claw</b> \u2501\u2501");
|
|
29199
|
-
for (const m of centralMcps) {
|
|
29200
|
-
totalCount++;
|
|
29201
|
-
connectedCount++;
|
|
29202
|
-
const autoTag = m.enabledByDefault ? " \u{1F4CC}" : "";
|
|
29203
|
-
const desc = m.description ? ` <i>${m.description}</i>` : "";
|
|
29204
|
-
lines.push(` \u2705 <b>${m.name}</b>${autoTag}${desc}`);
|
|
29205
|
-
}
|
|
29206
|
-
}
|
|
29207
|
-
if (process.env.DASHBOARD_ENABLED === "1") {
|
|
29208
|
-
totalCount++;
|
|
29209
|
-
connectedCount++;
|
|
29210
|
-
lines.push("", "\u2501\u2501 <b>Built-in</b> \u2501\u2501");
|
|
29211
|
-
lines.push(` \u2705 <b>cc-claw</b> <i>Agent orchestrator (spawn, tasks, inbox)</i>`);
|
|
29212
|
-
}
|
|
29213
|
-
const { execFile: execFile6 } = await import("child_process");
|
|
29214
|
-
const { homedir: homedirImport } = await import("os");
|
|
29215
|
-
const discoveryCwd = homedirImport();
|
|
29216
|
-
const runnerResults = await Promise.allSettled(
|
|
29217
|
-
getAllRunners().map((runner) => {
|
|
29218
|
-
const listCmd = runner.getMcpListCommand();
|
|
29219
|
-
if (!listCmd.length) return Promise.resolve({ runner, output: "" });
|
|
29220
|
-
const exe = runner.getExecutablePath();
|
|
29221
|
-
return new Promise((resolve3) => {
|
|
29222
|
-
execFile6(exe, listCmd.slice(1), {
|
|
29223
|
-
encoding: "utf-8",
|
|
29224
|
-
timeout: 3e4,
|
|
29225
|
-
cwd: discoveryCwd,
|
|
29226
|
-
env: runner.getEnv()
|
|
29227
|
-
}, (_err, stdout, stderr) => {
|
|
29228
|
-
const combined = ((stdout ?? "") + "\n" + (stderr ?? "")).trim();
|
|
29229
|
-
resolve3({ runner, output: combined });
|
|
29230
|
-
});
|
|
29231
|
-
});
|
|
29232
|
-
})
|
|
29233
|
-
);
|
|
29234
|
-
for (const result of runnerResults) {
|
|
29235
|
-
if (result.status !== "fulfilled") continue;
|
|
29236
|
-
const { runner, output: output2 } = result.value;
|
|
29237
|
-
if (!runner.getMcpListCommand().length) continue;
|
|
29238
|
-
const parsed = parseMcpListOutput(output2);
|
|
29239
|
-
lines.push("", `\u2501\u2501 <b>${runner.displayName}</b> \u2501\u2501`);
|
|
29240
|
-
if (parsed.length === 0) {
|
|
29241
|
-
lines.push(" <i>No servers configured</i>");
|
|
29242
|
-
continue;
|
|
29243
|
-
}
|
|
29244
|
-
for (const srv of parsed) {
|
|
29245
|
-
totalCount++;
|
|
29246
|
-
if (srv.connected) connectedCount++;
|
|
29247
|
-
const icon = srv.connected ? "\u2705" : "\u274C";
|
|
29248
|
-
lines.push(` ${icon} <b>${srv.name}</b>`);
|
|
29249
|
-
}
|
|
29250
|
-
}
|
|
29251
|
-
if (totalCount === 0) {
|
|
29252
|
-
lines.push("", "<i>No MCP servers found.</i>");
|
|
29253
|
-
} else {
|
|
29254
|
-
lines.splice(1, 0, `<i>${connectedCount}/${totalCount} connected</i>`);
|
|
29255
|
-
}
|
|
29256
|
-
await channel.sendText(chatId, lines.join("\n"), { parseMode: "html" });
|
|
29257
|
-
}
|
|
29258
29401
|
async function handleCronCommand(chatId, commandArgs, msg, channel) {
|
|
29259
29402
|
if (!commandArgs) {
|
|
29260
29403
|
await sendJobsBoard(chatId, channel, 1);
|
|
@@ -29393,6 +29536,514 @@ var init_command_handlers = __esm({
|
|
|
29393
29536
|
}
|
|
29394
29537
|
});
|
|
29395
29538
|
|
|
29539
|
+
// src/mcps/constants.ts
|
|
29540
|
+
function healthIcon(status) {
|
|
29541
|
+
switch (status) {
|
|
29542
|
+
case "healthy":
|
|
29543
|
+
return "\u{1F7E2}";
|
|
29544
|
+
case "unhealthy":
|
|
29545
|
+
return "\u{1F534}";
|
|
29546
|
+
default:
|
|
29547
|
+
return "\u26AA";
|
|
29548
|
+
}
|
|
29549
|
+
}
|
|
29550
|
+
var SYSTEM_MCP_NAMES;
|
|
29551
|
+
var init_constants = __esm({
|
|
29552
|
+
"src/mcps/constants.ts"() {
|
|
29553
|
+
"use strict";
|
|
29554
|
+
SYSTEM_MCP_NAMES = /* @__PURE__ */ new Set(["cc-claw"]);
|
|
29555
|
+
}
|
|
29556
|
+
});
|
|
29557
|
+
|
|
29558
|
+
// src/cli/api-client.ts
|
|
29559
|
+
var api_client_exports = {};
|
|
29560
|
+
__export(api_client_exports, {
|
|
29561
|
+
apiDelete: () => apiDelete,
|
|
29562
|
+
apiGet: () => apiGet,
|
|
29563
|
+
apiPost: () => apiPost,
|
|
29564
|
+
apiPut: () => apiPut,
|
|
29565
|
+
isDaemonRunning: () => isDaemonRunning
|
|
29566
|
+
});
|
|
29567
|
+
import { request as httpRequest, Agent } from "http";
|
|
29568
|
+
function getToken() {
|
|
29569
|
+
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
29570
|
+
return readApiToken();
|
|
29571
|
+
}
|
|
29572
|
+
async function isDaemonRunning() {
|
|
29573
|
+
try {
|
|
29574
|
+
const res = await apiGet("/api/health");
|
|
29575
|
+
return res.ok;
|
|
29576
|
+
} catch {
|
|
29577
|
+
return false;
|
|
29578
|
+
}
|
|
29579
|
+
}
|
|
29580
|
+
function makeRequest(method, path, body, timeout) {
|
|
29581
|
+
const token = getToken();
|
|
29582
|
+
return new Promise((resolve3, reject) => {
|
|
29583
|
+
const url = new URL(path, BASE_URL);
|
|
29584
|
+
const headers = {
|
|
29585
|
+
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
29586
|
+
};
|
|
29587
|
+
if (body !== null) {
|
|
29588
|
+
headers["Content-Type"] = "application/json";
|
|
29589
|
+
headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
29590
|
+
}
|
|
29591
|
+
const req = httpRequest(url, { method, headers, timeout, agent: keepAliveAgent }, (res) => {
|
|
29592
|
+
const chunks = [];
|
|
29593
|
+
res.on("data", (c) => chunks.push(c));
|
|
29594
|
+
res.on("end", () => {
|
|
29595
|
+
const responseBody = Buffer.concat(chunks).toString();
|
|
29596
|
+
try {
|
|
29597
|
+
const data = JSON.parse(responseBody);
|
|
29598
|
+
resolve3({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
|
|
29599
|
+
} catch {
|
|
29600
|
+
resolve3({ ok: false, status: res.statusCode ?? 0, data: responseBody });
|
|
29601
|
+
}
|
|
29602
|
+
});
|
|
29603
|
+
});
|
|
29604
|
+
req.on("error", reject);
|
|
29605
|
+
req.on("timeout", () => {
|
|
29606
|
+
req.destroy();
|
|
29607
|
+
reject(new Error("Request timed out"));
|
|
29608
|
+
});
|
|
29609
|
+
if (body !== null) req.write(body);
|
|
29610
|
+
req.end();
|
|
29611
|
+
});
|
|
29612
|
+
}
|
|
29613
|
+
function apiGet(path) {
|
|
29614
|
+
return makeRequest("GET", path, null, 3e3);
|
|
29615
|
+
}
|
|
29616
|
+
function apiPost(path, body, opts) {
|
|
29617
|
+
return makeRequest("POST", path, JSON.stringify(body), opts?.timeout ?? 3e4);
|
|
29618
|
+
}
|
|
29619
|
+
function apiPut(path, body, opts) {
|
|
29620
|
+
return makeRequest("PUT", path, JSON.stringify(body), opts?.timeout ?? 3e4);
|
|
29621
|
+
}
|
|
29622
|
+
function apiDelete(path) {
|
|
29623
|
+
return makeRequest("DELETE", path, null, 1e4);
|
|
29624
|
+
}
|
|
29625
|
+
var DEFAULT_PORT, API_HOST, BASE_URL, keepAliveAgent;
|
|
29626
|
+
var init_api_client = __esm({
|
|
29627
|
+
"src/cli/api-client.ts"() {
|
|
29628
|
+
"use strict";
|
|
29629
|
+
init_paths();
|
|
29630
|
+
DEFAULT_PORT = parseInt(process.env.DASHBOARD_PORT ?? "3141", 10);
|
|
29631
|
+
API_HOST = process.env.CC_CLAW_API_HOST ?? "127.0.0.1";
|
|
29632
|
+
BASE_URL = `http://${API_HOST}:${DEFAULT_PORT}`;
|
|
29633
|
+
keepAliveAgent = new Agent({ keepAlive: true, maxSockets: 4 });
|
|
29634
|
+
}
|
|
29635
|
+
});
|
|
29636
|
+
|
|
29637
|
+
// src/mcps/import.ts
|
|
29638
|
+
var import_exports = {};
|
|
29639
|
+
__export(import_exports, {
|
|
29640
|
+
discoverFromSource: () => discoverFromSource,
|
|
29641
|
+
mcpImport: () => mcpImport,
|
|
29642
|
+
parseClaudeConfig: () => parseClaudeConfig,
|
|
29643
|
+
parseCursorConfig: () => parseCursorConfig
|
|
29644
|
+
});
|
|
29645
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
29646
|
+
import { join as join31 } from "path";
|
|
29647
|
+
import { homedir as homedir10 } from "os";
|
|
29648
|
+
function parseClaudeConfig(config2) {
|
|
29649
|
+
const servers = config2.mcpServers ?? {};
|
|
29650
|
+
return Object.entries(servers).map(([name, s]) => ({
|
|
29651
|
+
name,
|
|
29652
|
+
command: s.command ?? "",
|
|
29653
|
+
args: Array.isArray(s.args) ? s.args : [],
|
|
29654
|
+
env: s.env && typeof s.env === "object" && !Array.isArray(s.env) ? s.env : {}
|
|
29655
|
+
})).filter((s) => Boolean(s.command));
|
|
29656
|
+
}
|
|
29657
|
+
async function discoverFromSource(source) {
|
|
29658
|
+
switch (source) {
|
|
29659
|
+
case "claude": {
|
|
29660
|
+
const path = join31(homedir10(), ".claude", "settings.json");
|
|
29661
|
+
try {
|
|
29662
|
+
return parseClaudeConfig(JSON.parse(readFileSync20(path, "utf-8")));
|
|
29663
|
+
} catch {
|
|
29664
|
+
warn(`[mcp-import] Could not read ${path}`);
|
|
29665
|
+
return [];
|
|
29666
|
+
}
|
|
29667
|
+
}
|
|
29668
|
+
case "cursor": {
|
|
29669
|
+
const path = join31(homedir10(), ".cursor", "mcp.json");
|
|
29670
|
+
try {
|
|
29671
|
+
return parseCursorConfig(JSON.parse(readFileSync20(path, "utf-8")));
|
|
29672
|
+
} catch {
|
|
29673
|
+
warn(`[mcp-import] Could not read ${path}`);
|
|
29674
|
+
return [];
|
|
29675
|
+
}
|
|
29676
|
+
}
|
|
29677
|
+
case "gemini":
|
|
29678
|
+
case "codex": {
|
|
29679
|
+
try {
|
|
29680
|
+
const { discoverExistingMcps: discoverExistingMcps2 } = await Promise.resolve().then(() => (init_propagate(), propagate_exports));
|
|
29681
|
+
const { getRunner: getRunner2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
29682
|
+
const runner = getRunner2(source);
|
|
29683
|
+
if (!runner) {
|
|
29684
|
+
warn(`[mcp-import] No runner registered for "${source}"`);
|
|
29685
|
+
return [];
|
|
29686
|
+
}
|
|
29687
|
+
const names = await discoverExistingMcps2(runner);
|
|
29688
|
+
return names.map((n) => ({ name: n, command: "", args: [], env: {} }));
|
|
29689
|
+
} catch (err) {
|
|
29690
|
+
warn(`[mcp-import] Failed to discover from ${source}: ${err instanceof Error ? err.message : err}`);
|
|
29691
|
+
return [];
|
|
29692
|
+
}
|
|
29693
|
+
}
|
|
29694
|
+
default:
|
|
29695
|
+
warn(`[mcp-import] Unknown source: ${source}`);
|
|
29696
|
+
return [];
|
|
29697
|
+
}
|
|
29698
|
+
}
|
|
29699
|
+
async function mcpImport(source, _opts) {
|
|
29700
|
+
const servers = await discoverFromSource(source);
|
|
29701
|
+
const readline = await import("readline");
|
|
29702
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
29703
|
+
const ask2 = (q) => new Promise((resolve3) => rl2.question(q, resolve3));
|
|
29704
|
+
try {
|
|
29705
|
+
if (servers.length === 0) {
|
|
29706
|
+
console.log(`No MCP servers found in ${source}.`);
|
|
29707
|
+
return;
|
|
29708
|
+
}
|
|
29709
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
29710
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
29711
|
+
const db3 = openDatabaseReadOnly2();
|
|
29712
|
+
const existing = new Set(listMcpServers2(db3).map((m) => m.name));
|
|
29713
|
+
db3.close();
|
|
29714
|
+
const available = servers.filter((s) => !existing.has(s.name));
|
|
29715
|
+
if (available.length === 0) {
|
|
29716
|
+
console.log(`All MCPs from ${source} are already registered in CC-Claw.`);
|
|
29717
|
+
return;
|
|
29718
|
+
}
|
|
29719
|
+
console.log(`
|
|
29720
|
+
Found ${available.length} new MCP(s) in ${source}:
|
|
29721
|
+
`);
|
|
29722
|
+
available.forEach((s, i) => {
|
|
29723
|
+
const cmd = s.command ? ` (${s.command})` : "";
|
|
29724
|
+
console.log(` ${i + 1}. ${s.name}${cmd}`);
|
|
29725
|
+
});
|
|
29726
|
+
console.log();
|
|
29727
|
+
const answer = await ask2(
|
|
29728
|
+
"Select MCPs to import (comma-separated numbers, or 'all', or Enter to cancel): "
|
|
29729
|
+
);
|
|
29730
|
+
const trimmed = answer.trim().toLowerCase();
|
|
29731
|
+
if (!trimmed || trimmed === "cancel") {
|
|
29732
|
+
console.log("Cancelled.");
|
|
29733
|
+
return;
|
|
29734
|
+
}
|
|
29735
|
+
const indices = trimmed === "all" ? available.map((_, i) => i) : trimmed.split(",").map((s) => parseInt(s.trim(), 10) - 1).filter((i) => Number.isInteger(i) && i >= 0 && i < available.length);
|
|
29736
|
+
if (indices.length === 0) {
|
|
29737
|
+
console.log("Nothing selected.");
|
|
29738
|
+
return;
|
|
29739
|
+
}
|
|
29740
|
+
const { apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
29741
|
+
let added = 0;
|
|
29742
|
+
for (const i of indices) {
|
|
29743
|
+
const s = available[i];
|
|
29744
|
+
if (!s.command) {
|
|
29745
|
+
console.warn(` \u26A0 Skipping "${s.name}" \u2014 no command available (discovered from ${source} CLI name only)`);
|
|
29746
|
+
continue;
|
|
29747
|
+
}
|
|
29748
|
+
try {
|
|
29749
|
+
await apiPost2("/api/mcps", {
|
|
29750
|
+
name: s.name,
|
|
29751
|
+
transport: "stdio",
|
|
29752
|
+
command: s.command || void 0,
|
|
29753
|
+
args: s.args.length > 0 ? s.args : void 0,
|
|
29754
|
+
env: Object.keys(s.env).length > 0 ? s.env : void 0,
|
|
29755
|
+
enabledByDefault: true
|
|
29756
|
+
});
|
|
29757
|
+
added++;
|
|
29758
|
+
} catch (err) {
|
|
29759
|
+
warn(`[mcp-import] Failed to add ${s.name}: ${err instanceof Error ? err.message : err}`);
|
|
29760
|
+
}
|
|
29761
|
+
}
|
|
29762
|
+
console.log(`
|
|
29763
|
+
\u2713 Imported ${added} MCP(s) from ${source}.`);
|
|
29764
|
+
} finally {
|
|
29765
|
+
rl2.close();
|
|
29766
|
+
}
|
|
29767
|
+
}
|
|
29768
|
+
var parseCursorConfig;
|
|
29769
|
+
var init_import = __esm({
|
|
29770
|
+
"src/mcps/import.ts"() {
|
|
29771
|
+
"use strict";
|
|
29772
|
+
init_log();
|
|
29773
|
+
parseCursorConfig = parseClaudeConfig;
|
|
29774
|
+
}
|
|
29775
|
+
});
|
|
29776
|
+
|
|
29777
|
+
// src/router/mcp.ts
|
|
29778
|
+
var mcp_exports = {};
|
|
29779
|
+
__export(mcp_exports, {
|
|
29780
|
+
handleMcpCallback: () => handleMcpCallback,
|
|
29781
|
+
sendMcpDetail: () => sendMcpDetail,
|
|
29782
|
+
sendMcpImportPicker: () => sendMcpImportPicker,
|
|
29783
|
+
sendMcpImportSelect: () => sendMcpImportSelect,
|
|
29784
|
+
sendMcpKeyboard: () => sendMcpKeyboard
|
|
29785
|
+
});
|
|
29786
|
+
async function sendMcpKeyboard(chatId, channel, messageId) {
|
|
29787
|
+
const db3 = getDb();
|
|
29788
|
+
const mcps = listMcpServers(db3);
|
|
29789
|
+
const lines = ["<b>MCP Servers</b>"];
|
|
29790
|
+
if (mcps.length === 0) {
|
|
29791
|
+
lines.push("\nNo MCPs registered yet. Add one below.");
|
|
29792
|
+
}
|
|
29793
|
+
const buttons = [];
|
|
29794
|
+
for (const mcp2 of mcps) {
|
|
29795
|
+
const isSystem = SYSTEM_MCP_NAMES.has(mcp2.name);
|
|
29796
|
+
const prefix = isSystem ? "\u{1F512}" : healthIcon(mcp2.healthStatus);
|
|
29797
|
+
const label2 = `${prefix} ${mcp2.name}${isSystem ? " (system)" : ""}`;
|
|
29798
|
+
buttons.push([{ label: label2, data: `mcp:detail:${mcp2.name}` }]);
|
|
29799
|
+
}
|
|
29800
|
+
buttons.push([
|
|
29801
|
+
{ label: "\u2795 Add", data: "mcp:add" },
|
|
29802
|
+
{ label: "\u2B07 Import", data: "mcp:import" }
|
|
29803
|
+
]);
|
|
29804
|
+
await sendOrEditKeyboard(chatId, channel, messageId, lines.join("\n"), buttons);
|
|
29805
|
+
}
|
|
29806
|
+
async function sendMcpDetail(chatId, channel, mcpName, messageId) {
|
|
29807
|
+
const db3 = getDb();
|
|
29808
|
+
const mcps = listMcpServers(db3);
|
|
29809
|
+
const mcp2 = mcps.find((m) => m.name === mcpName);
|
|
29810
|
+
if (!mcp2) {
|
|
29811
|
+
await sendOrEditKeyboard(chatId, channel, messageId, `MCP "${mcpName}" not found.`, [
|
|
29812
|
+
[{ label: "\u2190 Back", data: "mcp:back" }]
|
|
29813
|
+
]);
|
|
29814
|
+
return;
|
|
29815
|
+
}
|
|
29816
|
+
const isSystem = SYSTEM_MCP_NAMES.has(mcp2.name);
|
|
29817
|
+
const argsStr = mcp2.args ? (() => {
|
|
29818
|
+
try {
|
|
29819
|
+
return JSON.parse(mcp2.args).join(" ");
|
|
29820
|
+
} catch {
|
|
29821
|
+
return mcp2.args;
|
|
29822
|
+
}
|
|
29823
|
+
})() : "";
|
|
29824
|
+
const lines = [
|
|
29825
|
+
`<b>${mcp2.name}</b>${isSystem ? " \u{1F512}" : ""}`,
|
|
29826
|
+
`Transport: ${mcp2.transport}`,
|
|
29827
|
+
mcp2.command ? `Command: <code>${mcp2.command}${argsStr ? " " + argsStr : ""}</code>` : "",
|
|
29828
|
+
`Health: ${healthIcon(mcp2.healthStatus)} ${mcp2.healthStatus ?? "unknown"}`,
|
|
29829
|
+
`Status: ${mcp2.enabledByDefault ? "enabled" : "disabled"}`
|
|
29830
|
+
].filter(Boolean);
|
|
29831
|
+
const buttons = [];
|
|
29832
|
+
if (!isSystem) {
|
|
29833
|
+
const statusBtn = mcp2.enabledByDefault ? { label: "\u23F8 Disable", data: `mcp:disable:${mcp2.name}`, style: "danger" } : { label: "\u25B6 Enable", data: `mcp:enable:${mcp2.name}`, style: "success" };
|
|
29834
|
+
buttons.push([
|
|
29835
|
+
statusBtn,
|
|
29836
|
+
{ label: "\u{1F5D1} Remove", data: `mcp:remove:${mcp2.name}`, style: "danger" }
|
|
29837
|
+
]);
|
|
29838
|
+
}
|
|
29839
|
+
buttons.push([{ label: "\u2190 Back", data: "mcp:back" }]);
|
|
29840
|
+
await sendOrEditKeyboard(chatId, channel, messageId, lines.join("\n"), buttons);
|
|
29841
|
+
}
|
|
29842
|
+
async function sendMcpImportPicker(chatId, channel, messageId) {
|
|
29843
|
+
const buttons = IMPORT_SOURCES.map((src) => [
|
|
29844
|
+
{
|
|
29845
|
+
label: src.charAt(0).toUpperCase() + src.slice(1),
|
|
29846
|
+
data: `mcp:import:${src}`
|
|
29847
|
+
}
|
|
29848
|
+
]);
|
|
29849
|
+
buttons.push([{ label: "\u2190 Back", data: "mcp:back" }]);
|
|
29850
|
+
await sendOrEditKeyboard(
|
|
29851
|
+
chatId,
|
|
29852
|
+
channel,
|
|
29853
|
+
messageId,
|
|
29854
|
+
"<b>Import MCPs from:</b>",
|
|
29855
|
+
buttons
|
|
29856
|
+
);
|
|
29857
|
+
}
|
|
29858
|
+
async function sendMcpImportSelect(chatId, channel, source, selected, candidates, messageId) {
|
|
29859
|
+
if (candidates.length === 0) {
|
|
29860
|
+
await sendOrEditKeyboard(
|
|
29861
|
+
chatId,
|
|
29862
|
+
channel,
|
|
29863
|
+
messageId,
|
|
29864
|
+
`No new MCPs found in <b>${source}</b>.`,
|
|
29865
|
+
[[{ label: "\u2190 Back", data: "mcp:import" }]]
|
|
29866
|
+
);
|
|
29867
|
+
return;
|
|
29868
|
+
}
|
|
29869
|
+
const buttons = candidates.map((name) => {
|
|
29870
|
+
const checked = selected.has(name);
|
|
29871
|
+
return [
|
|
29872
|
+
{
|
|
29873
|
+
label: `${checked ? "\u2713 " : " "}${name}`,
|
|
29874
|
+
data: `mcp:import:toggle:${source}:${name}`
|
|
29875
|
+
}
|
|
29876
|
+
];
|
|
29877
|
+
});
|
|
29878
|
+
buttons.push([
|
|
29879
|
+
{
|
|
29880
|
+
label: "\u2713 Import Selected",
|
|
29881
|
+
data: `mcp:import:confirm:${source}`,
|
|
29882
|
+
style: "success"
|
|
29883
|
+
},
|
|
29884
|
+
{ label: "\u2190 Back", data: "mcp:import" }
|
|
29885
|
+
]);
|
|
29886
|
+
await sendOrEditKeyboard(
|
|
29887
|
+
chatId,
|
|
29888
|
+
channel,
|
|
29889
|
+
messageId,
|
|
29890
|
+
`<b>Found ${candidates.length} new MCP(s) in ${source}:</b>`,
|
|
29891
|
+
buttons
|
|
29892
|
+
);
|
|
29893
|
+
}
|
|
29894
|
+
async function handleMcpCallback(chatId, data, channel, messageId) {
|
|
29895
|
+
const { apiPost: apiPost2, apiPut: apiPut2, apiDelete: apiDelete2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
29896
|
+
const { pendingMcpImports: pendingMcpImports2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
29897
|
+
const { discoverFromSource: discoverFromSource2 } = await Promise.resolve().then(() => (init_import(), import_exports));
|
|
29898
|
+
if (data === "mcp:back") {
|
|
29899
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29900
|
+
return;
|
|
29901
|
+
}
|
|
29902
|
+
if (data === "mcp:import") {
|
|
29903
|
+
await sendMcpImportPicker(chatId, channel, messageId);
|
|
29904
|
+
return;
|
|
29905
|
+
}
|
|
29906
|
+
if (data.startsWith("mcp:detail:")) {
|
|
29907
|
+
await sendMcpDetail(chatId, channel, data.slice(11), messageId);
|
|
29908
|
+
return;
|
|
29909
|
+
}
|
|
29910
|
+
if (data.startsWith("mcp:disable:")) {
|
|
29911
|
+
const name = data.slice(12);
|
|
29912
|
+
await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: false });
|
|
29913
|
+
await sendMcpDetail(chatId, channel, name, messageId);
|
|
29914
|
+
return;
|
|
29915
|
+
}
|
|
29916
|
+
if (data.startsWith("mcp:enable:")) {
|
|
29917
|
+
const name = data.slice(11);
|
|
29918
|
+
await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: true });
|
|
29919
|
+
await sendMcpDetail(chatId, channel, name, messageId);
|
|
29920
|
+
return;
|
|
29921
|
+
}
|
|
29922
|
+
if (data.startsWith("mcp:remove:")) {
|
|
29923
|
+
const name = data.slice(11);
|
|
29924
|
+
await apiDelete2(`/api/mcps/${encodeURIComponent(name)}`);
|
|
29925
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29926
|
+
return;
|
|
29927
|
+
}
|
|
29928
|
+
if (data.startsWith("mcp:import:") && !data.includes(":toggle:") && !data.includes(":confirm:")) {
|
|
29929
|
+
const source = data.slice(11);
|
|
29930
|
+
if (IMPORT_SOURCES.includes(source)) {
|
|
29931
|
+
let servers;
|
|
29932
|
+
try {
|
|
29933
|
+
servers = await discoverFromSource2(source);
|
|
29934
|
+
} catch (err) {
|
|
29935
|
+
await sendOrEditKeyboard(
|
|
29936
|
+
chatId,
|
|
29937
|
+
channel,
|
|
29938
|
+
messageId,
|
|
29939
|
+
`Failed to discover MCPs from ${source}: ${err instanceof Error ? err.message : String(err)}`,
|
|
29940
|
+
[[{ label: "\u2190 Back", data: "mcp:import" }]]
|
|
29941
|
+
);
|
|
29942
|
+
return;
|
|
29943
|
+
}
|
|
29944
|
+
const db3 = getDb();
|
|
29945
|
+
const existing = new Set(listMcpServers(db3).map((m) => m.name));
|
|
29946
|
+
const candidates = servers.map((s) => s.name).filter((n) => !existing.has(n));
|
|
29947
|
+
pendingMcpImports2.set(chatId, {
|
|
29948
|
+
source,
|
|
29949
|
+
servers,
|
|
29950
|
+
selected: /* @__PURE__ */ new Set(),
|
|
29951
|
+
candidates,
|
|
29952
|
+
startedAt: Date.now()
|
|
29953
|
+
});
|
|
29954
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29955
|
+
await sendMcpImportSelect(
|
|
29956
|
+
chatId,
|
|
29957
|
+
channel,
|
|
29958
|
+
source,
|
|
29959
|
+
state.selected,
|
|
29960
|
+
state.candidates,
|
|
29961
|
+
messageId
|
|
29962
|
+
);
|
|
29963
|
+
}
|
|
29964
|
+
return;
|
|
29965
|
+
}
|
|
29966
|
+
if (data.startsWith("mcp:import:toggle:")) {
|
|
29967
|
+
const rest = data.slice(18);
|
|
29968
|
+
const colonIdx = rest.indexOf(":");
|
|
29969
|
+
if (colonIdx === -1) return;
|
|
29970
|
+
const source = rest.slice(0, colonIdx);
|
|
29971
|
+
const name = rest.slice(colonIdx + 1);
|
|
29972
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29973
|
+
if (!state || state.source !== source) return;
|
|
29974
|
+
if (state.selected.has(name)) {
|
|
29975
|
+
state.selected.delete(name);
|
|
29976
|
+
} else {
|
|
29977
|
+
state.selected.add(name);
|
|
29978
|
+
}
|
|
29979
|
+
await sendMcpImportSelect(
|
|
29980
|
+
chatId,
|
|
29981
|
+
channel,
|
|
29982
|
+
source,
|
|
29983
|
+
state.selected,
|
|
29984
|
+
state.candidates,
|
|
29985
|
+
messageId
|
|
29986
|
+
);
|
|
29987
|
+
return;
|
|
29988
|
+
}
|
|
29989
|
+
if (data.startsWith("mcp:import:confirm:")) {
|
|
29990
|
+
const source = data.slice(19);
|
|
29991
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29992
|
+
pendingMcpImports2.delete(chatId);
|
|
29993
|
+
if (!state || state.selected.size === 0) {
|
|
29994
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29995
|
+
return;
|
|
29996
|
+
}
|
|
29997
|
+
const serverMap = new Map((state.servers ?? []).map((s) => [s.name, s]));
|
|
29998
|
+
let added = 0;
|
|
29999
|
+
for (const name of state.selected) {
|
|
30000
|
+
const s = serverMap.get(name);
|
|
30001
|
+
if (!s || !s.command) continue;
|
|
30002
|
+
try {
|
|
30003
|
+
await apiPost2("/api/mcps", {
|
|
30004
|
+
name: s.name,
|
|
30005
|
+
transport: "stdio",
|
|
30006
|
+
command: s.command,
|
|
30007
|
+
args: s.args.length > 0 ? s.args : void 0,
|
|
30008
|
+
env: Object.keys(s.env).length > 0 ? s.env : void 0,
|
|
30009
|
+
enabledByDefault: true
|
|
30010
|
+
});
|
|
30011
|
+
added++;
|
|
30012
|
+
} catch {
|
|
30013
|
+
}
|
|
30014
|
+
}
|
|
30015
|
+
await sendOrEditKeyboard(
|
|
30016
|
+
chatId,
|
|
30017
|
+
channel,
|
|
30018
|
+
messageId,
|
|
30019
|
+
`\u2713 Imported ${added} MCP(s) from ${source}.`,
|
|
30020
|
+
[[{ label: "\u2190 Back to MCP List", data: "mcp:back" }]]
|
|
30021
|
+
);
|
|
30022
|
+
return;
|
|
30023
|
+
}
|
|
30024
|
+
if (data === "mcp:add") {
|
|
30025
|
+
await sendOrEditKeyboard(
|
|
30026
|
+
chatId,
|
|
30027
|
+
channel,
|
|
30028
|
+
messageId,
|
|
30029
|
+
"To add an MCP, use the CLI:\n<code>cc-claw mcp add <name> <command> [args...]</code>",
|
|
30030
|
+
[[{ label: "\u2190 Back", data: "mcp:back" }]]
|
|
30031
|
+
);
|
|
30032
|
+
return;
|
|
30033
|
+
}
|
|
30034
|
+
}
|
|
30035
|
+
var IMPORT_SOURCES;
|
|
30036
|
+
var init_mcp = __esm({
|
|
30037
|
+
"src/router/mcp.ts"() {
|
|
30038
|
+
"use strict";
|
|
30039
|
+
init_store5();
|
|
30040
|
+
init_store2();
|
|
30041
|
+
init_constants();
|
|
30042
|
+
init_helpers();
|
|
30043
|
+
IMPORT_SOURCES = ["claude", "gemini", "codex", "cursor"];
|
|
30044
|
+
}
|
|
30045
|
+
});
|
|
30046
|
+
|
|
29396
30047
|
// src/router/commands.ts
|
|
29397
30048
|
async function handleCommand(msg, channel) {
|
|
29398
30049
|
const { chatId, command, commandArgs } = msg;
|
|
@@ -29439,6 +30090,7 @@ async function handleCommand(msg, channel) {
|
|
|
29439
30090
|
case "claude":
|
|
29440
30091
|
case "codex":
|
|
29441
30092
|
case "cursor":
|
|
30093
|
+
case "openrouter":
|
|
29442
30094
|
await handleBackendShortcutCommand(chatId, commandArgs, msg, channel);
|
|
29443
30095
|
break;
|
|
29444
30096
|
case "gemini_accounts":
|
|
@@ -29565,9 +30217,11 @@ async function handleCommand(msg, channel) {
|
|
|
29565
30217
|
await handleRunnersCommand(chatId, commandArgs, msg, channel);
|
|
29566
30218
|
break;
|
|
29567
30219
|
case "mcp":
|
|
29568
|
-
case "mcps":
|
|
29569
|
-
await
|
|
30220
|
+
case "mcps": {
|
|
30221
|
+
const { sendMcpKeyboard: sendMcpKeyboard2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
30222
|
+
await sendMcpKeyboard2(chatId, channel);
|
|
29570
30223
|
break;
|
|
30224
|
+
}
|
|
29571
30225
|
case "cron":
|
|
29572
30226
|
await handleCronCommand(chatId, commandArgs, msg, channel);
|
|
29573
30227
|
break;
|
|
@@ -31383,8 +32037,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
31383
32037
|
}
|
|
31384
32038
|
try {
|
|
31385
32039
|
const { readFile: readFileFs } = await import("fs/promises");
|
|
31386
|
-
const { mkdir:
|
|
31387
|
-
const { join:
|
|
32040
|
+
const { mkdir: mkdir5, writeFile: writeFileFs } = await import("fs/promises");
|
|
32041
|
+
const { join: join42 } = await import("path");
|
|
31388
32042
|
const { SKILLS_PATH: SKILLS_PATH2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
31389
32043
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31390
32044
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
@@ -31392,9 +32046,9 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
31392
32046
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skillName, source });
|
|
31393
32047
|
const targetStatus = doApprove ? "approved" : "imported";
|
|
31394
32048
|
updated = updateFrontmatter2(updated, { status: targetStatus });
|
|
31395
|
-
const targetDir =
|
|
31396
|
-
await
|
|
31397
|
-
await writeFileFs(
|
|
32049
|
+
const targetDir = join42(SKILLS_PATH2, skillName);
|
|
32050
|
+
await mkdir5(targetDir, { recursive: true });
|
|
32051
|
+
await writeFileFs(join42(targetDir, "SKILL.md"), updated, "utf-8");
|
|
31398
32052
|
invalidateSkillCache2();
|
|
31399
32053
|
if (doApprove) {
|
|
31400
32054
|
await sendOrEditKeyboard(
|
|
@@ -31525,10 +32179,10 @@ ${formatValidationReport2(validation)}` : "\n\n\u2705 Quality checks passed.";
|
|
|
31525
32179
|
return;
|
|
31526
32180
|
}
|
|
31527
32181
|
try {
|
|
31528
|
-
const { readFileSync:
|
|
32182
|
+
const { readFileSync: readFileSync35, writeFileSync: writeFileSync16 } = await import("fs");
|
|
31529
32183
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31530
32184
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
31531
|
-
const raw =
|
|
32185
|
+
const raw = readFileSync35(skill.filePath, "utf-8");
|
|
31532
32186
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skillName, source: "cc-claw" });
|
|
31533
32187
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
31534
32188
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -31578,14 +32232,14 @@ ${stillUnapproved.length} more skill${stillUnapproved.length !== 1 ? "s" : ""} t
|
|
|
31578
32232
|
return;
|
|
31579
32233
|
}
|
|
31580
32234
|
try {
|
|
31581
|
-
const { readFileSync:
|
|
32235
|
+
const { readFileSync: readFileSync35, writeFileSync: writeFileSync16 } = await import("fs");
|
|
31582
32236
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31583
32237
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
31584
32238
|
let approvedCount = 0;
|
|
31585
32239
|
const issues = [];
|
|
31586
32240
|
for (const skill of unapproved) {
|
|
31587
32241
|
try {
|
|
31588
|
-
const raw =
|
|
32242
|
+
const raw = readFileSync35(skill.filePath, "utf-8");
|
|
31589
32243
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skill.name, source: "cc-claw" });
|
|
31590
32244
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
31591
32245
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -31636,7 +32290,7 @@ ${issues.join("\n")}`;
|
|
|
31636
32290
|
return;
|
|
31637
32291
|
}
|
|
31638
32292
|
const raw = await readFile7(skill.filePath, "utf-8");
|
|
31639
|
-
const skillContent =
|
|
32293
|
+
const skillContent = stripFrontmatter2(raw);
|
|
31640
32294
|
const tags = skill.sources.join(", ");
|
|
31641
32295
|
await channel.sendText(chatId, `Loading skill: ${skillName} [${tags}]...`, { parseMode: "plain" });
|
|
31642
32296
|
const skillModel = resolveModel(chatId);
|
|
@@ -31711,39 +32365,9 @@ Type a keyword below (e.g. gemma, llama, free, claude)`,
|
|
|
31711
32365
|
[[{ label: "\u2190 Back", data: `bconf:model:${backendId}` }]]
|
|
31712
32366
|
);
|
|
31713
32367
|
}
|
|
31714
|
-
} else if (data.startsWith("
|
|
31715
|
-
const
|
|
31716
|
-
|
|
31717
|
-
const backendId = rest.slice(7);
|
|
31718
|
-
if (!getAllBackendIds().includes(backendId)) return;
|
|
31719
|
-
await doBackendSwitch(chatId, backendId, channel, { messageId });
|
|
31720
|
-
const pending = getPendingEscalation(chatId);
|
|
31721
|
-
if (pending) {
|
|
31722
|
-
removePendingEscalation(chatId);
|
|
31723
|
-
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router2(), router_exports));
|
|
31724
|
-
await handleMessage2({ text: pending, chatId, source: "telegram", type: "text" }, channel);
|
|
31725
|
-
}
|
|
31726
|
-
} else if (rest === "bypass") {
|
|
31727
|
-
const { setEscalationBypass: setEscalationBypass2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
31728
|
-
setEscalationBypass2(chatId);
|
|
31729
|
-
await replaceWithText("\u26A1 Escalation bypassed for 30 minutes. Re-processing\u2026");
|
|
31730
|
-
const pending = getPendingEscalation(chatId);
|
|
31731
|
-
if (pending) {
|
|
31732
|
-
removePendingEscalation(chatId);
|
|
31733
|
-
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router2(), router_exports));
|
|
31734
|
-
await handleMessage2({ text: pending, chatId, source: "telegram", type: "text" }, channel);
|
|
31735
|
-
}
|
|
31736
|
-
} else if (rest === "proceed") {
|
|
31737
|
-
await replaceWithText("\u2192 Proceeding with API backend.");
|
|
31738
|
-
const pending = getPendingEscalation(chatId);
|
|
31739
|
-
if (pending) {
|
|
31740
|
-
removePendingEscalation(chatId);
|
|
31741
|
-
const { setAgenticBypass: setAgenticBypass2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
31742
|
-
setAgenticBypass2(chatId);
|
|
31743
|
-
const { handleMessage: handleMessage2 } = await Promise.resolve().then(() => (init_router2(), router_exports));
|
|
31744
|
-
await handleMessage2({ text: pending, chatId, source: "telegram", type: "text" }, channel);
|
|
31745
|
-
}
|
|
31746
|
-
}
|
|
32368
|
+
} else if (data.startsWith("mcp:")) {
|
|
32369
|
+
const { handleMcpCallback: handleMcpCallback2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
32370
|
+
await handleMcpCallback2(chatId, data, channel, messageId);
|
|
31747
32371
|
} else if (data.startsWith("apitools:")) {
|
|
31748
32372
|
const { sendApiToolsKeyboard: sendApiToolsKeyboard2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
31749
32373
|
const rest = data.slice(9);
|
|
@@ -31772,6 +32396,10 @@ Type a keyword below (e.g. gemma, llama, free, claude)`,
|
|
|
31772
32396
|
const { removeCliFromWhitelist: removeCliFromWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
31773
32397
|
removeCliFromWhitelist2(chatId, cmd);
|
|
31774
32398
|
await sendApiToolsKeyboard2(chatId, channel, messageId);
|
|
32399
|
+
} else if (rest === "toggle-web-search") {
|
|
32400
|
+
const { toggleApiWebSearchEnabled: toggleApiWebSearchEnabled2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
32401
|
+
toggleApiWebSearchEnabled2(chatId);
|
|
32402
|
+
await sendApiToolsKeyboard2(chatId, channel, messageId);
|
|
31775
32403
|
}
|
|
31776
32404
|
}
|
|
31777
32405
|
}
|
|
@@ -32507,7 +33135,10 @@ Try a different keyword.`,
|
|
|
32507
33135
|
const cmd = text.trim();
|
|
32508
33136
|
if (cmd) {
|
|
32509
33137
|
const { addCliToWhitelist: addCliToWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
32510
|
-
|
|
33138
|
+
const clis = cmd.split(",").map((s) => s.trim()).filter(Boolean);
|
|
33139
|
+
for (const cli of clis) {
|
|
33140
|
+
addCliToWhitelist2(chatId, cli);
|
|
33141
|
+
}
|
|
32511
33142
|
}
|
|
32512
33143
|
const { sendApiToolsKeyboard: sendApiToolsKeyboard2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32513
33144
|
await sendApiToolsKeyboard2(chatId, channel, msgId);
|
|
@@ -32572,21 +33203,6 @@ Try a different keyword.`,
|
|
|
32572
33203
|
}
|
|
32573
33204
|
effectiveAgentMode = "native";
|
|
32574
33205
|
}
|
|
32575
|
-
if (intent === "agentic" && !text.startsWith(">>")) {
|
|
32576
|
-
try {
|
|
32577
|
-
const adapter = getAdapterForChat(chatId);
|
|
32578
|
-
if (adapter.type === "api") {
|
|
32579
|
-
const { hasEscalationBypass: hasEscalationBypass2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
32580
|
-
if (!hasEscalationBypass2(chatId)) {
|
|
32581
|
-
storePendingEscalation(chatId, text);
|
|
32582
|
-
const { sendEscalationKeyboard: sendEscalationKeyboard2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32583
|
-
await sendEscalationKeyboard2(chatId, channel, adapter.id);
|
|
32584
|
-
return;
|
|
32585
|
-
}
|
|
32586
|
-
}
|
|
32587
|
-
} catch {
|
|
32588
|
-
}
|
|
32589
|
-
}
|
|
32590
33206
|
const { isSideQuest: hasSqPrefix, cleanText: sqCleanText } = parseSideQuestPrefix(text);
|
|
32591
33207
|
if (hasSqPrefix && isChatBusy(chatId)) {
|
|
32592
33208
|
const sqMsg = { ...msg, text: sqCleanText };
|
|
@@ -33444,7 +34060,7 @@ async function runWithRetry(job, model2, runId, t0) {
|
|
|
33444
34060
|
if (isFallback) {
|
|
33445
34061
|
log(`[scheduler] Job #${job.id} falling back to ${currentBackend}:${currentModel} (fallback ${chainIdx}/${job.fallbacks.length})`);
|
|
33446
34062
|
}
|
|
33447
|
-
for (let attempt = 0; attempt <=
|
|
34063
|
+
for (let attempt = 0; attempt <= MAX_RETRIES3; attempt++) {
|
|
33448
34064
|
try {
|
|
33449
34065
|
const { getVerboseLevel: getVerboseLevel4 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
33450
34066
|
const vLevel = getVerboseLevel4(chatId);
|
|
@@ -33499,11 +34115,11 @@ ${response.text}`;
|
|
|
33499
34115
|
log(`[scheduler] Job #${job.id} backend ${currentBackend} exhausted: ${errMsg}`);
|
|
33500
34116
|
break;
|
|
33501
34117
|
}
|
|
33502
|
-
if (errorClass === "permanent" || attempt >=
|
|
34118
|
+
if (errorClass === "permanent" || attempt >= MAX_RETRIES3) {
|
|
33503
34119
|
throw err;
|
|
33504
34120
|
}
|
|
33505
34121
|
const backoffMs = getBackoffMs(attempt);
|
|
33506
|
-
log(`[scheduler] Job #${job.id} transient error (attempt ${attempt + 1}/${
|
|
34122
|
+
log(`[scheduler] Job #${job.id} transient error (attempt ${attempt + 1}/${MAX_RETRIES3}), retrying in ${backoffMs / 1e3}s: ${errorMessage(err)}`);
|
|
33507
34123
|
await new Promise((r) => setTimeout(r, backoffMs));
|
|
33508
34124
|
}
|
|
33509
34125
|
}
|
|
@@ -33566,7 +34182,7 @@ var init_cron = __esm({
|
|
|
33566
34182
|
});
|
|
33567
34183
|
|
|
33568
34184
|
// src/agents/runners/wrap-backend.ts
|
|
33569
|
-
import { join as
|
|
34185
|
+
import { join as join32 } from "path";
|
|
33570
34186
|
function buildMcpCommands(backendId) {
|
|
33571
34187
|
const exe = backendId === BACKEND.CURSOR ? "agent" : backendId;
|
|
33572
34188
|
return {
|
|
@@ -33663,7 +34279,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
33663
34279
|
const configPath = writeMcpConfigFile(server);
|
|
33664
34280
|
return ["--mcp-config", configPath];
|
|
33665
34281
|
},
|
|
33666
|
-
getSkillPath: () =>
|
|
34282
|
+
getSkillPath: () => join32(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
33667
34283
|
};
|
|
33668
34284
|
}
|
|
33669
34285
|
var BACKEND_CAPABILITIES;
|
|
@@ -33735,18 +34351,18 @@ var init_wrap_backend = __esm({
|
|
|
33735
34351
|
});
|
|
33736
34352
|
|
|
33737
34353
|
// src/agents/runners/config-loader.ts
|
|
33738
|
-
import { readFileSync as
|
|
33739
|
-
import { join as
|
|
34354
|
+
import { readFileSync as readFileSync21, readdirSync as readdirSync14, existsSync as existsSync30, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
|
|
34355
|
+
import { join as join33 } from "path";
|
|
33740
34356
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
33741
34357
|
function resolveExecutable2(config2) {
|
|
33742
|
-
if (
|
|
34358
|
+
if (existsSync30(config2.executable)) return config2.executable;
|
|
33743
34359
|
try {
|
|
33744
34360
|
return execFileSync3("which", [config2.executable], { encoding: "utf-8" }).trim();
|
|
33745
34361
|
} catch {
|
|
33746
34362
|
}
|
|
33747
34363
|
for (const fallback of config2.executableFallbacks ?? []) {
|
|
33748
34364
|
const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
|
|
33749
|
-
if (
|
|
34365
|
+
if (existsSync30(resolved)) return resolved;
|
|
33750
34366
|
}
|
|
33751
34367
|
return config2.executable;
|
|
33752
34368
|
}
|
|
@@ -33872,12 +34488,12 @@ function configToRunner(config2) {
|
|
|
33872
34488
|
prepareMcpInjection() {
|
|
33873
34489
|
return [];
|
|
33874
34490
|
},
|
|
33875
|
-
getSkillPath: () =>
|
|
34491
|
+
getSkillPath: () => join33(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
33876
34492
|
};
|
|
33877
34493
|
}
|
|
33878
34494
|
function loadRunnerConfig(filePath) {
|
|
33879
34495
|
try {
|
|
33880
|
-
const content =
|
|
34496
|
+
const content = readFileSync21(filePath, "utf-8");
|
|
33881
34497
|
return JSON.parse(content);
|
|
33882
34498
|
} catch (err) {
|
|
33883
34499
|
warn(`[runners] Failed to load config ${filePath}: ${err}`);
|
|
@@ -33885,14 +34501,14 @@ function loadRunnerConfig(filePath) {
|
|
|
33885
34501
|
}
|
|
33886
34502
|
}
|
|
33887
34503
|
function loadAllRunnerConfigs() {
|
|
33888
|
-
if (!
|
|
34504
|
+
if (!existsSync30(RUNNERS_PATH)) {
|
|
33889
34505
|
mkdirSync10(RUNNERS_PATH, { recursive: true });
|
|
33890
34506
|
return [];
|
|
33891
34507
|
}
|
|
33892
34508
|
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
33893
34509
|
const configs = [];
|
|
33894
34510
|
for (const file of files) {
|
|
33895
|
-
const config2 = loadRunnerConfig(
|
|
34511
|
+
const config2 = loadRunnerConfig(join33(RUNNERS_PATH, file));
|
|
33896
34512
|
if (config2) configs.push(config2);
|
|
33897
34513
|
}
|
|
33898
34514
|
return configs;
|
|
@@ -33913,16 +34529,16 @@ function registerConfigRunners() {
|
|
|
33913
34529
|
return count;
|
|
33914
34530
|
}
|
|
33915
34531
|
function watchRunnerConfigs(onChange) {
|
|
33916
|
-
if (!
|
|
34532
|
+
if (!existsSync30(RUNNERS_PATH)) return;
|
|
33917
34533
|
for (const prev of watchedFiles) {
|
|
33918
|
-
if (!
|
|
34534
|
+
if (!existsSync30(prev)) {
|
|
33919
34535
|
unwatchFile(prev);
|
|
33920
34536
|
watchedFiles.delete(prev);
|
|
33921
34537
|
}
|
|
33922
34538
|
}
|
|
33923
34539
|
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
33924
34540
|
for (const file of files) {
|
|
33925
|
-
const fullPath =
|
|
34541
|
+
const fullPath = join33(RUNNERS_PATH, file);
|
|
33926
34542
|
if (watchedFiles.has(fullPath)) continue;
|
|
33927
34543
|
watchedFiles.add(fullPath);
|
|
33928
34544
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -34502,6 +35118,7 @@ var init_telegram2 = __esm({
|
|
|
34502
35118
|
{ command: "codex", description: "Switch to Codex backend" },
|
|
34503
35119
|
{ command: "codex_accounts", description: "Manage Codex credentials & rotation" },
|
|
34504
35120
|
{ command: "cursor", description: "Switch to Cursor backend" },
|
|
35121
|
+
{ command: "openrouter", description: "Switch to OpenRouter backend" },
|
|
34505
35122
|
{ command: "model", description: "Switch model for active backend" },
|
|
34506
35123
|
{ command: "thinking", description: "Adjust thinking/reasoning level" },
|
|
34507
35124
|
{ command: "summarizer", description: "Configure session summarization model" },
|
|
@@ -35220,19 +35837,19 @@ var init_telegram2 = __esm({
|
|
|
35220
35837
|
});
|
|
35221
35838
|
|
|
35222
35839
|
// src/skills/bootstrap.ts
|
|
35223
|
-
import { existsSync as
|
|
35224
|
-
import { readdir as readdir6,
|
|
35225
|
-
import { join as
|
|
35840
|
+
import { existsSync as existsSync31, readFileSync as readFileSync22, writeFileSync as writeFileSync10, copyFileSync as copyFileSync3, readdirSync as readdirSync15 } from "fs";
|
|
35841
|
+
import { readdir as readdir6, copyFile } from "fs/promises";
|
|
35842
|
+
import { join as join34, dirname as dirname6 } from "path";
|
|
35226
35843
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
35227
35844
|
async function copyAgentManifestSkills() {
|
|
35228
|
-
if (!
|
|
35845
|
+
if (!existsSync31(PKG_SKILLS)) return;
|
|
35229
35846
|
try {
|
|
35230
35847
|
const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
|
|
35231
35848
|
for (const entry of entries) {
|
|
35232
35849
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
35233
|
-
const src =
|
|
35234
|
-
const dest =
|
|
35235
|
-
if (
|
|
35850
|
+
const src = join34(PKG_SKILLS, entry.name);
|
|
35851
|
+
const dest = join34(SKILLS_PATH, entry.name);
|
|
35852
|
+
if (existsSync31(dest)) continue;
|
|
35236
35853
|
await copyFile(src, dest);
|
|
35237
35854
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
35238
35855
|
}
|
|
@@ -35243,73 +35860,11 @@ async function copyAgentManifestSkills() {
|
|
|
35243
35860
|
async function bootstrapSkills() {
|
|
35244
35861
|
await copyAgentManifestSkills();
|
|
35245
35862
|
migrateSkillsToThreeTier();
|
|
35246
|
-
const usmDir = join33(SKILLS_PATH, USM_DIR_NAME);
|
|
35247
|
-
if (existsSync32(usmDir)) return;
|
|
35248
|
-
try {
|
|
35249
|
-
const entries = await readdir6(SKILLS_PATH);
|
|
35250
|
-
const dirs = entries.filter((e) => !e.startsWith("."));
|
|
35251
|
-
if (dirs.length > 0) return;
|
|
35252
|
-
} catch (err) {
|
|
35253
|
-
log("[skills] Bootstrap: failed to read skills directory:", err instanceof Error ? err.message : err);
|
|
35254
|
-
return;
|
|
35255
|
-
}
|
|
35256
|
-
log("[skills] First run \u2014 bootstrapping Universal Skills Manager...");
|
|
35257
|
-
try {
|
|
35258
|
-
const result = await installSkillFromGitHub(USM_REPO);
|
|
35259
|
-
if (!result.success) {
|
|
35260
|
-
error(`[skills] USM bootstrap failed: ${result.error}`);
|
|
35261
|
-
return;
|
|
35262
|
-
}
|
|
35263
|
-
await patchUsmForCcClaw(usmDir);
|
|
35264
|
-
log("[skills] Universal Skills Manager bootstrapped successfully");
|
|
35265
|
-
} catch (err) {
|
|
35266
|
-
error(`[skills] USM bootstrap error: ${errorMessage(err)}`);
|
|
35267
|
-
}
|
|
35268
|
-
}
|
|
35269
|
-
async function patchUsmForCcClaw(usmDir) {
|
|
35270
|
-
const skillPath = join33(usmDir, "SKILL.md");
|
|
35271
|
-
if (!existsSync32(skillPath)) return;
|
|
35272
|
-
try {
|
|
35273
|
-
let content = await readFile8(skillPath, "utf-8");
|
|
35274
|
-
let patched = false;
|
|
35275
|
-
if (!content.includes("CC-Claw")) {
|
|
35276
|
-
const cursorLine = `| **Cursor**`;
|
|
35277
|
-
const cursorIdx = content.indexOf(cursorLine);
|
|
35278
|
-
if (cursorIdx !== -1) {
|
|
35279
|
-
const lineEnd = content.indexOf("\n", cursorIdx);
|
|
35280
|
-
if (lineEnd !== -1) {
|
|
35281
|
-
content = content.slice(0, lineEnd + 1) + CC_CLAW_ECOSYSTEM_PATCH + "\n" + content.slice(lineEnd + 1);
|
|
35282
|
-
patched = true;
|
|
35283
|
-
}
|
|
35284
|
-
}
|
|
35285
|
-
}
|
|
35286
|
-
const findPatterns = [
|
|
35287
|
-
"find ~/.{claude,agents,gemini/antigravity,openclaw/workspace,cursor,config/opencode,config/goose,roo,cline}/skills",
|
|
35288
|
-
"find ~/.{claude,agents,gemini,gemini/antigravity,openclaw/workspace,cursor,config/opencode,config/goose,roo,cline}/skills"
|
|
35289
|
-
];
|
|
35290
|
-
for (const oldFind of findPatterns) {
|
|
35291
|
-
if (content.includes(oldFind) && !content.includes("cc-claw/workspace")) {
|
|
35292
|
-
const newFind = oldFind.replace("openclaw/workspace,", "openclaw/workspace,cc-claw/workspace,");
|
|
35293
|
-
content = content.replace(oldFind, newFind);
|
|
35294
|
-
patched = true;
|
|
35295
|
-
break;
|
|
35296
|
-
}
|
|
35297
|
-
}
|
|
35298
|
-
const beforeFm = content;
|
|
35299
|
-
content = ensureThreeTierFrontmatter(content, { name: "universal-skills-manager", source: "cc-claw" });
|
|
35300
|
-
if (content !== beforeFm) patched = true;
|
|
35301
|
-
if (patched) {
|
|
35302
|
-
await writeFile6(skillPath, content, "utf-8");
|
|
35303
|
-
log("[skills] Patched USM SKILL.md with CC-Claw support");
|
|
35304
|
-
}
|
|
35305
|
-
} catch (err) {
|
|
35306
|
-
error(`[skills] Failed to patch USM: ${errorMessage(err)}`);
|
|
35307
|
-
}
|
|
35308
35863
|
}
|
|
35309
35864
|
function migrateSkillsToThreeTier() {
|
|
35310
|
-
const markerPath =
|
|
35311
|
-
if (
|
|
35312
|
-
if (!
|
|
35865
|
+
const markerPath = join34(SKILLS_PATH, MIGRATION_MARKER);
|
|
35866
|
+
if (existsSync31(markerPath)) return;
|
|
35867
|
+
if (!existsSync31(SKILLS_PATH)) return;
|
|
35313
35868
|
let entries;
|
|
35314
35869
|
try {
|
|
35315
35870
|
entries = readdirSync15(SKILLS_PATH, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
@@ -35323,15 +35878,15 @@ function migrateSkillsToThreeTier() {
|
|
|
35323
35878
|
for (const dirName of entries) {
|
|
35324
35879
|
let skillPath;
|
|
35325
35880
|
for (const candidate of SKILL_FILE_CANDIDATES2) {
|
|
35326
|
-
const p =
|
|
35327
|
-
if (
|
|
35881
|
+
const p = join34(SKILLS_PATH, dirName, candidate);
|
|
35882
|
+
if (existsSync31(p)) {
|
|
35328
35883
|
skillPath = p;
|
|
35329
35884
|
break;
|
|
35330
35885
|
}
|
|
35331
35886
|
}
|
|
35332
35887
|
if (!skillPath) continue;
|
|
35333
35888
|
try {
|
|
35334
|
-
const raw =
|
|
35889
|
+
const raw = readFileSync22(skillPath, "utf-8");
|
|
35335
35890
|
const fmMatch = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
35336
35891
|
if (fmMatch) {
|
|
35337
35892
|
const fm = fmMatch[1];
|
|
@@ -35368,20 +35923,16 @@ function migrateSkillsToThreeTier() {
|
|
|
35368
35923
|
log(`[skills] Three-tier migration complete: ${migrated} migrated, ${skipped} already current, ${failed} failed`);
|
|
35369
35924
|
}
|
|
35370
35925
|
}
|
|
35371
|
-
var
|
|
35926
|
+
var PKG_ROOT, PKG_SKILLS, MIGRATION_MARKER, SKILL_FILE_CANDIDATES2;
|
|
35372
35927
|
var init_bootstrap = __esm({
|
|
35373
35928
|
"src/skills/bootstrap.ts"() {
|
|
35374
35929
|
"use strict";
|
|
35375
35930
|
init_paths();
|
|
35376
|
-
init_install();
|
|
35377
35931
|
init_frontmatter();
|
|
35378
35932
|
init_discover();
|
|
35379
35933
|
init_log();
|
|
35380
|
-
|
|
35381
|
-
|
|
35382
|
-
CC_CLAW_ECOSYSTEM_PATCH = `| **CC-Claw** | \`~/.cc-claw/workspace/skills/\` | N/A (daemon, no project scope) |`;
|
|
35383
|
-
PKG_ROOT = join33(dirname6(fileURLToPath2(import.meta.url)), "..", "..");
|
|
35384
|
-
PKG_SKILLS = join33(PKG_ROOT, "skills");
|
|
35934
|
+
PKG_ROOT = join34(dirname6(fileURLToPath2(import.meta.url)), "..", "..");
|
|
35935
|
+
PKG_SKILLS = join34(PKG_ROOT, "skills");
|
|
35385
35936
|
MIGRATION_MARKER = ".three-tier-migrated";
|
|
35386
35937
|
SKILL_FILE_CANDIDATES2 = ["SKILL.md", "skill.md"];
|
|
35387
35938
|
}
|
|
@@ -35453,19 +36004,19 @@ var init_migrate_embeddings = __esm({
|
|
|
35453
36004
|
// src/mcps/bootstrap.ts
|
|
35454
36005
|
function bootstrapBuiltinMcps(db3) {
|
|
35455
36006
|
let seeded = 0;
|
|
35456
|
-
for (const
|
|
35457
|
-
const existing = getMcpServer(db3,
|
|
36007
|
+
for (const mcp2 of BUILTIN_MCPS) {
|
|
36008
|
+
const existing = getMcpServer(db3, mcp2.name);
|
|
35458
36009
|
if (existing) continue;
|
|
35459
36010
|
addMcpServer(db3, {
|
|
35460
|
-
name:
|
|
35461
|
-
transport:
|
|
35462
|
-
command:
|
|
35463
|
-
args:
|
|
35464
|
-
description:
|
|
35465
|
-
enabledByDefault:
|
|
36011
|
+
name: mcp2.name,
|
|
36012
|
+
transport: mcp2.transport,
|
|
36013
|
+
command: mcp2.command,
|
|
36014
|
+
args: mcp2.args,
|
|
36015
|
+
description: mcp2.description,
|
|
36016
|
+
enabledByDefault: mcp2.enabledByDefault
|
|
35466
36017
|
});
|
|
35467
36018
|
seeded++;
|
|
35468
|
-
log(`[mcps] Seeded built-in MCP: ${
|
|
36019
|
+
log(`[mcps] Seeded built-in MCP: ${mcp2.name}`);
|
|
35469
36020
|
}
|
|
35470
36021
|
if (seeded > 0) {
|
|
35471
36022
|
log(`[mcps] Bootstrapped ${seeded} built-in MCP server(s)`);
|
|
@@ -35496,13 +36047,13 @@ __export(ai_skill_exports, {
|
|
|
35496
36047
|
generateAiSkill: () => generateAiSkill,
|
|
35497
36048
|
installAiSkill: () => installAiSkill
|
|
35498
36049
|
});
|
|
35499
|
-
import { existsSync as
|
|
35500
|
-
import { join as
|
|
35501
|
-
import { homedir as
|
|
36050
|
+
import { existsSync as existsSync32, writeFileSync as writeFileSync11, mkdirSync as mkdirSync11 } from "fs";
|
|
36051
|
+
import { join as join35 } from "path";
|
|
36052
|
+
import { homedir as homedir11 } from "os";
|
|
35502
36053
|
function generateAiSkill() {
|
|
35503
36054
|
const version = VERSION;
|
|
35504
36055
|
let systemState = "";
|
|
35505
|
-
if (
|
|
36056
|
+
if (existsSync32(DB_PATH)) {
|
|
35506
36057
|
try {
|
|
35507
36058
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
35508
36059
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -35944,8 +36495,8 @@ function installAiSkill() {
|
|
|
35944
36495
|
const failed = [];
|
|
35945
36496
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
35946
36497
|
for (const dir of dirs) {
|
|
35947
|
-
const skillDir =
|
|
35948
|
-
const skillPath =
|
|
36498
|
+
const skillDir = join35(dir, "cc-claw-cli");
|
|
36499
|
+
const skillPath = join35(skillDir, "SKILL.md");
|
|
35949
36500
|
try {
|
|
35950
36501
|
mkdirSync11(skillDir, { recursive: true });
|
|
35951
36502
|
writeFileSync11(skillPath, skill, "utf-8");
|
|
@@ -35964,11 +36515,11 @@ var init_ai_skill = __esm({
|
|
|
35964
36515
|
init_paths();
|
|
35965
36516
|
init_version();
|
|
35966
36517
|
BACKEND_SKILL_DIRS2 = {
|
|
35967
|
-
"cc-claw": [
|
|
35968
|
-
claude: [
|
|
35969
|
-
gemini: [
|
|
35970
|
-
codex: [
|
|
35971
|
-
cursor: [
|
|
36518
|
+
"cc-claw": [join35(homedir11(), ".cc-claw", "workspace", "skills")],
|
|
36519
|
+
claude: [join35(homedir11(), ".claude", "skills")],
|
|
36520
|
+
gemini: [join35(homedir11(), ".gemini", "skills")],
|
|
36521
|
+
codex: [join35(homedir11(), ".agents", "skills")],
|
|
36522
|
+
cursor: [join35(homedir11(), ".cursor", "skills"), join35(homedir11(), ".cursor", "skills-cursor")]
|
|
35972
36523
|
};
|
|
35973
36524
|
}
|
|
35974
36525
|
});
|
|
@@ -35978,21 +36529,21 @@ var index_exports = {};
|
|
|
35978
36529
|
__export(index_exports, {
|
|
35979
36530
|
main: () => main
|
|
35980
36531
|
});
|
|
35981
|
-
import { mkdirSync as mkdirSync12, existsSync as
|
|
35982
|
-
import { join as
|
|
36532
|
+
import { mkdirSync as mkdirSync12, existsSync as existsSync33, renameSync as renameSync2, statSync as statSync9, readFileSync as readFileSync24 } from "fs";
|
|
36533
|
+
import { join as join36 } from "path";
|
|
35983
36534
|
import dotenv from "dotenv";
|
|
35984
36535
|
function migrateLayout() {
|
|
35985
36536
|
const moves = [
|
|
35986
|
-
[
|
|
35987
|
-
[
|
|
35988
|
-
[
|
|
35989
|
-
[
|
|
35990
|
-
[
|
|
35991
|
-
[
|
|
35992
|
-
[
|
|
36537
|
+
[join36(CC_CLAW_HOME, "cc-claw.db"), join36(DATA_PATH, "cc-claw.db")],
|
|
36538
|
+
[join36(CC_CLAW_HOME, "cc-claw.db-shm"), join36(DATA_PATH, "cc-claw.db-shm")],
|
|
36539
|
+
[join36(CC_CLAW_HOME, "cc-claw.db-wal"), join36(DATA_PATH, "cc-claw.db-wal")],
|
|
36540
|
+
[join36(CC_CLAW_HOME, "cc-claw.log"), join36(LOGS_PATH, "cc-claw.log")],
|
|
36541
|
+
[join36(CC_CLAW_HOME, "cc-claw.log.1"), join36(LOGS_PATH, "cc-claw.log.1")],
|
|
36542
|
+
[join36(CC_CLAW_HOME, "cc-claw.error.log"), join36(LOGS_PATH, "cc-claw.error.log")],
|
|
36543
|
+
[join36(CC_CLAW_HOME, "cc-claw.error.log.1"), join36(LOGS_PATH, "cc-claw.error.log.1")]
|
|
35993
36544
|
];
|
|
35994
36545
|
for (const [from, to] of moves) {
|
|
35995
|
-
if (
|
|
36546
|
+
if (existsSync33(from) && !existsSync33(to)) {
|
|
35996
36547
|
try {
|
|
35997
36548
|
renameSync2(from, to);
|
|
35998
36549
|
} catch {
|
|
@@ -36021,7 +36572,7 @@ async function main() {
|
|
|
36021
36572
|
let version = "unknown";
|
|
36022
36573
|
try {
|
|
36023
36574
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
36024
|
-
version = JSON.parse(
|
|
36575
|
+
version = JSON.parse(readFileSync24(pkgPath, "utf-8")).version;
|
|
36025
36576
|
} catch {
|
|
36026
36577
|
}
|
|
36027
36578
|
log(`[cc-claw] Starting v${version}`);
|
|
@@ -36196,10 +36747,10 @@ ${lines.join("\n")}`;
|
|
|
36196
36747
|
try {
|
|
36197
36748
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
36198
36749
|
const { writeFileSync: writeFileSync16, mkdirSync: mkdirSync19 } = await import("fs");
|
|
36199
|
-
const { join:
|
|
36200
|
-
const skillDir =
|
|
36750
|
+
const { join: join42 } = await import("path");
|
|
36751
|
+
const skillDir = join42(SKILLS_PATH, "cc-claw-cli");
|
|
36201
36752
|
mkdirSync19(skillDir, { recursive: true });
|
|
36202
|
-
writeFileSync16(
|
|
36753
|
+
writeFileSync16(join42(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
36203
36754
|
log("[cc-claw] AI skill updated");
|
|
36204
36755
|
} catch {
|
|
36205
36756
|
}
|
|
@@ -36237,6 +36788,8 @@ ${lines.join("\n")}`;
|
|
|
36237
36788
|
const { stopAllActiveAgents: stopAllActiveAgents2, stopStaleChatSweep: stopStaleChatSweep2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
36238
36789
|
stopAllActiveAgents2();
|
|
36239
36790
|
stopStaleChatSweep2();
|
|
36791
|
+
const { shutdownMcpPool: shutdownMcpPool2 } = await Promise.resolve().then(() => (init_pool(), pool_exports));
|
|
36792
|
+
await shutdownMcpPool2();
|
|
36240
36793
|
stopAllHeartbeats();
|
|
36241
36794
|
stopHealthMonitor3();
|
|
36242
36795
|
stopMonitor();
|
|
@@ -36299,10 +36852,10 @@ var init_index = __esm({
|
|
|
36299
36852
|
init_health3();
|
|
36300
36853
|
init_image_gen();
|
|
36301
36854
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
36302
|
-
if (!
|
|
36855
|
+
if (!existsSync33(dir)) mkdirSync12(dir, { recursive: true });
|
|
36303
36856
|
}
|
|
36304
36857
|
migrateLayout();
|
|
36305
|
-
if (
|
|
36858
|
+
if (existsSync33(ENV_PATH)) {
|
|
36306
36859
|
dotenv.config({ path: ENV_PATH });
|
|
36307
36860
|
} else {
|
|
36308
36861
|
console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
|
|
@@ -36316,104 +36869,6 @@ var init_index = __esm({
|
|
|
36316
36869
|
}
|
|
36317
36870
|
});
|
|
36318
36871
|
|
|
36319
|
-
// src/cli/api-client.ts
|
|
36320
|
-
var api_client_exports = {};
|
|
36321
|
-
__export(api_client_exports, {
|
|
36322
|
-
apiGet: () => apiGet,
|
|
36323
|
-
apiPost: () => apiPost,
|
|
36324
|
-
isDaemonRunning: () => isDaemonRunning
|
|
36325
|
-
});
|
|
36326
|
-
import { request as httpRequest, Agent } from "http";
|
|
36327
|
-
function getToken() {
|
|
36328
|
-
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
36329
|
-
return readApiToken();
|
|
36330
|
-
}
|
|
36331
|
-
async function isDaemonRunning() {
|
|
36332
|
-
try {
|
|
36333
|
-
const res = await apiGet("/api/health");
|
|
36334
|
-
return res.ok;
|
|
36335
|
-
} catch {
|
|
36336
|
-
return false;
|
|
36337
|
-
}
|
|
36338
|
-
}
|
|
36339
|
-
async function apiGet(path) {
|
|
36340
|
-
const token = getToken();
|
|
36341
|
-
return new Promise((resolve3, reject) => {
|
|
36342
|
-
const url = new URL(path, BASE_URL);
|
|
36343
|
-
const req = httpRequest(url, {
|
|
36344
|
-
method: "GET",
|
|
36345
|
-
headers: token ? { "Authorization": `Bearer ${token}` } : {},
|
|
36346
|
-
timeout: 3e3,
|
|
36347
|
-
agent: keepAliveAgent
|
|
36348
|
-
}, (res) => {
|
|
36349
|
-
const chunks = [];
|
|
36350
|
-
res.on("data", (c) => chunks.push(c));
|
|
36351
|
-
res.on("end", () => {
|
|
36352
|
-
const body = Buffer.concat(chunks).toString();
|
|
36353
|
-
try {
|
|
36354
|
-
const data = JSON.parse(body);
|
|
36355
|
-
resolve3({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
|
|
36356
|
-
} catch {
|
|
36357
|
-
resolve3({ ok: false, status: res.statusCode ?? 0, data: body });
|
|
36358
|
-
}
|
|
36359
|
-
});
|
|
36360
|
-
});
|
|
36361
|
-
req.on("error", reject);
|
|
36362
|
-
req.on("timeout", () => {
|
|
36363
|
-
req.destroy();
|
|
36364
|
-
reject(new Error("Request timed out"));
|
|
36365
|
-
});
|
|
36366
|
-
req.end();
|
|
36367
|
-
});
|
|
36368
|
-
}
|
|
36369
|
-
async function apiPost(path, body, opts) {
|
|
36370
|
-
const token = getToken();
|
|
36371
|
-
const payload = JSON.stringify(body);
|
|
36372
|
-
return new Promise((resolve3, reject) => {
|
|
36373
|
-
const url = new URL(path, BASE_URL);
|
|
36374
|
-
const req = httpRequest(url, {
|
|
36375
|
-
method: "POST",
|
|
36376
|
-
headers: {
|
|
36377
|
-
"Content-Type": "application/json",
|
|
36378
|
-
"Content-Length": Buffer.byteLength(payload).toString(),
|
|
36379
|
-
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
36380
|
-
},
|
|
36381
|
-
timeout: opts?.timeout ?? 3e4,
|
|
36382
|
-
agent: keepAliveAgent
|
|
36383
|
-
}, (res) => {
|
|
36384
|
-
const chunks = [];
|
|
36385
|
-
res.on("data", (c) => chunks.push(c));
|
|
36386
|
-
res.on("end", () => {
|
|
36387
|
-
const responseBody = Buffer.concat(chunks).toString();
|
|
36388
|
-
try {
|
|
36389
|
-
const data = JSON.parse(responseBody);
|
|
36390
|
-
resolve3({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
|
|
36391
|
-
} catch {
|
|
36392
|
-
resolve3({ ok: false, status: res.statusCode ?? 0, data: responseBody });
|
|
36393
|
-
}
|
|
36394
|
-
});
|
|
36395
|
-
});
|
|
36396
|
-
req.on("error", reject);
|
|
36397
|
-
req.on("timeout", () => {
|
|
36398
|
-
req.destroy();
|
|
36399
|
-
reject(new Error("Request timed out"));
|
|
36400
|
-
});
|
|
36401
|
-
req.write(payload);
|
|
36402
|
-
req.end();
|
|
36403
|
-
});
|
|
36404
|
-
}
|
|
36405
|
-
var DEFAULT_PORT, API_HOST, BASE_URL, keepAliveAgent;
|
|
36406
|
-
var init_api_client = __esm({
|
|
36407
|
-
"src/cli/api-client.ts"() {
|
|
36408
|
-
"use strict";
|
|
36409
|
-
init_paths();
|
|
36410
|
-
DEFAULT_PORT = parseInt(process.env.DASHBOARD_PORT ?? "3141", 10);
|
|
36411
|
-
API_HOST = process.env.CC_CLAW_API_HOST ?? "127.0.0.1";
|
|
36412
|
-
BASE_URL = `http://${API_HOST}:${DEFAULT_PORT}`;
|
|
36413
|
-
keepAliveAgent = new Agent({ keepAlive: true, maxSockets: 4 });
|
|
36414
|
-
}
|
|
36415
|
-
});
|
|
36416
|
-
|
|
36417
36872
|
// src/service.ts
|
|
36418
36873
|
var service_exports2 = {};
|
|
36419
36874
|
__export(service_exports2, {
|
|
@@ -36421,10 +36876,10 @@ __export(service_exports2, {
|
|
|
36421
36876
|
serviceStatus: () => serviceStatus,
|
|
36422
36877
|
uninstallService: () => uninstallService
|
|
36423
36878
|
});
|
|
36424
|
-
import { existsSync as
|
|
36879
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as writeFileSync12, unlinkSync as unlinkSync8 } from "fs";
|
|
36425
36880
|
import { execFileSync as execFileSync4, execSync as execSync5 } from "child_process";
|
|
36426
|
-
import { homedir as
|
|
36427
|
-
import { join as
|
|
36881
|
+
import { homedir as homedir12, platform } from "os";
|
|
36882
|
+
import { join as join37, dirname as dirname7 } from "path";
|
|
36428
36883
|
function xmlEscape(s) {
|
|
36429
36884
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
36430
36885
|
}
|
|
@@ -36433,23 +36888,23 @@ function resolveExecutable3(name) {
|
|
|
36433
36888
|
return execFileSync4("which", [name], { encoding: "utf-8" }).trim();
|
|
36434
36889
|
} catch {
|
|
36435
36890
|
const fallback = process.argv[1];
|
|
36436
|
-
if (fallback &&
|
|
36891
|
+
if (fallback && existsSync34(fallback)) return fallback;
|
|
36437
36892
|
throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
|
|
36438
36893
|
}
|
|
36439
36894
|
}
|
|
36440
36895
|
function getPathDirs() {
|
|
36441
36896
|
const nodeBin = dirname7(process.execPath);
|
|
36442
|
-
const home =
|
|
36897
|
+
const home = homedir12();
|
|
36443
36898
|
const dirs = /* @__PURE__ */ new Set([
|
|
36444
36899
|
nodeBin,
|
|
36445
|
-
|
|
36900
|
+
join37(home, ".local", "bin"),
|
|
36446
36901
|
"/usr/local/bin",
|
|
36447
36902
|
"/usr/bin",
|
|
36448
36903
|
"/bin"
|
|
36449
36904
|
]);
|
|
36450
36905
|
try {
|
|
36451
36906
|
const prefix = execSync5("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
36452
|
-
if (prefix) dirs.add(
|
|
36907
|
+
if (prefix) dirs.add(join37(prefix, "bin"));
|
|
36453
36908
|
} catch {
|
|
36454
36909
|
}
|
|
36455
36910
|
return [...dirs].join(":");
|
|
@@ -36457,7 +36912,7 @@ function getPathDirs() {
|
|
|
36457
36912
|
function generatePlist() {
|
|
36458
36913
|
const ccClawBin = resolveExecutable3("cc-claw");
|
|
36459
36914
|
const pathDirs = getPathDirs();
|
|
36460
|
-
const home =
|
|
36915
|
+
const home = homedir12();
|
|
36461
36916
|
const safeBin = xmlEscape(ccClawBin);
|
|
36462
36917
|
const safePaths = xmlEscape(pathDirs);
|
|
36463
36918
|
const safeHome = xmlEscape(home);
|
|
@@ -36508,9 +36963,9 @@ function generatePlist() {
|
|
|
36508
36963
|
}
|
|
36509
36964
|
function installMacOS() {
|
|
36510
36965
|
const agentsDir = dirname7(PLIST_PATH);
|
|
36511
|
-
if (!
|
|
36512
|
-
if (!
|
|
36513
|
-
if (
|
|
36966
|
+
if (!existsSync34(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
|
|
36967
|
+
if (!existsSync34(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
36968
|
+
if (existsSync34(PLIST_PATH)) {
|
|
36514
36969
|
try {
|
|
36515
36970
|
execFileSync4("launchctl", ["unload", PLIST_PATH]);
|
|
36516
36971
|
} catch {
|
|
@@ -36522,7 +36977,7 @@ function installMacOS() {
|
|
|
36522
36977
|
console.log(" Service loaded and starting.");
|
|
36523
36978
|
}
|
|
36524
36979
|
function uninstallMacOS() {
|
|
36525
|
-
if (!
|
|
36980
|
+
if (!existsSync34(PLIST_PATH)) {
|
|
36526
36981
|
console.log(" No service found to uninstall.");
|
|
36527
36982
|
return;
|
|
36528
36983
|
}
|
|
@@ -36590,15 +37045,15 @@ Restart=on-failure
|
|
|
36590
37045
|
RestartSec=10
|
|
36591
37046
|
WorkingDirectory=${CC_CLAW_HOME}
|
|
36592
37047
|
Environment=PATH=${pathDirs}
|
|
36593
|
-
Environment=HOME=${
|
|
37048
|
+
Environment=HOME=${homedir12()}
|
|
36594
37049
|
|
|
36595
37050
|
[Install]
|
|
36596
37051
|
WantedBy=default.target
|
|
36597
37052
|
`;
|
|
36598
37053
|
}
|
|
36599
37054
|
function installLinux() {
|
|
36600
|
-
if (!
|
|
36601
|
-
if (!
|
|
37055
|
+
if (!existsSync34(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
|
|
37056
|
+
if (!existsSync34(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
36602
37057
|
writeFileSync12(UNIT_PATH, generateUnit());
|
|
36603
37058
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
36604
37059
|
execFileSync4("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -36607,7 +37062,7 @@ function installLinux() {
|
|
|
36607
37062
|
console.log(" Service enabled and started.");
|
|
36608
37063
|
}
|
|
36609
37064
|
function uninstallLinux() {
|
|
36610
|
-
if (!
|
|
37065
|
+
if (!existsSync34(UNIT_PATH)) {
|
|
36611
37066
|
console.log(" No service found to uninstall.");
|
|
36612
37067
|
return;
|
|
36613
37068
|
}
|
|
@@ -36632,7 +37087,7 @@ function statusLinux() {
|
|
|
36632
37087
|
}
|
|
36633
37088
|
}
|
|
36634
37089
|
function installService() {
|
|
36635
|
-
if (!
|
|
37090
|
+
if (!existsSync34(join37(CC_CLAW_HOME, ".env"))) {
|
|
36636
37091
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
36637
37092
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
36638
37093
|
process.exitCode = 1;
|
|
@@ -36661,9 +37116,9 @@ var init_service2 = __esm({
|
|
|
36661
37116
|
"use strict";
|
|
36662
37117
|
init_paths();
|
|
36663
37118
|
PLIST_LABEL = "com.cc-claw";
|
|
36664
|
-
PLIST_PATH =
|
|
36665
|
-
SYSTEMD_DIR =
|
|
36666
|
-
UNIT_PATH =
|
|
37119
|
+
PLIST_PATH = join37(homedir12(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
37120
|
+
SYSTEMD_DIR = join37(homedir12(), ".config", "systemd", "user");
|
|
37121
|
+
UNIT_PATH = join37(SYSTEMD_DIR, "cc-claw.service");
|
|
36667
37122
|
}
|
|
36668
37123
|
});
|
|
36669
37124
|
|
|
@@ -36830,13 +37285,13 @@ var init_daemon = __esm({
|
|
|
36830
37285
|
});
|
|
36831
37286
|
|
|
36832
37287
|
// src/cli/resolve-chat.ts
|
|
36833
|
-
import { readFileSync as
|
|
37288
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
36834
37289
|
function resolveChatId2(globalOpts) {
|
|
36835
37290
|
const explicit = globalOpts.chat;
|
|
36836
37291
|
if (explicit) return explicit;
|
|
36837
37292
|
if (_cachedDefault) return _cachedDefault;
|
|
36838
37293
|
try {
|
|
36839
|
-
const content =
|
|
37294
|
+
const content = readFileSync26(ENV_PATH, "utf-8");
|
|
36840
37295
|
const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
|
|
36841
37296
|
if (match) {
|
|
36842
37297
|
_cachedDefault = match[1].split(",")[0].trim();
|
|
@@ -36860,7 +37315,7 @@ var status_exports = {};
|
|
|
36860
37315
|
__export(status_exports, {
|
|
36861
37316
|
statusCommand: () => statusCommand
|
|
36862
37317
|
});
|
|
36863
|
-
import { existsSync as
|
|
37318
|
+
import { existsSync as existsSync35, statSync as statSync10 } from "fs";
|
|
36864
37319
|
async function statusCommand(globalOpts, localOpts) {
|
|
36865
37320
|
try {
|
|
36866
37321
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -36900,7 +37355,7 @@ async function statusCommand(globalOpts, localOpts) {
|
|
|
36900
37355
|
const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
|
|
36901
37356
|
const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
|
|
36902
37357
|
const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
|
|
36903
|
-
const dbStat =
|
|
37358
|
+
const dbStat = existsSync35(DB_PATH) ? statSync10(DB_PATH) : null;
|
|
36904
37359
|
let daemonRunning = false;
|
|
36905
37360
|
let daemonInfo = {};
|
|
36906
37361
|
try {
|
|
@@ -37012,13 +37467,13 @@ __export(doctor_exports, {
|
|
|
37012
37467
|
doctorCommand: () => doctorCommand,
|
|
37013
37468
|
doctorErrors: () => doctorErrors
|
|
37014
37469
|
});
|
|
37015
|
-
import { existsSync as
|
|
37470
|
+
import { existsSync as existsSync36, accessSync, constants } from "fs";
|
|
37016
37471
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
37017
37472
|
async function doctorCommand(globalOpts, localOpts) {
|
|
37018
37473
|
const checks = [];
|
|
37019
37474
|
const dbChecks = checkDatabase();
|
|
37020
37475
|
checks.push(...dbChecks);
|
|
37021
|
-
if (
|
|
37476
|
+
if (existsSync36(DB_PATH)) {
|
|
37022
37477
|
try {
|
|
37023
37478
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
37024
37479
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -37044,7 +37499,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37044
37499
|
checks.push({ name: "Database health", status: "error", message: err.message });
|
|
37045
37500
|
}
|
|
37046
37501
|
}
|
|
37047
|
-
if (
|
|
37502
|
+
if (existsSync36(ENV_PATH)) {
|
|
37048
37503
|
checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
|
|
37049
37504
|
} else {
|
|
37050
37505
|
checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
|
|
@@ -37087,7 +37542,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37087
37542
|
} catch {
|
|
37088
37543
|
}
|
|
37089
37544
|
const tokenPath = `${DATA_PATH}/api-token`;
|
|
37090
|
-
if (
|
|
37545
|
+
if (existsSync36(tokenPath)) {
|
|
37091
37546
|
try {
|
|
37092
37547
|
accessSync(tokenPath, constants.R_OK);
|
|
37093
37548
|
checks.push({ name: "API token", status: "ok", message: "token file readable" });
|
|
@@ -37156,7 +37611,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37156
37611
|
const errorChecks = checks.filter(
|
|
37157
37612
|
(c) => ["Rate limits", "Content silence", "Spawn timeouts", "Other errors"].includes(c.name) && c.status !== "ok"
|
|
37158
37613
|
);
|
|
37159
|
-
if (errorChecks.length > 0 &&
|
|
37614
|
+
if (errorChecks.length > 0 && existsSync36(ERROR_LOG_PATH)) {
|
|
37160
37615
|
try {
|
|
37161
37616
|
const { writeFileSync: writeFileSync16 } = await import("fs");
|
|
37162
37617
|
writeFileSync16(ERROR_LOG_PATH, "");
|
|
@@ -37285,15 +37740,15 @@ var logs_exports = {};
|
|
|
37285
37740
|
__export(logs_exports, {
|
|
37286
37741
|
logsCommand: () => logsCommand
|
|
37287
37742
|
});
|
|
37288
|
-
import { existsSync as
|
|
37743
|
+
import { existsSync as existsSync37, readFileSync as readFileSync28, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
|
|
37289
37744
|
async function logsCommand(opts) {
|
|
37290
37745
|
const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
|
|
37291
|
-
if (!
|
|
37746
|
+
if (!existsSync37(logFile)) {
|
|
37292
37747
|
outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
|
|
37293
37748
|
process.exit(1);
|
|
37294
37749
|
}
|
|
37295
37750
|
const maxLines = parseInt(opts.lines ?? "100", 10);
|
|
37296
|
-
const content =
|
|
37751
|
+
const content = readFileSync28(logFile, "utf-8");
|
|
37297
37752
|
const allLines = content.split("\n");
|
|
37298
37753
|
const tailLines = allLines.slice(-maxLines);
|
|
37299
37754
|
console.log(muted(` \u2500\u2500 ${logFile} (last ${tailLines.length} lines) \u2500\u2500`));
|
|
@@ -37303,7 +37758,7 @@ async function logsCommand(opts) {
|
|
|
37303
37758
|
let lastLength = content.length;
|
|
37304
37759
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
37305
37760
|
try {
|
|
37306
|
-
const newContent =
|
|
37761
|
+
const newContent = readFileSync28(logFile, "utf-8");
|
|
37307
37762
|
if (newContent.length > lastLength) {
|
|
37308
37763
|
const newPart = newContent.slice(lastLength);
|
|
37309
37764
|
process.stdout.write(newPart);
|
|
@@ -37335,7 +37790,7 @@ __export(session_logs_exports, {
|
|
|
37335
37790
|
sessionLogsList: () => sessionLogsList,
|
|
37336
37791
|
sessionLogsTail: () => sessionLogsTail
|
|
37337
37792
|
});
|
|
37338
|
-
import { readFileSync as
|
|
37793
|
+
import { readFileSync as readFileSync29, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
|
|
37339
37794
|
async function sessionLogsList(opts) {
|
|
37340
37795
|
const logs = listSessionLogs();
|
|
37341
37796
|
if (logs.length === 0) {
|
|
@@ -37392,12 +37847,12 @@ async function sessionLogsTail(opts) {
|
|
|
37392
37847
|
console.log(muted("\n Following... (Ctrl+C to stop)\n"));
|
|
37393
37848
|
let lastLength = 0;
|
|
37394
37849
|
try {
|
|
37395
|
-
lastLength =
|
|
37850
|
+
lastLength = readFileSync29(targetPath, "utf-8").length;
|
|
37396
37851
|
} catch {
|
|
37397
37852
|
}
|
|
37398
37853
|
watchFile3(targetPath, { interval: 500 }, () => {
|
|
37399
37854
|
try {
|
|
37400
|
-
const content =
|
|
37855
|
+
const content = readFileSync29(targetPath, "utf-8");
|
|
37401
37856
|
if (content.length > lastLength) {
|
|
37402
37857
|
process.stdout.write(content.slice(lastLength));
|
|
37403
37858
|
lastLength = content.length;
|
|
@@ -37441,11 +37896,11 @@ __export(gemini_exports, {
|
|
|
37441
37896
|
geminiReorder: () => geminiReorder,
|
|
37442
37897
|
geminiRotation: () => geminiRotation
|
|
37443
37898
|
});
|
|
37444
|
-
import { existsSync as
|
|
37445
|
-
import { join as
|
|
37899
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13, readFileSync as readFileSync30, chmodSync } from "fs";
|
|
37900
|
+
import { join as join38 } from "path";
|
|
37446
37901
|
import { createInterface as createInterface8 } from "readline";
|
|
37447
37902
|
function requireDb() {
|
|
37448
|
-
if (!
|
|
37903
|
+
if (!existsSync39(DB_PATH)) {
|
|
37449
37904
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
37450
37905
|
process.exit(1);
|
|
37451
37906
|
}
|
|
@@ -37470,9 +37925,9 @@ async function resolveSlotId(idOrLabel) {
|
|
|
37470
37925
|
function resolveOAuthEmail(configHome) {
|
|
37471
37926
|
if (!configHome) return null;
|
|
37472
37927
|
try {
|
|
37473
|
-
const accountsPath =
|
|
37474
|
-
if (!
|
|
37475
|
-
const accounts = JSON.parse(
|
|
37928
|
+
const accountsPath = join38(configHome, ".gemini", "google_accounts.json");
|
|
37929
|
+
if (!existsSync39(accountsPath)) return null;
|
|
37930
|
+
const accounts = JSON.parse(readFileSync30(accountsPath, "utf-8"));
|
|
37476
37931
|
return accounts.active || null;
|
|
37477
37932
|
} catch {
|
|
37478
37933
|
return null;
|
|
@@ -37554,14 +38009,14 @@ async function geminiAddKey(globalOpts, opts) {
|
|
|
37554
38009
|
}
|
|
37555
38010
|
async function geminiAddAccount(globalOpts, opts) {
|
|
37556
38011
|
await requireWriteDb();
|
|
37557
|
-
const slotsDir =
|
|
37558
|
-
if (!
|
|
38012
|
+
const slotsDir = join38(CC_CLAW_HOME, "gemini-slots");
|
|
38013
|
+
if (!existsSync39(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
|
|
37559
38014
|
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
37560
38015
|
const tempId = Date.now();
|
|
37561
|
-
const slotDir =
|
|
38016
|
+
const slotDir = join38(slotsDir, `slot-${tempId}`);
|
|
37562
38017
|
mkdirSync14(slotDir, { recursive: true, mode: 448 });
|
|
37563
|
-
mkdirSync14(
|
|
37564
|
-
writeFileSync13(
|
|
38018
|
+
mkdirSync14(join38(slotDir, ".gemini"), { recursive: true });
|
|
38019
|
+
writeFileSync13(join38(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
37565
38020
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
37566
38021
|
}, null, 2));
|
|
37567
38022
|
console.log("");
|
|
@@ -37578,8 +38033,8 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
37578
38033
|
});
|
|
37579
38034
|
} catch {
|
|
37580
38035
|
}
|
|
37581
|
-
const oauthPath =
|
|
37582
|
-
if (!
|
|
38036
|
+
const oauthPath = join38(slotDir, ".gemini", "oauth_creds.json");
|
|
38037
|
+
if (!existsSync39(oauthPath)) {
|
|
37583
38038
|
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
37584
38039
|
console.log(" The slot directory is preserved at: " + slotDir);
|
|
37585
38040
|
console.log(" Re-run: cc-claw gemini add-account\n");
|
|
@@ -37587,7 +38042,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
37587
38042
|
}
|
|
37588
38043
|
let accountEmail = "unknown";
|
|
37589
38044
|
try {
|
|
37590
|
-
const accounts = JSON.parse(__require("fs").readFileSync(
|
|
38045
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join38(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
37591
38046
|
accountEmail = accounts.active || accountEmail;
|
|
37592
38047
|
} catch {
|
|
37593
38048
|
}
|
|
@@ -37698,9 +38153,9 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37698
38153
|
outputError("NO_CONFIG", `Slot "${idOrLabel}" has no config directory \u2014 cannot re-login.`);
|
|
37699
38154
|
return;
|
|
37700
38155
|
}
|
|
37701
|
-
const settingsPath =
|
|
37702
|
-
if (!
|
|
37703
|
-
mkdirSync14(
|
|
38156
|
+
const settingsPath = join38(slot.configHome, ".gemini", "settings.json");
|
|
38157
|
+
if (!existsSync39(settingsPath)) {
|
|
38158
|
+
mkdirSync14(join38(slot.configHome, ".gemini"), { recursive: true });
|
|
37704
38159
|
writeFileSync13(settingsPath, JSON.stringify({
|
|
37705
38160
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
37706
38161
|
}, null, 2));
|
|
@@ -37724,8 +38179,8 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37724
38179
|
});
|
|
37725
38180
|
} catch {
|
|
37726
38181
|
}
|
|
37727
|
-
const oauthPath =
|
|
37728
|
-
if (!
|
|
38182
|
+
const oauthPath = join38(slot.configHome, ".gemini", "oauth_creds.json");
|
|
38183
|
+
if (!existsSync39(oauthPath)) {
|
|
37729
38184
|
console.log(error2("\n Re-login failed \u2014 no OAuth credentials found."));
|
|
37730
38185
|
console.log(` Try again: cc-claw gemini re-login ${idOrLabel}
|
|
37731
38186
|
`);
|
|
@@ -37735,7 +38190,7 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37735
38190
|
setGeminiSlotEnabled2(slotId, true);
|
|
37736
38191
|
let accountEmail = slot.label;
|
|
37737
38192
|
try {
|
|
37738
|
-
const accounts = JSON.parse(
|
|
38193
|
+
const accounts = JSON.parse(readFileSync30(join38(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
|
|
37739
38194
|
if (accounts.active) accountEmail = accounts.active;
|
|
37740
38195
|
} catch {
|
|
37741
38196
|
}
|
|
@@ -37794,11 +38249,11 @@ __export(backend_cmd_factory_exports, {
|
|
|
37794
38249
|
makeReorder: () => makeReorder,
|
|
37795
38250
|
registerBackendSlotCommands: () => registerBackendSlotCommands
|
|
37796
38251
|
});
|
|
37797
|
-
import { existsSync as
|
|
37798
|
-
import { join as
|
|
38252
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as readFileSync31 } from "fs";
|
|
38253
|
+
import { join as join39 } from "path";
|
|
37799
38254
|
import { createInterface as createInterface9 } from "readline";
|
|
37800
38255
|
function requireDb2() {
|
|
37801
|
-
if (!
|
|
38256
|
+
if (!existsSync40(DB_PATH)) {
|
|
37802
38257
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
37803
38258
|
process.exit(1);
|
|
37804
38259
|
}
|
|
@@ -37887,10 +38342,10 @@ function makeAddAccount(backend2, displayName) {
|
|
|
37887
38342
|
process.exit(1);
|
|
37888
38343
|
}
|
|
37889
38344
|
await requireWriteDb2();
|
|
37890
|
-
const slotsDir =
|
|
37891
|
-
if (!
|
|
38345
|
+
const slotsDir = join39(CC_CLAW_HOME, config2.slotsSubdir);
|
|
38346
|
+
if (!existsSync40(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
|
|
37892
38347
|
const tempId = Date.now();
|
|
37893
|
-
const slotDir =
|
|
38348
|
+
const slotDir = join39(slotsDir, `slot-${tempId}`);
|
|
37894
38349
|
mkdirSync15(slotDir, { recursive: true, mode: 448 });
|
|
37895
38350
|
if (config2.preSetup) config2.preSetup(slotDir);
|
|
37896
38351
|
console.log("");
|
|
@@ -38141,22 +38596,22 @@ var init_backend_cmd_factory = __esm({
|
|
|
38141
38596
|
envValue: (slotDir) => slotDir,
|
|
38142
38597
|
envOverrides: { ANTHROPIC_API_KEY: void 0 },
|
|
38143
38598
|
preSetup: (slotDir) => {
|
|
38144
|
-
mkdirSync15(
|
|
38599
|
+
mkdirSync15(join39(slotDir, ".claude"), { recursive: true });
|
|
38145
38600
|
},
|
|
38146
38601
|
verifyCredentials: (slotDir) => {
|
|
38147
|
-
const claudeJson =
|
|
38148
|
-
const claudeJsonNested =
|
|
38149
|
-
if (
|
|
38602
|
+
const claudeJson = join39(slotDir, ".claude.json");
|
|
38603
|
+
const claudeJsonNested = join39(slotDir, ".claude", ".claude.json");
|
|
38604
|
+
if (existsSync40(claudeJson)) {
|
|
38150
38605
|
try {
|
|
38151
|
-
const data = JSON.parse(
|
|
38606
|
+
const data = JSON.parse(readFileSync31(claudeJson, "utf-8"));
|
|
38152
38607
|
return Boolean(data.oauthAccount);
|
|
38153
38608
|
} catch {
|
|
38154
38609
|
return false;
|
|
38155
38610
|
}
|
|
38156
38611
|
}
|
|
38157
|
-
if (
|
|
38612
|
+
if (existsSync40(claudeJsonNested)) {
|
|
38158
38613
|
try {
|
|
38159
|
-
const data = JSON.parse(
|
|
38614
|
+
const data = JSON.parse(readFileSync31(claudeJsonNested, "utf-8"));
|
|
38160
38615
|
return Boolean(data.oauthAccount);
|
|
38161
38616
|
} catch {
|
|
38162
38617
|
return false;
|
|
@@ -38177,9 +38632,9 @@ var init_backend_cmd_factory = __esm({
|
|
|
38177
38632
|
} catch {
|
|
38178
38633
|
}
|
|
38179
38634
|
try {
|
|
38180
|
-
const claudeJson =
|
|
38181
|
-
if (
|
|
38182
|
-
const data = JSON.parse(
|
|
38635
|
+
const claudeJson = join39(slotDir, ".claude.json");
|
|
38636
|
+
if (existsSync40(claudeJson)) {
|
|
38637
|
+
const data = JSON.parse(readFileSync31(claudeJson, "utf-8"));
|
|
38183
38638
|
if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
|
|
38184
38639
|
}
|
|
38185
38640
|
} catch {
|
|
@@ -38194,11 +38649,11 @@ var init_backend_cmd_factory = __esm({
|
|
|
38194
38649
|
envValue: (slotDir) => slotDir,
|
|
38195
38650
|
envOverrides: { OPENAI_API_KEY: void 0 },
|
|
38196
38651
|
verifyCredentials: (slotDir) => {
|
|
38197
|
-
return
|
|
38652
|
+
return existsSync40(join39(slotDir, "auth.json"));
|
|
38198
38653
|
},
|
|
38199
38654
|
extractLabel: (slotDir) => {
|
|
38200
38655
|
try {
|
|
38201
|
-
const authData = JSON.parse(
|
|
38656
|
+
const authData = JSON.parse(readFileSync31(join39(slotDir, "auth.json"), "utf-8"));
|
|
38202
38657
|
if (authData.email) return authData.email;
|
|
38203
38658
|
if (authData.account_name) return authData.account_name;
|
|
38204
38659
|
if (authData.user?.email) return authData.user.email;
|
|
@@ -38262,9 +38717,9 @@ __export(ollama_exports3, {
|
|
|
38262
38717
|
ollamaRemove: () => ollamaRemove,
|
|
38263
38718
|
ollamaTest: () => ollamaTest
|
|
38264
38719
|
});
|
|
38265
|
-
import { existsSync as
|
|
38720
|
+
import { existsSync as existsSync41 } from "fs";
|
|
38266
38721
|
function requireDb3() {
|
|
38267
|
-
if (!
|
|
38722
|
+
if (!existsSync41(DB_PATH)) {
|
|
38268
38723
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38269
38724
|
process.exit(1);
|
|
38270
38725
|
}
|
|
@@ -38526,12 +38981,12 @@ __export(backend_exports, {
|
|
|
38526
38981
|
backendList: () => backendList,
|
|
38527
38982
|
backendSet: () => backendSet
|
|
38528
38983
|
});
|
|
38529
|
-
import { existsSync as
|
|
38984
|
+
import { existsSync as existsSync42 } from "fs";
|
|
38530
38985
|
async function backendList(globalOpts) {
|
|
38531
38986
|
const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
38532
38987
|
const chatId = resolveChatId2(globalOpts);
|
|
38533
38988
|
let activeBackend = null;
|
|
38534
|
-
if (
|
|
38989
|
+
if (existsSync42(DB_PATH)) {
|
|
38535
38990
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
38536
38991
|
const readDb = openDatabaseReadOnly2();
|
|
38537
38992
|
try {
|
|
@@ -38562,7 +39017,7 @@ async function backendList(globalOpts) {
|
|
|
38562
39017
|
}
|
|
38563
39018
|
async function backendGet(globalOpts) {
|
|
38564
39019
|
const chatId = resolveChatId2(globalOpts);
|
|
38565
|
-
if (!
|
|
39020
|
+
if (!existsSync42(DB_PATH)) {
|
|
38566
39021
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38567
39022
|
process.exit(1);
|
|
38568
39023
|
}
|
|
@@ -38606,13 +39061,13 @@ __export(model_exports, {
|
|
|
38606
39061
|
modelList: () => modelList,
|
|
38607
39062
|
modelSet: () => modelSet
|
|
38608
39063
|
});
|
|
38609
|
-
import { existsSync as
|
|
39064
|
+
import { existsSync as existsSync43 } from "fs";
|
|
38610
39065
|
async function modelList(globalOpts) {
|
|
38611
39066
|
const chatId = resolveChatId2(globalOpts);
|
|
38612
39067
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
38613
39068
|
const { getAdapter: getAdapter3, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
38614
39069
|
let backendId = "claude";
|
|
38615
|
-
if (
|
|
39070
|
+
if (existsSync43(DB_PATH)) {
|
|
38616
39071
|
const readDb = openDatabaseReadOnly2();
|
|
38617
39072
|
try {
|
|
38618
39073
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -38645,7 +39100,7 @@ async function modelList(globalOpts) {
|
|
|
38645
39100
|
}
|
|
38646
39101
|
async function modelGet(globalOpts) {
|
|
38647
39102
|
const chatId = resolveChatId2(globalOpts);
|
|
38648
|
-
if (!
|
|
39103
|
+
if (!existsSync43(DB_PATH)) {
|
|
38649
39104
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38650
39105
|
process.exit(1);
|
|
38651
39106
|
}
|
|
@@ -38690,9 +39145,9 @@ __export(memory_exports2, {
|
|
|
38690
39145
|
memoryOptimize: () => memoryOptimize,
|
|
38691
39146
|
memorySearch: () => memorySearch
|
|
38692
39147
|
});
|
|
38693
|
-
import { existsSync as
|
|
39148
|
+
import { existsSync as existsSync44 } from "fs";
|
|
38694
39149
|
async function memoryList(globalOpts) {
|
|
38695
|
-
if (!
|
|
39150
|
+
if (!existsSync44(DB_PATH)) {
|
|
38696
39151
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38697
39152
|
process.exit(1);
|
|
38698
39153
|
}
|
|
@@ -38716,7 +39171,7 @@ async function memoryList(globalOpts) {
|
|
|
38716
39171
|
});
|
|
38717
39172
|
}
|
|
38718
39173
|
async function memorySearch(globalOpts, query) {
|
|
38719
|
-
if (!
|
|
39174
|
+
if (!existsSync44(DB_PATH)) {
|
|
38720
39175
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38721
39176
|
process.exit(1);
|
|
38722
39177
|
}
|
|
@@ -38738,7 +39193,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
38738
39193
|
});
|
|
38739
39194
|
}
|
|
38740
39195
|
async function memoryHistory(globalOpts, opts) {
|
|
38741
|
-
if (!
|
|
39196
|
+
if (!existsSync44(DB_PATH)) {
|
|
38742
39197
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38743
39198
|
process.exit(1);
|
|
38744
39199
|
}
|
|
@@ -38839,7 +39294,7 @@ __export(cron_exports2, {
|
|
|
38839
39294
|
cronList: () => cronList,
|
|
38840
39295
|
cronRuns: () => cronRuns
|
|
38841
39296
|
});
|
|
38842
|
-
import { existsSync as
|
|
39297
|
+
import { existsSync as existsSync45 } from "fs";
|
|
38843
39298
|
function parseFallbacks(raw) {
|
|
38844
39299
|
return raw.slice(0, 3).map((f) => {
|
|
38845
39300
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -38860,7 +39315,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
38860
39315
|
return val;
|
|
38861
39316
|
}
|
|
38862
39317
|
async function cronList(globalOpts) {
|
|
38863
|
-
if (!
|
|
39318
|
+
if (!existsSync45(DB_PATH)) {
|
|
38864
39319
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38865
39320
|
process.exit(1);
|
|
38866
39321
|
}
|
|
@@ -38898,7 +39353,7 @@ async function cronList(globalOpts) {
|
|
|
38898
39353
|
});
|
|
38899
39354
|
}
|
|
38900
39355
|
async function cronHealth(globalOpts) {
|
|
38901
|
-
if (!
|
|
39356
|
+
if (!existsSync45(DB_PATH)) {
|
|
38902
39357
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38903
39358
|
process.exit(1);
|
|
38904
39359
|
}
|
|
@@ -39082,7 +39537,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
39082
39537
|
}
|
|
39083
39538
|
}
|
|
39084
39539
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
39085
|
-
if (!
|
|
39540
|
+
if (!existsSync45(DB_PATH)) {
|
|
39086
39541
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39087
39542
|
process.exit(1);
|
|
39088
39543
|
}
|
|
@@ -39129,9 +39584,9 @@ __export(agents_exports, {
|
|
|
39129
39584
|
runnersList: () => runnersList,
|
|
39130
39585
|
tasksList: () => tasksList
|
|
39131
39586
|
});
|
|
39132
|
-
import { existsSync as
|
|
39587
|
+
import { existsSync as existsSync46 } from "fs";
|
|
39133
39588
|
async function agentsList(globalOpts) {
|
|
39134
|
-
if (!
|
|
39589
|
+
if (!existsSync46(DB_PATH)) {
|
|
39135
39590
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39136
39591
|
process.exit(1);
|
|
39137
39592
|
}
|
|
@@ -39162,7 +39617,7 @@ async function agentsList(globalOpts) {
|
|
|
39162
39617
|
});
|
|
39163
39618
|
}
|
|
39164
39619
|
async function tasksList(globalOpts) {
|
|
39165
|
-
if (!
|
|
39620
|
+
if (!existsSync46(DB_PATH)) {
|
|
39166
39621
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39167
39622
|
process.exit(1);
|
|
39168
39623
|
}
|
|
@@ -39290,10 +39745,10 @@ __export(db_exports, {
|
|
|
39290
39745
|
dbPath: () => dbPath,
|
|
39291
39746
|
dbStats: () => dbStats
|
|
39292
39747
|
});
|
|
39293
|
-
import { existsSync as
|
|
39748
|
+
import { existsSync as existsSync47, statSync as statSync11, copyFileSync as copyFileSync4, mkdirSync as mkdirSync16 } from "fs";
|
|
39294
39749
|
import { dirname as dirname8 } from "path";
|
|
39295
39750
|
async function dbStats(globalOpts) {
|
|
39296
|
-
if (!
|
|
39751
|
+
if (!existsSync47(DB_PATH)) {
|
|
39297
39752
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
39298
39753
|
process.exit(1);
|
|
39299
39754
|
}
|
|
@@ -39301,7 +39756,7 @@ async function dbStats(globalOpts) {
|
|
|
39301
39756
|
const readDb = openDatabaseReadOnly2();
|
|
39302
39757
|
const mainSize = statSync11(DB_PATH).size;
|
|
39303
39758
|
const walPath = DB_PATH + "-wal";
|
|
39304
|
-
const walSize =
|
|
39759
|
+
const walSize = existsSync47(walPath) ? statSync11(walPath).size : 0;
|
|
39305
39760
|
const tableNames = readDb.prepare(
|
|
39306
39761
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
39307
39762
|
).all();
|
|
@@ -39335,7 +39790,7 @@ async function dbPath(globalOpts) {
|
|
|
39335
39790
|
output({ path: DB_PATH }, (d) => d.path);
|
|
39336
39791
|
}
|
|
39337
39792
|
async function dbBackup(globalOpts, destPath) {
|
|
39338
|
-
if (!
|
|
39793
|
+
if (!existsSync47(DB_PATH)) {
|
|
39339
39794
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
39340
39795
|
process.exit(1);
|
|
39341
39796
|
}
|
|
@@ -39344,7 +39799,7 @@ async function dbBackup(globalOpts, destPath) {
|
|
|
39344
39799
|
mkdirSync16(dirname8(dest), { recursive: true });
|
|
39345
39800
|
copyFileSync4(DB_PATH, dest);
|
|
39346
39801
|
const walPath = DB_PATH + "-wal";
|
|
39347
|
-
if (
|
|
39802
|
+
if (existsSync47(walPath)) copyFileSync4(walPath, dest + "-wal");
|
|
39348
39803
|
output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
|
|
39349
39804
|
const b = d;
|
|
39350
39805
|
return `
|
|
@@ -39373,9 +39828,9 @@ __export(usage_exports, {
|
|
|
39373
39828
|
usageCost: () => usageCost,
|
|
39374
39829
|
usageTokens: () => usageTokens
|
|
39375
39830
|
});
|
|
39376
|
-
import { existsSync as
|
|
39831
|
+
import { existsSync as existsSync48 } from "fs";
|
|
39377
39832
|
function ensureDb() {
|
|
39378
|
-
if (!
|
|
39833
|
+
if (!existsSync48(DB_PATH)) {
|
|
39379
39834
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
39380
39835
|
process.exit(1);
|
|
39381
39836
|
}
|
|
@@ -39565,9 +40020,9 @@ __export(config_exports2, {
|
|
|
39565
40020
|
configList: () => configList,
|
|
39566
40021
|
configSet: () => configSet
|
|
39567
40022
|
});
|
|
39568
|
-
import { existsSync as
|
|
40023
|
+
import { existsSync as existsSync49, readFileSync as readFileSync32 } from "fs";
|
|
39569
40024
|
async function configList(globalOpts) {
|
|
39570
|
-
if (!
|
|
40025
|
+
if (!existsSync49(DB_PATH)) {
|
|
39571
40026
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39572
40027
|
process.exit(1);
|
|
39573
40028
|
}
|
|
@@ -39601,7 +40056,7 @@ async function configGet(globalOpts, key) {
|
|
|
39601
40056
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
39602
40057
|
process.exit(1);
|
|
39603
40058
|
}
|
|
39604
|
-
if (!
|
|
40059
|
+
if (!existsSync49(DB_PATH)) {
|
|
39605
40060
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39606
40061
|
process.exit(1);
|
|
39607
40062
|
}
|
|
@@ -39647,11 +40102,11 @@ async function configSet(globalOpts, key, value) {
|
|
|
39647
40102
|
}
|
|
39648
40103
|
}
|
|
39649
40104
|
async function configEnv(_globalOpts) {
|
|
39650
|
-
if (!
|
|
40105
|
+
if (!existsSync49(ENV_PATH)) {
|
|
39651
40106
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
39652
40107
|
process.exit(1);
|
|
39653
40108
|
}
|
|
39654
|
-
const content =
|
|
40109
|
+
const content = readFileSync32(ENV_PATH, "utf-8");
|
|
39655
40110
|
const entries = {};
|
|
39656
40111
|
const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
|
|
39657
40112
|
for (const line of content.split("\n")) {
|
|
@@ -39701,9 +40156,9 @@ __export(session_exports, {
|
|
|
39701
40156
|
sessionGet: () => sessionGet,
|
|
39702
40157
|
sessionNew: () => sessionNew
|
|
39703
40158
|
});
|
|
39704
|
-
import { existsSync as
|
|
40159
|
+
import { existsSync as existsSync50 } from "fs";
|
|
39705
40160
|
async function sessionGet(globalOpts) {
|
|
39706
|
-
if (!
|
|
40161
|
+
if (!existsSync50(DB_PATH)) {
|
|
39707
40162
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39708
40163
|
process.exit(1);
|
|
39709
40164
|
}
|
|
@@ -39764,9 +40219,9 @@ __export(permissions_exports, {
|
|
|
39764
40219
|
verboseGet: () => verboseGet,
|
|
39765
40220
|
verboseSet: () => verboseSet
|
|
39766
40221
|
});
|
|
39767
|
-
import { existsSync as
|
|
40222
|
+
import { existsSync as existsSync51 } from "fs";
|
|
39768
40223
|
function ensureDb2() {
|
|
39769
|
-
if (!
|
|
40224
|
+
if (!existsSync51(DB_PATH)) {
|
|
39770
40225
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39771
40226
|
process.exit(1);
|
|
39772
40227
|
}
|
|
@@ -39913,9 +40368,9 @@ __export(cwd_exports, {
|
|
|
39913
40368
|
cwdGet: () => cwdGet,
|
|
39914
40369
|
cwdSet: () => cwdSet
|
|
39915
40370
|
});
|
|
39916
|
-
import { existsSync as
|
|
40371
|
+
import { existsSync as existsSync52 } from "fs";
|
|
39917
40372
|
async function cwdGet(globalOpts) {
|
|
39918
|
-
if (!
|
|
40373
|
+
if (!existsSync52(DB_PATH)) {
|
|
39919
40374
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39920
40375
|
process.exit(1);
|
|
39921
40376
|
}
|
|
@@ -39977,9 +40432,9 @@ __export(voice_exports, {
|
|
|
39977
40432
|
voiceGet: () => voiceGet,
|
|
39978
40433
|
voiceSet: () => voiceSet
|
|
39979
40434
|
});
|
|
39980
|
-
import { existsSync as
|
|
40435
|
+
import { existsSync as existsSync53 } from "fs";
|
|
39981
40436
|
async function voiceGet(globalOpts) {
|
|
39982
|
-
if (!
|
|
40437
|
+
if (!existsSync53(DB_PATH)) {
|
|
39983
40438
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39984
40439
|
process.exit(1);
|
|
39985
40440
|
}
|
|
@@ -40028,9 +40483,9 @@ __export(heartbeat_exports2, {
|
|
|
40028
40483
|
heartbeatGet: () => heartbeatGet,
|
|
40029
40484
|
heartbeatSet: () => heartbeatSet
|
|
40030
40485
|
});
|
|
40031
|
-
import { existsSync as
|
|
40486
|
+
import { existsSync as existsSync54 } from "fs";
|
|
40032
40487
|
async function heartbeatGet(globalOpts) {
|
|
40033
|
-
if (!
|
|
40488
|
+
if (!existsSync54(DB_PATH)) {
|
|
40034
40489
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40035
40490
|
process.exit(1);
|
|
40036
40491
|
}
|
|
@@ -40241,9 +40696,9 @@ __export(summarizer_exports, {
|
|
|
40241
40696
|
summarizerGet: () => summarizerGet,
|
|
40242
40697
|
summarizerSet: () => summarizerSet
|
|
40243
40698
|
});
|
|
40244
|
-
import { existsSync as
|
|
40699
|
+
import { existsSync as existsSync55 } from "fs";
|
|
40245
40700
|
async function summarizerGet(globalOpts) {
|
|
40246
|
-
if (!
|
|
40701
|
+
if (!existsSync55(DB_PATH)) {
|
|
40247
40702
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40248
40703
|
process.exit(1);
|
|
40249
40704
|
}
|
|
@@ -40287,9 +40742,9 @@ __export(thinking_exports, {
|
|
|
40287
40742
|
thinkingGet: () => thinkingGet,
|
|
40288
40743
|
thinkingSet: () => thinkingSet
|
|
40289
40744
|
});
|
|
40290
|
-
import { existsSync as
|
|
40745
|
+
import { existsSync as existsSync56 } from "fs";
|
|
40291
40746
|
async function thinkingGet(globalOpts) {
|
|
40292
|
-
if (!
|
|
40747
|
+
if (!existsSync56(DB_PATH)) {
|
|
40293
40748
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40294
40749
|
process.exit(1);
|
|
40295
40750
|
}
|
|
@@ -40333,9 +40788,9 @@ __export(chats_exports, {
|
|
|
40333
40788
|
chatsList: () => chatsList,
|
|
40334
40789
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
40335
40790
|
});
|
|
40336
|
-
import { existsSync as
|
|
40791
|
+
import { existsSync as existsSync57 } from "fs";
|
|
40337
40792
|
async function chatsList(_globalOpts) {
|
|
40338
|
-
if (!
|
|
40793
|
+
if (!existsSync57(DB_PATH)) {
|
|
40339
40794
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40340
40795
|
process.exit(1);
|
|
40341
40796
|
}
|
|
@@ -40458,41 +40913,186 @@ var init_skills = __esm({
|
|
|
40458
40913
|
}
|
|
40459
40914
|
});
|
|
40460
40915
|
|
|
40461
|
-
// src/cli/commands/
|
|
40462
|
-
var
|
|
40463
|
-
__export(
|
|
40464
|
-
|
|
40916
|
+
// src/cli/commands/mcp.ts
|
|
40917
|
+
var mcp_exports2 = {};
|
|
40918
|
+
__export(mcp_exports2, {
|
|
40919
|
+
mcpAdd: () => mcpAdd,
|
|
40920
|
+
mcpDisable: () => mcpDisable,
|
|
40921
|
+
mcpEnable: () => mcpEnable,
|
|
40922
|
+
mcpExport: () => mcpExport,
|
|
40923
|
+
mcpHealth: () => mcpHealth,
|
|
40924
|
+
mcpList: () => mcpList,
|
|
40925
|
+
mcpRemove: () => mcpRemove
|
|
40465
40926
|
});
|
|
40466
|
-
import { existsSync as
|
|
40467
|
-
|
|
40468
|
-
if (!
|
|
40469
|
-
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40927
|
+
import { existsSync as existsSync58 } from "fs";
|
|
40928
|
+
function requireDb4() {
|
|
40929
|
+
if (!existsSync58(DB_PATH)) {
|
|
40930
|
+
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
40470
40931
|
process.exit(1);
|
|
40471
40932
|
}
|
|
40933
|
+
}
|
|
40934
|
+
async function mcpList(globalOpts) {
|
|
40935
|
+
requireDb4();
|
|
40472
40936
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
40473
|
-
const
|
|
40474
|
-
const
|
|
40475
|
-
|
|
40476
|
-
|
|
40937
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
40938
|
+
const db3 = openDatabaseReadOnly2();
|
|
40939
|
+
const mcps = listMcpServers2(db3);
|
|
40940
|
+
db3.close();
|
|
40941
|
+
output(mcps, (d) => {
|
|
40477
40942
|
const list = d;
|
|
40478
|
-
if (list.length === 0)
|
|
40479
|
-
|
|
40943
|
+
if (list.length === 0) {
|
|
40944
|
+
return `
|
|
40945
|
+
${muted("No MCP servers registered. Use `cc-claw mcp add` or `cc-claw mcp import`.")}
|
|
40480
40946
|
`;
|
|
40947
|
+
}
|
|
40481
40948
|
const lines = ["", divider(`MCP Servers (${list.length})`), ""];
|
|
40482
40949
|
for (const m of list) {
|
|
40483
|
-
const
|
|
40484
|
-
const
|
|
40485
|
-
|
|
40950
|
+
const lock = SYSTEM_MCP_NAMES.has(m.name) ? " \u{1F512}" : "";
|
|
40951
|
+
const pin = m.enabledByDefault ? " \u{1F4CC}" : "";
|
|
40952
|
+
const desc = m.description ? ` \u2014 ${muted(m.description)}` : "";
|
|
40953
|
+
const transport = muted(`[${m.transport}]`);
|
|
40954
|
+
const cmd = m.command ? muted(` ${m.command}`) : "";
|
|
40955
|
+
lines.push(
|
|
40956
|
+
` ${healthIcon(m.healthStatus)} ${success(m.name)}${lock}${pin} ${transport}${cmd}${desc}`
|
|
40957
|
+
);
|
|
40486
40958
|
}
|
|
40487
40959
|
lines.push("");
|
|
40488
40960
|
return lines.join("\n");
|
|
40489
40961
|
});
|
|
40490
40962
|
}
|
|
40491
|
-
|
|
40492
|
-
|
|
40963
|
+
async function mcpAdd(name, command, args, globalOpts) {
|
|
40964
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
40965
|
+
outputError("RESERVED_NAME", `"${name}" is a reserved system MCP name.`);
|
|
40966
|
+
process.exit(1);
|
|
40967
|
+
}
|
|
40968
|
+
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
40969
|
+
if (!await isDaemonRunning2()) {
|
|
40970
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
40971
|
+
process.exit(1);
|
|
40972
|
+
}
|
|
40973
|
+
const res = await apiPost2("/api/mcps", {
|
|
40974
|
+
name,
|
|
40975
|
+
transport: "stdio",
|
|
40976
|
+
command,
|
|
40977
|
+
args,
|
|
40978
|
+
enabledByDefault: true
|
|
40979
|
+
});
|
|
40980
|
+
output(
|
|
40981
|
+
res.data,
|
|
40982
|
+
() => res.ok ? `
|
|
40983
|
+
${success("\u2713")} Added MCP server "${name}"
|
|
40984
|
+
` : `
|
|
40985
|
+
${error2("\u2717")} Failed to add MCP: ${JSON.stringify(res.data)}
|
|
40986
|
+
`
|
|
40987
|
+
);
|
|
40988
|
+
if (!res.ok) process.exit(1);
|
|
40989
|
+
}
|
|
40990
|
+
async function mcpRemove(name, globalOpts) {
|
|
40991
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
40992
|
+
outputError("PROTECTED", `Cannot remove system MCP "${name}"`);
|
|
40993
|
+
process.exit(1);
|
|
40994
|
+
}
|
|
40995
|
+
const { isDaemonRunning: isDaemonRunning2, apiDelete: apiDelete2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
40996
|
+
if (!await isDaemonRunning2()) {
|
|
40997
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
40998
|
+
process.exit(1);
|
|
40999
|
+
}
|
|
41000
|
+
const res = await apiDelete2(`/api/mcps/${encodeURIComponent(name)}`);
|
|
41001
|
+
output(
|
|
41002
|
+
res.data,
|
|
41003
|
+
() => res.ok ? `
|
|
41004
|
+
${success("\u2713")} Removed MCP server "${name}"
|
|
41005
|
+
` : `
|
|
41006
|
+
${error2("\u2717")} Failed to remove MCP: ${JSON.stringify(res.data)}
|
|
41007
|
+
`
|
|
41008
|
+
);
|
|
41009
|
+
if (!res.ok) process.exit(1);
|
|
41010
|
+
}
|
|
41011
|
+
async function mcpEnable(name, globalOpts) {
|
|
41012
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
41013
|
+
outputError("PROTECTED", `Cannot enable system MCP "${name}"`);
|
|
41014
|
+
process.exit(1);
|
|
41015
|
+
}
|
|
41016
|
+
const { isDaemonRunning: isDaemonRunning2, apiPut: apiPut2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41017
|
+
if (!await isDaemonRunning2()) {
|
|
41018
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41019
|
+
process.exit(1);
|
|
41020
|
+
}
|
|
41021
|
+
const res = await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: true });
|
|
41022
|
+
output(
|
|
41023
|
+
res.data,
|
|
41024
|
+
() => res.ok ? `
|
|
41025
|
+
${success("\u2713")} Enabled "${name}"
|
|
41026
|
+
` : `
|
|
41027
|
+
${error2("\u2717")} Failed to enable MCP: ${JSON.stringify(res.data)}
|
|
41028
|
+
`
|
|
41029
|
+
);
|
|
41030
|
+
if (!res.ok) process.exit(1);
|
|
41031
|
+
}
|
|
41032
|
+
async function mcpDisable(name, globalOpts) {
|
|
41033
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
41034
|
+
outputError("PROTECTED", `Cannot disable system MCP "${name}"`);
|
|
41035
|
+
process.exit(1);
|
|
41036
|
+
}
|
|
41037
|
+
const { isDaemonRunning: isDaemonRunning2, apiPut: apiPut2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41038
|
+
if (!await isDaemonRunning2()) {
|
|
41039
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41040
|
+
process.exit(1);
|
|
41041
|
+
}
|
|
41042
|
+
const res = await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: false });
|
|
41043
|
+
output(
|
|
41044
|
+
res.data,
|
|
41045
|
+
() => res.ok ? `
|
|
41046
|
+
${success("\u2713")} Disabled "${name}"
|
|
41047
|
+
` : `
|
|
41048
|
+
${error2("\u2717")} Failed to disable MCP: ${JSON.stringify(res.data)}
|
|
41049
|
+
`
|
|
41050
|
+
);
|
|
41051
|
+
if (!res.ok) process.exit(1);
|
|
41052
|
+
}
|
|
41053
|
+
async function mcpExport(globalOpts) {
|
|
41054
|
+
requireDb4();
|
|
41055
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
41056
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
41057
|
+
const db3 = openDatabaseReadOnly2();
|
|
41058
|
+
const mcps = listMcpServers2(db3);
|
|
41059
|
+
db3.close();
|
|
41060
|
+
const servers = {};
|
|
41061
|
+
for (const m of mcps) {
|
|
41062
|
+
if (SYSTEM_MCP_NAMES.has(m.name)) continue;
|
|
41063
|
+
servers[m.name] = {
|
|
41064
|
+
transport: m.transport,
|
|
41065
|
+
command: m.command ?? void 0,
|
|
41066
|
+
args: m.args ? JSON.parse(m.args) : void 0,
|
|
41067
|
+
env: m.env ? JSON.parse(m.env) : void 0
|
|
41068
|
+
};
|
|
41069
|
+
}
|
|
41070
|
+
const exportData = { mcpServers: servers };
|
|
41071
|
+
output(exportData, () => JSON.stringify(exportData, null, 2));
|
|
41072
|
+
}
|
|
41073
|
+
async function mcpHealth(globalOpts) {
|
|
41074
|
+
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41075
|
+
if (!await isDaemonRunning2()) {
|
|
41076
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41077
|
+
process.exit(1);
|
|
41078
|
+
}
|
|
41079
|
+
const res = await apiPost2("/api/mcps/health", {});
|
|
41080
|
+
output(
|
|
41081
|
+
res.data,
|
|
41082
|
+
() => res.ok ? `
|
|
41083
|
+
${success("\u2713")} Health checks triggered. Run \`cc-claw mcp list\` to see updated status.
|
|
41084
|
+
` : `
|
|
41085
|
+
${error2("\u2717")} Health check failed: ${JSON.stringify(res.data)}
|
|
41086
|
+
`
|
|
41087
|
+
);
|
|
41088
|
+
if (!res.ok) process.exit(1);
|
|
41089
|
+
}
|
|
41090
|
+
var init_mcp2 = __esm({
|
|
41091
|
+
"src/cli/commands/mcp.ts"() {
|
|
40493
41092
|
"use strict";
|
|
40494
41093
|
init_format2();
|
|
40495
41094
|
init_paths();
|
|
41095
|
+
init_constants();
|
|
40496
41096
|
}
|
|
40497
41097
|
});
|
|
40498
41098
|
|
|
@@ -40502,11 +41102,11 @@ __export(chat_exports2, {
|
|
|
40502
41102
|
chatSend: () => chatSend
|
|
40503
41103
|
});
|
|
40504
41104
|
import { request as httpRequest2 } from "http";
|
|
40505
|
-
import { readFileSync as
|
|
41105
|
+
import { readFileSync as readFileSync33, existsSync as existsSync59 } from "fs";
|
|
40506
41106
|
function getToken2() {
|
|
40507
41107
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
40508
41108
|
try {
|
|
40509
|
-
if (
|
|
41109
|
+
if (existsSync59(TOKEN_PATH)) return readFileSync33(TOKEN_PATH, "utf-8").trim();
|
|
40510
41110
|
} catch {
|
|
40511
41111
|
}
|
|
40512
41112
|
return null;
|
|
@@ -40994,8 +41594,8 @@ __export(completion_exports, {
|
|
|
40994
41594
|
completionCommand: () => completionCommand
|
|
40995
41595
|
});
|
|
40996
41596
|
import { writeFileSync as writeFileSync14, mkdirSync as mkdirSync17 } from "fs";
|
|
40997
|
-
import { join as
|
|
40998
|
-
import { homedir as
|
|
41597
|
+
import { join as join40 } from "path";
|
|
41598
|
+
import { homedir as homedir13 } from "os";
|
|
40999
41599
|
async function completionCommand(opts) {
|
|
41000
41600
|
const shell = opts.shell ?? detectShell();
|
|
41001
41601
|
let script;
|
|
@@ -41010,10 +41610,10 @@ async function completionCommand(opts) {
|
|
|
41010
41610
|
process.exit(1);
|
|
41011
41611
|
}
|
|
41012
41612
|
if (opts.install) {
|
|
41013
|
-
const dir =
|
|
41613
|
+
const dir = join40(homedir13(), ".config", "cc-claw", "completions");
|
|
41014
41614
|
mkdirSync17(dir, { recursive: true });
|
|
41015
41615
|
const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
|
|
41016
|
-
const filepath =
|
|
41616
|
+
const filepath = join40(dir, filename);
|
|
41017
41617
|
writeFileSync14(filepath, script, "utf-8");
|
|
41018
41618
|
console.log(`\u2713 Completion script written to ${filepath}
|
|
41019
41619
|
`);
|
|
@@ -41186,9 +41786,9 @@ __export(evolve_exports2, {
|
|
|
41186
41786
|
evolveStatus: () => evolveStatus,
|
|
41187
41787
|
evolveUndo: () => evolveUndo
|
|
41188
41788
|
});
|
|
41189
|
-
import { existsSync as
|
|
41789
|
+
import { existsSync as existsSync60 } from "fs";
|
|
41190
41790
|
function ensureDb3() {
|
|
41191
|
-
if (!
|
|
41791
|
+
if (!existsSync60(DB_PATH)) {
|
|
41192
41792
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
41193
41793
|
process.exit(1);
|
|
41194
41794
|
}
|
|
@@ -41662,10 +42262,10 @@ var init_optimize3 = __esm({
|
|
|
41662
42262
|
|
|
41663
42263
|
// src/setup.ts
|
|
41664
42264
|
var setup_exports = {};
|
|
41665
|
-
import { existsSync as
|
|
42265
|
+
import { existsSync as existsSync61, writeFileSync as writeFileSync15, readFileSync as readFileSync34, copyFileSync as copyFileSync5, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
|
|
41666
42266
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
41667
42267
|
import { createInterface as createInterface11 } from "readline";
|
|
41668
|
-
import { join as
|
|
42268
|
+
import { join as join41 } from "path";
|
|
41669
42269
|
function divider2() {
|
|
41670
42270
|
console.log(dim("\u2500".repeat(55)));
|
|
41671
42271
|
}
|
|
@@ -41746,22 +42346,22 @@ async function setup() {
|
|
|
41746
42346
|
console.log("");
|
|
41747
42347
|
if (!DRY_RUN) {
|
|
41748
42348
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
41749
|
-
if (!
|
|
42349
|
+
if (!existsSync61(dir)) mkdirSync18(dir, { recursive: true });
|
|
41750
42350
|
}
|
|
41751
42351
|
}
|
|
41752
42352
|
const env = {};
|
|
41753
|
-
const envSource =
|
|
42353
|
+
const envSource = existsSync61(ENV_PATH) ? ENV_PATH : existsSync61(".env") ? ".env" : null;
|
|
41754
42354
|
if (envSource) {
|
|
41755
42355
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
41756
42356
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
41757
|
-
const existing =
|
|
42357
|
+
const existing = readFileSync34(envSource, "utf-8");
|
|
41758
42358
|
for (const line of existing.split("\n")) {
|
|
41759
42359
|
const match = line.match(/^([^#=]+)=(.*)$/);
|
|
41760
42360
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
41761
42361
|
}
|
|
41762
42362
|
}
|
|
41763
|
-
const cwdDb =
|
|
41764
|
-
if (
|
|
42363
|
+
const cwdDb = join41(process.cwd(), "cc-claw.db");
|
|
42364
|
+
if (existsSync61(cwdDb) && !existsSync61(DB_PATH)) {
|
|
41765
42365
|
const { size } = statSync12(cwdDb);
|
|
41766
42366
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
41767
42367
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
@@ -42622,10 +43222,38 @@ skills.command("install <url>").description("Install a skill from GitHub").actio
|
|
|
42622
43222
|
const { skillsInstall: skillsInstall2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
42623
43223
|
await skillsInstall2(program.opts(), url);
|
|
42624
43224
|
});
|
|
42625
|
-
var
|
|
42626
|
-
|
|
42627
|
-
const {
|
|
42628
|
-
await
|
|
43225
|
+
var mcp = program.command("mcp").alias("mcps").description("MCP server management");
|
|
43226
|
+
mcp.command("list").description("List all registered MCP servers").action(async () => {
|
|
43227
|
+
const { mcpList: mcpList2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43228
|
+
await mcpList2(program.opts());
|
|
43229
|
+
});
|
|
43230
|
+
mcp.command("add <name> <command> [args...]").description("Add a stdio MCP server").action(async (name, command, args) => {
|
|
43231
|
+
const { mcpAdd: mcpAdd2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43232
|
+
await mcpAdd2(name, command, args, program.opts());
|
|
43233
|
+
});
|
|
43234
|
+
mcp.command("remove <name>").description("Remove an MCP server").action(async (name) => {
|
|
43235
|
+
const { mcpRemove: mcpRemove2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43236
|
+
await mcpRemove2(name, program.opts());
|
|
43237
|
+
});
|
|
43238
|
+
mcp.command("enable <name>").description("Enable an MCP server").action(async (name) => {
|
|
43239
|
+
const { mcpEnable: mcpEnable2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43240
|
+
await mcpEnable2(name, program.opts());
|
|
43241
|
+
});
|
|
43242
|
+
mcp.command("disable <name>").description("Disable an MCP server").action(async (name) => {
|
|
43243
|
+
const { mcpDisable: mcpDisable2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43244
|
+
await mcpDisable2(name, program.opts());
|
|
43245
|
+
});
|
|
43246
|
+
mcp.command("import <source>").description("Import MCPs from another CLI (claude, gemini, codex, cursor)").action(async (source) => {
|
|
43247
|
+
const { mcpImport: mcpImport2 } = await Promise.resolve().then(() => (init_import(), import_exports));
|
|
43248
|
+
await mcpImport2(source, program.opts());
|
|
43249
|
+
});
|
|
43250
|
+
mcp.command("export").description("Export MCP registry to JSON").action(async () => {
|
|
43251
|
+
const { mcpExport: mcpExport2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43252
|
+
await mcpExport2(program.opts());
|
|
43253
|
+
});
|
|
43254
|
+
mcp.command("health").description("Trigger health checks on all MCPs").action(async () => {
|
|
43255
|
+
const { mcpHealth: mcpHealth2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43256
|
+
await mcpHealth2(program.opts());
|
|
42629
43257
|
});
|
|
42630
43258
|
var chat2 = program.command("chat").description("Chat with the AI");
|
|
42631
43259
|
chat2.command("send <message>").description("Send a message and get a response").option("--backend <name>", "Override backend").option("--model <name>", "Override model").option("--thinking <level>", "Override thinking level").option("--cwd <path>", "Override working directory").option("--stream", "Stream response tokens as they arrive").action(async (message, opts) => {
|