cc-claw 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1623 -1004
- 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.0" : (() => {
|
|
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: "Run a shell command. Only commands starting with a whitelisted CLI are allowed. Use this for tasks like searching, fetching URLs, running scripts, or interacting with tools the user has approved.",
|
|
6452
|
+
description: isYolo ? "Run any shell command. No restrictions." : "Run a shell command. Only commands starting with a whitelisted CLI are allowed. Use this for tasks like searching, fetching URLs, running scripts, or interacting with tools the user has approved.",
|
|
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;
|
|
@@ -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,56 +9817,71 @@ 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
9886
|
async function assembleBootstrapPrompt(userMessage, entityType = "main", profile = "interactive", chatId, permMode, responseStyle, agentMode, sideQuestContext, planningDirective, chatContext) {
|
|
9685
9887
|
const sections = [];
|
|
@@ -9720,6 +9922,13 @@ ${parts.join("\n")}`);
|
|
|
9720
9922
|
${ctx}`);
|
|
9721
9923
|
}
|
|
9722
9924
|
}
|
|
9925
|
+
if (profile === "interactive" || profile === "chat") {
|
|
9926
|
+
const skill = searchSkill(userMessage);
|
|
9927
|
+
if (skill) {
|
|
9928
|
+
sections.push(`[Relevant skill]
|
|
9929
|
+
${skill}`);
|
|
9930
|
+
}
|
|
9931
|
+
}
|
|
9723
9932
|
if (chatId && profile !== "minimal" && profile !== "chat") {
|
|
9724
9933
|
if (sideQuestContext) {
|
|
9725
9934
|
const bridge = buildContextBridge(sideQuestContext.parentChatId, 15);
|
|
@@ -9879,7 +10088,7 @@ ${parts.join("\n")}${MEMORY_DISCIPLINE}`;
|
|
|
9879
10088
|
}
|
|
9880
10089
|
return null;
|
|
9881
10090
|
}
|
|
9882
|
-
var lastSyncMs, CONTEXT_DIR2, MAX_CONTEXT_CHARS,
|
|
10091
|
+
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
10092
|
var init_loader = __esm({
|
|
9884
10093
|
"src/bootstrap/loader.ts"() {
|
|
9885
10094
|
"use strict";
|
|
@@ -9893,9 +10102,12 @@ var init_loader = __esm({
|
|
|
9893
10102
|
init_backends();
|
|
9894
10103
|
lastSyncMs = 0;
|
|
9895
10104
|
CONTEXT_DIR2 = join10(WORKSPACE_PATH, "context");
|
|
10105
|
+
SKILLS_DIR = join10(WORKSPACE_PATH, "skills");
|
|
9896
10106
|
MAX_CONTEXT_CHARS = 4e3;
|
|
9897
|
-
|
|
9898
|
-
|
|
10107
|
+
MAX_SKILL_CHARS = 6e3;
|
|
10108
|
+
CACHE_TTL_MS2 = 3e4;
|
|
10109
|
+
contextCacheRef = { v: null };
|
|
10110
|
+
skillCacheRef = { v: null };
|
|
9899
10111
|
ACTIVITY_TOKEN_BUDGET = 1500;
|
|
9900
10112
|
INBOX_TOKEN_BUDGET = 2e3;
|
|
9901
10113
|
WHITEBOARD_TOKEN_BUDGET = 500;
|
|
@@ -10192,7 +10404,7 @@ async function summarizeWithFallbackChain(chatId, targetBackendId, excludeBacken
|
|
|
10192
10404
|
const key = `${targetAdapter.id}:${model2}`;
|
|
10193
10405
|
if (!tried.has(key)) {
|
|
10194
10406
|
tried.add(key);
|
|
10195
|
-
const result = await attemptSummarize(chatId, targetAdapter, model2, entries);
|
|
10407
|
+
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
10408
|
if (result.success) {
|
|
10197
10409
|
await extractAndLogSignals(result.rawText, chatId, targetAdapter.id, model2);
|
|
10198
10410
|
if (clearLogAfter) clearLog(chatId);
|
|
@@ -10210,7 +10422,7 @@ async function summarizeWithFallbackChain(chatId, targetBackendId, excludeBacken
|
|
|
10210
10422
|
const key = `${adapter.id}:${model2}`;
|
|
10211
10423
|
if (!tried.has(key)) {
|
|
10212
10424
|
tried.add(key);
|
|
10213
|
-
const result = await attemptSummarize(chatId, adapter, model2, entries);
|
|
10425
|
+
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
10426
|
if (result.success) {
|
|
10215
10427
|
await extractAndLogSignals(result.rawText, chatId, adapter.id, model2);
|
|
10216
10428
|
if (clearLogAfter) clearLog(chatId);
|
|
@@ -11199,7 +11411,7 @@ __export(discover_exports, {
|
|
|
11199
11411
|
discoverAllSkills: () => discoverAllSkills,
|
|
11200
11412
|
invalidateSkillCache: () => invalidateSkillCache,
|
|
11201
11413
|
resolveSkillForTask: () => resolveSkillForTask,
|
|
11202
|
-
stripFrontmatter: () =>
|
|
11414
|
+
stripFrontmatter: () => stripFrontmatter2
|
|
11203
11415
|
});
|
|
11204
11416
|
import { readdir, readFile } from "fs/promises";
|
|
11205
11417
|
import { createHash } from "crypto";
|
|
@@ -11211,7 +11423,7 @@ function invalidateSkillCache() {
|
|
|
11211
11423
|
}
|
|
11212
11424
|
async function discoverAllSkills() {
|
|
11213
11425
|
const now = Date.now();
|
|
11214
|
-
if (cachedSkills !== null && now - cacheTimestamp <
|
|
11426
|
+
if (cachedSkills !== null && now - cacheTimestamp < CACHE_TTL_MS3) {
|
|
11215
11427
|
return cachedSkills;
|
|
11216
11428
|
}
|
|
11217
11429
|
if (pendingScan !== null) {
|
|
@@ -11371,7 +11583,7 @@ function parseFrontmatter(content, fallbackName, source) {
|
|
|
11371
11583
|
requires
|
|
11372
11584
|
};
|
|
11373
11585
|
}
|
|
11374
|
-
function
|
|
11586
|
+
function stripFrontmatter2(content) {
|
|
11375
11587
|
return content.replace(/^---\s*\n[\s\S]*?\n---\s*\n?/, "").trim();
|
|
11376
11588
|
}
|
|
11377
11589
|
function resolveSkillForTask(skillName) {
|
|
@@ -11379,15 +11591,15 @@ function resolveSkillForTask(skillName) {
|
|
|
11379
11591
|
for (const candidate of SKILL_FILE_CANDIDATES3) {
|
|
11380
11592
|
const skillPath = join11(SKILLS_PATH, skillName, candidate);
|
|
11381
11593
|
try {
|
|
11382
|
-
const { readFileSync:
|
|
11383
|
-
if (!
|
|
11384
|
-
const raw =
|
|
11594
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = __require("fs");
|
|
11595
|
+
if (!existsSync62(skillPath)) continue;
|
|
11596
|
+
const raw = readFileSync35(skillPath, "utf-8");
|
|
11385
11597
|
const fm = parseFrontmatter(raw, skillName, "cc-claw");
|
|
11386
11598
|
if (fm.status !== "approved") {
|
|
11387
11599
|
log(`[skills] Skill "${skillName}" has status "${fm.status}" \u2014 only approved skills can be used as task worker identity`);
|
|
11388
11600
|
return null;
|
|
11389
11601
|
}
|
|
11390
|
-
const content =
|
|
11602
|
+
const content = stripFrontmatter2(raw);
|
|
11391
11603
|
return { content, requires: fm.requires };
|
|
11392
11604
|
} catch {
|
|
11393
11605
|
continue;
|
|
@@ -11395,7 +11607,7 @@ function resolveSkillForTask(skillName) {
|
|
|
11395
11607
|
}
|
|
11396
11608
|
return null;
|
|
11397
11609
|
}
|
|
11398
|
-
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS,
|
|
11610
|
+
var SKILL_FILE_CANDIDATES, BACKEND_SKILL_DIRS, CACHE_TTL_MS3, cachedSkills, cacheTimestamp, pendingScan;
|
|
11399
11611
|
var init_discover = __esm({
|
|
11400
11612
|
"src/skills/discover.ts"() {
|
|
11401
11613
|
"use strict";
|
|
@@ -11415,7 +11627,7 @@ var init_discover = __esm({
|
|
|
11415
11627
|
join11(homedir4(), ".cursor", "skills-cursor")
|
|
11416
11628
|
]
|
|
11417
11629
|
};
|
|
11418
|
-
|
|
11630
|
+
CACHE_TTL_MS3 = 3e5;
|
|
11419
11631
|
cachedSkills = null;
|
|
11420
11632
|
cacheTimestamp = 0;
|
|
11421
11633
|
pendingScan = null;
|
|
@@ -11425,9 +11637,9 @@ var init_discover = __esm({
|
|
|
11425
11637
|
// src/agents/spawn.ts
|
|
11426
11638
|
import { spawn as spawn2 } from "child_process";
|
|
11427
11639
|
import { createInterface as createInterface2 } from "readline";
|
|
11428
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
11640
|
+
import { readFileSync as readFileSync8, existsSync as existsSync12 } from "fs";
|
|
11429
11641
|
import { join as join12 } from "path";
|
|
11430
|
-
function
|
|
11642
|
+
function stripFrontmatter3(text) {
|
|
11431
11643
|
const lines = text.split("\n");
|
|
11432
11644
|
if (lines.length < 2 || lines[0].trim() !== "---") return text;
|
|
11433
11645
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -11442,10 +11654,10 @@ function resolveSkillContent(skillName) {
|
|
|
11442
11654
|
const SKILL_FILE_CANDIDATES3 = ["SKILL.md", "skill.md"];
|
|
11443
11655
|
for (const candidate of SKILL_FILE_CANDIDATES3) {
|
|
11444
11656
|
const skillPath = join12(SKILLS_PATH, skillName, candidate);
|
|
11445
|
-
if (
|
|
11657
|
+
if (existsSync12(skillPath)) {
|
|
11446
11658
|
try {
|
|
11447
11659
|
const raw = readFileSync8(skillPath, "utf-8");
|
|
11448
|
-
return
|
|
11660
|
+
return stripFrontmatter3(raw).trim();
|
|
11449
11661
|
} catch {
|
|
11450
11662
|
return null;
|
|
11451
11663
|
}
|
|
@@ -11501,7 +11713,7 @@ function buildAgentPrompt(opts, runnerSkillPath) {
|
|
|
11501
11713
|
if (runnerSkillPath) {
|
|
11502
11714
|
try {
|
|
11503
11715
|
const raw = readFileSync8(runnerSkillPath, "utf-8");
|
|
11504
|
-
const content =
|
|
11716
|
+
const content = stripFrontmatter3(raw).trim();
|
|
11505
11717
|
if (content) parts.push(content, "");
|
|
11506
11718
|
} catch {
|
|
11507
11719
|
}
|
|
@@ -11512,7 +11724,7 @@ function buildAgentPrompt(opts, runnerSkillPath) {
|
|
|
11512
11724
|
if (runnerSkillPath) {
|
|
11513
11725
|
try {
|
|
11514
11726
|
const raw = readFileSync8(runnerSkillPath, "utf-8");
|
|
11515
|
-
const content =
|
|
11727
|
+
const content = stripFrontmatter3(raw).trim();
|
|
11516
11728
|
if (content) parts.push(content);
|
|
11517
11729
|
parts.push("");
|
|
11518
11730
|
} catch {
|
|
@@ -11697,8 +11909,15 @@ var init_cost = __esm({
|
|
|
11697
11909
|
});
|
|
11698
11910
|
|
|
11699
11911
|
// src/mcps/propagate.ts
|
|
11912
|
+
var propagate_exports = {};
|
|
11913
|
+
__export(propagate_exports, {
|
|
11914
|
+
cleanupMcps: () => cleanupMcps,
|
|
11915
|
+
diffMcps: () => diffMcps,
|
|
11916
|
+
discoverExistingMcps: () => discoverExistingMcps,
|
|
11917
|
+
injectMcps: () => injectMcps
|
|
11918
|
+
});
|
|
11700
11919
|
import { execFile as execFile2 } from "child_process";
|
|
11701
|
-
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as
|
|
11920
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync13 } from "fs";
|
|
11702
11921
|
import { promisify as promisify3 } from "util";
|
|
11703
11922
|
import { homedir as homedir5 } from "os";
|
|
11704
11923
|
import { join as join13 } from "path";
|
|
@@ -11777,7 +11996,7 @@ function injectMcpToCursorConfig(config2) {
|
|
|
11777
11996
|
const configPath = join13(homedir5(), ".cursor", "mcp.json");
|
|
11778
11997
|
let existing = {};
|
|
11779
11998
|
try {
|
|
11780
|
-
if (
|
|
11999
|
+
if (existsSync13(configPath)) {
|
|
11781
12000
|
existing = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
11782
12001
|
}
|
|
11783
12002
|
} catch {
|
|
@@ -11830,10 +12049,10 @@ async function injectMcps(runner, mcpNames, db3, scope) {
|
|
|
11830
12049
|
}
|
|
11831
12050
|
return added;
|
|
11832
12051
|
}
|
|
11833
|
-
async function cleanupMcps(runner,
|
|
12052
|
+
async function cleanupMcps(runner, mcps, db3, scope) {
|
|
11834
12053
|
const exe = runner.getExecutablePath();
|
|
11835
12054
|
const runnerId = runner.id;
|
|
11836
|
-
for (const name of
|
|
12055
|
+
for (const name of mcps) {
|
|
11837
12056
|
try {
|
|
11838
12057
|
const removeCmd = runner.getMcpRemoveCommand(name);
|
|
11839
12058
|
const args = removeCmd.slice(1);
|
|
@@ -11930,14 +12149,14 @@ function scanTemplates() {
|
|
|
11930
12149
|
}
|
|
11931
12150
|
}
|
|
11932
12151
|
function getTemplate(name) {
|
|
11933
|
-
if (Date.now() - lastScanMs >
|
|
12152
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS4) scanTemplates();
|
|
11934
12153
|
return templateCache.get(name) ?? null;
|
|
11935
12154
|
}
|
|
11936
12155
|
function listTemplates() {
|
|
11937
|
-
if (Date.now() - lastScanMs >
|
|
12156
|
+
if (Date.now() - lastScanMs > CACHE_TTL_MS4) scanTemplates();
|
|
11938
12157
|
return Array.from(templateCache.values());
|
|
11939
12158
|
}
|
|
11940
|
-
var templateCache, lastScanMs,
|
|
12159
|
+
var templateCache, lastScanMs, CACHE_TTL_MS4;
|
|
11941
12160
|
var init_loader2 = __esm({
|
|
11942
12161
|
"src/agents/templates/loader.ts"() {
|
|
11943
12162
|
"use strict";
|
|
@@ -11945,7 +12164,7 @@ var init_loader2 = __esm({
|
|
|
11945
12164
|
init_log();
|
|
11946
12165
|
templateCache = /* @__PURE__ */ new Map();
|
|
11947
12166
|
lastScanMs = 0;
|
|
11948
|
-
|
|
12167
|
+
CACHE_TTL_MS4 = 3e4;
|
|
11949
12168
|
}
|
|
11950
12169
|
});
|
|
11951
12170
|
|
|
@@ -12062,7 +12281,7 @@ __export(orchestrator_exports, {
|
|
|
12062
12281
|
spawnSubAgent: () => spawnSubAgent,
|
|
12063
12282
|
suppressNotifications: () => suppressNotifications
|
|
12064
12283
|
});
|
|
12065
|
-
import { existsSync as
|
|
12284
|
+
import { existsSync as existsSync14 } from "fs";
|
|
12066
12285
|
async function withRunnerLock(runnerId, fn) {
|
|
12067
12286
|
const prev = runnerLocks.get(runnerId) ?? Promise.resolve();
|
|
12068
12287
|
const next = prev.then(fn, () => fn());
|
|
@@ -12194,7 +12413,7 @@ async function spawnSubAgent(chatId, opts) {
|
|
|
12194
12413
|
async function startAgent(agentId, chatId, opts) {
|
|
12195
12414
|
const db3 = getDb();
|
|
12196
12415
|
const runner = getRunner(opts.runner);
|
|
12197
|
-
if (opts.cwd && !
|
|
12416
|
+
if (opts.cwd && !existsSync14(opts.cwd)) {
|
|
12198
12417
|
const msg = `Directory not found: ${opts.cwd}`;
|
|
12199
12418
|
error(`[orchestrator] Agent ${agentId}: ${msg}`);
|
|
12200
12419
|
updateAgentStatus(db3, agentId, "failed");
|
|
@@ -12216,7 +12435,7 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
12216
12435
|
return;
|
|
12217
12436
|
}
|
|
12218
12437
|
const exePath = runner.getExecutablePath();
|
|
12219
|
-
if (exePath.startsWith("/") && !
|
|
12438
|
+
if (exePath.startsWith("/") && !existsSync14(exePath)) {
|
|
12220
12439
|
const msg = `Executable not found: ${exePath}`;
|
|
12221
12440
|
error(`[orchestrator] Agent ${agentId}: ${msg}`);
|
|
12222
12441
|
updateAgentStatus(db3, agentId, "failed");
|
|
@@ -12503,10 +12722,10 @@ async function startAgent(agentId, chatId, opts) {
|
|
|
12503
12722
|
function diagnoseSpawnError(err, exePath, cwd) {
|
|
12504
12723
|
const nodeErr = err;
|
|
12505
12724
|
if (nodeErr.code === "ENOENT") {
|
|
12506
|
-
if (cwd && !
|
|
12725
|
+
if (cwd && !existsSync14(cwd)) {
|
|
12507
12726
|
return `Directory not found: ${cwd}`;
|
|
12508
12727
|
}
|
|
12509
|
-
if (exePath.startsWith("/") && !
|
|
12728
|
+
if (exePath.startsWith("/") && !existsSync14(exePath)) {
|
|
12510
12729
|
return `Executable not found: ${exePath}`;
|
|
12511
12730
|
}
|
|
12512
12731
|
return `ENOENT spawning ${exePath} (cwd: ${cwd ?? "inherited"}) \u2014 check that both the binary and directory exist`;
|
|
@@ -12905,7 +13124,7 @@ var init_registry2 = __esm({
|
|
|
12905
13124
|
});
|
|
12906
13125
|
|
|
12907
13126
|
// src/dashboard/routes/orchestrator.ts
|
|
12908
|
-
import { existsSync as
|
|
13127
|
+
import { existsSync as existsSync15 } from "fs";
|
|
12909
13128
|
var handleSpawn, handleCancel, handleCancelAll, handleCreateTask, handleUpdateTask, handleSendMessage, handleReadInbox, handleSetState, handleGetState, handleListState, handleBroadcast, handleListRunners, handleListMcps, handleListTemplates, handleCheckAgent;
|
|
12910
13129
|
var init_orchestrator2 = __esm({
|
|
12911
13130
|
"src/dashboard/routes/orchestrator.ts"() {
|
|
@@ -12921,7 +13140,7 @@ var init_orchestrator2 = __esm({
|
|
|
12921
13140
|
handleSpawn = async (req, res) => {
|
|
12922
13141
|
try {
|
|
12923
13142
|
const body = JSON.parse(await readBody(req));
|
|
12924
|
-
if (body.cwd && !
|
|
13143
|
+
if (body.cwd && !existsSync15(body.cwd)) {
|
|
12925
13144
|
return jsonResponse(res, { error: `Directory not found: ${body.cwd}` }, 400);
|
|
12926
13145
|
}
|
|
12927
13146
|
if (!body.permMode || body.permMode === "inherit") {
|
|
@@ -13163,28 +13382,28 @@ async function checkHttpHealth(url) {
|
|
|
13163
13382
|
}
|
|
13164
13383
|
}
|
|
13165
13384
|
async function runHealthChecks(db3) {
|
|
13166
|
-
const
|
|
13167
|
-
const sorted =
|
|
13385
|
+
const mcps = listMcpServers(db3);
|
|
13386
|
+
const sorted = mcps.sort((a, b) => {
|
|
13168
13387
|
const aTime = a.lastHealthCheck ?? "0";
|
|
13169
13388
|
const bTime = b.lastHealthCheck ?? "0";
|
|
13170
13389
|
return aTime < bTime ? -1 : aTime > bTime ? 1 : 0;
|
|
13171
13390
|
});
|
|
13172
13391
|
const batch = sorted.slice(0, MAX_CHECKS_PER_CYCLE);
|
|
13173
|
-
for (const
|
|
13392
|
+
for (const mcp2 of batch) {
|
|
13174
13393
|
let status = "unhealthy";
|
|
13175
13394
|
try {
|
|
13176
|
-
if (
|
|
13177
|
-
const args =
|
|
13178
|
-
status = await checkStdioHealth(
|
|
13179
|
-
} else if ((
|
|
13180
|
-
status = await checkHttpHealth(
|
|
13395
|
+
if (mcp2.transport === "stdio" && mcp2.command) {
|
|
13396
|
+
const args = mcp2.args ? JSON.parse(mcp2.args) : [];
|
|
13397
|
+
status = await checkStdioHealth(mcp2.command, args);
|
|
13398
|
+
} else if ((mcp2.transport === "sse" || mcp2.transport === "streamable-http") && mcp2.url) {
|
|
13399
|
+
status = await checkHttpHealth(mcp2.url);
|
|
13181
13400
|
} else {
|
|
13182
13401
|
status = "unknown";
|
|
13183
13402
|
}
|
|
13184
13403
|
} catch {
|
|
13185
13404
|
status = "unhealthy";
|
|
13186
13405
|
}
|
|
13187
|
-
updateMcpHealth(db3,
|
|
13406
|
+
updateMcpHealth(db3, mcp2.name, status);
|
|
13188
13407
|
}
|
|
13189
13408
|
}
|
|
13190
13409
|
function startHealthMonitor(db3) {
|
|
@@ -13252,8 +13471,8 @@ var init_mcps = __esm({
|
|
|
13252
13471
|
try {
|
|
13253
13472
|
const { runHealthChecks: runHealthChecks2 } = await Promise.resolve().then(() => (init_health(), health_exports));
|
|
13254
13473
|
await runHealthChecks2(getDb());
|
|
13255
|
-
const
|
|
13256
|
-
jsonResponse(res,
|
|
13474
|
+
const mcps = listMcpServers(getDb());
|
|
13475
|
+
jsonResponse(res, mcps);
|
|
13257
13476
|
} catch (err) {
|
|
13258
13477
|
jsonResponse(res, { error: errorMessage(err) }, 400);
|
|
13259
13478
|
}
|
|
@@ -14293,7 +14512,7 @@ __export(stt_exports, {
|
|
|
14293
14512
|
import crypto from "crypto";
|
|
14294
14513
|
import { execFile as execFile3, execFileSync } from "child_process";
|
|
14295
14514
|
import { readFile as readFile2, unlink, writeFile } from "fs/promises";
|
|
14296
|
-
import { existsSync as
|
|
14515
|
+
import { existsSync as existsSync16 } from "fs";
|
|
14297
14516
|
import { join as join16, sep } from "path";
|
|
14298
14517
|
import { promisify as promisify4 } from "util";
|
|
14299
14518
|
import { createRequire } from "module";
|
|
@@ -14394,13 +14613,13 @@ function isWhisperModelDownloaded(model2) {
|
|
|
14394
14613
|
if (idx >= 0) {
|
|
14395
14614
|
const pkgRoot = hfMain.slice(0, idx + marker.length - 1);
|
|
14396
14615
|
const v4CacheDir = join16(pkgRoot, ".cache", org, modelName);
|
|
14397
|
-
if (
|
|
14616
|
+
if (existsSync16(v4CacheDir)) return true;
|
|
14398
14617
|
}
|
|
14399
14618
|
} catch {
|
|
14400
14619
|
}
|
|
14401
14620
|
const home = process.env.HOME ?? "/tmp";
|
|
14402
14621
|
const hubCacheDir = join16(home, ".cache", "huggingface", "hub", `models--${hfId.replace("/", "--")}`);
|
|
14403
|
-
return
|
|
14622
|
+
return existsSync16(hubCacheDir);
|
|
14404
14623
|
}
|
|
14405
14624
|
async function downloadWhisperModel(model2, onProgress) {
|
|
14406
14625
|
const info = LOCAL_WHISPER_MODELS[model2];
|
|
@@ -14583,8 +14802,8 @@ async function mp3ToOgg(mp3Buffer) {
|
|
|
14583
14802
|
const id = crypto.randomUUID();
|
|
14584
14803
|
const tmpMp3 = `/tmp/cc-claw-tts-${id}.mp3`;
|
|
14585
14804
|
const tmpOgg = `/tmp/cc-claw-tts-${id}.ogg`;
|
|
14586
|
-
const { writeFile:
|
|
14587
|
-
await
|
|
14805
|
+
const { writeFile: writeFile6 } = await import("fs/promises");
|
|
14806
|
+
await writeFile6(tmpMp3, mp3Buffer);
|
|
14588
14807
|
await execFileAsync4("ffmpeg", ["-y", "-i", tmpMp3, "-c:a", "libopus", "-b:a", "64k", tmpOgg]);
|
|
14589
14808
|
const oggBuffer = await readFile2(tmpOgg);
|
|
14590
14809
|
unlink(tmpMp3).catch((err) => {
|
|
@@ -14762,7 +14981,7 @@ function is429(err) {
|
|
|
14762
14981
|
function sleep(ms) {
|
|
14763
14982
|
return new Promise((r) => setTimeout(r, ms));
|
|
14764
14983
|
}
|
|
14765
|
-
var PER_DM_INTERVAL_MS, PER_GROUP_INTERVAL_MS, GLOBAL_INTERVAL_MS,
|
|
14984
|
+
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
14985
|
var init_telegram_throttle = __esm({
|
|
14767
14986
|
"src/channels/telegram-throttle.ts"() {
|
|
14768
14987
|
"use strict";
|
|
@@ -14770,7 +14989,7 @@ var init_telegram_throttle = __esm({
|
|
|
14770
14989
|
PER_DM_INTERVAL_MS = 1e3;
|
|
14771
14990
|
PER_GROUP_INTERVAL_MS = 3500;
|
|
14772
14991
|
GLOBAL_INTERVAL_MS = 100;
|
|
14773
|
-
|
|
14992
|
+
MAX_RETRIES2 = 2;
|
|
14774
14993
|
RETRY_DELAY_MS = 1e3;
|
|
14775
14994
|
MAX_QUEUE_SIZE = 100;
|
|
14776
14995
|
MAX_TOTAL_PAUSE_MS = 30 * 60 * 1e3;
|
|
@@ -14903,13 +15122,13 @@ var init_telegram_throttle = __esm({
|
|
|
14903
15122
|
}
|
|
14904
15123
|
// ── Retry logic (non-429 errors only) ───────────────────────────────
|
|
14905
15124
|
async execWithRetry(label2, fn) {
|
|
14906
|
-
for (let attempt = 0; attempt <=
|
|
15125
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
14907
15126
|
try {
|
|
14908
15127
|
return await fn();
|
|
14909
15128
|
} catch (err) {
|
|
14910
15129
|
if (is429(err)) throw err;
|
|
14911
|
-
if (attempt <
|
|
14912
|
-
warn(`[throttle] ${label2} attempt ${attempt + 1}/${
|
|
15130
|
+
if (attempt < MAX_RETRIES2 && err instanceof GrammyError) {
|
|
15131
|
+
warn(`[throttle] ${label2} attempt ${attempt + 1}/${MAX_RETRIES2} failed (${err.error_code}), retrying`);
|
|
14913
15132
|
await sleep(RETRY_DELAY_MS);
|
|
14914
15133
|
continue;
|
|
14915
15134
|
}
|
|
@@ -14969,10 +15188,10 @@ var init_telegram_throttle = __esm({
|
|
|
14969
15188
|
});
|
|
14970
15189
|
|
|
14971
15190
|
// src/health/checks.ts
|
|
14972
|
-
import { existsSync as
|
|
15191
|
+
import { existsSync as existsSync17, statSync as statSync5, readFileSync as readFileSync11 } from "fs";
|
|
14973
15192
|
import { execFileSync as execFileSync2, execSync as execSync3 } from "child_process";
|
|
14974
15193
|
function getRecentErrors() {
|
|
14975
|
-
if (!
|
|
15194
|
+
if (!existsSync17(ERROR_LOG_PATH)) return null;
|
|
14976
15195
|
const logContent = readFileSync11(ERROR_LOG_PATH, "utf-8");
|
|
14977
15196
|
const allLines = logContent.split("\n").filter(Boolean).slice(-500);
|
|
14978
15197
|
const last24h = Date.now() - 864e5;
|
|
@@ -14994,7 +15213,7 @@ function getRecentErrors() {
|
|
|
14994
15213
|
}
|
|
14995
15214
|
function checkDatabase() {
|
|
14996
15215
|
const checks = [];
|
|
14997
|
-
if (
|
|
15216
|
+
if (existsSync17(DB_PATH)) {
|
|
14998
15217
|
const size = statSync5(DB_PATH).size;
|
|
14999
15218
|
checks.push({ name: "Database", status: "ok", message: `${(size / 1024).toFixed(0)}KB` });
|
|
15000
15219
|
} else {
|
|
@@ -15202,7 +15421,7 @@ __export(heartbeat_exports, {
|
|
|
15202
15421
|
stopHeartbeatForChat: () => stopHeartbeatForChat,
|
|
15203
15422
|
updateHeartbeatConfig: () => updateHeartbeatConfig
|
|
15204
15423
|
});
|
|
15205
|
-
import { readFileSync as readFileSync12, existsSync as
|
|
15424
|
+
import { readFileSync as readFileSync12, existsSync as existsSync18 } from "fs";
|
|
15206
15425
|
import { join as join17 } from "path";
|
|
15207
15426
|
function findHeartbeatJob() {
|
|
15208
15427
|
try {
|
|
@@ -15382,7 +15601,7 @@ ${healthText}`);
|
|
|
15382
15601
|
sections.push(`[Active Watches \u2014 execute these checks using your tools]
|
|
15383
15602
|
${watchLines.join("\n")}`);
|
|
15384
15603
|
}
|
|
15385
|
-
if (
|
|
15604
|
+
if (existsSync18(HEARTBEAT_MD_PATH)) {
|
|
15386
15605
|
try {
|
|
15387
15606
|
const custom = readFileSync12(HEARTBEAT_MD_PATH, "utf-8").trim();
|
|
15388
15607
|
if (custom) {
|
|
@@ -15646,7 +15865,6 @@ __export(ui_exports, {
|
|
|
15646
15865
|
sendBackendThinkingPicker: () => sendBackendThinkingPicker,
|
|
15647
15866
|
sendCouncilResults: () => sendCouncilResults,
|
|
15648
15867
|
sendCurrentProposal: () => sendCurrentProposal,
|
|
15649
|
-
sendEscalationKeyboard: () => sendEscalationKeyboard,
|
|
15650
15868
|
sendForgetPicker: () => sendForgetPicker,
|
|
15651
15869
|
sendHeartbeatEngine: () => sendHeartbeatEngine,
|
|
15652
15870
|
sendHeartbeatFallbacks: () => sendHeartbeatFallbacks,
|
|
@@ -17285,45 +17503,18 @@ async function doBackendSwitch(chatId, backendId, channel, opts) {
|
|
|
17285
17503
|
}
|
|
17286
17504
|
}
|
|
17287
17505
|
}
|
|
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
17506
|
async function sendApiToolsKeyboard(chatId, channel, messageId) {
|
|
17319
|
-
const { getApiCliWhitelist: getApiCliWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
17507
|
+
const { getApiCliWhitelist: getApiCliWhitelist2, getApiWebSearchEnabled: getApiWebSearchEnabled2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
17320
17508
|
const entries = getApiCliWhitelist2(chatId);
|
|
17321
17509
|
const whitelist = entries.map((e) => e.cli);
|
|
17510
|
+
const webSearchEnabled = getApiWebSearchEnabled2(chatId);
|
|
17322
17511
|
const lines = [
|
|
17323
|
-
"\u{1F527} API Backend \u2014
|
|
17512
|
+
"\u{1F527} API Backend \u2014 Tools",
|
|
17324
17513
|
buildSectionHeader("", 26),
|
|
17325
17514
|
"",
|
|
17326
|
-
|
|
17515
|
+
`\u{1F50D} Built-in web search (DuckDuckGo): ${webSearchEnabled ? "\u{1F7E2} On" : "\u26AB Off"}`,
|
|
17516
|
+
"",
|
|
17517
|
+
"CLI Whitelist \u2014 commands the AI can run:",
|
|
17327
17518
|
""
|
|
17328
17519
|
];
|
|
17329
17520
|
if (whitelist.length > 0) {
|
|
@@ -17336,6 +17527,11 @@ async function sendApiToolsKeyboard(chatId, channel, messageId) {
|
|
|
17336
17527
|
lines.push("");
|
|
17337
17528
|
lines.push("Tap \u2795 to add a command pattern.");
|
|
17338
17529
|
const buttons = [];
|
|
17530
|
+
buttons.push([{
|
|
17531
|
+
label: webSearchEnabled ? "\u{1F50D} Disable Web Search" : "\u{1F50D} Enable Web Search",
|
|
17532
|
+
data: "apitools:toggle-web-search",
|
|
17533
|
+
style: webSearchEnabled ? "danger" : "success"
|
|
17534
|
+
}]);
|
|
17339
17535
|
for (const cmd of whitelist.slice(0, 10)) {
|
|
17340
17536
|
buttons.push([{
|
|
17341
17537
|
label: `\u2715 ${cmd.length > 25 ? cmd.slice(0, 25) + "\u2026" : cmd}`,
|
|
@@ -18721,7 +18917,7 @@ __export(analyze_exports, {
|
|
|
18721
18917
|
});
|
|
18722
18918
|
import { spawn as spawn4 } from "child_process";
|
|
18723
18919
|
import { createInterface as createInterface3 } from "readline";
|
|
18724
|
-
import { readFileSync as readFileSync13, existsSync as
|
|
18920
|
+
import { readFileSync as readFileSync13, existsSync as existsSync19, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
|
|
18725
18921
|
import { join as join18 } from "path";
|
|
18726
18922
|
import { homedir as homedir6 } from "os";
|
|
18727
18923
|
function applySignalDecay(confidence, createdAt) {
|
|
@@ -18735,12 +18931,12 @@ function discoverReflectionTargets() {
|
|
|
18735
18931
|
const targets = [];
|
|
18736
18932
|
try {
|
|
18737
18933
|
const skillsDir = join18(ccClawHome, "workspace", "skills");
|
|
18738
|
-
if (
|
|
18934
|
+
if (existsSync19(skillsDir)) {
|
|
18739
18935
|
for (const entry of readdirSync7(skillsDir)) {
|
|
18740
18936
|
const entryPath = join18(skillsDir, entry);
|
|
18741
18937
|
if (!statSync6(entryPath).isDirectory()) continue;
|
|
18742
18938
|
const skillFile = join18(entryPath, "SKILL.md");
|
|
18743
|
-
if (!
|
|
18939
|
+
if (!existsSync19(skillFile)) continue;
|
|
18744
18940
|
let desc = "skill";
|
|
18745
18941
|
try {
|
|
18746
18942
|
const content = readFileSync13(skillFile, "utf-8");
|
|
@@ -18755,7 +18951,7 @@ function discoverReflectionTargets() {
|
|
|
18755
18951
|
}
|
|
18756
18952
|
try {
|
|
18757
18953
|
const contextDir = join18(ccClawHome, "workspace", "context");
|
|
18758
|
-
if (
|
|
18954
|
+
if (existsSync19(contextDir)) {
|
|
18759
18955
|
for (const entry of readdirSync7(contextDir)) {
|
|
18760
18956
|
if (!entry.endsWith(".md")) continue;
|
|
18761
18957
|
const name = entry.replace(/\.md$/, "");
|
|
@@ -19110,7 +19306,7 @@ async function runAnalysisImpl(chatId, opts) {
|
|
|
19110
19306
|
if (!isRelevant) continue;
|
|
19111
19307
|
try {
|
|
19112
19308
|
const fullPath = join18(ccClawHome, target.path);
|
|
19113
|
-
if (
|
|
19309
|
+
if (existsSync19(fullPath)) {
|
|
19114
19310
|
const content = readFileSync13(fullPath, "utf-8");
|
|
19115
19311
|
if (totalSkillChars + content.length > SKILL_CONTENT_CAP) break;
|
|
19116
19312
|
skillContents.push({ path: target.path, content });
|
|
@@ -19491,7 +19687,7 @@ __export(apply_exports, {
|
|
|
19491
19687
|
isTargetAllowed: () => isTargetAllowed,
|
|
19492
19688
|
rollbackInsight: () => rollbackInsight
|
|
19493
19689
|
});
|
|
19494
|
-
import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as
|
|
19690
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, existsSync as existsSync20, mkdirSync as mkdirSync7, readdirSync as readdirSync8, unlinkSync as unlinkSync5 } from "fs";
|
|
19495
19691
|
import { join as join19, dirname as dirname4 } from "path";
|
|
19496
19692
|
function isTargetAllowed(relativePath) {
|
|
19497
19693
|
if (relativePath.includes("..")) return false;
|
|
@@ -19578,7 +19774,7 @@ async function applyInsight(insightId) {
|
|
|
19578
19774
|
}
|
|
19579
19775
|
const absolutePath = join19(CC_CLAW_HOME, insight.targetFile);
|
|
19580
19776
|
if (insight.proposedAction === "append" && insight.targetFile === "identity/SOUL.md") {
|
|
19581
|
-
if (
|
|
19777
|
+
if (existsSync20(absolutePath)) {
|
|
19582
19778
|
const currentContent = readFileSync14(absolutePath, "utf-8");
|
|
19583
19779
|
const lineCount = currentContent.split("\n").length;
|
|
19584
19780
|
if (lineCount >= SOUL_LINE_CAP) {
|
|
@@ -19600,7 +19796,7 @@ async function applyInsight(insightId) {
|
|
|
19600
19796
|
};
|
|
19601
19797
|
}
|
|
19602
19798
|
let original = "";
|
|
19603
|
-
if (
|
|
19799
|
+
if (existsSync20(absolutePath)) {
|
|
19604
19800
|
original = readFileSync14(absolutePath, "utf-8");
|
|
19605
19801
|
} else if (insight.proposedAction !== "create") {
|
|
19606
19802
|
return { success: false, message: `Target file "${insight.targetFile}" does not exist` };
|
|
@@ -19609,7 +19805,7 @@ async function applyInsight(insightId) {
|
|
|
19609
19805
|
const backupPath = absolutePath + `.bak.${timestamp}`;
|
|
19610
19806
|
try {
|
|
19611
19807
|
const parentDir = dirname4(absolutePath);
|
|
19612
|
-
if (!
|
|
19808
|
+
if (!existsSync20(parentDir)) {
|
|
19613
19809
|
mkdirSync7(parentDir, { recursive: true });
|
|
19614
19810
|
}
|
|
19615
19811
|
if (original) {
|
|
@@ -19741,7 +19937,7 @@ function computeLineDrift(baseline, absolutePath) {
|
|
|
19741
19937
|
if (!baseline) return 0;
|
|
19742
19938
|
let current = "";
|
|
19743
19939
|
try {
|
|
19744
|
-
if (
|
|
19940
|
+
if (existsSync20(absolutePath)) {
|
|
19745
19941
|
current = readFileSync14(absolutePath, "utf-8");
|
|
19746
19942
|
}
|
|
19747
19943
|
} catch {
|
|
@@ -19841,12 +20037,12 @@ var init_evolve = __esm({
|
|
|
19841
20037
|
const body = JSON.parse(await readBody(req));
|
|
19842
20038
|
const { setReflectionStatus: setReflectionStatus2 } = await Promise.resolve().then(() => (init_store4(), store_exports4));
|
|
19843
20039
|
const { existsSync: fileExists, readFileSync: fileRead } = await import("fs");
|
|
19844
|
-
const { join:
|
|
20040
|
+
const { join: join42 } = await import("path");
|
|
19845
20041
|
const { CC_CLAW_HOME: home } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
19846
20042
|
const chatId = resolveChatId(body);
|
|
19847
20043
|
if (!chatId) return jsonResponse(res, { error: "No chatId provided and ALLOWED_CHAT_ID is not set" }, 400);
|
|
19848
|
-
const soulPath =
|
|
19849
|
-
const userPath =
|
|
20044
|
+
const soulPath = join42(home, "identity/SOUL.md");
|
|
20045
|
+
const userPath = join42(home, "identity/USER.md");
|
|
19850
20046
|
const soul = fileExists(soulPath) ? fileRead(soulPath, "utf-8") : "";
|
|
19851
20047
|
const user = fileExists(userPath) ? fileRead(userPath, "utf-8") : "";
|
|
19852
20048
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
@@ -19899,7 +20095,7 @@ var init_evolve = __esm({
|
|
|
19899
20095
|
});
|
|
19900
20096
|
|
|
19901
20097
|
// src/dashboard/routes/files.ts
|
|
19902
|
-
import { createWriteStream, existsSync as
|
|
20098
|
+
import { createWriteStream, existsSync as existsSync21 } from "fs";
|
|
19903
20099
|
import { readdir as readdir2, stat, unlink as unlink2, mkdir } from "fs/promises";
|
|
19904
20100
|
import { join as join20, extname } from "path";
|
|
19905
20101
|
function getUploadHtml(token, host) {
|
|
@@ -20107,7 +20303,7 @@ async function handleFileServe(req, res, url) {
|
|
|
20107
20303
|
return;
|
|
20108
20304
|
}
|
|
20109
20305
|
const filePath = join20(INCOMING_PATH, filename);
|
|
20110
|
-
if (!
|
|
20306
|
+
if (!existsSync21(filePath)) {
|
|
20111
20307
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
20112
20308
|
res.end("File not found");
|
|
20113
20309
|
return;
|
|
@@ -20533,6 +20729,36 @@ var init_detect_subagent = __esm({
|
|
|
20533
20729
|
}
|
|
20534
20730
|
});
|
|
20535
20731
|
|
|
20732
|
+
// src/mcps/unified-config.ts
|
|
20733
|
+
function buildUnifiedMcpConfig(orchestratorOpts) {
|
|
20734
|
+
const orchestrator = generateOrchestratorMcpConfig(orchestratorOpts);
|
|
20735
|
+
const servers = {};
|
|
20736
|
+
servers[orchestrator.name] = {
|
|
20737
|
+
command: orchestrator.command,
|
|
20738
|
+
args: orchestrator.args,
|
|
20739
|
+
env: orchestrator.env
|
|
20740
|
+
};
|
|
20741
|
+
const db3 = getDb();
|
|
20742
|
+
const mcps = getEnabledMcps(db3);
|
|
20743
|
+
for (const mcp2 of mcps) {
|
|
20744
|
+
if (mcp2.transport !== "stdio") continue;
|
|
20745
|
+
servers[mcp2.name] = {
|
|
20746
|
+
command: mcp2.command ?? void 0,
|
|
20747
|
+
args: mcp2.args ? JSON.parse(mcp2.args) : void 0,
|
|
20748
|
+
env: mcp2.env ? JSON.parse(mcp2.env) : void 0
|
|
20749
|
+
};
|
|
20750
|
+
}
|
|
20751
|
+
return { mcpServers: servers };
|
|
20752
|
+
}
|
|
20753
|
+
var init_unified_config = __esm({
|
|
20754
|
+
"src/mcps/unified-config.ts"() {
|
|
20755
|
+
"use strict";
|
|
20756
|
+
init_store5();
|
|
20757
|
+
init_store2();
|
|
20758
|
+
init_mcp_config();
|
|
20759
|
+
}
|
|
20760
|
+
});
|
|
20761
|
+
|
|
20536
20762
|
// src/reflection/detect.ts
|
|
20537
20763
|
var detect_exports = {};
|
|
20538
20764
|
__export(detect_exports, {
|
|
@@ -21334,8 +21560,9 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
21334
21560
|
if (cancelState2.cancelled) {
|
|
21335
21561
|
return { text: "Stopped.", usage: { input: sdUsage.input, output: sdUsage.output, cacheRead: 0 } };
|
|
21336
21562
|
}
|
|
21563
|
+
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
21564
|
return {
|
|
21338
|
-
text: sdResult.text ||
|
|
21565
|
+
text: sdResult.text || fallbackText,
|
|
21339
21566
|
usage: { input: sdUsage.input, output: sdUsage.output, cacheRead: 0 },
|
|
21340
21567
|
resolvedModel: resolvedModel2
|
|
21341
21568
|
};
|
|
@@ -21655,13 +21882,19 @@ async function askAgentImpl(chatId, userMessage, opts) {
|
|
|
21655
21882
|
function getMcpConfigPath(chatId) {
|
|
21656
21883
|
if (process.env.DASHBOARD_ENABLED !== "1") return null;
|
|
21657
21884
|
const token = getDashboardToken();
|
|
21658
|
-
|
|
21659
|
-
|
|
21885
|
+
if (!token) return null;
|
|
21886
|
+
const config2 = buildUnifiedMcpConfig({
|
|
21887
|
+
chatId,
|
|
21888
|
+
agentId: "main",
|
|
21889
|
+
token,
|
|
21890
|
+
port: process.env.DASHBOARD_PORT ?? "3141"
|
|
21891
|
+
});
|
|
21892
|
+
return writeUnifiedMcpConfigFile(config2);
|
|
21660
21893
|
}
|
|
21661
21894
|
function injectMcpConfig(adapterId, args, mcpConfigPath) {
|
|
21662
21895
|
const flag = MCP_CONFIG_FLAG[adapterId];
|
|
21663
21896
|
if (!flag) return args;
|
|
21664
|
-
return [...args, ...flag, mcpConfigPath];
|
|
21897
|
+
return [...args, ...flag, mcpConfigPath, "--strict-mcp-config"];
|
|
21665
21898
|
}
|
|
21666
21899
|
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
21900
|
var init_agent = __esm({
|
|
@@ -21686,9 +21919,10 @@ var init_agent = __esm({
|
|
|
21686
21919
|
init_store5();
|
|
21687
21920
|
init_store5();
|
|
21688
21921
|
init_server();
|
|
21689
|
-
init_mcp_config();
|
|
21690
21922
|
init_store5();
|
|
21691
21923
|
init_detect_subagent();
|
|
21924
|
+
init_unified_config();
|
|
21925
|
+
init_mcp_config();
|
|
21692
21926
|
activeChats = /* @__PURE__ */ new Map();
|
|
21693
21927
|
chatLocks = /* @__PURE__ */ new Map();
|
|
21694
21928
|
SPAWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
@@ -21925,7 +22159,7 @@ function getBackoffMs(retryCount) {
|
|
|
21925
22159
|
const jitter = Math.floor(base * 0.2 * (Math.random() * 2 - 1));
|
|
21926
22160
|
return base + jitter;
|
|
21927
22161
|
}
|
|
21928
|
-
var EXHAUSTED_PATTERNS, TRANSIENT_PATTERNS, PERMANENT_PATTERNS, BACKOFF_MS,
|
|
22162
|
+
var EXHAUSTED_PATTERNS, TRANSIENT_PATTERNS, PERMANENT_PATTERNS, BACKOFF_MS, MAX_RETRIES3, AUTO_PAUSE_THRESHOLD;
|
|
21929
22163
|
var init_retry = __esm({
|
|
21930
22164
|
"src/scheduler/retry.ts"() {
|
|
21931
22165
|
"use strict";
|
|
@@ -21975,13 +22209,13 @@ var init_retry = __esm({
|
|
|
21975
22209
|
/subscription.*expired/i
|
|
21976
22210
|
];
|
|
21977
22211
|
BACKOFF_MS = [3e4, 6e4, 3e5];
|
|
21978
|
-
|
|
22212
|
+
MAX_RETRIES3 = 3;
|
|
21979
22213
|
AUTO_PAUSE_THRESHOLD = 5;
|
|
21980
22214
|
}
|
|
21981
22215
|
});
|
|
21982
22216
|
|
|
21983
22217
|
// src/bootstrap/profile.ts
|
|
21984
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, existsSync as
|
|
22218
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, existsSync as existsSync22 } from "fs";
|
|
21985
22219
|
import { join as join21 } from "path";
|
|
21986
22220
|
function hasActiveProfile(chatId) {
|
|
21987
22221
|
return activeProfiles.has(chatId);
|
|
@@ -22111,7 +22345,7 @@ function extractUserUpdates(text) {
|
|
|
22111
22345
|
return { cleanText, updates };
|
|
22112
22346
|
}
|
|
22113
22347
|
function appendToUserProfile(key, value) {
|
|
22114
|
-
if (!
|
|
22348
|
+
if (!existsSync22(USER_PATH2)) return;
|
|
22115
22349
|
const content = readFileSync15(USER_PATH2, "utf-8");
|
|
22116
22350
|
const line = `- **${key}**: ${value}`;
|
|
22117
22351
|
if (content.includes(line)) return;
|
|
@@ -22132,203 +22366,13 @@ var init_profile = __esm({
|
|
|
22132
22366
|
}
|
|
22133
22367
|
});
|
|
22134
22368
|
|
|
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
22369
|
// src/intent/classify.ts
|
|
22325
22370
|
var classify_exports = {};
|
|
22326
22371
|
__export(classify_exports, {
|
|
22327
22372
|
classifyIntent: () => classifyIntent,
|
|
22328
22373
|
classifyIntentAsync: () => classifyIntentAsync,
|
|
22329
22374
|
getIntentStats: () => getIntentStats,
|
|
22330
|
-
resetIntentStats: () => resetIntentStats
|
|
22331
|
-
shouldEscalate: () => shouldEscalate
|
|
22375
|
+
resetIntentStats: () => resetIntentStats
|
|
22332
22376
|
});
|
|
22333
22377
|
function getIntentStats() {
|
|
22334
22378
|
return { ...intentCounts };
|
|
@@ -22338,7 +22382,6 @@ function resetIntentStats() {
|
|
|
22338
22382
|
intentCounts.agentic = 0;
|
|
22339
22383
|
}
|
|
22340
22384
|
function classifyIntentFast(text, chatId) {
|
|
22341
|
-
if (consumeAgenticBypass(chatId)) return "agentic";
|
|
22342
22385
|
const trimmed = text.trim();
|
|
22343
22386
|
if (trimmed.startsWith(">>")) return "agentic";
|
|
22344
22387
|
if (trimmed.startsWith("/")) return "agentic";
|
|
@@ -22508,16 +22551,12 @@ async function classifyIntentAsync(text, chatId) {
|
|
|
22508
22551
|
intentCounts.agentic++;
|
|
22509
22552
|
return "agentic";
|
|
22510
22553
|
}
|
|
22511
|
-
function shouldEscalate(backendType, intent) {
|
|
22512
|
-
return backendType === "api" && intent === "agentic";
|
|
22513
|
-
}
|
|
22514
22554
|
var intentCounts, CHAT_EXACT, MUTATION_PATTERNS, CHAT_QUESTION_PATTERNS, STRUCTURAL_PATTERNS, LLM_CLASSIFY_PROMPT, LLM_CLASSIFY_TIMEOUT_MS;
|
|
22515
22555
|
var init_classify = __esm({
|
|
22516
22556
|
"src/intent/classify.ts"() {
|
|
22517
22557
|
"use strict";
|
|
22518
22558
|
init_store5();
|
|
22519
22559
|
init_session_log();
|
|
22520
|
-
init_state();
|
|
22521
22560
|
init_log();
|
|
22522
22561
|
intentCounts = { chat: 0, agentic: 0 };
|
|
22523
22562
|
CHAT_EXACT = /* @__PURE__ */ new Set([
|
|
@@ -23305,7 +23344,7 @@ __export(session_log_exports2, {
|
|
|
23305
23344
|
startSessionLogCleanupTimer: () => startSessionLogCleanupTimer,
|
|
23306
23345
|
tailSessionLog: () => tailSessionLog
|
|
23307
23346
|
});
|
|
23308
|
-
import { existsSync as
|
|
23347
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, appendFileSync, readdirSync as readdirSync9, unlinkSync as unlinkSync6, statSync as statSync7, createReadStream } from "fs";
|
|
23309
23348
|
import { join as join22, basename } from "path";
|
|
23310
23349
|
import { createInterface as createInterface6 } from "readline";
|
|
23311
23350
|
function getRetentionDays() {
|
|
@@ -23318,7 +23357,7 @@ function getRetentionDays() {
|
|
|
23318
23357
|
}
|
|
23319
23358
|
function cleanupSessionLogs(retentionDays) {
|
|
23320
23359
|
const days = retentionDays ?? getRetentionDays();
|
|
23321
|
-
if (!
|
|
23360
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return 0;
|
|
23322
23361
|
const cutoff = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
23323
23362
|
let cleaned = 0;
|
|
23324
23363
|
try {
|
|
@@ -23350,7 +23389,7 @@ function startSessionLogCleanupTimer() {
|
|
|
23350
23389
|
return timer;
|
|
23351
23390
|
}
|
|
23352
23391
|
function listSessionLogs() {
|
|
23353
|
-
if (!
|
|
23392
|
+
if (!existsSync23(SESSION_LOGS_PATH)) return [];
|
|
23354
23393
|
const logs = [];
|
|
23355
23394
|
for (const file of readdirSync9(SESSION_LOGS_PATH)) {
|
|
23356
23395
|
if (!file.startsWith("session-") || !file.endsWith(".log")) continue;
|
|
@@ -23373,7 +23412,7 @@ function listSessionLogs() {
|
|
|
23373
23412
|
return logs;
|
|
23374
23413
|
}
|
|
23375
23414
|
async function* tailSessionLog(filePath, lines = 50) {
|
|
23376
|
-
if (!
|
|
23415
|
+
if (!existsSync23(filePath)) {
|
|
23377
23416
|
yield `File not found: ${filePath}`;
|
|
23378
23417
|
return;
|
|
23379
23418
|
}
|
|
@@ -23401,7 +23440,7 @@ var init_session_log2 = __esm({
|
|
|
23401
23440
|
constructor(chatId, backend2, model2) {
|
|
23402
23441
|
this.backend = backend2;
|
|
23403
23442
|
this.model = model2;
|
|
23404
|
-
if (!
|
|
23443
|
+
if (!existsSync23(SESSION_LOGS_PATH)) {
|
|
23405
23444
|
mkdirSync8(SESSION_LOGS_PATH, { recursive: true });
|
|
23406
23445
|
}
|
|
23407
23446
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
@@ -23887,7 +23926,7 @@ var init_gate = __esm({
|
|
|
23887
23926
|
});
|
|
23888
23927
|
|
|
23889
23928
|
// src/media/image-gen.ts
|
|
23890
|
-
import { mkdirSync as mkdirSync9, existsSync as
|
|
23929
|
+
import { mkdirSync as mkdirSync9, existsSync as existsSync24, unlink as unlink3, readdir as readdir3, stat as stat2 } from "fs";
|
|
23891
23930
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
23892
23931
|
import { join as join23 } from "path";
|
|
23893
23932
|
async function generateImage(prompt) {
|
|
@@ -23936,7 +23975,7 @@ async function generateImage(prompt) {
|
|
|
23936
23975
|
if (!imageData) {
|
|
23937
23976
|
throw new Error(textResponse ?? "Gemini did not generate an image. The prompt may have been filtered.");
|
|
23938
23977
|
}
|
|
23939
|
-
if (!
|
|
23978
|
+
if (!existsSync24(IMAGE_OUTPUT_DIR)) {
|
|
23940
23979
|
mkdirSync9(IMAGE_OUTPUT_DIR, { recursive: true });
|
|
23941
23980
|
}
|
|
23942
23981
|
const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
|
|
@@ -24765,6 +24804,168 @@ var init_media = __esm({
|
|
|
24765
24804
|
}
|
|
24766
24805
|
});
|
|
24767
24806
|
|
|
24807
|
+
// src/router/state.ts
|
|
24808
|
+
var state_exports = {};
|
|
24809
|
+
__export(state_exports, {
|
|
24810
|
+
activeSideQuests: () => activeSideQuests,
|
|
24811
|
+
bypassBusyCheck: () => bypassBusyCheck,
|
|
24812
|
+
clearHistoryFilter: () => clearHistoryFilter,
|
|
24813
|
+
clearPendingCliAddition: () => clearPendingCliAddition,
|
|
24814
|
+
clearPendingModelResults: () => clearPendingModelResults,
|
|
24815
|
+
clearPendingModelSearch: () => clearPendingModelSearch,
|
|
24816
|
+
councilResults: () => councilResults,
|
|
24817
|
+
dashboardClawWarnings: () => dashboardClawWarnings,
|
|
24818
|
+
getActiveSideQuestCount: () => getActiveSideQuestCount,
|
|
24819
|
+
historyFilters: () => historyFilters,
|
|
24820
|
+
parseSideQuestPrefix: () => parseSideQuestPrefix,
|
|
24821
|
+
pendingCliAdditions: () => pendingCliAdditions,
|
|
24822
|
+
pendingInterrupts: () => pendingInterrupts,
|
|
24823
|
+
pendingMcpImports: () => pendingMcpImports,
|
|
24824
|
+
pendingModelResults: () => pendingModelResults,
|
|
24825
|
+
pendingModelSearch: () => pendingModelSearch,
|
|
24826
|
+
pendingNewchatUndo: () => pendingNewchatUndo,
|
|
24827
|
+
pendingSummaryUndo: () => pendingSummaryUndo,
|
|
24828
|
+
setCouncilResult: () => setCouncilResult,
|
|
24829
|
+
setHistoryFilter: () => setHistoryFilter,
|
|
24830
|
+
setPendingCliAddition: () => setPendingCliAddition,
|
|
24831
|
+
setPendingModelResults: () => setPendingModelResults,
|
|
24832
|
+
setPendingModelSearch: () => setPendingModelSearch,
|
|
24833
|
+
startStateSweep: () => startStateSweep,
|
|
24834
|
+
stopAllSideQuests: () => stopAllSideQuests,
|
|
24835
|
+
stopStateSweep: () => stopStateSweep
|
|
24836
|
+
});
|
|
24837
|
+
function setHistoryFilter(chatId, filter) {
|
|
24838
|
+
historyFilters.set(chatId, filter);
|
|
24839
|
+
historyFilterTimestamps.set(chatId, Date.now());
|
|
24840
|
+
}
|
|
24841
|
+
function clearHistoryFilter(chatId) {
|
|
24842
|
+
historyFilters.delete(chatId);
|
|
24843
|
+
historyFilterTimestamps.delete(chatId);
|
|
24844
|
+
}
|
|
24845
|
+
function setCouncilResult(chatId, result) {
|
|
24846
|
+
councilResults.set(chatId, result);
|
|
24847
|
+
councilResultTimestamps.set(chatId, Date.now());
|
|
24848
|
+
}
|
|
24849
|
+
function setPendingModelSearch(chatId, state) {
|
|
24850
|
+
pendingModelSearch.set(chatId, state);
|
|
24851
|
+
pendingModelSearchTimestamps.set(chatId, Date.now());
|
|
24852
|
+
}
|
|
24853
|
+
function clearPendingModelSearch(chatId) {
|
|
24854
|
+
pendingModelSearch.delete(chatId);
|
|
24855
|
+
pendingModelSearchTimestamps.delete(chatId);
|
|
24856
|
+
}
|
|
24857
|
+
function setPendingModelResults(chatId, results) {
|
|
24858
|
+
pendingModelResults.set(chatId, results);
|
|
24859
|
+
}
|
|
24860
|
+
function clearPendingModelResults(chatId) {
|
|
24861
|
+
pendingModelResults.delete(chatId);
|
|
24862
|
+
}
|
|
24863
|
+
function parseSideQuestPrefix(text) {
|
|
24864
|
+
const match = text.match(/^(?:sq|btw):\s*/i);
|
|
24865
|
+
if (match) return { isSideQuest: true, cleanText: text.slice(match[0].length) };
|
|
24866
|
+
return { isSideQuest: false, cleanText: text };
|
|
24867
|
+
}
|
|
24868
|
+
function getActiveSideQuestCount(chatId) {
|
|
24869
|
+
return activeSideQuests.get(chatId)?.size ?? 0;
|
|
24870
|
+
}
|
|
24871
|
+
function stopAllSideQuests(chatId) {
|
|
24872
|
+
const active = activeSideQuests.get(chatId);
|
|
24873
|
+
if (active) {
|
|
24874
|
+
for (const sqId of active) {
|
|
24875
|
+
stopAgent(sqId);
|
|
24876
|
+
}
|
|
24877
|
+
}
|
|
24878
|
+
}
|
|
24879
|
+
function startStateSweep() {
|
|
24880
|
+
if (sweepTimer) return;
|
|
24881
|
+
sweepTimer = setInterval(() => {
|
|
24882
|
+
const now = Date.now();
|
|
24883
|
+
for (const [chatId, ts2] of dashboardClawWarnings) {
|
|
24884
|
+
if (now - ts2 > STALE_THRESHOLD_MS) dashboardClawWarnings.delete(chatId);
|
|
24885
|
+
}
|
|
24886
|
+
for (const [cid, ts2] of historyFilterTimestamps) {
|
|
24887
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24888
|
+
historyFilters.delete(cid);
|
|
24889
|
+
historyFilterTimestamps.delete(cid);
|
|
24890
|
+
}
|
|
24891
|
+
}
|
|
24892
|
+
for (const [cid, ts2] of councilResultTimestamps) {
|
|
24893
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24894
|
+
councilResults.delete(cid);
|
|
24895
|
+
councilResultTimestamps.delete(cid);
|
|
24896
|
+
}
|
|
24897
|
+
}
|
|
24898
|
+
for (const [cid, ts2] of pendingModelSearchTimestamps) {
|
|
24899
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24900
|
+
pendingModelSearch.delete(cid);
|
|
24901
|
+
pendingModelSearchTimestamps.delete(cid);
|
|
24902
|
+
}
|
|
24903
|
+
}
|
|
24904
|
+
for (const chatId of pendingInterrupts.keys()) {
|
|
24905
|
+
if (!_interruptSeen.has(chatId)) {
|
|
24906
|
+
_interruptSeen.add(chatId);
|
|
24907
|
+
} else {
|
|
24908
|
+
pendingInterrupts.delete(chatId);
|
|
24909
|
+
_interruptSeen.delete(chatId);
|
|
24910
|
+
}
|
|
24911
|
+
}
|
|
24912
|
+
for (const chatId of _interruptSeen) {
|
|
24913
|
+
if (!pendingInterrupts.has(chatId)) _interruptSeen.delete(chatId);
|
|
24914
|
+
}
|
|
24915
|
+
for (const [cid, ts2] of pendingCliTimestamps) {
|
|
24916
|
+
if (now - ts2 > STALE_THRESHOLD_MS) {
|
|
24917
|
+
pendingCliAdditions.delete(cid);
|
|
24918
|
+
pendingCliTimestamps.delete(cid);
|
|
24919
|
+
}
|
|
24920
|
+
}
|
|
24921
|
+
for (const [cid, state] of pendingMcpImports) {
|
|
24922
|
+
if (now - state.startedAt > STALE_THRESHOLD_MS) pendingMcpImports.delete(cid);
|
|
24923
|
+
}
|
|
24924
|
+
}, SWEEP_INTERVAL_MS);
|
|
24925
|
+
sweepTimer.unref();
|
|
24926
|
+
}
|
|
24927
|
+
function stopStateSweep() {
|
|
24928
|
+
if (sweepTimer) {
|
|
24929
|
+
clearInterval(sweepTimer);
|
|
24930
|
+
sweepTimer = null;
|
|
24931
|
+
}
|
|
24932
|
+
}
|
|
24933
|
+
function setPendingCliAddition(chatId, messageId) {
|
|
24934
|
+
pendingCliAdditions.set(chatId, messageId);
|
|
24935
|
+
pendingCliTimestamps.set(chatId, Date.now());
|
|
24936
|
+
}
|
|
24937
|
+
function clearPendingCliAddition(chatId) {
|
|
24938
|
+
pendingCliAdditions.delete(chatId);
|
|
24939
|
+
pendingCliTimestamps.delete(chatId);
|
|
24940
|
+
}
|
|
24941
|
+
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;
|
|
24942
|
+
var init_state = __esm({
|
|
24943
|
+
"src/router/state.ts"() {
|
|
24944
|
+
"use strict";
|
|
24945
|
+
init_agent();
|
|
24946
|
+
pendingInterrupts = /* @__PURE__ */ new Map();
|
|
24947
|
+
bypassBusyCheck = /* @__PURE__ */ new Set();
|
|
24948
|
+
activeSideQuests = /* @__PURE__ */ new Map();
|
|
24949
|
+
dashboardClawWarnings = /* @__PURE__ */ new Map();
|
|
24950
|
+
pendingSummaryUndo = /* @__PURE__ */ new Map();
|
|
24951
|
+
pendingNewchatUndo = /* @__PURE__ */ new Map();
|
|
24952
|
+
historyFilters = /* @__PURE__ */ new Map();
|
|
24953
|
+
historyFilterTimestamps = /* @__PURE__ */ new Map();
|
|
24954
|
+
councilResults = /* @__PURE__ */ new Map();
|
|
24955
|
+
councilResultTimestamps = /* @__PURE__ */ new Map();
|
|
24956
|
+
pendingModelSearch = /* @__PURE__ */ new Map();
|
|
24957
|
+
pendingModelSearchTimestamps = /* @__PURE__ */ new Map();
|
|
24958
|
+
pendingModelResults = /* @__PURE__ */ new Map();
|
|
24959
|
+
SWEEP_INTERVAL_MS = 30 * 60 * 1e3;
|
|
24960
|
+
STALE_THRESHOLD_MS = 30 * 60 * 1e3;
|
|
24961
|
+
sweepTimer = null;
|
|
24962
|
+
_interruptSeen = /* @__PURE__ */ new Set();
|
|
24963
|
+
pendingMcpImports = /* @__PURE__ */ new Map();
|
|
24964
|
+
pendingCliAdditions = /* @__PURE__ */ new Map();
|
|
24965
|
+
pendingCliTimestamps = /* @__PURE__ */ new Map();
|
|
24966
|
+
}
|
|
24967
|
+
});
|
|
24968
|
+
|
|
24768
24969
|
// src/router/sidequest.ts
|
|
24769
24970
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
24770
24971
|
async function handleSideQuest(parentChatId, msg, channel) {
|
|
@@ -24954,7 +25155,7 @@ __export(install_exports, {
|
|
|
24954
25155
|
installSkillFromGitHub: () => installSkillFromGitHub
|
|
24955
25156
|
});
|
|
24956
25157
|
import { mkdir as mkdir3, readdir as readdir5, readFile as readFile5, cp } from "fs/promises";
|
|
24957
|
-
import { existsSync as
|
|
25158
|
+
import { existsSync as existsSync25 } from "fs";
|
|
24958
25159
|
import { join as join25, basename as basename2 } from "path";
|
|
24959
25160
|
import { execSync as execSync4 } from "child_process";
|
|
24960
25161
|
async function installSkillFromGitHub(urlOrShorthand) {
|
|
@@ -24973,7 +25174,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
24973
25174
|
stdio: "pipe",
|
|
24974
25175
|
timeout: 3e4
|
|
24975
25176
|
});
|
|
24976
|
-
if (!
|
|
25177
|
+
if (!existsSync25(join25(tmpDir, ".git"))) {
|
|
24977
25178
|
return { success: false, error: "Git clone failed: no .git directory produced" };
|
|
24978
25179
|
}
|
|
24979
25180
|
const searchRoot = subPath ? join25(tmpDir, subPath) : tmpDir;
|
|
@@ -24983,7 +25184,7 @@ async function installSkillFromGitHub(urlOrShorthand) {
|
|
|
24983
25184
|
}
|
|
24984
25185
|
const skillFolderName = basename2(skillDir);
|
|
24985
25186
|
const destDir = join25(SKILLS_PATH, skillFolderName);
|
|
24986
|
-
if (
|
|
25187
|
+
if (existsSync25(destDir)) {
|
|
24987
25188
|
log(`[skill-install] Overwriting existing skill at ${destDir}`);
|
|
24988
25189
|
}
|
|
24989
25190
|
await mkdir3(destDir, { recursive: true });
|
|
@@ -25030,14 +25231,14 @@ function parseGitHubUrl(input) {
|
|
|
25030
25231
|
async function findSkillDir(root) {
|
|
25031
25232
|
const candidates = ["SKILL.md", "skill.md"];
|
|
25032
25233
|
for (const c of candidates) {
|
|
25033
|
-
if (
|
|
25234
|
+
if (existsSync25(join25(root, c))) return root;
|
|
25034
25235
|
}
|
|
25035
25236
|
try {
|
|
25036
25237
|
const entries = await readdir5(root, { withFileTypes: true });
|
|
25037
25238
|
for (const entry of entries) {
|
|
25038
25239
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
25039
25240
|
for (const c of candidates) {
|
|
25040
|
-
if (
|
|
25241
|
+
if (existsSync25(join25(root, entry.name, c))) {
|
|
25041
25242
|
return join25(root, entry.name);
|
|
25042
25243
|
}
|
|
25043
25244
|
}
|
|
@@ -25057,7 +25258,7 @@ async function findSkillDir(root) {
|
|
|
25057
25258
|
for (const sub of subEntries) {
|
|
25058
25259
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
25059
25260
|
for (const c of candidates) {
|
|
25060
|
-
if (
|
|
25261
|
+
if (existsSync25(join25(root, entry.name, sub.name, c))) {
|
|
25061
25262
|
return join25(root, entry.name, sub.name);
|
|
25062
25263
|
}
|
|
25063
25264
|
}
|
|
@@ -25348,12 +25549,12 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
25348
25549
|
);
|
|
25349
25550
|
break;
|
|
25350
25551
|
}
|
|
25351
|
-
const { readFileSync:
|
|
25352
|
-
const { join:
|
|
25353
|
-
const targetPath =
|
|
25552
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = await import("fs");
|
|
25553
|
+
const { join: join42 } = await import("path");
|
|
25554
|
+
const targetPath = join42(homedir7(), ".cc-claw", insight.targetFile);
|
|
25354
25555
|
let previewText;
|
|
25355
|
-
if (
|
|
25356
|
-
const current =
|
|
25556
|
+
if (existsSync62(targetPath)) {
|
|
25557
|
+
const current = readFileSync35(targetPath, "utf-8");
|
|
25357
25558
|
const diffLines = insight.proposedDiff.split("\n");
|
|
25358
25559
|
const additions = diffLines.filter((l) => l.startsWith("+")).map((l) => ` + ${l.slice(1).trim()}`);
|
|
25359
25560
|
const removals = diffLines.filter((l) => l.startsWith("-")).map((l) => ` - ${l.slice(1).trim()}`);
|
|
@@ -25425,13 +25626,13 @@ async function handleEvolveCallback(chatId, data, channel, messageId) {
|
|
|
25425
25626
|
const { logActivity: logActivity2 } = await Promise.resolve().then(() => (init_store3(), store_exports3));
|
|
25426
25627
|
const current = getReflectionStatus2(getDb(), chatId);
|
|
25427
25628
|
if (current === "frozen") {
|
|
25428
|
-
const { readFileSync:
|
|
25429
|
-
const { join:
|
|
25629
|
+
const { readFileSync: readFileSync35, existsSync: existsSync62 } = await import("fs");
|
|
25630
|
+
const { join: join42 } = await import("path");
|
|
25430
25631
|
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 =
|
|
25632
|
+
const soulPath = join42(CC_CLAW_HOME3, "identity/SOUL.md");
|
|
25633
|
+
const userPath = join42(CC_CLAW_HOME3, "identity/USER.md");
|
|
25634
|
+
const soul = existsSync62(soulPath) ? readFileSync35(soulPath, "utf-8") : "";
|
|
25635
|
+
const user = existsSync62(userPath) ? readFileSync35(userPath, "utf-8") : "";
|
|
25435
25636
|
setReflectionStatus2(getDb(), chatId, "active", soul, user);
|
|
25436
25637
|
logActivity2(getDb(), { chatId, source: "telegram", eventType: "reflection_unfrozen", summary: "Reflection enabled" });
|
|
25437
25638
|
await sendEvolveDashboard(chatId, reflChatId, channel, messageId);
|
|
@@ -25568,7 +25769,7 @@ var init_evolve2 = __esm({
|
|
|
25568
25769
|
});
|
|
25569
25770
|
|
|
25570
25771
|
// src/optimizer/identity-audit.ts
|
|
25571
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
25772
|
+
import { readFileSync as readFileSync16, existsSync as existsSync26, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
|
|
25572
25773
|
import { join as join26 } from "path";
|
|
25573
25774
|
function readIdentityFile2(filename) {
|
|
25574
25775
|
try {
|
|
@@ -25588,7 +25789,7 @@ function findBackupFiles() {
|
|
|
25588
25789
|
const backups = [];
|
|
25589
25790
|
const dirs = [IDENTITY_PATH];
|
|
25590
25791
|
const contextDir = join26(IDENTITY_PATH, "..", "workspace", "context");
|
|
25591
|
-
if (
|
|
25792
|
+
if (existsSync26(contextDir)) dirs.push(contextDir);
|
|
25592
25793
|
for (const dir of dirs) {
|
|
25593
25794
|
try {
|
|
25594
25795
|
for (const entry of readdirSync10(dir)) {
|
|
@@ -25725,7 +25926,7 @@ var init_identity_audit = __esm({
|
|
|
25725
25926
|
});
|
|
25726
25927
|
|
|
25727
25928
|
// src/optimizer/skill-audit.ts
|
|
25728
|
-
import { readFileSync as readFileSync17, existsSync as
|
|
25929
|
+
import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
|
|
25729
25930
|
import { join as join27, basename as basename3 } from "path";
|
|
25730
25931
|
function parseFrontmatter3(content) {
|
|
25731
25932
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -25798,7 +25999,7 @@ function loadDependentSkillContents(depNames, ccClawSkillsDir) {
|
|
|
25798
25999
|
join27(ccClawSkillsDir, `${name}-skill`, "SKILL.md")
|
|
25799
26000
|
];
|
|
25800
26001
|
for (const candidate of candidates) {
|
|
25801
|
-
if (
|
|
26002
|
+
if (existsSync27(candidate)) {
|
|
25802
26003
|
try {
|
|
25803
26004
|
const content = readFileSync17(candidate, "utf-8");
|
|
25804
26005
|
results.push({
|
|
@@ -25944,7 +26145,7 @@ __export(analyze_exports2, {
|
|
|
25944
26145
|
});
|
|
25945
26146
|
import { spawn as spawn7 } from "child_process";
|
|
25946
26147
|
import { createInterface as createInterface7 } from "readline";
|
|
25947
|
-
import { readFileSync as readFileSync18, existsSync as
|
|
26148
|
+
import { readFileSync as readFileSync18, existsSync as existsSync28, readdirSync as readdirSync12 } from "fs";
|
|
25948
26149
|
import { join as join28 } from "path";
|
|
25949
26150
|
import { homedir as homedir8 } from "os";
|
|
25950
26151
|
function parseOptimizeOutput(raw, validAreas) {
|
|
@@ -26080,10 +26281,10 @@ function readIdentityFile3(filename) {
|
|
|
26080
26281
|
return "";
|
|
26081
26282
|
}
|
|
26082
26283
|
}
|
|
26083
|
-
function
|
|
26284
|
+
function loadContextFiles() {
|
|
26084
26285
|
const contextDir = join28(homedir8(), ".cc-claw", "workspace", "context");
|
|
26085
26286
|
const results = [];
|
|
26086
|
-
if (!
|
|
26287
|
+
if (!existsSync28(contextDir)) return results;
|
|
26087
26288
|
try {
|
|
26088
26289
|
for (const entry of readdirSync12(contextDir)) {
|
|
26089
26290
|
if (!entry.endsWith(".md")) continue;
|
|
@@ -26119,7 +26320,7 @@ async function runIdentityAudit(chatId) {
|
|
|
26119
26320
|
const soulMd = readIdentityFile3("SOUL.md");
|
|
26120
26321
|
const userMd = readIdentityFile3("USER.md");
|
|
26121
26322
|
const ccClawMd = readIdentityFile3("CC-CLAW.md");
|
|
26122
|
-
const contextFiles =
|
|
26323
|
+
const contextFiles = loadContextFiles();
|
|
26123
26324
|
const prompt = buildIdentityAuditPrompt(soulMd, userMd, ccClawMd, stats, contextFiles);
|
|
26124
26325
|
const raw = await spawnAnalysis2(adapter, model2, prompt);
|
|
26125
26326
|
const findings = parseOptimizeOutput(raw, VALID_IDENTITY_AREAS);
|
|
@@ -26156,11 +26357,11 @@ async function runSkillAudit(chatId, skillPath) {
|
|
|
26156
26357
|
function listCcClawSkills() {
|
|
26157
26358
|
const skillsDir = join28(homedir8(), ".cc-claw", "workspace", "skills");
|
|
26158
26359
|
const entries = [];
|
|
26159
|
-
if (!
|
|
26360
|
+
if (!existsSync28(skillsDir)) return entries;
|
|
26160
26361
|
try {
|
|
26161
26362
|
for (const dir of readdirSync12(skillsDir)) {
|
|
26162
26363
|
const skillFile = join28(skillsDir, dir, "SKILL.md");
|
|
26163
|
-
if (!
|
|
26364
|
+
if (!existsSync28(skillFile)) continue;
|
|
26164
26365
|
let description = "skill";
|
|
26165
26366
|
try {
|
|
26166
26367
|
const content = readFileSync18(skillFile, "utf-8");
|
|
@@ -26490,7 +26691,7 @@ __export(optimize_exports2, {
|
|
|
26490
26691
|
handleOptimizeCallback: () => handleOptimizeCallback,
|
|
26491
26692
|
handleOptimizeCommand: () => handleOptimizeCommand
|
|
26492
26693
|
});
|
|
26493
|
-
import { readFileSync as readFileSync19, writeFileSync as writeFileSync9, existsSync as
|
|
26694
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync9, existsSync as existsSync29, readdirSync as readdirSync13, unlinkSync as unlinkSync7 } from "fs";
|
|
26494
26695
|
import { join as join29, dirname as dirname5 } from "path";
|
|
26495
26696
|
import { homedir as homedir9 } from "os";
|
|
26496
26697
|
async function handleOptimizeCommand(chatId, channel, _args, messageId) {
|
|
@@ -26715,7 +26916,7 @@ async function applyFinding(chatId, channel, index, messageId) {
|
|
|
26715
26916
|
}
|
|
26716
26917
|
try {
|
|
26717
26918
|
const targetPath = resolveTargetFile(finding.location, session2.result.target);
|
|
26718
|
-
if (!targetPath || !
|
|
26919
|
+
if (!targetPath || !existsSync29(targetPath)) {
|
|
26719
26920
|
session2.skipped.push(index);
|
|
26720
26921
|
await showFinding(chatId, channel, index + 1, effectiveMsgId);
|
|
26721
26922
|
return;
|
|
@@ -29188,73 +29389,6 @@ ${agentLines.join("\n")}`, buttons);
|
|
|
29188
29389
|
const ok = cancelAgent(match.id);
|
|
29189
29390
|
await channel.sendText(chatId, ok ? `Agent ${match.id.slice(0, 8)} cancelled.` : "Could not cancel agent.", { parseMode: "plain" });
|
|
29190
29391
|
}
|
|
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
29392
|
async function handleCronCommand(chatId, commandArgs, msg, channel) {
|
|
29259
29393
|
if (!commandArgs) {
|
|
29260
29394
|
await sendJobsBoard(chatId, channel, 1);
|
|
@@ -29393,6 +29527,514 @@ var init_command_handlers = __esm({
|
|
|
29393
29527
|
}
|
|
29394
29528
|
});
|
|
29395
29529
|
|
|
29530
|
+
// src/mcps/constants.ts
|
|
29531
|
+
function healthIcon(status) {
|
|
29532
|
+
switch (status) {
|
|
29533
|
+
case "healthy":
|
|
29534
|
+
return "\u{1F7E2}";
|
|
29535
|
+
case "unhealthy":
|
|
29536
|
+
return "\u{1F534}";
|
|
29537
|
+
default:
|
|
29538
|
+
return "\u26AA";
|
|
29539
|
+
}
|
|
29540
|
+
}
|
|
29541
|
+
var SYSTEM_MCP_NAMES;
|
|
29542
|
+
var init_constants = __esm({
|
|
29543
|
+
"src/mcps/constants.ts"() {
|
|
29544
|
+
"use strict";
|
|
29545
|
+
SYSTEM_MCP_NAMES = /* @__PURE__ */ new Set(["cc-claw"]);
|
|
29546
|
+
}
|
|
29547
|
+
});
|
|
29548
|
+
|
|
29549
|
+
// src/cli/api-client.ts
|
|
29550
|
+
var api_client_exports = {};
|
|
29551
|
+
__export(api_client_exports, {
|
|
29552
|
+
apiDelete: () => apiDelete,
|
|
29553
|
+
apiGet: () => apiGet,
|
|
29554
|
+
apiPost: () => apiPost,
|
|
29555
|
+
apiPut: () => apiPut,
|
|
29556
|
+
isDaemonRunning: () => isDaemonRunning
|
|
29557
|
+
});
|
|
29558
|
+
import { request as httpRequest, Agent } from "http";
|
|
29559
|
+
function getToken() {
|
|
29560
|
+
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
29561
|
+
return readApiToken();
|
|
29562
|
+
}
|
|
29563
|
+
async function isDaemonRunning() {
|
|
29564
|
+
try {
|
|
29565
|
+
const res = await apiGet("/api/health");
|
|
29566
|
+
return res.ok;
|
|
29567
|
+
} catch {
|
|
29568
|
+
return false;
|
|
29569
|
+
}
|
|
29570
|
+
}
|
|
29571
|
+
function makeRequest(method, path, body, timeout) {
|
|
29572
|
+
const token = getToken();
|
|
29573
|
+
return new Promise((resolve3, reject) => {
|
|
29574
|
+
const url = new URL(path, BASE_URL);
|
|
29575
|
+
const headers = {
|
|
29576
|
+
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
29577
|
+
};
|
|
29578
|
+
if (body !== null) {
|
|
29579
|
+
headers["Content-Type"] = "application/json";
|
|
29580
|
+
headers["Content-Length"] = Buffer.byteLength(body).toString();
|
|
29581
|
+
}
|
|
29582
|
+
const req = httpRequest(url, { method, headers, timeout, agent: keepAliveAgent }, (res) => {
|
|
29583
|
+
const chunks = [];
|
|
29584
|
+
res.on("data", (c) => chunks.push(c));
|
|
29585
|
+
res.on("end", () => {
|
|
29586
|
+
const responseBody = Buffer.concat(chunks).toString();
|
|
29587
|
+
try {
|
|
29588
|
+
const data = JSON.parse(responseBody);
|
|
29589
|
+
resolve3({ ok: res.statusCode === 200, status: res.statusCode ?? 0, data });
|
|
29590
|
+
} catch {
|
|
29591
|
+
resolve3({ ok: false, status: res.statusCode ?? 0, data: responseBody });
|
|
29592
|
+
}
|
|
29593
|
+
});
|
|
29594
|
+
});
|
|
29595
|
+
req.on("error", reject);
|
|
29596
|
+
req.on("timeout", () => {
|
|
29597
|
+
req.destroy();
|
|
29598
|
+
reject(new Error("Request timed out"));
|
|
29599
|
+
});
|
|
29600
|
+
if (body !== null) req.write(body);
|
|
29601
|
+
req.end();
|
|
29602
|
+
});
|
|
29603
|
+
}
|
|
29604
|
+
function apiGet(path) {
|
|
29605
|
+
return makeRequest("GET", path, null, 3e3);
|
|
29606
|
+
}
|
|
29607
|
+
function apiPost(path, body, opts) {
|
|
29608
|
+
return makeRequest("POST", path, JSON.stringify(body), opts?.timeout ?? 3e4);
|
|
29609
|
+
}
|
|
29610
|
+
function apiPut(path, body, opts) {
|
|
29611
|
+
return makeRequest("PUT", path, JSON.stringify(body), opts?.timeout ?? 3e4);
|
|
29612
|
+
}
|
|
29613
|
+
function apiDelete(path) {
|
|
29614
|
+
return makeRequest("DELETE", path, null, 1e4);
|
|
29615
|
+
}
|
|
29616
|
+
var DEFAULT_PORT, API_HOST, BASE_URL, keepAliveAgent;
|
|
29617
|
+
var init_api_client = __esm({
|
|
29618
|
+
"src/cli/api-client.ts"() {
|
|
29619
|
+
"use strict";
|
|
29620
|
+
init_paths();
|
|
29621
|
+
DEFAULT_PORT = parseInt(process.env.DASHBOARD_PORT ?? "3141", 10);
|
|
29622
|
+
API_HOST = process.env.CC_CLAW_API_HOST ?? "127.0.0.1";
|
|
29623
|
+
BASE_URL = `http://${API_HOST}:${DEFAULT_PORT}`;
|
|
29624
|
+
keepAliveAgent = new Agent({ keepAlive: true, maxSockets: 4 });
|
|
29625
|
+
}
|
|
29626
|
+
});
|
|
29627
|
+
|
|
29628
|
+
// src/mcps/import.ts
|
|
29629
|
+
var import_exports = {};
|
|
29630
|
+
__export(import_exports, {
|
|
29631
|
+
discoverFromSource: () => discoverFromSource,
|
|
29632
|
+
mcpImport: () => mcpImport,
|
|
29633
|
+
parseClaudeConfig: () => parseClaudeConfig,
|
|
29634
|
+
parseCursorConfig: () => parseCursorConfig
|
|
29635
|
+
});
|
|
29636
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
29637
|
+
import { join as join31 } from "path";
|
|
29638
|
+
import { homedir as homedir10 } from "os";
|
|
29639
|
+
function parseClaudeConfig(config2) {
|
|
29640
|
+
const servers = config2.mcpServers ?? {};
|
|
29641
|
+
return Object.entries(servers).map(([name, s]) => ({
|
|
29642
|
+
name,
|
|
29643
|
+
command: s.command ?? "",
|
|
29644
|
+
args: Array.isArray(s.args) ? s.args : [],
|
|
29645
|
+
env: s.env && typeof s.env === "object" && !Array.isArray(s.env) ? s.env : {}
|
|
29646
|
+
})).filter((s) => Boolean(s.command));
|
|
29647
|
+
}
|
|
29648
|
+
async function discoverFromSource(source) {
|
|
29649
|
+
switch (source) {
|
|
29650
|
+
case "claude": {
|
|
29651
|
+
const path = join31(homedir10(), ".claude", "settings.json");
|
|
29652
|
+
try {
|
|
29653
|
+
return parseClaudeConfig(JSON.parse(readFileSync20(path, "utf-8")));
|
|
29654
|
+
} catch {
|
|
29655
|
+
warn(`[mcp-import] Could not read ${path}`);
|
|
29656
|
+
return [];
|
|
29657
|
+
}
|
|
29658
|
+
}
|
|
29659
|
+
case "cursor": {
|
|
29660
|
+
const path = join31(homedir10(), ".cursor", "mcp.json");
|
|
29661
|
+
try {
|
|
29662
|
+
return parseCursorConfig(JSON.parse(readFileSync20(path, "utf-8")));
|
|
29663
|
+
} catch {
|
|
29664
|
+
warn(`[mcp-import] Could not read ${path}`);
|
|
29665
|
+
return [];
|
|
29666
|
+
}
|
|
29667
|
+
}
|
|
29668
|
+
case "gemini":
|
|
29669
|
+
case "codex": {
|
|
29670
|
+
try {
|
|
29671
|
+
const { discoverExistingMcps: discoverExistingMcps2 } = await Promise.resolve().then(() => (init_propagate(), propagate_exports));
|
|
29672
|
+
const { getRunner: getRunner2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
29673
|
+
const runner = getRunner2(source);
|
|
29674
|
+
if (!runner) {
|
|
29675
|
+
warn(`[mcp-import] No runner registered for "${source}"`);
|
|
29676
|
+
return [];
|
|
29677
|
+
}
|
|
29678
|
+
const names = await discoverExistingMcps2(runner);
|
|
29679
|
+
return names.map((n) => ({ name: n, command: "", args: [], env: {} }));
|
|
29680
|
+
} catch (err) {
|
|
29681
|
+
warn(`[mcp-import] Failed to discover from ${source}: ${err instanceof Error ? err.message : err}`);
|
|
29682
|
+
return [];
|
|
29683
|
+
}
|
|
29684
|
+
}
|
|
29685
|
+
default:
|
|
29686
|
+
warn(`[mcp-import] Unknown source: ${source}`);
|
|
29687
|
+
return [];
|
|
29688
|
+
}
|
|
29689
|
+
}
|
|
29690
|
+
async function mcpImport(source, _opts) {
|
|
29691
|
+
const servers = await discoverFromSource(source);
|
|
29692
|
+
const readline = await import("readline");
|
|
29693
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
29694
|
+
const ask2 = (q) => new Promise((resolve3) => rl2.question(q, resolve3));
|
|
29695
|
+
try {
|
|
29696
|
+
if (servers.length === 0) {
|
|
29697
|
+
console.log(`No MCP servers found in ${source}.`);
|
|
29698
|
+
return;
|
|
29699
|
+
}
|
|
29700
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
29701
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
29702
|
+
const db3 = openDatabaseReadOnly2();
|
|
29703
|
+
const existing = new Set(listMcpServers2(db3).map((m) => m.name));
|
|
29704
|
+
db3.close();
|
|
29705
|
+
const available = servers.filter((s) => !existing.has(s.name));
|
|
29706
|
+
if (available.length === 0) {
|
|
29707
|
+
console.log(`All MCPs from ${source} are already registered in CC-Claw.`);
|
|
29708
|
+
return;
|
|
29709
|
+
}
|
|
29710
|
+
console.log(`
|
|
29711
|
+
Found ${available.length} new MCP(s) in ${source}:
|
|
29712
|
+
`);
|
|
29713
|
+
available.forEach((s, i) => {
|
|
29714
|
+
const cmd = s.command ? ` (${s.command})` : "";
|
|
29715
|
+
console.log(` ${i + 1}. ${s.name}${cmd}`);
|
|
29716
|
+
});
|
|
29717
|
+
console.log();
|
|
29718
|
+
const answer = await ask2(
|
|
29719
|
+
"Select MCPs to import (comma-separated numbers, or 'all', or Enter to cancel): "
|
|
29720
|
+
);
|
|
29721
|
+
const trimmed = answer.trim().toLowerCase();
|
|
29722
|
+
if (!trimmed || trimmed === "cancel") {
|
|
29723
|
+
console.log("Cancelled.");
|
|
29724
|
+
return;
|
|
29725
|
+
}
|
|
29726
|
+
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);
|
|
29727
|
+
if (indices.length === 0) {
|
|
29728
|
+
console.log("Nothing selected.");
|
|
29729
|
+
return;
|
|
29730
|
+
}
|
|
29731
|
+
const { apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
29732
|
+
let added = 0;
|
|
29733
|
+
for (const i of indices) {
|
|
29734
|
+
const s = available[i];
|
|
29735
|
+
if (!s.command) {
|
|
29736
|
+
console.warn(` \u26A0 Skipping "${s.name}" \u2014 no command available (discovered from ${source} CLI name only)`);
|
|
29737
|
+
continue;
|
|
29738
|
+
}
|
|
29739
|
+
try {
|
|
29740
|
+
await apiPost2("/api/mcps", {
|
|
29741
|
+
name: s.name,
|
|
29742
|
+
transport: "stdio",
|
|
29743
|
+
command: s.command || void 0,
|
|
29744
|
+
args: s.args.length > 0 ? s.args : void 0,
|
|
29745
|
+
env: Object.keys(s.env).length > 0 ? s.env : void 0,
|
|
29746
|
+
enabledByDefault: true
|
|
29747
|
+
});
|
|
29748
|
+
added++;
|
|
29749
|
+
} catch (err) {
|
|
29750
|
+
warn(`[mcp-import] Failed to add ${s.name}: ${err instanceof Error ? err.message : err}`);
|
|
29751
|
+
}
|
|
29752
|
+
}
|
|
29753
|
+
console.log(`
|
|
29754
|
+
\u2713 Imported ${added} MCP(s) from ${source}.`);
|
|
29755
|
+
} finally {
|
|
29756
|
+
rl2.close();
|
|
29757
|
+
}
|
|
29758
|
+
}
|
|
29759
|
+
var parseCursorConfig;
|
|
29760
|
+
var init_import = __esm({
|
|
29761
|
+
"src/mcps/import.ts"() {
|
|
29762
|
+
"use strict";
|
|
29763
|
+
init_log();
|
|
29764
|
+
parseCursorConfig = parseClaudeConfig;
|
|
29765
|
+
}
|
|
29766
|
+
});
|
|
29767
|
+
|
|
29768
|
+
// src/router/mcp.ts
|
|
29769
|
+
var mcp_exports = {};
|
|
29770
|
+
__export(mcp_exports, {
|
|
29771
|
+
handleMcpCallback: () => handleMcpCallback,
|
|
29772
|
+
sendMcpDetail: () => sendMcpDetail,
|
|
29773
|
+
sendMcpImportPicker: () => sendMcpImportPicker,
|
|
29774
|
+
sendMcpImportSelect: () => sendMcpImportSelect,
|
|
29775
|
+
sendMcpKeyboard: () => sendMcpKeyboard
|
|
29776
|
+
});
|
|
29777
|
+
async function sendMcpKeyboard(chatId, channel, messageId) {
|
|
29778
|
+
const db3 = getDb();
|
|
29779
|
+
const mcps = listMcpServers(db3);
|
|
29780
|
+
const lines = ["<b>MCP Servers</b>"];
|
|
29781
|
+
if (mcps.length === 0) {
|
|
29782
|
+
lines.push("\nNo MCPs registered yet. Add one below.");
|
|
29783
|
+
}
|
|
29784
|
+
const buttons = [];
|
|
29785
|
+
for (const mcp2 of mcps) {
|
|
29786
|
+
const isSystem = SYSTEM_MCP_NAMES.has(mcp2.name);
|
|
29787
|
+
const prefix = isSystem ? "\u{1F512}" : healthIcon(mcp2.healthStatus);
|
|
29788
|
+
const label2 = `${prefix} ${mcp2.name}${isSystem ? " (system)" : ""}`;
|
|
29789
|
+
buttons.push([{ label: label2, data: `mcp:detail:${mcp2.name}` }]);
|
|
29790
|
+
}
|
|
29791
|
+
buttons.push([
|
|
29792
|
+
{ label: "\u2795 Add", data: "mcp:add" },
|
|
29793
|
+
{ label: "\u2B07 Import", data: "mcp:import" }
|
|
29794
|
+
]);
|
|
29795
|
+
await sendOrEditKeyboard(chatId, channel, messageId, lines.join("\n"), buttons);
|
|
29796
|
+
}
|
|
29797
|
+
async function sendMcpDetail(chatId, channel, mcpName, messageId) {
|
|
29798
|
+
const db3 = getDb();
|
|
29799
|
+
const mcps = listMcpServers(db3);
|
|
29800
|
+
const mcp2 = mcps.find((m) => m.name === mcpName);
|
|
29801
|
+
if (!mcp2) {
|
|
29802
|
+
await sendOrEditKeyboard(chatId, channel, messageId, `MCP "${mcpName}" not found.`, [
|
|
29803
|
+
[{ label: "\u2190 Back", data: "mcp:back" }]
|
|
29804
|
+
]);
|
|
29805
|
+
return;
|
|
29806
|
+
}
|
|
29807
|
+
const isSystem = SYSTEM_MCP_NAMES.has(mcp2.name);
|
|
29808
|
+
const argsStr = mcp2.args ? (() => {
|
|
29809
|
+
try {
|
|
29810
|
+
return JSON.parse(mcp2.args).join(" ");
|
|
29811
|
+
} catch {
|
|
29812
|
+
return mcp2.args;
|
|
29813
|
+
}
|
|
29814
|
+
})() : "";
|
|
29815
|
+
const lines = [
|
|
29816
|
+
`<b>${mcp2.name}</b>${isSystem ? " \u{1F512}" : ""}`,
|
|
29817
|
+
`Transport: ${mcp2.transport}`,
|
|
29818
|
+
mcp2.command ? `Command: <code>${mcp2.command}${argsStr ? " " + argsStr : ""}</code>` : "",
|
|
29819
|
+
`Health: ${healthIcon(mcp2.healthStatus)} ${mcp2.healthStatus ?? "unknown"}`,
|
|
29820
|
+
`Status: ${mcp2.enabledByDefault ? "enabled" : "disabled"}`
|
|
29821
|
+
].filter(Boolean);
|
|
29822
|
+
const buttons = [];
|
|
29823
|
+
if (!isSystem) {
|
|
29824
|
+
const statusBtn = mcp2.enabledByDefault ? { label: "\u23F8 Disable", data: `mcp:disable:${mcp2.name}`, style: "danger" } : { label: "\u25B6 Enable", data: `mcp:enable:${mcp2.name}`, style: "success" };
|
|
29825
|
+
buttons.push([
|
|
29826
|
+
statusBtn,
|
|
29827
|
+
{ label: "\u{1F5D1} Remove", data: `mcp:remove:${mcp2.name}`, style: "danger" }
|
|
29828
|
+
]);
|
|
29829
|
+
}
|
|
29830
|
+
buttons.push([{ label: "\u2190 Back", data: "mcp:back" }]);
|
|
29831
|
+
await sendOrEditKeyboard(chatId, channel, messageId, lines.join("\n"), buttons);
|
|
29832
|
+
}
|
|
29833
|
+
async function sendMcpImportPicker(chatId, channel, messageId) {
|
|
29834
|
+
const buttons = IMPORT_SOURCES.map((src) => [
|
|
29835
|
+
{
|
|
29836
|
+
label: src.charAt(0).toUpperCase() + src.slice(1),
|
|
29837
|
+
data: `mcp:import:${src}`
|
|
29838
|
+
}
|
|
29839
|
+
]);
|
|
29840
|
+
buttons.push([{ label: "\u2190 Back", data: "mcp:back" }]);
|
|
29841
|
+
await sendOrEditKeyboard(
|
|
29842
|
+
chatId,
|
|
29843
|
+
channel,
|
|
29844
|
+
messageId,
|
|
29845
|
+
"<b>Import MCPs from:</b>",
|
|
29846
|
+
buttons
|
|
29847
|
+
);
|
|
29848
|
+
}
|
|
29849
|
+
async function sendMcpImportSelect(chatId, channel, source, selected, candidates, messageId) {
|
|
29850
|
+
if (candidates.length === 0) {
|
|
29851
|
+
await sendOrEditKeyboard(
|
|
29852
|
+
chatId,
|
|
29853
|
+
channel,
|
|
29854
|
+
messageId,
|
|
29855
|
+
`No new MCPs found in <b>${source}</b>.`,
|
|
29856
|
+
[[{ label: "\u2190 Back", data: "mcp:import" }]]
|
|
29857
|
+
);
|
|
29858
|
+
return;
|
|
29859
|
+
}
|
|
29860
|
+
const buttons = candidates.map((name) => {
|
|
29861
|
+
const checked = selected.has(name);
|
|
29862
|
+
return [
|
|
29863
|
+
{
|
|
29864
|
+
label: `${checked ? "\u2713 " : " "}${name}`,
|
|
29865
|
+
data: `mcp:import:toggle:${source}:${name}`
|
|
29866
|
+
}
|
|
29867
|
+
];
|
|
29868
|
+
});
|
|
29869
|
+
buttons.push([
|
|
29870
|
+
{
|
|
29871
|
+
label: "\u2713 Import Selected",
|
|
29872
|
+
data: `mcp:import:confirm:${source}`,
|
|
29873
|
+
style: "success"
|
|
29874
|
+
},
|
|
29875
|
+
{ label: "\u2190 Back", data: "mcp:import" }
|
|
29876
|
+
]);
|
|
29877
|
+
await sendOrEditKeyboard(
|
|
29878
|
+
chatId,
|
|
29879
|
+
channel,
|
|
29880
|
+
messageId,
|
|
29881
|
+
`<b>Found ${candidates.length} new MCP(s) in ${source}:</b>`,
|
|
29882
|
+
buttons
|
|
29883
|
+
);
|
|
29884
|
+
}
|
|
29885
|
+
async function handleMcpCallback(chatId, data, channel, messageId) {
|
|
29886
|
+
const { apiPost: apiPost2, apiPut: apiPut2, apiDelete: apiDelete2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
29887
|
+
const { pendingMcpImports: pendingMcpImports2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
29888
|
+
const { discoverFromSource: discoverFromSource2 } = await Promise.resolve().then(() => (init_import(), import_exports));
|
|
29889
|
+
if (data === "mcp:back") {
|
|
29890
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29891
|
+
return;
|
|
29892
|
+
}
|
|
29893
|
+
if (data === "mcp:import") {
|
|
29894
|
+
await sendMcpImportPicker(chatId, channel, messageId);
|
|
29895
|
+
return;
|
|
29896
|
+
}
|
|
29897
|
+
if (data.startsWith("mcp:detail:")) {
|
|
29898
|
+
await sendMcpDetail(chatId, channel, data.slice(11), messageId);
|
|
29899
|
+
return;
|
|
29900
|
+
}
|
|
29901
|
+
if (data.startsWith("mcp:disable:")) {
|
|
29902
|
+
const name = data.slice(12);
|
|
29903
|
+
await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: false });
|
|
29904
|
+
await sendMcpDetail(chatId, channel, name, messageId);
|
|
29905
|
+
return;
|
|
29906
|
+
}
|
|
29907
|
+
if (data.startsWith("mcp:enable:")) {
|
|
29908
|
+
const name = data.slice(11);
|
|
29909
|
+
await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: true });
|
|
29910
|
+
await sendMcpDetail(chatId, channel, name, messageId);
|
|
29911
|
+
return;
|
|
29912
|
+
}
|
|
29913
|
+
if (data.startsWith("mcp:remove:")) {
|
|
29914
|
+
const name = data.slice(11);
|
|
29915
|
+
await apiDelete2(`/api/mcps/${encodeURIComponent(name)}`);
|
|
29916
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29917
|
+
return;
|
|
29918
|
+
}
|
|
29919
|
+
if (data.startsWith("mcp:import:") && !data.includes(":toggle:") && !data.includes(":confirm:")) {
|
|
29920
|
+
const source = data.slice(11);
|
|
29921
|
+
if (IMPORT_SOURCES.includes(source)) {
|
|
29922
|
+
let servers;
|
|
29923
|
+
try {
|
|
29924
|
+
servers = await discoverFromSource2(source);
|
|
29925
|
+
} catch (err) {
|
|
29926
|
+
await sendOrEditKeyboard(
|
|
29927
|
+
chatId,
|
|
29928
|
+
channel,
|
|
29929
|
+
messageId,
|
|
29930
|
+
`Failed to discover MCPs from ${source}: ${err instanceof Error ? err.message : String(err)}`,
|
|
29931
|
+
[[{ label: "\u2190 Back", data: "mcp:import" }]]
|
|
29932
|
+
);
|
|
29933
|
+
return;
|
|
29934
|
+
}
|
|
29935
|
+
const db3 = getDb();
|
|
29936
|
+
const existing = new Set(listMcpServers(db3).map((m) => m.name));
|
|
29937
|
+
const candidates = servers.map((s) => s.name).filter((n) => !existing.has(n));
|
|
29938
|
+
pendingMcpImports2.set(chatId, {
|
|
29939
|
+
source,
|
|
29940
|
+
servers,
|
|
29941
|
+
selected: /* @__PURE__ */ new Set(),
|
|
29942
|
+
candidates,
|
|
29943
|
+
startedAt: Date.now()
|
|
29944
|
+
});
|
|
29945
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29946
|
+
await sendMcpImportSelect(
|
|
29947
|
+
chatId,
|
|
29948
|
+
channel,
|
|
29949
|
+
source,
|
|
29950
|
+
state.selected,
|
|
29951
|
+
state.candidates,
|
|
29952
|
+
messageId
|
|
29953
|
+
);
|
|
29954
|
+
}
|
|
29955
|
+
return;
|
|
29956
|
+
}
|
|
29957
|
+
if (data.startsWith("mcp:import:toggle:")) {
|
|
29958
|
+
const rest = data.slice(18);
|
|
29959
|
+
const colonIdx = rest.indexOf(":");
|
|
29960
|
+
if (colonIdx === -1) return;
|
|
29961
|
+
const source = rest.slice(0, colonIdx);
|
|
29962
|
+
const name = rest.slice(colonIdx + 1);
|
|
29963
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29964
|
+
if (!state || state.source !== source) return;
|
|
29965
|
+
if (state.selected.has(name)) {
|
|
29966
|
+
state.selected.delete(name);
|
|
29967
|
+
} else {
|
|
29968
|
+
state.selected.add(name);
|
|
29969
|
+
}
|
|
29970
|
+
await sendMcpImportSelect(
|
|
29971
|
+
chatId,
|
|
29972
|
+
channel,
|
|
29973
|
+
source,
|
|
29974
|
+
state.selected,
|
|
29975
|
+
state.candidates,
|
|
29976
|
+
messageId
|
|
29977
|
+
);
|
|
29978
|
+
return;
|
|
29979
|
+
}
|
|
29980
|
+
if (data.startsWith("mcp:import:confirm:")) {
|
|
29981
|
+
const source = data.slice(19);
|
|
29982
|
+
const state = pendingMcpImports2.get(chatId);
|
|
29983
|
+
pendingMcpImports2.delete(chatId);
|
|
29984
|
+
if (!state || state.selected.size === 0) {
|
|
29985
|
+
await sendMcpKeyboard(chatId, channel, messageId);
|
|
29986
|
+
return;
|
|
29987
|
+
}
|
|
29988
|
+
const serverMap = new Map((state.servers ?? []).map((s) => [s.name, s]));
|
|
29989
|
+
let added = 0;
|
|
29990
|
+
for (const name of state.selected) {
|
|
29991
|
+
const s = serverMap.get(name);
|
|
29992
|
+
if (!s || !s.command) continue;
|
|
29993
|
+
try {
|
|
29994
|
+
await apiPost2("/api/mcps", {
|
|
29995
|
+
name: s.name,
|
|
29996
|
+
transport: "stdio",
|
|
29997
|
+
command: s.command,
|
|
29998
|
+
args: s.args.length > 0 ? s.args : void 0,
|
|
29999
|
+
env: Object.keys(s.env).length > 0 ? s.env : void 0,
|
|
30000
|
+
enabledByDefault: true
|
|
30001
|
+
});
|
|
30002
|
+
added++;
|
|
30003
|
+
} catch {
|
|
30004
|
+
}
|
|
30005
|
+
}
|
|
30006
|
+
await sendOrEditKeyboard(
|
|
30007
|
+
chatId,
|
|
30008
|
+
channel,
|
|
30009
|
+
messageId,
|
|
30010
|
+
`\u2713 Imported ${added} MCP(s) from ${source}.`,
|
|
30011
|
+
[[{ label: "\u2190 Back to MCP List", data: "mcp:back" }]]
|
|
30012
|
+
);
|
|
30013
|
+
return;
|
|
30014
|
+
}
|
|
30015
|
+
if (data === "mcp:add") {
|
|
30016
|
+
await sendOrEditKeyboard(
|
|
30017
|
+
chatId,
|
|
30018
|
+
channel,
|
|
30019
|
+
messageId,
|
|
30020
|
+
"To add an MCP, use the CLI:\n<code>cc-claw mcp add <name> <command> [args...]</code>",
|
|
30021
|
+
[[{ label: "\u2190 Back", data: "mcp:back" }]]
|
|
30022
|
+
);
|
|
30023
|
+
return;
|
|
30024
|
+
}
|
|
30025
|
+
}
|
|
30026
|
+
var IMPORT_SOURCES;
|
|
30027
|
+
var init_mcp = __esm({
|
|
30028
|
+
"src/router/mcp.ts"() {
|
|
30029
|
+
"use strict";
|
|
30030
|
+
init_store5();
|
|
30031
|
+
init_store2();
|
|
30032
|
+
init_constants();
|
|
30033
|
+
init_helpers();
|
|
30034
|
+
IMPORT_SOURCES = ["claude", "gemini", "codex", "cursor"];
|
|
30035
|
+
}
|
|
30036
|
+
});
|
|
30037
|
+
|
|
29396
30038
|
// src/router/commands.ts
|
|
29397
30039
|
async function handleCommand(msg, channel) {
|
|
29398
30040
|
const { chatId, command, commandArgs } = msg;
|
|
@@ -29439,6 +30081,7 @@ async function handleCommand(msg, channel) {
|
|
|
29439
30081
|
case "claude":
|
|
29440
30082
|
case "codex":
|
|
29441
30083
|
case "cursor":
|
|
30084
|
+
case "openrouter":
|
|
29442
30085
|
await handleBackendShortcutCommand(chatId, commandArgs, msg, channel);
|
|
29443
30086
|
break;
|
|
29444
30087
|
case "gemini_accounts":
|
|
@@ -29565,9 +30208,11 @@ async function handleCommand(msg, channel) {
|
|
|
29565
30208
|
await handleRunnersCommand(chatId, commandArgs, msg, channel);
|
|
29566
30209
|
break;
|
|
29567
30210
|
case "mcp":
|
|
29568
|
-
case "mcps":
|
|
29569
|
-
await
|
|
30211
|
+
case "mcps": {
|
|
30212
|
+
const { sendMcpKeyboard: sendMcpKeyboard2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
30213
|
+
await sendMcpKeyboard2(chatId, channel);
|
|
29570
30214
|
break;
|
|
30215
|
+
}
|
|
29571
30216
|
case "cron":
|
|
29572
30217
|
await handleCronCommand(chatId, commandArgs, msg, channel);
|
|
29573
30218
|
break;
|
|
@@ -31383,8 +32028,8 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
31383
32028
|
}
|
|
31384
32029
|
try {
|
|
31385
32030
|
const { readFile: readFileFs } = await import("fs/promises");
|
|
31386
|
-
const { mkdir:
|
|
31387
|
-
const { join:
|
|
32031
|
+
const { mkdir: mkdir5, writeFile: writeFileFs } = await import("fs/promises");
|
|
32032
|
+
const { join: join42 } = await import("path");
|
|
31388
32033
|
const { SKILLS_PATH: SKILLS_PATH2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
31389
32034
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31390
32035
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
@@ -31392,9 +32037,9 @@ ${lines.join("\n")}`, { parseMode: "plain" });
|
|
|
31392
32037
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skillName, source });
|
|
31393
32038
|
const targetStatus = doApprove ? "approved" : "imported";
|
|
31394
32039
|
updated = updateFrontmatter2(updated, { status: targetStatus });
|
|
31395
|
-
const targetDir =
|
|
31396
|
-
await
|
|
31397
|
-
await writeFileFs(
|
|
32040
|
+
const targetDir = join42(SKILLS_PATH2, skillName);
|
|
32041
|
+
await mkdir5(targetDir, { recursive: true });
|
|
32042
|
+
await writeFileFs(join42(targetDir, "SKILL.md"), updated, "utf-8");
|
|
31398
32043
|
invalidateSkillCache2();
|
|
31399
32044
|
if (doApprove) {
|
|
31400
32045
|
await sendOrEditKeyboard(
|
|
@@ -31525,10 +32170,10 @@ ${formatValidationReport2(validation)}` : "\n\n\u2705 Quality checks passed.";
|
|
|
31525
32170
|
return;
|
|
31526
32171
|
}
|
|
31527
32172
|
try {
|
|
31528
|
-
const { readFileSync:
|
|
32173
|
+
const { readFileSync: readFileSync35, writeFileSync: writeFileSync16 } = await import("fs");
|
|
31529
32174
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31530
32175
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
31531
|
-
const raw =
|
|
32176
|
+
const raw = readFileSync35(skill.filePath, "utf-8");
|
|
31532
32177
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skillName, source: "cc-claw" });
|
|
31533
32178
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
31534
32179
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -31578,14 +32223,14 @@ ${stillUnapproved.length} more skill${stillUnapproved.length !== 1 ? "s" : ""} t
|
|
|
31578
32223
|
return;
|
|
31579
32224
|
}
|
|
31580
32225
|
try {
|
|
31581
|
-
const { readFileSync:
|
|
32226
|
+
const { readFileSync: readFileSync35, writeFileSync: writeFileSync16 } = await import("fs");
|
|
31582
32227
|
const { updateFrontmatter: updateFrontmatter2, ensureThreeTierFrontmatter: ensureThreeTierFrontmatter2 } = await Promise.resolve().then(() => (init_frontmatter(), frontmatter_exports));
|
|
31583
32228
|
const { invalidateSkillCache: invalidateSkillCache2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
31584
32229
|
let approvedCount = 0;
|
|
31585
32230
|
const issues = [];
|
|
31586
32231
|
for (const skill of unapproved) {
|
|
31587
32232
|
try {
|
|
31588
|
-
const raw =
|
|
32233
|
+
const raw = readFileSync35(skill.filePath, "utf-8");
|
|
31589
32234
|
let updated = ensureThreeTierFrontmatter2(raw, { name: skill.name, source: "cc-claw" });
|
|
31590
32235
|
updated = updateFrontmatter2(updated, { status: "approved" });
|
|
31591
32236
|
writeFileSync16(skill.filePath, updated, "utf-8");
|
|
@@ -31636,7 +32281,7 @@ ${issues.join("\n")}`;
|
|
|
31636
32281
|
return;
|
|
31637
32282
|
}
|
|
31638
32283
|
const raw = await readFile7(skill.filePath, "utf-8");
|
|
31639
|
-
const skillContent =
|
|
32284
|
+
const skillContent = stripFrontmatter2(raw);
|
|
31640
32285
|
const tags = skill.sources.join(", ");
|
|
31641
32286
|
await channel.sendText(chatId, `Loading skill: ${skillName} [${tags}]...`, { parseMode: "plain" });
|
|
31642
32287
|
const skillModel = resolveModel(chatId);
|
|
@@ -31711,39 +32356,9 @@ Type a keyword below (e.g. gemma, llama, free, claude)`,
|
|
|
31711
32356
|
[[{ label: "\u2190 Back", data: `bconf:model:${backendId}` }]]
|
|
31712
32357
|
);
|
|
31713
32358
|
}
|
|
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
|
-
}
|
|
32359
|
+
} else if (data.startsWith("mcp:")) {
|
|
32360
|
+
const { handleMcpCallback: handleMcpCallback2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
|
|
32361
|
+
await handleMcpCallback2(chatId, data, channel, messageId);
|
|
31747
32362
|
} else if (data.startsWith("apitools:")) {
|
|
31748
32363
|
const { sendApiToolsKeyboard: sendApiToolsKeyboard2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
31749
32364
|
const rest = data.slice(9);
|
|
@@ -31772,6 +32387,10 @@ Type a keyword below (e.g. gemma, llama, free, claude)`,
|
|
|
31772
32387
|
const { removeCliFromWhitelist: removeCliFromWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
31773
32388
|
removeCliFromWhitelist2(chatId, cmd);
|
|
31774
32389
|
await sendApiToolsKeyboard2(chatId, channel, messageId);
|
|
32390
|
+
} else if (rest === "toggle-web-search") {
|
|
32391
|
+
const { toggleApiWebSearchEnabled: toggleApiWebSearchEnabled2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
32392
|
+
toggleApiWebSearchEnabled2(chatId);
|
|
32393
|
+
await sendApiToolsKeyboard2(chatId, channel, messageId);
|
|
31775
32394
|
}
|
|
31776
32395
|
}
|
|
31777
32396
|
}
|
|
@@ -32507,7 +33126,10 @@ Try a different keyword.`,
|
|
|
32507
33126
|
const cmd = text.trim();
|
|
32508
33127
|
if (cmd) {
|
|
32509
33128
|
const { addCliToWhitelist: addCliToWhitelist2 } = await Promise.resolve().then(() => (init_api_whitelist(), api_whitelist_exports));
|
|
32510
|
-
|
|
33129
|
+
const clis = cmd.split(",").map((s) => s.trim()).filter(Boolean);
|
|
33130
|
+
for (const cli of clis) {
|
|
33131
|
+
addCliToWhitelist2(chatId, cli);
|
|
33132
|
+
}
|
|
32511
33133
|
}
|
|
32512
33134
|
const { sendApiToolsKeyboard: sendApiToolsKeyboard2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
32513
33135
|
await sendApiToolsKeyboard2(chatId, channel, msgId);
|
|
@@ -32572,21 +33194,6 @@ Try a different keyword.`,
|
|
|
32572
33194
|
}
|
|
32573
33195
|
effectiveAgentMode = "native";
|
|
32574
33196
|
}
|
|
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
33197
|
const { isSideQuest: hasSqPrefix, cleanText: sqCleanText } = parseSideQuestPrefix(text);
|
|
32591
33198
|
if (hasSqPrefix && isChatBusy(chatId)) {
|
|
32592
33199
|
const sqMsg = { ...msg, text: sqCleanText };
|
|
@@ -33444,7 +34051,7 @@ async function runWithRetry(job, model2, runId, t0) {
|
|
|
33444
34051
|
if (isFallback) {
|
|
33445
34052
|
log(`[scheduler] Job #${job.id} falling back to ${currentBackend}:${currentModel} (fallback ${chainIdx}/${job.fallbacks.length})`);
|
|
33446
34053
|
}
|
|
33447
|
-
for (let attempt = 0; attempt <=
|
|
34054
|
+
for (let attempt = 0; attempt <= MAX_RETRIES3; attempt++) {
|
|
33448
34055
|
try {
|
|
33449
34056
|
const { getVerboseLevel: getVerboseLevel4 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
33450
34057
|
const vLevel = getVerboseLevel4(chatId);
|
|
@@ -33499,11 +34106,11 @@ ${response.text}`;
|
|
|
33499
34106
|
log(`[scheduler] Job #${job.id} backend ${currentBackend} exhausted: ${errMsg}`);
|
|
33500
34107
|
break;
|
|
33501
34108
|
}
|
|
33502
|
-
if (errorClass === "permanent" || attempt >=
|
|
34109
|
+
if (errorClass === "permanent" || attempt >= MAX_RETRIES3) {
|
|
33503
34110
|
throw err;
|
|
33504
34111
|
}
|
|
33505
34112
|
const backoffMs = getBackoffMs(attempt);
|
|
33506
|
-
log(`[scheduler] Job #${job.id} transient error (attempt ${attempt + 1}/${
|
|
34113
|
+
log(`[scheduler] Job #${job.id} transient error (attempt ${attempt + 1}/${MAX_RETRIES3}), retrying in ${backoffMs / 1e3}s: ${errorMessage(err)}`);
|
|
33507
34114
|
await new Promise((r) => setTimeout(r, backoffMs));
|
|
33508
34115
|
}
|
|
33509
34116
|
}
|
|
@@ -33566,7 +34173,7 @@ var init_cron = __esm({
|
|
|
33566
34173
|
});
|
|
33567
34174
|
|
|
33568
34175
|
// src/agents/runners/wrap-backend.ts
|
|
33569
|
-
import { join as
|
|
34176
|
+
import { join as join32 } from "path";
|
|
33570
34177
|
function buildMcpCommands(backendId) {
|
|
33571
34178
|
const exe = backendId === BACKEND.CURSOR ? "agent" : backendId;
|
|
33572
34179
|
return {
|
|
@@ -33663,7 +34270,7 @@ function wrapBackendAdapter(adapter) {
|
|
|
33663
34270
|
const configPath = writeMcpConfigFile(server);
|
|
33664
34271
|
return ["--mcp-config", configPath];
|
|
33665
34272
|
},
|
|
33666
|
-
getSkillPath: () =>
|
|
34273
|
+
getSkillPath: () => join32(SKILLS_PATH, `agent-${adapter.id}.md`)
|
|
33667
34274
|
};
|
|
33668
34275
|
}
|
|
33669
34276
|
var BACKEND_CAPABILITIES;
|
|
@@ -33735,18 +34342,18 @@ var init_wrap_backend = __esm({
|
|
|
33735
34342
|
});
|
|
33736
34343
|
|
|
33737
34344
|
// src/agents/runners/config-loader.ts
|
|
33738
|
-
import { readFileSync as
|
|
33739
|
-
import { join as
|
|
34345
|
+
import { readFileSync as readFileSync21, readdirSync as readdirSync14, existsSync as existsSync30, mkdirSync as mkdirSync10, watchFile, unwatchFile } from "fs";
|
|
34346
|
+
import { join as join33 } from "path";
|
|
33740
34347
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
33741
34348
|
function resolveExecutable2(config2) {
|
|
33742
|
-
if (
|
|
34349
|
+
if (existsSync30(config2.executable)) return config2.executable;
|
|
33743
34350
|
try {
|
|
33744
34351
|
return execFileSync3("which", [config2.executable], { encoding: "utf-8" }).trim();
|
|
33745
34352
|
} catch {
|
|
33746
34353
|
}
|
|
33747
34354
|
for (const fallback of config2.executableFallbacks ?? []) {
|
|
33748
34355
|
const resolved = fallback.replace(/^~/, process.env.HOME ?? "");
|
|
33749
|
-
if (
|
|
34356
|
+
if (existsSync30(resolved)) return resolved;
|
|
33750
34357
|
}
|
|
33751
34358
|
return config2.executable;
|
|
33752
34359
|
}
|
|
@@ -33872,12 +34479,12 @@ function configToRunner(config2) {
|
|
|
33872
34479
|
prepareMcpInjection() {
|
|
33873
34480
|
return [];
|
|
33874
34481
|
},
|
|
33875
|
-
getSkillPath: () =>
|
|
34482
|
+
getSkillPath: () => join33(SKILLS_PATH, `agent-${config2.id}.md`)
|
|
33876
34483
|
};
|
|
33877
34484
|
}
|
|
33878
34485
|
function loadRunnerConfig(filePath) {
|
|
33879
34486
|
try {
|
|
33880
|
-
const content =
|
|
34487
|
+
const content = readFileSync21(filePath, "utf-8");
|
|
33881
34488
|
return JSON.parse(content);
|
|
33882
34489
|
} catch (err) {
|
|
33883
34490
|
warn(`[runners] Failed to load config ${filePath}: ${err}`);
|
|
@@ -33885,14 +34492,14 @@ function loadRunnerConfig(filePath) {
|
|
|
33885
34492
|
}
|
|
33886
34493
|
}
|
|
33887
34494
|
function loadAllRunnerConfigs() {
|
|
33888
|
-
if (!
|
|
34495
|
+
if (!existsSync30(RUNNERS_PATH)) {
|
|
33889
34496
|
mkdirSync10(RUNNERS_PATH, { recursive: true });
|
|
33890
34497
|
return [];
|
|
33891
34498
|
}
|
|
33892
34499
|
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
33893
34500
|
const configs = [];
|
|
33894
34501
|
for (const file of files) {
|
|
33895
|
-
const config2 = loadRunnerConfig(
|
|
34502
|
+
const config2 = loadRunnerConfig(join33(RUNNERS_PATH, file));
|
|
33896
34503
|
if (config2) configs.push(config2);
|
|
33897
34504
|
}
|
|
33898
34505
|
return configs;
|
|
@@ -33913,16 +34520,16 @@ function registerConfigRunners() {
|
|
|
33913
34520
|
return count;
|
|
33914
34521
|
}
|
|
33915
34522
|
function watchRunnerConfigs(onChange) {
|
|
33916
|
-
if (!
|
|
34523
|
+
if (!existsSync30(RUNNERS_PATH)) return;
|
|
33917
34524
|
for (const prev of watchedFiles) {
|
|
33918
|
-
if (!
|
|
34525
|
+
if (!existsSync30(prev)) {
|
|
33919
34526
|
unwatchFile(prev);
|
|
33920
34527
|
watchedFiles.delete(prev);
|
|
33921
34528
|
}
|
|
33922
34529
|
}
|
|
33923
34530
|
const files = readdirSync14(RUNNERS_PATH).filter((f) => f.endsWith(".json"));
|
|
33924
34531
|
for (const file of files) {
|
|
33925
|
-
const fullPath =
|
|
34532
|
+
const fullPath = join33(RUNNERS_PATH, file);
|
|
33926
34533
|
if (watchedFiles.has(fullPath)) continue;
|
|
33927
34534
|
watchedFiles.add(fullPath);
|
|
33928
34535
|
watchFile(fullPath, { interval: 5e3 }, () => {
|
|
@@ -34502,6 +35109,7 @@ var init_telegram2 = __esm({
|
|
|
34502
35109
|
{ command: "codex", description: "Switch to Codex backend" },
|
|
34503
35110
|
{ command: "codex_accounts", description: "Manage Codex credentials & rotation" },
|
|
34504
35111
|
{ command: "cursor", description: "Switch to Cursor backend" },
|
|
35112
|
+
{ command: "openrouter", description: "Switch to OpenRouter backend" },
|
|
34505
35113
|
{ command: "model", description: "Switch model for active backend" },
|
|
34506
35114
|
{ command: "thinking", description: "Adjust thinking/reasoning level" },
|
|
34507
35115
|
{ command: "summarizer", description: "Configure session summarization model" },
|
|
@@ -35220,19 +35828,19 @@ var init_telegram2 = __esm({
|
|
|
35220
35828
|
});
|
|
35221
35829
|
|
|
35222
35830
|
// src/skills/bootstrap.ts
|
|
35223
|
-
import { existsSync as
|
|
35224
|
-
import { readdir as readdir6,
|
|
35225
|
-
import { join as
|
|
35831
|
+
import { existsSync as existsSync31, readFileSync as readFileSync22, writeFileSync as writeFileSync10, copyFileSync as copyFileSync3, readdirSync as readdirSync15 } from "fs";
|
|
35832
|
+
import { readdir as readdir6, copyFile } from "fs/promises";
|
|
35833
|
+
import { join as join34, dirname as dirname6 } from "path";
|
|
35226
35834
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
35227
35835
|
async function copyAgentManifestSkills() {
|
|
35228
|
-
if (!
|
|
35836
|
+
if (!existsSync31(PKG_SKILLS)) return;
|
|
35229
35837
|
try {
|
|
35230
35838
|
const entries = await readdir6(PKG_SKILLS, { withFileTypes: true });
|
|
35231
35839
|
for (const entry of entries) {
|
|
35232
35840
|
if (!entry.isFile() || !entry.name.startsWith("agent-") || !entry.name.endsWith(".md")) continue;
|
|
35233
|
-
const src =
|
|
35234
|
-
const dest =
|
|
35235
|
-
if (
|
|
35841
|
+
const src = join34(PKG_SKILLS, entry.name);
|
|
35842
|
+
const dest = join34(SKILLS_PATH, entry.name);
|
|
35843
|
+
if (existsSync31(dest)) continue;
|
|
35236
35844
|
await copyFile(src, dest);
|
|
35237
35845
|
log(`[skills] Bootstrapped ${entry.name} to ${SKILLS_PATH}`);
|
|
35238
35846
|
}
|
|
@@ -35243,73 +35851,11 @@ async function copyAgentManifestSkills() {
|
|
|
35243
35851
|
async function bootstrapSkills() {
|
|
35244
35852
|
await copyAgentManifestSkills();
|
|
35245
35853
|
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
35854
|
}
|
|
35309
35855
|
function migrateSkillsToThreeTier() {
|
|
35310
|
-
const markerPath =
|
|
35311
|
-
if (
|
|
35312
|
-
if (!
|
|
35856
|
+
const markerPath = join34(SKILLS_PATH, MIGRATION_MARKER);
|
|
35857
|
+
if (existsSync31(markerPath)) return;
|
|
35858
|
+
if (!existsSync31(SKILLS_PATH)) return;
|
|
35313
35859
|
let entries;
|
|
35314
35860
|
try {
|
|
35315
35861
|
entries = readdirSync15(SKILLS_PATH, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name);
|
|
@@ -35323,15 +35869,15 @@ function migrateSkillsToThreeTier() {
|
|
|
35323
35869
|
for (const dirName of entries) {
|
|
35324
35870
|
let skillPath;
|
|
35325
35871
|
for (const candidate of SKILL_FILE_CANDIDATES2) {
|
|
35326
|
-
const p =
|
|
35327
|
-
if (
|
|
35872
|
+
const p = join34(SKILLS_PATH, dirName, candidate);
|
|
35873
|
+
if (existsSync31(p)) {
|
|
35328
35874
|
skillPath = p;
|
|
35329
35875
|
break;
|
|
35330
35876
|
}
|
|
35331
35877
|
}
|
|
35332
35878
|
if (!skillPath) continue;
|
|
35333
35879
|
try {
|
|
35334
|
-
const raw =
|
|
35880
|
+
const raw = readFileSync22(skillPath, "utf-8");
|
|
35335
35881
|
const fmMatch = raw.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
35336
35882
|
if (fmMatch) {
|
|
35337
35883
|
const fm = fmMatch[1];
|
|
@@ -35368,20 +35914,16 @@ function migrateSkillsToThreeTier() {
|
|
|
35368
35914
|
log(`[skills] Three-tier migration complete: ${migrated} migrated, ${skipped} already current, ${failed} failed`);
|
|
35369
35915
|
}
|
|
35370
35916
|
}
|
|
35371
|
-
var
|
|
35917
|
+
var PKG_ROOT, PKG_SKILLS, MIGRATION_MARKER, SKILL_FILE_CANDIDATES2;
|
|
35372
35918
|
var init_bootstrap = __esm({
|
|
35373
35919
|
"src/skills/bootstrap.ts"() {
|
|
35374
35920
|
"use strict";
|
|
35375
35921
|
init_paths();
|
|
35376
|
-
init_install();
|
|
35377
35922
|
init_frontmatter();
|
|
35378
35923
|
init_discover();
|
|
35379
35924
|
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");
|
|
35925
|
+
PKG_ROOT = join34(dirname6(fileURLToPath2(import.meta.url)), "..", "..");
|
|
35926
|
+
PKG_SKILLS = join34(PKG_ROOT, "skills");
|
|
35385
35927
|
MIGRATION_MARKER = ".three-tier-migrated";
|
|
35386
35928
|
SKILL_FILE_CANDIDATES2 = ["SKILL.md", "skill.md"];
|
|
35387
35929
|
}
|
|
@@ -35453,19 +35995,19 @@ var init_migrate_embeddings = __esm({
|
|
|
35453
35995
|
// src/mcps/bootstrap.ts
|
|
35454
35996
|
function bootstrapBuiltinMcps(db3) {
|
|
35455
35997
|
let seeded = 0;
|
|
35456
|
-
for (const
|
|
35457
|
-
const existing = getMcpServer(db3,
|
|
35998
|
+
for (const mcp2 of BUILTIN_MCPS) {
|
|
35999
|
+
const existing = getMcpServer(db3, mcp2.name);
|
|
35458
36000
|
if (existing) continue;
|
|
35459
36001
|
addMcpServer(db3, {
|
|
35460
|
-
name:
|
|
35461
|
-
transport:
|
|
35462
|
-
command:
|
|
35463
|
-
args:
|
|
35464
|
-
description:
|
|
35465
|
-
enabledByDefault:
|
|
36002
|
+
name: mcp2.name,
|
|
36003
|
+
transport: mcp2.transport,
|
|
36004
|
+
command: mcp2.command,
|
|
36005
|
+
args: mcp2.args,
|
|
36006
|
+
description: mcp2.description,
|
|
36007
|
+
enabledByDefault: mcp2.enabledByDefault
|
|
35466
36008
|
});
|
|
35467
36009
|
seeded++;
|
|
35468
|
-
log(`[mcps] Seeded built-in MCP: ${
|
|
36010
|
+
log(`[mcps] Seeded built-in MCP: ${mcp2.name}`);
|
|
35469
36011
|
}
|
|
35470
36012
|
if (seeded > 0) {
|
|
35471
36013
|
log(`[mcps] Bootstrapped ${seeded} built-in MCP server(s)`);
|
|
@@ -35496,13 +36038,13 @@ __export(ai_skill_exports, {
|
|
|
35496
36038
|
generateAiSkill: () => generateAiSkill,
|
|
35497
36039
|
installAiSkill: () => installAiSkill
|
|
35498
36040
|
});
|
|
35499
|
-
import { existsSync as
|
|
35500
|
-
import { join as
|
|
35501
|
-
import { homedir as
|
|
36041
|
+
import { existsSync as existsSync32, writeFileSync as writeFileSync11, mkdirSync as mkdirSync11 } from "fs";
|
|
36042
|
+
import { join as join35 } from "path";
|
|
36043
|
+
import { homedir as homedir11 } from "os";
|
|
35502
36044
|
function generateAiSkill() {
|
|
35503
36045
|
const version = VERSION;
|
|
35504
36046
|
let systemState = "";
|
|
35505
|
-
if (
|
|
36047
|
+
if (existsSync32(DB_PATH)) {
|
|
35506
36048
|
try {
|
|
35507
36049
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = (init_store5(), __toCommonJS(store_exports5));
|
|
35508
36050
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -35944,8 +36486,8 @@ function installAiSkill() {
|
|
|
35944
36486
|
const failed = [];
|
|
35945
36487
|
for (const [backend2, dirs] of Object.entries(BACKEND_SKILL_DIRS2)) {
|
|
35946
36488
|
for (const dir of dirs) {
|
|
35947
|
-
const skillDir =
|
|
35948
|
-
const skillPath =
|
|
36489
|
+
const skillDir = join35(dir, "cc-claw-cli");
|
|
36490
|
+
const skillPath = join35(skillDir, "SKILL.md");
|
|
35949
36491
|
try {
|
|
35950
36492
|
mkdirSync11(skillDir, { recursive: true });
|
|
35951
36493
|
writeFileSync11(skillPath, skill, "utf-8");
|
|
@@ -35964,11 +36506,11 @@ var init_ai_skill = __esm({
|
|
|
35964
36506
|
init_paths();
|
|
35965
36507
|
init_version();
|
|
35966
36508
|
BACKEND_SKILL_DIRS2 = {
|
|
35967
|
-
"cc-claw": [
|
|
35968
|
-
claude: [
|
|
35969
|
-
gemini: [
|
|
35970
|
-
codex: [
|
|
35971
|
-
cursor: [
|
|
36509
|
+
"cc-claw": [join35(homedir11(), ".cc-claw", "workspace", "skills")],
|
|
36510
|
+
claude: [join35(homedir11(), ".claude", "skills")],
|
|
36511
|
+
gemini: [join35(homedir11(), ".gemini", "skills")],
|
|
36512
|
+
codex: [join35(homedir11(), ".agents", "skills")],
|
|
36513
|
+
cursor: [join35(homedir11(), ".cursor", "skills"), join35(homedir11(), ".cursor", "skills-cursor")]
|
|
35972
36514
|
};
|
|
35973
36515
|
}
|
|
35974
36516
|
});
|
|
@@ -35978,21 +36520,21 @@ var index_exports = {};
|
|
|
35978
36520
|
__export(index_exports, {
|
|
35979
36521
|
main: () => main
|
|
35980
36522
|
});
|
|
35981
|
-
import { mkdirSync as mkdirSync12, existsSync as
|
|
35982
|
-
import { join as
|
|
36523
|
+
import { mkdirSync as mkdirSync12, existsSync as existsSync33, renameSync as renameSync2, statSync as statSync9, readFileSync as readFileSync24 } from "fs";
|
|
36524
|
+
import { join as join36 } from "path";
|
|
35983
36525
|
import dotenv from "dotenv";
|
|
35984
36526
|
function migrateLayout() {
|
|
35985
36527
|
const moves = [
|
|
35986
|
-
[
|
|
35987
|
-
[
|
|
35988
|
-
[
|
|
35989
|
-
[
|
|
35990
|
-
[
|
|
35991
|
-
[
|
|
35992
|
-
[
|
|
36528
|
+
[join36(CC_CLAW_HOME, "cc-claw.db"), join36(DATA_PATH, "cc-claw.db")],
|
|
36529
|
+
[join36(CC_CLAW_HOME, "cc-claw.db-shm"), join36(DATA_PATH, "cc-claw.db-shm")],
|
|
36530
|
+
[join36(CC_CLAW_HOME, "cc-claw.db-wal"), join36(DATA_PATH, "cc-claw.db-wal")],
|
|
36531
|
+
[join36(CC_CLAW_HOME, "cc-claw.log"), join36(LOGS_PATH, "cc-claw.log")],
|
|
36532
|
+
[join36(CC_CLAW_HOME, "cc-claw.log.1"), join36(LOGS_PATH, "cc-claw.log.1")],
|
|
36533
|
+
[join36(CC_CLAW_HOME, "cc-claw.error.log"), join36(LOGS_PATH, "cc-claw.error.log")],
|
|
36534
|
+
[join36(CC_CLAW_HOME, "cc-claw.error.log.1"), join36(LOGS_PATH, "cc-claw.error.log.1")]
|
|
35993
36535
|
];
|
|
35994
36536
|
for (const [from, to] of moves) {
|
|
35995
|
-
if (
|
|
36537
|
+
if (existsSync33(from) && !existsSync33(to)) {
|
|
35996
36538
|
try {
|
|
35997
36539
|
renameSync2(from, to);
|
|
35998
36540
|
} catch {
|
|
@@ -36021,7 +36563,7 @@ async function main() {
|
|
|
36021
36563
|
let version = "unknown";
|
|
36022
36564
|
try {
|
|
36023
36565
|
const pkgPath = new URL("../package.json", import.meta.url);
|
|
36024
|
-
version = JSON.parse(
|
|
36566
|
+
version = JSON.parse(readFileSync24(pkgPath, "utf-8")).version;
|
|
36025
36567
|
} catch {
|
|
36026
36568
|
}
|
|
36027
36569
|
log(`[cc-claw] Starting v${version}`);
|
|
@@ -36196,10 +36738,10 @@ ${lines.join("\n")}`;
|
|
|
36196
36738
|
try {
|
|
36197
36739
|
const { generateAiSkill: generateAiSkill2 } = await Promise.resolve().then(() => (init_ai_skill(), ai_skill_exports));
|
|
36198
36740
|
const { writeFileSync: writeFileSync16, mkdirSync: mkdirSync19 } = await import("fs");
|
|
36199
|
-
const { join:
|
|
36200
|
-
const skillDir =
|
|
36741
|
+
const { join: join42 } = await import("path");
|
|
36742
|
+
const skillDir = join42(SKILLS_PATH, "cc-claw-cli");
|
|
36201
36743
|
mkdirSync19(skillDir, { recursive: true });
|
|
36202
|
-
writeFileSync16(
|
|
36744
|
+
writeFileSync16(join42(skillDir, "SKILL.md"), generateAiSkill2(), "utf-8");
|
|
36203
36745
|
log("[cc-claw] AI skill updated");
|
|
36204
36746
|
} catch {
|
|
36205
36747
|
}
|
|
@@ -36237,6 +36779,8 @@ ${lines.join("\n")}`;
|
|
|
36237
36779
|
const { stopAllActiveAgents: stopAllActiveAgents2, stopStaleChatSweep: stopStaleChatSweep2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
36238
36780
|
stopAllActiveAgents2();
|
|
36239
36781
|
stopStaleChatSweep2();
|
|
36782
|
+
const { shutdownMcpPool: shutdownMcpPool2 } = await Promise.resolve().then(() => (init_pool(), pool_exports));
|
|
36783
|
+
await shutdownMcpPool2();
|
|
36240
36784
|
stopAllHeartbeats();
|
|
36241
36785
|
stopHealthMonitor3();
|
|
36242
36786
|
stopMonitor();
|
|
@@ -36299,10 +36843,10 @@ var init_index = __esm({
|
|
|
36299
36843
|
init_health3();
|
|
36300
36844
|
init_image_gen();
|
|
36301
36845
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SESSION_LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
36302
|
-
if (!
|
|
36846
|
+
if (!existsSync33(dir)) mkdirSync12(dir, { recursive: true });
|
|
36303
36847
|
}
|
|
36304
36848
|
migrateLayout();
|
|
36305
|
-
if (
|
|
36849
|
+
if (existsSync33(ENV_PATH)) {
|
|
36306
36850
|
dotenv.config({ path: ENV_PATH });
|
|
36307
36851
|
} else {
|
|
36308
36852
|
console.error(`[cc-claw] Config not found at ${ENV_PATH} \u2014 run 'cc-claw setup' first`);
|
|
@@ -36316,104 +36860,6 @@ var init_index = __esm({
|
|
|
36316
36860
|
}
|
|
36317
36861
|
});
|
|
36318
36862
|
|
|
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
36863
|
// src/service.ts
|
|
36418
36864
|
var service_exports2 = {};
|
|
36419
36865
|
__export(service_exports2, {
|
|
@@ -36421,10 +36867,10 @@ __export(service_exports2, {
|
|
|
36421
36867
|
serviceStatus: () => serviceStatus,
|
|
36422
36868
|
uninstallService: () => uninstallService
|
|
36423
36869
|
});
|
|
36424
|
-
import { existsSync as
|
|
36870
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as writeFileSync12, unlinkSync as unlinkSync8 } from "fs";
|
|
36425
36871
|
import { execFileSync as execFileSync4, execSync as execSync5 } from "child_process";
|
|
36426
|
-
import { homedir as
|
|
36427
|
-
import { join as
|
|
36872
|
+
import { homedir as homedir12, platform } from "os";
|
|
36873
|
+
import { join as join37, dirname as dirname7 } from "path";
|
|
36428
36874
|
function xmlEscape(s) {
|
|
36429
36875
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
36430
36876
|
}
|
|
@@ -36433,23 +36879,23 @@ function resolveExecutable3(name) {
|
|
|
36433
36879
|
return execFileSync4("which", [name], { encoding: "utf-8" }).trim();
|
|
36434
36880
|
} catch {
|
|
36435
36881
|
const fallback = process.argv[1];
|
|
36436
|
-
if (fallback &&
|
|
36882
|
+
if (fallback && existsSync34(fallback)) return fallback;
|
|
36437
36883
|
throw new Error(`Cannot find '${name}' executable. Install globally: npm install -g cc-claw`);
|
|
36438
36884
|
}
|
|
36439
36885
|
}
|
|
36440
36886
|
function getPathDirs() {
|
|
36441
36887
|
const nodeBin = dirname7(process.execPath);
|
|
36442
|
-
const home =
|
|
36888
|
+
const home = homedir12();
|
|
36443
36889
|
const dirs = /* @__PURE__ */ new Set([
|
|
36444
36890
|
nodeBin,
|
|
36445
|
-
|
|
36891
|
+
join37(home, ".local", "bin"),
|
|
36446
36892
|
"/usr/local/bin",
|
|
36447
36893
|
"/usr/bin",
|
|
36448
36894
|
"/bin"
|
|
36449
36895
|
]);
|
|
36450
36896
|
try {
|
|
36451
36897
|
const prefix = execSync5("npm config get prefix", { encoding: "utf-8" }).trim();
|
|
36452
|
-
if (prefix) dirs.add(
|
|
36898
|
+
if (prefix) dirs.add(join37(prefix, "bin"));
|
|
36453
36899
|
} catch {
|
|
36454
36900
|
}
|
|
36455
36901
|
return [...dirs].join(":");
|
|
@@ -36457,7 +36903,7 @@ function getPathDirs() {
|
|
|
36457
36903
|
function generatePlist() {
|
|
36458
36904
|
const ccClawBin = resolveExecutable3("cc-claw");
|
|
36459
36905
|
const pathDirs = getPathDirs();
|
|
36460
|
-
const home =
|
|
36906
|
+
const home = homedir12();
|
|
36461
36907
|
const safeBin = xmlEscape(ccClawBin);
|
|
36462
36908
|
const safePaths = xmlEscape(pathDirs);
|
|
36463
36909
|
const safeHome = xmlEscape(home);
|
|
@@ -36508,9 +36954,9 @@ function generatePlist() {
|
|
|
36508
36954
|
}
|
|
36509
36955
|
function installMacOS() {
|
|
36510
36956
|
const agentsDir = dirname7(PLIST_PATH);
|
|
36511
|
-
if (!
|
|
36512
|
-
if (!
|
|
36513
|
-
if (
|
|
36957
|
+
if (!existsSync34(agentsDir)) mkdirSync13(agentsDir, { recursive: true });
|
|
36958
|
+
if (!existsSync34(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
36959
|
+
if (existsSync34(PLIST_PATH)) {
|
|
36514
36960
|
try {
|
|
36515
36961
|
execFileSync4("launchctl", ["unload", PLIST_PATH]);
|
|
36516
36962
|
} catch {
|
|
@@ -36522,7 +36968,7 @@ function installMacOS() {
|
|
|
36522
36968
|
console.log(" Service loaded and starting.");
|
|
36523
36969
|
}
|
|
36524
36970
|
function uninstallMacOS() {
|
|
36525
|
-
if (!
|
|
36971
|
+
if (!existsSync34(PLIST_PATH)) {
|
|
36526
36972
|
console.log(" No service found to uninstall.");
|
|
36527
36973
|
return;
|
|
36528
36974
|
}
|
|
@@ -36590,15 +37036,15 @@ Restart=on-failure
|
|
|
36590
37036
|
RestartSec=10
|
|
36591
37037
|
WorkingDirectory=${CC_CLAW_HOME}
|
|
36592
37038
|
Environment=PATH=${pathDirs}
|
|
36593
|
-
Environment=HOME=${
|
|
37039
|
+
Environment=HOME=${homedir12()}
|
|
36594
37040
|
|
|
36595
37041
|
[Install]
|
|
36596
37042
|
WantedBy=default.target
|
|
36597
37043
|
`;
|
|
36598
37044
|
}
|
|
36599
37045
|
function installLinux() {
|
|
36600
|
-
if (!
|
|
36601
|
-
if (!
|
|
37046
|
+
if (!existsSync34(SYSTEMD_DIR)) mkdirSync13(SYSTEMD_DIR, { recursive: true });
|
|
37047
|
+
if (!existsSync34(LOGS_PATH)) mkdirSync13(LOGS_PATH, { recursive: true });
|
|
36602
37048
|
writeFileSync12(UNIT_PATH, generateUnit());
|
|
36603
37049
|
console.log(` Installed: ${UNIT_PATH}`);
|
|
36604
37050
|
execFileSync4("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -36607,7 +37053,7 @@ function installLinux() {
|
|
|
36607
37053
|
console.log(" Service enabled and started.");
|
|
36608
37054
|
}
|
|
36609
37055
|
function uninstallLinux() {
|
|
36610
|
-
if (!
|
|
37056
|
+
if (!existsSync34(UNIT_PATH)) {
|
|
36611
37057
|
console.log(" No service found to uninstall.");
|
|
36612
37058
|
return;
|
|
36613
37059
|
}
|
|
@@ -36632,7 +37078,7 @@ function statusLinux() {
|
|
|
36632
37078
|
}
|
|
36633
37079
|
}
|
|
36634
37080
|
function installService() {
|
|
36635
|
-
if (!
|
|
37081
|
+
if (!existsSync34(join37(CC_CLAW_HOME, ".env"))) {
|
|
36636
37082
|
console.error(` Config not found at ${CC_CLAW_HOME}/.env`);
|
|
36637
37083
|
console.error(" Run 'cc-claw setup' before installing the service.");
|
|
36638
37084
|
process.exitCode = 1;
|
|
@@ -36661,9 +37107,9 @@ var init_service2 = __esm({
|
|
|
36661
37107
|
"use strict";
|
|
36662
37108
|
init_paths();
|
|
36663
37109
|
PLIST_LABEL = "com.cc-claw";
|
|
36664
|
-
PLIST_PATH =
|
|
36665
|
-
SYSTEMD_DIR =
|
|
36666
|
-
UNIT_PATH =
|
|
37110
|
+
PLIST_PATH = join37(homedir12(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
37111
|
+
SYSTEMD_DIR = join37(homedir12(), ".config", "systemd", "user");
|
|
37112
|
+
UNIT_PATH = join37(SYSTEMD_DIR, "cc-claw.service");
|
|
36667
37113
|
}
|
|
36668
37114
|
});
|
|
36669
37115
|
|
|
@@ -36830,13 +37276,13 @@ var init_daemon = __esm({
|
|
|
36830
37276
|
});
|
|
36831
37277
|
|
|
36832
37278
|
// src/cli/resolve-chat.ts
|
|
36833
|
-
import { readFileSync as
|
|
37279
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
36834
37280
|
function resolveChatId2(globalOpts) {
|
|
36835
37281
|
const explicit = globalOpts.chat;
|
|
36836
37282
|
if (explicit) return explicit;
|
|
36837
37283
|
if (_cachedDefault) return _cachedDefault;
|
|
36838
37284
|
try {
|
|
36839
|
-
const content =
|
|
37285
|
+
const content = readFileSync26(ENV_PATH, "utf-8");
|
|
36840
37286
|
const match = content.match(/^ALLOWED_CHAT_ID=(.+)$/m);
|
|
36841
37287
|
if (match) {
|
|
36842
37288
|
_cachedDefault = match[1].split(",")[0].trim();
|
|
@@ -36860,7 +37306,7 @@ var status_exports = {};
|
|
|
36860
37306
|
__export(status_exports, {
|
|
36861
37307
|
statusCommand: () => statusCommand
|
|
36862
37308
|
});
|
|
36863
|
-
import { existsSync as
|
|
37309
|
+
import { existsSync as existsSync35, statSync as statSync10 } from "fs";
|
|
36864
37310
|
async function statusCommand(globalOpts, localOpts) {
|
|
36865
37311
|
try {
|
|
36866
37312
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
@@ -36900,7 +37346,7 @@ async function statusCommand(globalOpts, localOpts) {
|
|
|
36900
37346
|
const cwdRow = readDb.prepare("SELECT cwd FROM chat_cwd WHERE chat_id = ?").get(chatId);
|
|
36901
37347
|
const voiceRow = readDb.prepare("SELECT enabled FROM chat_voice WHERE chat_id = ?").get(chatId);
|
|
36902
37348
|
const usageRow = readDb.prepare("SELECT * FROM chat_usage WHERE chat_id = ?").get(chatId);
|
|
36903
|
-
const dbStat =
|
|
37349
|
+
const dbStat = existsSync35(DB_PATH) ? statSync10(DB_PATH) : null;
|
|
36904
37350
|
let daemonRunning = false;
|
|
36905
37351
|
let daemonInfo = {};
|
|
36906
37352
|
try {
|
|
@@ -37012,13 +37458,13 @@ __export(doctor_exports, {
|
|
|
37012
37458
|
doctorCommand: () => doctorCommand,
|
|
37013
37459
|
doctorErrors: () => doctorErrors
|
|
37014
37460
|
});
|
|
37015
|
-
import { existsSync as
|
|
37461
|
+
import { existsSync as existsSync36, accessSync, constants } from "fs";
|
|
37016
37462
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
37017
37463
|
async function doctorCommand(globalOpts, localOpts) {
|
|
37018
37464
|
const checks = [];
|
|
37019
37465
|
const dbChecks = checkDatabase();
|
|
37020
37466
|
checks.push(...dbChecks);
|
|
37021
|
-
if (
|
|
37467
|
+
if (existsSync36(DB_PATH)) {
|
|
37022
37468
|
try {
|
|
37023
37469
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
37024
37470
|
const readDb = openDatabaseReadOnly2();
|
|
@@ -37044,7 +37490,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37044
37490
|
checks.push({ name: "Database health", status: "error", message: err.message });
|
|
37045
37491
|
}
|
|
37046
37492
|
}
|
|
37047
|
-
if (
|
|
37493
|
+
if (existsSync36(ENV_PATH)) {
|
|
37048
37494
|
checks.push({ name: "Environment", status: "ok", message: `.env loaded` });
|
|
37049
37495
|
} else {
|
|
37050
37496
|
checks.push({ name: "Environment", status: "error", message: "No .env found", fix: "cc-claw setup" });
|
|
@@ -37087,7 +37533,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37087
37533
|
} catch {
|
|
37088
37534
|
}
|
|
37089
37535
|
const tokenPath = `${DATA_PATH}/api-token`;
|
|
37090
|
-
if (
|
|
37536
|
+
if (existsSync36(tokenPath)) {
|
|
37091
37537
|
try {
|
|
37092
37538
|
accessSync(tokenPath, constants.R_OK);
|
|
37093
37539
|
checks.push({ name: "API token", status: "ok", message: "token file readable" });
|
|
@@ -37156,7 +37602,7 @@ async function doctorCommand(globalOpts, localOpts) {
|
|
|
37156
37602
|
const errorChecks = checks.filter(
|
|
37157
37603
|
(c) => ["Rate limits", "Content silence", "Spawn timeouts", "Other errors"].includes(c.name) && c.status !== "ok"
|
|
37158
37604
|
);
|
|
37159
|
-
if (errorChecks.length > 0 &&
|
|
37605
|
+
if (errorChecks.length > 0 && existsSync36(ERROR_LOG_PATH)) {
|
|
37160
37606
|
try {
|
|
37161
37607
|
const { writeFileSync: writeFileSync16 } = await import("fs");
|
|
37162
37608
|
writeFileSync16(ERROR_LOG_PATH, "");
|
|
@@ -37285,15 +37731,15 @@ var logs_exports = {};
|
|
|
37285
37731
|
__export(logs_exports, {
|
|
37286
37732
|
logsCommand: () => logsCommand
|
|
37287
37733
|
});
|
|
37288
|
-
import { existsSync as
|
|
37734
|
+
import { existsSync as existsSync37, readFileSync as readFileSync28, watchFile as watchFile2, unwatchFile as unwatchFile2 } from "fs";
|
|
37289
37735
|
async function logsCommand(opts) {
|
|
37290
37736
|
const logFile = opts.error ? ERROR_LOG_PATH : LOG_PATH;
|
|
37291
|
-
if (!
|
|
37737
|
+
if (!existsSync37(logFile)) {
|
|
37292
37738
|
outputError("LOG_NOT_FOUND", `Log file not found: ${logFile}`);
|
|
37293
37739
|
process.exit(1);
|
|
37294
37740
|
}
|
|
37295
37741
|
const maxLines = parseInt(opts.lines ?? "100", 10);
|
|
37296
|
-
const content =
|
|
37742
|
+
const content = readFileSync28(logFile, "utf-8");
|
|
37297
37743
|
const allLines = content.split("\n");
|
|
37298
37744
|
const tailLines = allLines.slice(-maxLines);
|
|
37299
37745
|
console.log(muted(` \u2500\u2500 ${logFile} (last ${tailLines.length} lines) \u2500\u2500`));
|
|
@@ -37303,7 +37749,7 @@ async function logsCommand(opts) {
|
|
|
37303
37749
|
let lastLength = content.length;
|
|
37304
37750
|
watchFile2(logFile, { interval: 500 }, () => {
|
|
37305
37751
|
try {
|
|
37306
|
-
const newContent =
|
|
37752
|
+
const newContent = readFileSync28(logFile, "utf-8");
|
|
37307
37753
|
if (newContent.length > lastLength) {
|
|
37308
37754
|
const newPart = newContent.slice(lastLength);
|
|
37309
37755
|
process.stdout.write(newPart);
|
|
@@ -37335,7 +37781,7 @@ __export(session_logs_exports, {
|
|
|
37335
37781
|
sessionLogsList: () => sessionLogsList,
|
|
37336
37782
|
sessionLogsTail: () => sessionLogsTail
|
|
37337
37783
|
});
|
|
37338
|
-
import { readFileSync as
|
|
37784
|
+
import { readFileSync as readFileSync29, watchFile as watchFile3, unwatchFile as unwatchFile3 } from "fs";
|
|
37339
37785
|
async function sessionLogsList(opts) {
|
|
37340
37786
|
const logs = listSessionLogs();
|
|
37341
37787
|
if (logs.length === 0) {
|
|
@@ -37392,12 +37838,12 @@ async function sessionLogsTail(opts) {
|
|
|
37392
37838
|
console.log(muted("\n Following... (Ctrl+C to stop)\n"));
|
|
37393
37839
|
let lastLength = 0;
|
|
37394
37840
|
try {
|
|
37395
|
-
lastLength =
|
|
37841
|
+
lastLength = readFileSync29(targetPath, "utf-8").length;
|
|
37396
37842
|
} catch {
|
|
37397
37843
|
}
|
|
37398
37844
|
watchFile3(targetPath, { interval: 500 }, () => {
|
|
37399
37845
|
try {
|
|
37400
|
-
const content =
|
|
37846
|
+
const content = readFileSync29(targetPath, "utf-8");
|
|
37401
37847
|
if (content.length > lastLength) {
|
|
37402
37848
|
process.stdout.write(content.slice(lastLength));
|
|
37403
37849
|
lastLength = content.length;
|
|
@@ -37441,11 +37887,11 @@ __export(gemini_exports, {
|
|
|
37441
37887
|
geminiReorder: () => geminiReorder,
|
|
37442
37888
|
geminiRotation: () => geminiRotation
|
|
37443
37889
|
});
|
|
37444
|
-
import { existsSync as
|
|
37445
|
-
import { join as
|
|
37890
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync14, writeFileSync as writeFileSync13, readFileSync as readFileSync30, chmodSync } from "fs";
|
|
37891
|
+
import { join as join38 } from "path";
|
|
37446
37892
|
import { createInterface as createInterface8 } from "readline";
|
|
37447
37893
|
function requireDb() {
|
|
37448
|
-
if (!
|
|
37894
|
+
if (!existsSync39(DB_PATH)) {
|
|
37449
37895
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
37450
37896
|
process.exit(1);
|
|
37451
37897
|
}
|
|
@@ -37470,9 +37916,9 @@ async function resolveSlotId(idOrLabel) {
|
|
|
37470
37916
|
function resolveOAuthEmail(configHome) {
|
|
37471
37917
|
if (!configHome) return null;
|
|
37472
37918
|
try {
|
|
37473
|
-
const accountsPath =
|
|
37474
|
-
if (!
|
|
37475
|
-
const accounts = JSON.parse(
|
|
37919
|
+
const accountsPath = join38(configHome, ".gemini", "google_accounts.json");
|
|
37920
|
+
if (!existsSync39(accountsPath)) return null;
|
|
37921
|
+
const accounts = JSON.parse(readFileSync30(accountsPath, "utf-8"));
|
|
37476
37922
|
return accounts.active || null;
|
|
37477
37923
|
} catch {
|
|
37478
37924
|
return null;
|
|
@@ -37554,14 +38000,14 @@ async function geminiAddKey(globalOpts, opts) {
|
|
|
37554
38000
|
}
|
|
37555
38001
|
async function geminiAddAccount(globalOpts, opts) {
|
|
37556
38002
|
await requireWriteDb();
|
|
37557
|
-
const slotsDir =
|
|
37558
|
-
if (!
|
|
38003
|
+
const slotsDir = join38(CC_CLAW_HOME, "gemini-slots");
|
|
38004
|
+
if (!existsSync39(slotsDir)) mkdirSync14(slotsDir, { recursive: true });
|
|
37559
38005
|
const { addGeminiSlot: addGeminiSlot2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
37560
38006
|
const tempId = Date.now();
|
|
37561
|
-
const slotDir =
|
|
38007
|
+
const slotDir = join38(slotsDir, `slot-${tempId}`);
|
|
37562
38008
|
mkdirSync14(slotDir, { recursive: true, mode: 448 });
|
|
37563
|
-
mkdirSync14(
|
|
37564
|
-
writeFileSync13(
|
|
38009
|
+
mkdirSync14(join38(slotDir, ".gemini"), { recursive: true });
|
|
38010
|
+
writeFileSync13(join38(slotDir, ".gemini", "settings.json"), JSON.stringify({
|
|
37565
38011
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
37566
38012
|
}, null, 2));
|
|
37567
38013
|
console.log("");
|
|
@@ -37578,8 +38024,8 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
37578
38024
|
});
|
|
37579
38025
|
} catch {
|
|
37580
38026
|
}
|
|
37581
|
-
const oauthPath =
|
|
37582
|
-
if (!
|
|
38027
|
+
const oauthPath = join38(slotDir, ".gemini", "oauth_creds.json");
|
|
38028
|
+
if (!existsSync39(oauthPath)) {
|
|
37583
38029
|
console.log(error2("\n No OAuth credentials found. Sign-in may have failed."));
|
|
37584
38030
|
console.log(" The slot directory is preserved at: " + slotDir);
|
|
37585
38031
|
console.log(" Re-run: cc-claw gemini add-account\n");
|
|
@@ -37587,7 +38033,7 @@ async function geminiAddAccount(globalOpts, opts) {
|
|
|
37587
38033
|
}
|
|
37588
38034
|
let accountEmail = "unknown";
|
|
37589
38035
|
try {
|
|
37590
|
-
const accounts = JSON.parse(__require("fs").readFileSync(
|
|
38036
|
+
const accounts = JSON.parse(__require("fs").readFileSync(join38(slotDir, ".gemini", "google_accounts.json"), "utf-8"));
|
|
37591
38037
|
accountEmail = accounts.active || accountEmail;
|
|
37592
38038
|
} catch {
|
|
37593
38039
|
}
|
|
@@ -37698,9 +38144,9 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37698
38144
|
outputError("NO_CONFIG", `Slot "${idOrLabel}" has no config directory \u2014 cannot re-login.`);
|
|
37699
38145
|
return;
|
|
37700
38146
|
}
|
|
37701
|
-
const settingsPath =
|
|
37702
|
-
if (!
|
|
37703
|
-
mkdirSync14(
|
|
38147
|
+
const settingsPath = join38(slot.configHome, ".gemini", "settings.json");
|
|
38148
|
+
if (!existsSync39(settingsPath)) {
|
|
38149
|
+
mkdirSync14(join38(slot.configHome, ".gemini"), { recursive: true });
|
|
37704
38150
|
writeFileSync13(settingsPath, JSON.stringify({
|
|
37705
38151
|
security: { auth: { selectedType: "oauth-personal" } }
|
|
37706
38152
|
}, null, 2));
|
|
@@ -37724,8 +38170,8 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37724
38170
|
});
|
|
37725
38171
|
} catch {
|
|
37726
38172
|
}
|
|
37727
|
-
const oauthPath =
|
|
37728
|
-
if (!
|
|
38173
|
+
const oauthPath = join38(slot.configHome, ".gemini", "oauth_creds.json");
|
|
38174
|
+
if (!existsSync39(oauthPath)) {
|
|
37729
38175
|
console.log(error2("\n Re-login failed \u2014 no OAuth credentials found."));
|
|
37730
38176
|
console.log(` Try again: cc-claw gemini re-login ${idOrLabel}
|
|
37731
38177
|
`);
|
|
@@ -37735,7 +38181,7 @@ async function geminiRelogin(globalOpts, idOrLabel) {
|
|
|
37735
38181
|
setGeminiSlotEnabled2(slotId, true);
|
|
37736
38182
|
let accountEmail = slot.label;
|
|
37737
38183
|
try {
|
|
37738
|
-
const accounts = JSON.parse(
|
|
38184
|
+
const accounts = JSON.parse(readFileSync30(join38(slot.configHome, ".gemini", "google_accounts.json"), "utf-8"));
|
|
37739
38185
|
if (accounts.active) accountEmail = accounts.active;
|
|
37740
38186
|
} catch {
|
|
37741
38187
|
}
|
|
@@ -37794,11 +38240,11 @@ __export(backend_cmd_factory_exports, {
|
|
|
37794
38240
|
makeReorder: () => makeReorder,
|
|
37795
38241
|
registerBackendSlotCommands: () => registerBackendSlotCommands
|
|
37796
38242
|
});
|
|
37797
|
-
import { existsSync as
|
|
37798
|
-
import { join as
|
|
38243
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync15, readFileSync as readFileSync31 } from "fs";
|
|
38244
|
+
import { join as join39 } from "path";
|
|
37799
38245
|
import { createInterface as createInterface9 } from "readline";
|
|
37800
38246
|
function requireDb2() {
|
|
37801
|
-
if (!
|
|
38247
|
+
if (!existsSync40(DB_PATH)) {
|
|
37802
38248
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
37803
38249
|
process.exit(1);
|
|
37804
38250
|
}
|
|
@@ -37887,10 +38333,10 @@ function makeAddAccount(backend2, displayName) {
|
|
|
37887
38333
|
process.exit(1);
|
|
37888
38334
|
}
|
|
37889
38335
|
await requireWriteDb2();
|
|
37890
|
-
const slotsDir =
|
|
37891
|
-
if (!
|
|
38336
|
+
const slotsDir = join39(CC_CLAW_HOME, config2.slotsSubdir);
|
|
38337
|
+
if (!existsSync40(slotsDir)) mkdirSync15(slotsDir, { recursive: true });
|
|
37892
38338
|
const tempId = Date.now();
|
|
37893
|
-
const slotDir =
|
|
38339
|
+
const slotDir = join39(slotsDir, `slot-${tempId}`);
|
|
37894
38340
|
mkdirSync15(slotDir, { recursive: true, mode: 448 });
|
|
37895
38341
|
if (config2.preSetup) config2.preSetup(slotDir);
|
|
37896
38342
|
console.log("");
|
|
@@ -38141,22 +38587,22 @@ var init_backend_cmd_factory = __esm({
|
|
|
38141
38587
|
envValue: (slotDir) => slotDir,
|
|
38142
38588
|
envOverrides: { ANTHROPIC_API_KEY: void 0 },
|
|
38143
38589
|
preSetup: (slotDir) => {
|
|
38144
|
-
mkdirSync15(
|
|
38590
|
+
mkdirSync15(join39(slotDir, ".claude"), { recursive: true });
|
|
38145
38591
|
},
|
|
38146
38592
|
verifyCredentials: (slotDir) => {
|
|
38147
|
-
const claudeJson =
|
|
38148
|
-
const claudeJsonNested =
|
|
38149
|
-
if (
|
|
38593
|
+
const claudeJson = join39(slotDir, ".claude.json");
|
|
38594
|
+
const claudeJsonNested = join39(slotDir, ".claude", ".claude.json");
|
|
38595
|
+
if (existsSync40(claudeJson)) {
|
|
38150
38596
|
try {
|
|
38151
|
-
const data = JSON.parse(
|
|
38597
|
+
const data = JSON.parse(readFileSync31(claudeJson, "utf-8"));
|
|
38152
38598
|
return Boolean(data.oauthAccount);
|
|
38153
38599
|
} catch {
|
|
38154
38600
|
return false;
|
|
38155
38601
|
}
|
|
38156
38602
|
}
|
|
38157
|
-
if (
|
|
38603
|
+
if (existsSync40(claudeJsonNested)) {
|
|
38158
38604
|
try {
|
|
38159
|
-
const data = JSON.parse(
|
|
38605
|
+
const data = JSON.parse(readFileSync31(claudeJsonNested, "utf-8"));
|
|
38160
38606
|
return Boolean(data.oauthAccount);
|
|
38161
38607
|
} catch {
|
|
38162
38608
|
return false;
|
|
@@ -38177,9 +38623,9 @@ var init_backend_cmd_factory = __esm({
|
|
|
38177
38623
|
} catch {
|
|
38178
38624
|
}
|
|
38179
38625
|
try {
|
|
38180
|
-
const claudeJson =
|
|
38181
|
-
if (
|
|
38182
|
-
const data = JSON.parse(
|
|
38626
|
+
const claudeJson = join39(slotDir, ".claude.json");
|
|
38627
|
+
if (existsSync40(claudeJson)) {
|
|
38628
|
+
const data = JSON.parse(readFileSync31(claudeJson, "utf-8"));
|
|
38183
38629
|
if (data.oauthAccount?.emailAddress) return data.oauthAccount.emailAddress;
|
|
38184
38630
|
}
|
|
38185
38631
|
} catch {
|
|
@@ -38194,11 +38640,11 @@ var init_backend_cmd_factory = __esm({
|
|
|
38194
38640
|
envValue: (slotDir) => slotDir,
|
|
38195
38641
|
envOverrides: { OPENAI_API_KEY: void 0 },
|
|
38196
38642
|
verifyCredentials: (slotDir) => {
|
|
38197
|
-
return
|
|
38643
|
+
return existsSync40(join39(slotDir, "auth.json"));
|
|
38198
38644
|
},
|
|
38199
38645
|
extractLabel: (slotDir) => {
|
|
38200
38646
|
try {
|
|
38201
|
-
const authData = JSON.parse(
|
|
38647
|
+
const authData = JSON.parse(readFileSync31(join39(slotDir, "auth.json"), "utf-8"));
|
|
38202
38648
|
if (authData.email) return authData.email;
|
|
38203
38649
|
if (authData.account_name) return authData.account_name;
|
|
38204
38650
|
if (authData.user?.email) return authData.user.email;
|
|
@@ -38262,9 +38708,9 @@ __export(ollama_exports3, {
|
|
|
38262
38708
|
ollamaRemove: () => ollamaRemove,
|
|
38263
38709
|
ollamaTest: () => ollamaTest
|
|
38264
38710
|
});
|
|
38265
|
-
import { existsSync as
|
|
38711
|
+
import { existsSync as existsSync41 } from "fs";
|
|
38266
38712
|
function requireDb3() {
|
|
38267
|
-
if (!
|
|
38713
|
+
if (!existsSync41(DB_PATH)) {
|
|
38268
38714
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38269
38715
|
process.exit(1);
|
|
38270
38716
|
}
|
|
@@ -38526,12 +38972,12 @@ __export(backend_exports, {
|
|
|
38526
38972
|
backendList: () => backendList,
|
|
38527
38973
|
backendSet: () => backendSet
|
|
38528
38974
|
});
|
|
38529
|
-
import { existsSync as
|
|
38975
|
+
import { existsSync as existsSync42 } from "fs";
|
|
38530
38976
|
async function backendList(globalOpts) {
|
|
38531
38977
|
const { getAvailableAdapters: getAvailableAdapters3 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
38532
38978
|
const chatId = resolveChatId2(globalOpts);
|
|
38533
38979
|
let activeBackend = null;
|
|
38534
|
-
if (
|
|
38980
|
+
if (existsSync42(DB_PATH)) {
|
|
38535
38981
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
38536
38982
|
const readDb = openDatabaseReadOnly2();
|
|
38537
38983
|
try {
|
|
@@ -38562,7 +39008,7 @@ async function backendList(globalOpts) {
|
|
|
38562
39008
|
}
|
|
38563
39009
|
async function backendGet(globalOpts) {
|
|
38564
39010
|
const chatId = resolveChatId2(globalOpts);
|
|
38565
|
-
if (!
|
|
39011
|
+
if (!existsSync42(DB_PATH)) {
|
|
38566
39012
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38567
39013
|
process.exit(1);
|
|
38568
39014
|
}
|
|
@@ -38606,13 +39052,13 @@ __export(model_exports, {
|
|
|
38606
39052
|
modelList: () => modelList,
|
|
38607
39053
|
modelSet: () => modelSet
|
|
38608
39054
|
});
|
|
38609
|
-
import { existsSync as
|
|
39055
|
+
import { existsSync as existsSync43 } from "fs";
|
|
38610
39056
|
async function modelList(globalOpts) {
|
|
38611
39057
|
const chatId = resolveChatId2(globalOpts);
|
|
38612
39058
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
38613
39059
|
const { getAdapter: getAdapter3, getAllAdapters: getAllAdapters5 } = await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
38614
39060
|
let backendId = "claude";
|
|
38615
|
-
if (
|
|
39061
|
+
if (existsSync43(DB_PATH)) {
|
|
38616
39062
|
const readDb = openDatabaseReadOnly2();
|
|
38617
39063
|
try {
|
|
38618
39064
|
const row = readDb.prepare("SELECT backend FROM chat_backend WHERE chat_id = ?").get(chatId);
|
|
@@ -38645,7 +39091,7 @@ async function modelList(globalOpts) {
|
|
|
38645
39091
|
}
|
|
38646
39092
|
async function modelGet(globalOpts) {
|
|
38647
39093
|
const chatId = resolveChatId2(globalOpts);
|
|
38648
|
-
if (!
|
|
39094
|
+
if (!existsSync43(DB_PATH)) {
|
|
38649
39095
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38650
39096
|
process.exit(1);
|
|
38651
39097
|
}
|
|
@@ -38690,9 +39136,9 @@ __export(memory_exports2, {
|
|
|
38690
39136
|
memoryOptimize: () => memoryOptimize,
|
|
38691
39137
|
memorySearch: () => memorySearch
|
|
38692
39138
|
});
|
|
38693
|
-
import { existsSync as
|
|
39139
|
+
import { existsSync as existsSync44 } from "fs";
|
|
38694
39140
|
async function memoryList(globalOpts) {
|
|
38695
|
-
if (!
|
|
39141
|
+
if (!existsSync44(DB_PATH)) {
|
|
38696
39142
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
38697
39143
|
process.exit(1);
|
|
38698
39144
|
}
|
|
@@ -38716,7 +39162,7 @@ async function memoryList(globalOpts) {
|
|
|
38716
39162
|
});
|
|
38717
39163
|
}
|
|
38718
39164
|
async function memorySearch(globalOpts, query) {
|
|
38719
|
-
if (!
|
|
39165
|
+
if (!existsSync44(DB_PATH)) {
|
|
38720
39166
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38721
39167
|
process.exit(1);
|
|
38722
39168
|
}
|
|
@@ -38738,7 +39184,7 @@ async function memorySearch(globalOpts, query) {
|
|
|
38738
39184
|
});
|
|
38739
39185
|
}
|
|
38740
39186
|
async function memoryHistory(globalOpts, opts) {
|
|
38741
|
-
if (!
|
|
39187
|
+
if (!existsSync44(DB_PATH)) {
|
|
38742
39188
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38743
39189
|
process.exit(1);
|
|
38744
39190
|
}
|
|
@@ -38839,7 +39285,7 @@ __export(cron_exports2, {
|
|
|
38839
39285
|
cronList: () => cronList,
|
|
38840
39286
|
cronRuns: () => cronRuns
|
|
38841
39287
|
});
|
|
38842
|
-
import { existsSync as
|
|
39288
|
+
import { existsSync as existsSync45 } from "fs";
|
|
38843
39289
|
function parseFallbacks(raw) {
|
|
38844
39290
|
return raw.slice(0, 3).map((f) => {
|
|
38845
39291
|
const [backend2, ...rest] = f.split(":");
|
|
@@ -38860,7 +39306,7 @@ function parseAndValidateTimeout(raw) {
|
|
|
38860
39306
|
return val;
|
|
38861
39307
|
}
|
|
38862
39308
|
async function cronList(globalOpts) {
|
|
38863
|
-
if (!
|
|
39309
|
+
if (!existsSync45(DB_PATH)) {
|
|
38864
39310
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38865
39311
|
process.exit(1);
|
|
38866
39312
|
}
|
|
@@ -38898,7 +39344,7 @@ async function cronList(globalOpts) {
|
|
|
38898
39344
|
});
|
|
38899
39345
|
}
|
|
38900
39346
|
async function cronHealth(globalOpts) {
|
|
38901
|
-
if (!
|
|
39347
|
+
if (!existsSync45(DB_PATH)) {
|
|
38902
39348
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
38903
39349
|
process.exit(1);
|
|
38904
39350
|
}
|
|
@@ -39082,7 +39528,7 @@ async function cronEdit(globalOpts, id, opts) {
|
|
|
39082
39528
|
}
|
|
39083
39529
|
}
|
|
39084
39530
|
async function cronRuns(globalOpts, jobId, opts) {
|
|
39085
|
-
if (!
|
|
39531
|
+
if (!existsSync45(DB_PATH)) {
|
|
39086
39532
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39087
39533
|
process.exit(1);
|
|
39088
39534
|
}
|
|
@@ -39129,9 +39575,9 @@ __export(agents_exports, {
|
|
|
39129
39575
|
runnersList: () => runnersList,
|
|
39130
39576
|
tasksList: () => tasksList
|
|
39131
39577
|
});
|
|
39132
|
-
import { existsSync as
|
|
39578
|
+
import { existsSync as existsSync46 } from "fs";
|
|
39133
39579
|
async function agentsList(globalOpts) {
|
|
39134
|
-
if (!
|
|
39580
|
+
if (!existsSync46(DB_PATH)) {
|
|
39135
39581
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39136
39582
|
process.exit(1);
|
|
39137
39583
|
}
|
|
@@ -39162,7 +39608,7 @@ async function agentsList(globalOpts) {
|
|
|
39162
39608
|
});
|
|
39163
39609
|
}
|
|
39164
39610
|
async function tasksList(globalOpts) {
|
|
39165
|
-
if (!
|
|
39611
|
+
if (!existsSync46(DB_PATH)) {
|
|
39166
39612
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39167
39613
|
process.exit(1);
|
|
39168
39614
|
}
|
|
@@ -39290,10 +39736,10 @@ __export(db_exports, {
|
|
|
39290
39736
|
dbPath: () => dbPath,
|
|
39291
39737
|
dbStats: () => dbStats
|
|
39292
39738
|
});
|
|
39293
|
-
import { existsSync as
|
|
39739
|
+
import { existsSync as existsSync47, statSync as statSync11, copyFileSync as copyFileSync4, mkdirSync as mkdirSync16 } from "fs";
|
|
39294
39740
|
import { dirname as dirname8 } from "path";
|
|
39295
39741
|
async function dbStats(globalOpts) {
|
|
39296
|
-
if (!
|
|
39742
|
+
if (!existsSync47(DB_PATH)) {
|
|
39297
39743
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
39298
39744
|
process.exit(1);
|
|
39299
39745
|
}
|
|
@@ -39301,7 +39747,7 @@ async function dbStats(globalOpts) {
|
|
|
39301
39747
|
const readDb = openDatabaseReadOnly2();
|
|
39302
39748
|
const mainSize = statSync11(DB_PATH).size;
|
|
39303
39749
|
const walPath = DB_PATH + "-wal";
|
|
39304
|
-
const walSize =
|
|
39750
|
+
const walSize = existsSync47(walPath) ? statSync11(walPath).size : 0;
|
|
39305
39751
|
const tableNames = readDb.prepare(
|
|
39306
39752
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '%_fts%' ORDER BY name"
|
|
39307
39753
|
).all();
|
|
@@ -39335,7 +39781,7 @@ async function dbPath(globalOpts) {
|
|
|
39335
39781
|
output({ path: DB_PATH }, (d) => d.path);
|
|
39336
39782
|
}
|
|
39337
39783
|
async function dbBackup(globalOpts, destPath) {
|
|
39338
|
-
if (!
|
|
39784
|
+
if (!existsSync47(DB_PATH)) {
|
|
39339
39785
|
outputError("DB_NOT_FOUND", `Database not found at ${DB_PATH}`);
|
|
39340
39786
|
process.exit(1);
|
|
39341
39787
|
}
|
|
@@ -39344,7 +39790,7 @@ async function dbBackup(globalOpts, destPath) {
|
|
|
39344
39790
|
mkdirSync16(dirname8(dest), { recursive: true });
|
|
39345
39791
|
copyFileSync4(DB_PATH, dest);
|
|
39346
39792
|
const walPath = DB_PATH + "-wal";
|
|
39347
|
-
if (
|
|
39793
|
+
if (existsSync47(walPath)) copyFileSync4(walPath, dest + "-wal");
|
|
39348
39794
|
output({ path: dest, sizeBytes: statSync11(dest).size }, (d) => {
|
|
39349
39795
|
const b = d;
|
|
39350
39796
|
return `
|
|
@@ -39373,9 +39819,9 @@ __export(usage_exports, {
|
|
|
39373
39819
|
usageCost: () => usageCost,
|
|
39374
39820
|
usageTokens: () => usageTokens
|
|
39375
39821
|
});
|
|
39376
|
-
import { existsSync as
|
|
39822
|
+
import { existsSync as existsSync48 } from "fs";
|
|
39377
39823
|
function ensureDb() {
|
|
39378
|
-
if (!
|
|
39824
|
+
if (!existsSync48(DB_PATH)) {
|
|
39379
39825
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
39380
39826
|
process.exit(1);
|
|
39381
39827
|
}
|
|
@@ -39565,9 +40011,9 @@ __export(config_exports2, {
|
|
|
39565
40011
|
configList: () => configList,
|
|
39566
40012
|
configSet: () => configSet
|
|
39567
40013
|
});
|
|
39568
|
-
import { existsSync as
|
|
40014
|
+
import { existsSync as existsSync49, readFileSync as readFileSync32 } from "fs";
|
|
39569
40015
|
async function configList(globalOpts) {
|
|
39570
|
-
if (!
|
|
40016
|
+
if (!existsSync49(DB_PATH)) {
|
|
39571
40017
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39572
40018
|
process.exit(1);
|
|
39573
40019
|
}
|
|
@@ -39601,7 +40047,7 @@ async function configGet(globalOpts, key) {
|
|
|
39601
40047
|
outputError("INVALID_KEY", `Unknown config key "${key}". Valid keys: ${RUNTIME_KEYS.join(", ")}`);
|
|
39602
40048
|
process.exit(1);
|
|
39603
40049
|
}
|
|
39604
|
-
if (!
|
|
40050
|
+
if (!existsSync49(DB_PATH)) {
|
|
39605
40051
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39606
40052
|
process.exit(1);
|
|
39607
40053
|
}
|
|
@@ -39647,11 +40093,11 @@ async function configSet(globalOpts, key, value) {
|
|
|
39647
40093
|
}
|
|
39648
40094
|
}
|
|
39649
40095
|
async function configEnv(_globalOpts) {
|
|
39650
|
-
if (!
|
|
40096
|
+
if (!existsSync49(ENV_PATH)) {
|
|
39651
40097
|
outputError("ENV_NOT_FOUND", `No .env file at ${ENV_PATH}. Run cc-claw setup.`);
|
|
39652
40098
|
process.exit(1);
|
|
39653
40099
|
}
|
|
39654
|
-
const content =
|
|
40100
|
+
const content = readFileSync32(ENV_PATH, "utf-8");
|
|
39655
40101
|
const entries = {};
|
|
39656
40102
|
const secretPatterns = /TOKEN|KEY|SECRET|PASSWORD|CREDENTIALS/i;
|
|
39657
40103
|
for (const line of content.split("\n")) {
|
|
@@ -39701,9 +40147,9 @@ __export(session_exports, {
|
|
|
39701
40147
|
sessionGet: () => sessionGet,
|
|
39702
40148
|
sessionNew: () => sessionNew
|
|
39703
40149
|
});
|
|
39704
|
-
import { existsSync as
|
|
40150
|
+
import { existsSync as existsSync50 } from "fs";
|
|
39705
40151
|
async function sessionGet(globalOpts) {
|
|
39706
|
-
if (!
|
|
40152
|
+
if (!existsSync50(DB_PATH)) {
|
|
39707
40153
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39708
40154
|
process.exit(1);
|
|
39709
40155
|
}
|
|
@@ -39764,9 +40210,9 @@ __export(permissions_exports, {
|
|
|
39764
40210
|
verboseGet: () => verboseGet,
|
|
39765
40211
|
verboseSet: () => verboseSet
|
|
39766
40212
|
});
|
|
39767
|
-
import { existsSync as
|
|
40213
|
+
import { existsSync as existsSync51 } from "fs";
|
|
39768
40214
|
function ensureDb2() {
|
|
39769
|
-
if (!
|
|
40215
|
+
if (!existsSync51(DB_PATH)) {
|
|
39770
40216
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39771
40217
|
process.exit(1);
|
|
39772
40218
|
}
|
|
@@ -39913,9 +40359,9 @@ __export(cwd_exports, {
|
|
|
39913
40359
|
cwdGet: () => cwdGet,
|
|
39914
40360
|
cwdSet: () => cwdSet
|
|
39915
40361
|
});
|
|
39916
|
-
import { existsSync as
|
|
40362
|
+
import { existsSync as existsSync52 } from "fs";
|
|
39917
40363
|
async function cwdGet(globalOpts) {
|
|
39918
|
-
if (!
|
|
40364
|
+
if (!existsSync52(DB_PATH)) {
|
|
39919
40365
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39920
40366
|
process.exit(1);
|
|
39921
40367
|
}
|
|
@@ -39977,9 +40423,9 @@ __export(voice_exports, {
|
|
|
39977
40423
|
voiceGet: () => voiceGet,
|
|
39978
40424
|
voiceSet: () => voiceSet
|
|
39979
40425
|
});
|
|
39980
|
-
import { existsSync as
|
|
40426
|
+
import { existsSync as existsSync53 } from "fs";
|
|
39981
40427
|
async function voiceGet(globalOpts) {
|
|
39982
|
-
if (!
|
|
40428
|
+
if (!existsSync53(DB_PATH)) {
|
|
39983
40429
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
39984
40430
|
process.exit(1);
|
|
39985
40431
|
}
|
|
@@ -40028,9 +40474,9 @@ __export(heartbeat_exports2, {
|
|
|
40028
40474
|
heartbeatGet: () => heartbeatGet,
|
|
40029
40475
|
heartbeatSet: () => heartbeatSet
|
|
40030
40476
|
});
|
|
40031
|
-
import { existsSync as
|
|
40477
|
+
import { existsSync as existsSync54 } from "fs";
|
|
40032
40478
|
async function heartbeatGet(globalOpts) {
|
|
40033
|
-
if (!
|
|
40479
|
+
if (!existsSync54(DB_PATH)) {
|
|
40034
40480
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40035
40481
|
process.exit(1);
|
|
40036
40482
|
}
|
|
@@ -40241,9 +40687,9 @@ __export(summarizer_exports, {
|
|
|
40241
40687
|
summarizerGet: () => summarizerGet,
|
|
40242
40688
|
summarizerSet: () => summarizerSet
|
|
40243
40689
|
});
|
|
40244
|
-
import { existsSync as
|
|
40690
|
+
import { existsSync as existsSync55 } from "fs";
|
|
40245
40691
|
async function summarizerGet(globalOpts) {
|
|
40246
|
-
if (!
|
|
40692
|
+
if (!existsSync55(DB_PATH)) {
|
|
40247
40693
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40248
40694
|
process.exit(1);
|
|
40249
40695
|
}
|
|
@@ -40287,9 +40733,9 @@ __export(thinking_exports, {
|
|
|
40287
40733
|
thinkingGet: () => thinkingGet,
|
|
40288
40734
|
thinkingSet: () => thinkingSet
|
|
40289
40735
|
});
|
|
40290
|
-
import { existsSync as
|
|
40736
|
+
import { existsSync as existsSync56 } from "fs";
|
|
40291
40737
|
async function thinkingGet(globalOpts) {
|
|
40292
|
-
if (!
|
|
40738
|
+
if (!existsSync56(DB_PATH)) {
|
|
40293
40739
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40294
40740
|
process.exit(1);
|
|
40295
40741
|
}
|
|
@@ -40333,9 +40779,9 @@ __export(chats_exports, {
|
|
|
40333
40779
|
chatsList: () => chatsList,
|
|
40334
40780
|
chatsRemoveAlias: () => chatsRemoveAlias
|
|
40335
40781
|
});
|
|
40336
|
-
import { existsSync as
|
|
40782
|
+
import { existsSync as existsSync57 } from "fs";
|
|
40337
40783
|
async function chatsList(_globalOpts) {
|
|
40338
|
-
if (!
|
|
40784
|
+
if (!existsSync57(DB_PATH)) {
|
|
40339
40785
|
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40340
40786
|
process.exit(1);
|
|
40341
40787
|
}
|
|
@@ -40458,41 +40904,186 @@ var init_skills = __esm({
|
|
|
40458
40904
|
}
|
|
40459
40905
|
});
|
|
40460
40906
|
|
|
40461
|
-
// src/cli/commands/
|
|
40462
|
-
var
|
|
40463
|
-
__export(
|
|
40464
|
-
|
|
40907
|
+
// src/cli/commands/mcp.ts
|
|
40908
|
+
var mcp_exports2 = {};
|
|
40909
|
+
__export(mcp_exports2, {
|
|
40910
|
+
mcpAdd: () => mcpAdd,
|
|
40911
|
+
mcpDisable: () => mcpDisable,
|
|
40912
|
+
mcpEnable: () => mcpEnable,
|
|
40913
|
+
mcpExport: () => mcpExport,
|
|
40914
|
+
mcpHealth: () => mcpHealth,
|
|
40915
|
+
mcpList: () => mcpList,
|
|
40916
|
+
mcpRemove: () => mcpRemove
|
|
40465
40917
|
});
|
|
40466
|
-
import { existsSync as
|
|
40467
|
-
|
|
40468
|
-
if (!
|
|
40469
|
-
outputError("DB_NOT_FOUND", "Database not found.");
|
|
40918
|
+
import { existsSync as existsSync58 } from "fs";
|
|
40919
|
+
function requireDb4() {
|
|
40920
|
+
if (!existsSync58(DB_PATH)) {
|
|
40921
|
+
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
40470
40922
|
process.exit(1);
|
|
40471
40923
|
}
|
|
40924
|
+
}
|
|
40925
|
+
async function mcpList(globalOpts) {
|
|
40926
|
+
requireDb4();
|
|
40472
40927
|
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
40473
|
-
const
|
|
40474
|
-
const
|
|
40475
|
-
|
|
40476
|
-
|
|
40928
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
40929
|
+
const db3 = openDatabaseReadOnly2();
|
|
40930
|
+
const mcps = listMcpServers2(db3);
|
|
40931
|
+
db3.close();
|
|
40932
|
+
output(mcps, (d) => {
|
|
40477
40933
|
const list = d;
|
|
40478
|
-
if (list.length === 0)
|
|
40479
|
-
|
|
40934
|
+
if (list.length === 0) {
|
|
40935
|
+
return `
|
|
40936
|
+
${muted("No MCP servers registered. Use `cc-claw mcp add` or `cc-claw mcp import`.")}
|
|
40480
40937
|
`;
|
|
40938
|
+
}
|
|
40481
40939
|
const lines = ["", divider(`MCP Servers (${list.length})`), ""];
|
|
40482
40940
|
for (const m of list) {
|
|
40483
|
-
const
|
|
40484
|
-
const
|
|
40485
|
-
|
|
40941
|
+
const lock = SYSTEM_MCP_NAMES.has(m.name) ? " \u{1F512}" : "";
|
|
40942
|
+
const pin = m.enabledByDefault ? " \u{1F4CC}" : "";
|
|
40943
|
+
const desc = m.description ? ` \u2014 ${muted(m.description)}` : "";
|
|
40944
|
+
const transport = muted(`[${m.transport}]`);
|
|
40945
|
+
const cmd = m.command ? muted(` ${m.command}`) : "";
|
|
40946
|
+
lines.push(
|
|
40947
|
+
` ${healthIcon(m.healthStatus)} ${success(m.name)}${lock}${pin} ${transport}${cmd}${desc}`
|
|
40948
|
+
);
|
|
40486
40949
|
}
|
|
40487
40950
|
lines.push("");
|
|
40488
40951
|
return lines.join("\n");
|
|
40489
40952
|
});
|
|
40490
40953
|
}
|
|
40491
|
-
|
|
40492
|
-
|
|
40954
|
+
async function mcpAdd(name, command, args, globalOpts) {
|
|
40955
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
40956
|
+
outputError("RESERVED_NAME", `"${name}" is a reserved system MCP name.`);
|
|
40957
|
+
process.exit(1);
|
|
40958
|
+
}
|
|
40959
|
+
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
40960
|
+
if (!await isDaemonRunning2()) {
|
|
40961
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
40962
|
+
process.exit(1);
|
|
40963
|
+
}
|
|
40964
|
+
const res = await apiPost2("/api/mcps", {
|
|
40965
|
+
name,
|
|
40966
|
+
transport: "stdio",
|
|
40967
|
+
command,
|
|
40968
|
+
args,
|
|
40969
|
+
enabledByDefault: true
|
|
40970
|
+
});
|
|
40971
|
+
output(
|
|
40972
|
+
res.data,
|
|
40973
|
+
() => res.ok ? `
|
|
40974
|
+
${success("\u2713")} Added MCP server "${name}"
|
|
40975
|
+
` : `
|
|
40976
|
+
${error2("\u2717")} Failed to add MCP: ${JSON.stringify(res.data)}
|
|
40977
|
+
`
|
|
40978
|
+
);
|
|
40979
|
+
if (!res.ok) process.exit(1);
|
|
40980
|
+
}
|
|
40981
|
+
async function mcpRemove(name, globalOpts) {
|
|
40982
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
40983
|
+
outputError("PROTECTED", `Cannot remove system MCP "${name}"`);
|
|
40984
|
+
process.exit(1);
|
|
40985
|
+
}
|
|
40986
|
+
const { isDaemonRunning: isDaemonRunning2, apiDelete: apiDelete2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
40987
|
+
if (!await isDaemonRunning2()) {
|
|
40988
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
40989
|
+
process.exit(1);
|
|
40990
|
+
}
|
|
40991
|
+
const res = await apiDelete2(`/api/mcps/${encodeURIComponent(name)}`);
|
|
40992
|
+
output(
|
|
40993
|
+
res.data,
|
|
40994
|
+
() => res.ok ? `
|
|
40995
|
+
${success("\u2713")} Removed MCP server "${name}"
|
|
40996
|
+
` : `
|
|
40997
|
+
${error2("\u2717")} Failed to remove MCP: ${JSON.stringify(res.data)}
|
|
40998
|
+
`
|
|
40999
|
+
);
|
|
41000
|
+
if (!res.ok) process.exit(1);
|
|
41001
|
+
}
|
|
41002
|
+
async function mcpEnable(name, globalOpts) {
|
|
41003
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
41004
|
+
outputError("PROTECTED", `Cannot enable system MCP "${name}"`);
|
|
41005
|
+
process.exit(1);
|
|
41006
|
+
}
|
|
41007
|
+
const { isDaemonRunning: isDaemonRunning2, apiPut: apiPut2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41008
|
+
if (!await isDaemonRunning2()) {
|
|
41009
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41010
|
+
process.exit(1);
|
|
41011
|
+
}
|
|
41012
|
+
const res = await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: true });
|
|
41013
|
+
output(
|
|
41014
|
+
res.data,
|
|
41015
|
+
() => res.ok ? `
|
|
41016
|
+
${success("\u2713")} Enabled "${name}"
|
|
41017
|
+
` : `
|
|
41018
|
+
${error2("\u2717")} Failed to enable MCP: ${JSON.stringify(res.data)}
|
|
41019
|
+
`
|
|
41020
|
+
);
|
|
41021
|
+
if (!res.ok) process.exit(1);
|
|
41022
|
+
}
|
|
41023
|
+
async function mcpDisable(name, globalOpts) {
|
|
41024
|
+
if (SYSTEM_MCP_NAMES.has(name)) {
|
|
41025
|
+
outputError("PROTECTED", `Cannot disable system MCP "${name}"`);
|
|
41026
|
+
process.exit(1);
|
|
41027
|
+
}
|
|
41028
|
+
const { isDaemonRunning: isDaemonRunning2, apiPut: apiPut2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41029
|
+
if (!await isDaemonRunning2()) {
|
|
41030
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41031
|
+
process.exit(1);
|
|
41032
|
+
}
|
|
41033
|
+
const res = await apiPut2(`/api/mcps/${encodeURIComponent(name)}`, { enabledByDefault: false });
|
|
41034
|
+
output(
|
|
41035
|
+
res.data,
|
|
41036
|
+
() => res.ok ? `
|
|
41037
|
+
${success("\u2713")} Disabled "${name}"
|
|
41038
|
+
` : `
|
|
41039
|
+
${error2("\u2717")} Failed to disable MCP: ${JSON.stringify(res.data)}
|
|
41040
|
+
`
|
|
41041
|
+
);
|
|
41042
|
+
if (!res.ok) process.exit(1);
|
|
41043
|
+
}
|
|
41044
|
+
async function mcpExport(globalOpts) {
|
|
41045
|
+
requireDb4();
|
|
41046
|
+
const { openDatabaseReadOnly: openDatabaseReadOnly2 } = await Promise.resolve().then(() => (init_store5(), store_exports5));
|
|
41047
|
+
const { listMcpServers: listMcpServers2 } = await Promise.resolve().then(() => (init_store2(), store_exports2));
|
|
41048
|
+
const db3 = openDatabaseReadOnly2();
|
|
41049
|
+
const mcps = listMcpServers2(db3);
|
|
41050
|
+
db3.close();
|
|
41051
|
+
const servers = {};
|
|
41052
|
+
for (const m of mcps) {
|
|
41053
|
+
if (SYSTEM_MCP_NAMES.has(m.name)) continue;
|
|
41054
|
+
servers[m.name] = {
|
|
41055
|
+
transport: m.transport,
|
|
41056
|
+
command: m.command ?? void 0,
|
|
41057
|
+
args: m.args ? JSON.parse(m.args) : void 0,
|
|
41058
|
+
env: m.env ? JSON.parse(m.env) : void 0
|
|
41059
|
+
};
|
|
41060
|
+
}
|
|
41061
|
+
const exportData = { mcpServers: servers };
|
|
41062
|
+
output(exportData, () => JSON.stringify(exportData, null, 2));
|
|
41063
|
+
}
|
|
41064
|
+
async function mcpHealth(globalOpts) {
|
|
41065
|
+
const { isDaemonRunning: isDaemonRunning2, apiPost: apiPost2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
41066
|
+
if (!await isDaemonRunning2()) {
|
|
41067
|
+
outputError("DAEMON_DOWN", "Daemon is not running. Start it with: cc-claw service start");
|
|
41068
|
+
process.exit(1);
|
|
41069
|
+
}
|
|
41070
|
+
const res = await apiPost2("/api/mcps/health", {});
|
|
41071
|
+
output(
|
|
41072
|
+
res.data,
|
|
41073
|
+
() => res.ok ? `
|
|
41074
|
+
${success("\u2713")} Health checks triggered. Run \`cc-claw mcp list\` to see updated status.
|
|
41075
|
+
` : `
|
|
41076
|
+
${error2("\u2717")} Health check failed: ${JSON.stringify(res.data)}
|
|
41077
|
+
`
|
|
41078
|
+
);
|
|
41079
|
+
if (!res.ok) process.exit(1);
|
|
41080
|
+
}
|
|
41081
|
+
var init_mcp2 = __esm({
|
|
41082
|
+
"src/cli/commands/mcp.ts"() {
|
|
40493
41083
|
"use strict";
|
|
40494
41084
|
init_format2();
|
|
40495
41085
|
init_paths();
|
|
41086
|
+
init_constants();
|
|
40496
41087
|
}
|
|
40497
41088
|
});
|
|
40498
41089
|
|
|
@@ -40502,11 +41093,11 @@ __export(chat_exports2, {
|
|
|
40502
41093
|
chatSend: () => chatSend
|
|
40503
41094
|
});
|
|
40504
41095
|
import { request as httpRequest2 } from "http";
|
|
40505
|
-
import { readFileSync as
|
|
41096
|
+
import { readFileSync as readFileSync33, existsSync as existsSync59 } from "fs";
|
|
40506
41097
|
function getToken2() {
|
|
40507
41098
|
if (process.env.CC_CLAW_API_TOKEN) return process.env.CC_CLAW_API_TOKEN;
|
|
40508
41099
|
try {
|
|
40509
|
-
if (
|
|
41100
|
+
if (existsSync59(TOKEN_PATH)) return readFileSync33(TOKEN_PATH, "utf-8").trim();
|
|
40510
41101
|
} catch {
|
|
40511
41102
|
}
|
|
40512
41103
|
return null;
|
|
@@ -40994,8 +41585,8 @@ __export(completion_exports, {
|
|
|
40994
41585
|
completionCommand: () => completionCommand
|
|
40995
41586
|
});
|
|
40996
41587
|
import { writeFileSync as writeFileSync14, mkdirSync as mkdirSync17 } from "fs";
|
|
40997
|
-
import { join as
|
|
40998
|
-
import { homedir as
|
|
41588
|
+
import { join as join40 } from "path";
|
|
41589
|
+
import { homedir as homedir13 } from "os";
|
|
40999
41590
|
async function completionCommand(opts) {
|
|
41000
41591
|
const shell = opts.shell ?? detectShell();
|
|
41001
41592
|
let script;
|
|
@@ -41010,10 +41601,10 @@ async function completionCommand(opts) {
|
|
|
41010
41601
|
process.exit(1);
|
|
41011
41602
|
}
|
|
41012
41603
|
if (opts.install) {
|
|
41013
|
-
const dir =
|
|
41604
|
+
const dir = join40(homedir13(), ".config", "cc-claw", "completions");
|
|
41014
41605
|
mkdirSync17(dir, { recursive: true });
|
|
41015
41606
|
const filename = shell === "zsh" ? "_cc-claw" : shell === "fish" ? "cc-claw.fish" : "cc-claw.bash";
|
|
41016
|
-
const filepath =
|
|
41607
|
+
const filepath = join40(dir, filename);
|
|
41017
41608
|
writeFileSync14(filepath, script, "utf-8");
|
|
41018
41609
|
console.log(`\u2713 Completion script written to ${filepath}
|
|
41019
41610
|
`);
|
|
@@ -41186,9 +41777,9 @@ __export(evolve_exports2, {
|
|
|
41186
41777
|
evolveStatus: () => evolveStatus,
|
|
41187
41778
|
evolveUndo: () => evolveUndo
|
|
41188
41779
|
});
|
|
41189
|
-
import { existsSync as
|
|
41780
|
+
import { existsSync as existsSync60 } from "fs";
|
|
41190
41781
|
function ensureDb3() {
|
|
41191
|
-
if (!
|
|
41782
|
+
if (!existsSync60(DB_PATH)) {
|
|
41192
41783
|
outputError("DB_NOT_FOUND", "Database not found. Run cc-claw setup first.");
|
|
41193
41784
|
process.exit(1);
|
|
41194
41785
|
}
|
|
@@ -41662,10 +42253,10 @@ var init_optimize3 = __esm({
|
|
|
41662
42253
|
|
|
41663
42254
|
// src/setup.ts
|
|
41664
42255
|
var setup_exports = {};
|
|
41665
|
-
import { existsSync as
|
|
42256
|
+
import { existsSync as existsSync61, writeFileSync as writeFileSync15, readFileSync as readFileSync34, copyFileSync as copyFileSync5, mkdirSync as mkdirSync18, statSync as statSync12 } from "fs";
|
|
41666
42257
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
41667
42258
|
import { createInterface as createInterface11 } from "readline";
|
|
41668
|
-
import { join as
|
|
42259
|
+
import { join as join41 } from "path";
|
|
41669
42260
|
function divider2() {
|
|
41670
42261
|
console.log(dim("\u2500".repeat(55)));
|
|
41671
42262
|
}
|
|
@@ -41746,22 +42337,22 @@ async function setup() {
|
|
|
41746
42337
|
console.log("");
|
|
41747
42338
|
if (!DRY_RUN) {
|
|
41748
42339
|
for (const dir of [CC_CLAW_HOME, DATA_PATH, LOGS_PATH, SKILLS_PATH, RUNNERS_PATH, AGENTS_PATH]) {
|
|
41749
|
-
if (!
|
|
42340
|
+
if (!existsSync61(dir)) mkdirSync18(dir, { recursive: true });
|
|
41750
42341
|
}
|
|
41751
42342
|
}
|
|
41752
42343
|
const env = {};
|
|
41753
|
-
const envSource =
|
|
42344
|
+
const envSource = existsSync61(ENV_PATH) ? ENV_PATH : existsSync61(".env") ? ".env" : null;
|
|
41754
42345
|
if (envSource) {
|
|
41755
42346
|
console.log(yellow(` Found existing config at ${envSource} \u2014 your values will be preserved`));
|
|
41756
42347
|
console.log(yellow(" unless you enter new ones. Just press Enter to keep existing values.\n"));
|
|
41757
|
-
const existing =
|
|
42348
|
+
const existing = readFileSync34(envSource, "utf-8");
|
|
41758
42349
|
for (const line of existing.split("\n")) {
|
|
41759
42350
|
const match = line.match(/^([^#=]+)=(.*)$/);
|
|
41760
42351
|
if (match) env[match[1].trim()] = match[2].trim();
|
|
41761
42352
|
}
|
|
41762
42353
|
}
|
|
41763
|
-
const cwdDb =
|
|
41764
|
-
if (
|
|
42354
|
+
const cwdDb = join41(process.cwd(), "cc-claw.db");
|
|
42355
|
+
if (existsSync61(cwdDb) && !existsSync61(DB_PATH)) {
|
|
41765
42356
|
const { size } = statSync12(cwdDb);
|
|
41766
42357
|
console.log(yellow(` Found existing database at ${cwdDb} (${(size / 1024).toFixed(0)}KB)`));
|
|
41767
42358
|
const migrate = await confirm("Copy database to ~/.cc-claw/? (preserves memories & history)", true);
|
|
@@ -42622,10 +43213,38 @@ skills.command("install <url>").description("Install a skill from GitHub").actio
|
|
|
42622
43213
|
const { skillsInstall: skillsInstall2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
42623
43214
|
await skillsInstall2(program.opts(), url);
|
|
42624
43215
|
});
|
|
42625
|
-
var
|
|
42626
|
-
|
|
42627
|
-
const {
|
|
42628
|
-
await
|
|
43216
|
+
var mcp = program.command("mcp").alias("mcps").description("MCP server management");
|
|
43217
|
+
mcp.command("list").description("List all registered MCP servers").action(async () => {
|
|
43218
|
+
const { mcpList: mcpList2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43219
|
+
await mcpList2(program.opts());
|
|
43220
|
+
});
|
|
43221
|
+
mcp.command("add <name> <command> [args...]").description("Add a stdio MCP server").action(async (name, command, args) => {
|
|
43222
|
+
const { mcpAdd: mcpAdd2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43223
|
+
await mcpAdd2(name, command, args, program.opts());
|
|
43224
|
+
});
|
|
43225
|
+
mcp.command("remove <name>").description("Remove an MCP server").action(async (name) => {
|
|
43226
|
+
const { mcpRemove: mcpRemove2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43227
|
+
await mcpRemove2(name, program.opts());
|
|
43228
|
+
});
|
|
43229
|
+
mcp.command("enable <name>").description("Enable an MCP server").action(async (name) => {
|
|
43230
|
+
const { mcpEnable: mcpEnable2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43231
|
+
await mcpEnable2(name, program.opts());
|
|
43232
|
+
});
|
|
43233
|
+
mcp.command("disable <name>").description("Disable an MCP server").action(async (name) => {
|
|
43234
|
+
const { mcpDisable: mcpDisable2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43235
|
+
await mcpDisable2(name, program.opts());
|
|
43236
|
+
});
|
|
43237
|
+
mcp.command("import <source>").description("Import MCPs from another CLI (claude, gemini, codex, cursor)").action(async (source) => {
|
|
43238
|
+
const { mcpImport: mcpImport2 } = await Promise.resolve().then(() => (init_import(), import_exports));
|
|
43239
|
+
await mcpImport2(source, program.opts());
|
|
43240
|
+
});
|
|
43241
|
+
mcp.command("export").description("Export MCP registry to JSON").action(async () => {
|
|
43242
|
+
const { mcpExport: mcpExport2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43243
|
+
await mcpExport2(program.opts());
|
|
43244
|
+
});
|
|
43245
|
+
mcp.command("health").description("Trigger health checks on all MCPs").action(async () => {
|
|
43246
|
+
const { mcpHealth: mcpHealth2 } = await Promise.resolve().then(() => (init_mcp2(), mcp_exports2));
|
|
43247
|
+
await mcpHealth2(program.opts());
|
|
42629
43248
|
});
|
|
42630
43249
|
var chat2 = program.command("chat").description("Chat with the AI");
|
|
42631
43250
|
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) => {
|