jinzd-ai-cli 0.4.134 → 0.4.135
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/{batch-ZCBWXMNR.js → batch-NOEJSHCZ.js} +2 -2
- package/dist/{chunk-JER6BUQL.js → chunk-5XL4HXY5.js} +176 -13
- package/dist/{chunk-CQZMVPOW.js → chunk-BS6JUZPS.js} +1 -1
- package/dist/{chunk-BQL6IYCI.js → chunk-NCZWD2KK.js} +1 -1
- package/dist/{chunk-4SSCJXAA.js → chunk-OMB3XLCV.js} +1 -1
- package/dist/{chunk-ZOFXDRJT.js → chunk-P73ARSFY.js} +1 -1
- package/dist/{chunk-WKITLEBR.js → chunk-PVZE6NWC.js} +1 -1
- package/dist/{chunk-2QPEE3AY.js → chunk-SUJFSZ6U.js} +2 -2
- package/dist/{chunk-63YPIF2A.js → chunk-UJLTBN7R.js} +13 -1
- package/dist/{chunk-P6CGP7CU.js → chunk-Y2IWJDJA.js} +1 -1
- package/dist/{constants-7VLZQ2ZS.js → constants-7LFVO52M.js} +1 -1
- package/dist/{doctor-cli-FCJ4W3ZH.js → doctor-cli-4FQM4BHM.js} +5 -5
- package/dist/electron-server.js +187 -12
- package/dist/{hub-6LOXFNGG.js → hub-JJF5BNY4.js} +1 -1
- package/dist/index.js +21 -17
- package/dist/{run-tests-I6RJ35P6.js → run-tests-7VI5TCNL.js} +2 -2
- package/dist/{run-tests-CL7X7D4R.js → run-tests-P436Z5DF.js} +1 -1
- package/dist/{server-432AF6JW.js → server-33SKWAUV.js} +4 -4
- package/dist/{server-HIJQRAOG.js → server-ELFHR6KD.js} +8 -8
- package/dist/{task-orchestrator-HL2GAAGA.js → task-orchestrator-WTBUOVNZ.js} +4 -4
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UJLTBN7R.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-PVZE6NWC.js";
|
|
7
7
|
import "./chunk-PDX44BCA.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/batch.ts
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
} from "./chunk-3BICTI5M.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-Y2IWJDJA.js";
|
|
9
9
|
import {
|
|
10
10
|
getDangerLevel,
|
|
11
11
|
isFileWriteTool,
|
|
12
12
|
runTool
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-P73ARSFY.js";
|
|
14
14
|
import {
|
|
15
15
|
EnvLoader,
|
|
16
16
|
NetworkError,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
SUBAGENT_ALLOWED_TOOLS,
|
|
24
24
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
25
25
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-PVZE6NWC.js";
|
|
27
27
|
import {
|
|
28
28
|
fileCheckpoints
|
|
29
29
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -3386,6 +3386,161 @@ var webFetchTool = {
|
|
|
3386
3386
|
}
|
|
3387
3387
|
};
|
|
3388
3388
|
|
|
3389
|
+
// src/tools/builtin/web-search.ts
|
|
3390
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
3391
|
+
var MAX_RESULTS = 10;
|
|
3392
|
+
var DEFAULT_RESULTS = 5;
|
|
3393
|
+
var UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36";
|
|
3394
|
+
var webSearchTool = {
|
|
3395
|
+
definition: {
|
|
3396
|
+
name: "web_search",
|
|
3397
|
+
description: 'Search the web using Bing or Google by scraping their public result pages. No API key required, no billing risk. Returns structured {title, url, snippet} for each result. Use this for fresh facts, news, or any "what does X say about Y" lookup. Prefer this over google_search (which needs a paid API key).',
|
|
3398
|
+
parameters: {
|
|
3399
|
+
query: {
|
|
3400
|
+
type: "string",
|
|
3401
|
+
description: "The search query string.",
|
|
3402
|
+
required: true
|
|
3403
|
+
},
|
|
3404
|
+
num_results: {
|
|
3405
|
+
type: "number",
|
|
3406
|
+
description: "Number of results to return (1-10, default 5).",
|
|
3407
|
+
required: false
|
|
3408
|
+
},
|
|
3409
|
+
engine: {
|
|
3410
|
+
type: "string",
|
|
3411
|
+
description: "Search engine: 'bing' (default for CN reachability), 'google', or 'auto' (try bing first, fall back to google on empty/error). Default 'auto'.",
|
|
3412
|
+
required: false
|
|
3413
|
+
}
|
|
3414
|
+
},
|
|
3415
|
+
dangerous: false
|
|
3416
|
+
},
|
|
3417
|
+
async execute(args) {
|
|
3418
|
+
const query = String(args["query"] ?? "").trim();
|
|
3419
|
+
if (!query) throw new ToolError("web_search", "query parameter is required");
|
|
3420
|
+
const numResults = Math.min(
|
|
3421
|
+
Math.max(Math.floor(Number(args["num_results"] ?? DEFAULT_RESULTS)), 1),
|
|
3422
|
+
MAX_RESULTS
|
|
3423
|
+
);
|
|
3424
|
+
const engine = String(args["engine"] ?? "auto").toLowerCase();
|
|
3425
|
+
if (!["bing", "google", "auto"].includes(engine)) {
|
|
3426
|
+
throw new ToolError("web_search", `engine must be one of: bing, google, auto (got: ${engine})`);
|
|
3427
|
+
}
|
|
3428
|
+
const order = engine === "auto" ? ["bing", "google"] : engine === "bing" ? ["bing"] : ["google"];
|
|
3429
|
+
const errors = [];
|
|
3430
|
+
for (const eng of order) {
|
|
3431
|
+
try {
|
|
3432
|
+
const results = eng === "bing" ? await searchBing(query, numResults) : await searchGoogle(query, numResults);
|
|
3433
|
+
if (results.length > 0) {
|
|
3434
|
+
return formatResults(query, eng, results);
|
|
3435
|
+
}
|
|
3436
|
+
errors.push(`${eng}: 0 results`);
|
|
3437
|
+
} catch (err) {
|
|
3438
|
+
errors.push(`${eng}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
throw new NetworkError(
|
|
3442
|
+
`web_search failed across all engines.
|
|
3443
|
+
${errors.map((e) => " - " + e).join("\n")}
|
|
3444
|
+
Tip: a CAPTCHA wall or a result-page redesign can cause this. Try web_fetch with a specific URL, or report at https://github.com/jinzhengdong/ai-cli/issues.`
|
|
3445
|
+
);
|
|
3446
|
+
}
|
|
3447
|
+
};
|
|
3448
|
+
async function searchBing(query, num) {
|
|
3449
|
+
const url = new URL("https://cn.bing.com/search");
|
|
3450
|
+
url.searchParams.set("q", query);
|
|
3451
|
+
url.searchParams.set("count", String(num));
|
|
3452
|
+
url.searchParams.set("mkt", "zh-CN");
|
|
3453
|
+
const html = await fetchHtml(url.toString());
|
|
3454
|
+
return parseBingResults(html, num);
|
|
3455
|
+
}
|
|
3456
|
+
function parseBingResults(html, maxResults) {
|
|
3457
|
+
if (/CaptchaRedirect|sysmsg/i.test(html) && !/b_algo/.test(html)) {
|
|
3458
|
+
throw new NetworkError('Bing returned a CAPTCHA / interstitial \u2014 try again later or use engine: "google".');
|
|
3459
|
+
}
|
|
3460
|
+
const results = [];
|
|
3461
|
+
const liRegex = /<li[^>]*class="[^"]*\bb_algo\b[^"]*"[^>]*>([\s\S]*?)<\/li>/gi;
|
|
3462
|
+
let match;
|
|
3463
|
+
while ((match = liRegex.exec(html)) !== null && results.length < maxResults) {
|
|
3464
|
+
const block = match[1];
|
|
3465
|
+
const titleMatch = /<h2[^>]*>[\s\S]*?<a[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<\/h2>/i.exec(block);
|
|
3466
|
+
if (!titleMatch) continue;
|
|
3467
|
+
const url = decodeHtmlEntities(titleMatch[1]);
|
|
3468
|
+
const title = decodeHtmlEntities(stripTags2(titleMatch[2])).trim();
|
|
3469
|
+
const snippetMatch = /<p[^>]*class="[^"]*b_(lineclamp\d*|paractl|algoSlug)[^"]*"[^>]*>([\s\S]*?)<\/p>/i.exec(block) ?? /<div[^>]*class="[^"]*b_caption[^"]*"[^>]*>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/i.exec(block);
|
|
3470
|
+
const snippet = snippetMatch ? decodeHtmlEntities(stripTags2(snippetMatch[snippetMatch.length - 1])).trim() : "";
|
|
3471
|
+
if (!url || !title) continue;
|
|
3472
|
+
results.push({ title, url, snippet });
|
|
3473
|
+
}
|
|
3474
|
+
return results;
|
|
3475
|
+
}
|
|
3476
|
+
async function searchGoogle(query, num) {
|
|
3477
|
+
const url = new URL("https://www.google.com/search");
|
|
3478
|
+
url.searchParams.set("q", query);
|
|
3479
|
+
url.searchParams.set("num", String(num));
|
|
3480
|
+
url.searchParams.set("hl", "en");
|
|
3481
|
+
const html = await fetchHtml(url.toString());
|
|
3482
|
+
return parseGoogleResults(html, num);
|
|
3483
|
+
}
|
|
3484
|
+
function parseGoogleResults(html, maxResults) {
|
|
3485
|
+
if (/CaptchaRedirect|\/sorry\/index/i.test(html)) {
|
|
3486
|
+
throw new NetworkError('Google returned a CAPTCHA wall \u2014 try again later or use engine: "bing".');
|
|
3487
|
+
}
|
|
3488
|
+
const results = [];
|
|
3489
|
+
const linkRegex = /<a[^>]+href="\/url\?q=([^&"]+)[^"]*"[^>]*>[\s\S]*?<h3[^>]*>([\s\S]*?)<\/h3>([\s\S]*?)(?=<a[^>]+href="\/url\?q=|<\/body>)/gi;
|
|
3490
|
+
let match;
|
|
3491
|
+
while ((match = linkRegex.exec(html)) !== null && results.length < maxResults) {
|
|
3492
|
+
const rawUrl = decodeHtmlEntities(decodeURIComponent(match[1]));
|
|
3493
|
+
const title = decodeHtmlEntities(stripTags2(match[2])).trim();
|
|
3494
|
+
const tail = match[3] ?? "";
|
|
3495
|
+
if (!rawUrl.startsWith("http")) continue;
|
|
3496
|
+
if (/google\.com\/(images|maps|search|webhp)/i.test(rawUrl)) continue;
|
|
3497
|
+
const snippetMatch = /<span[^>]*>([\s\S]{40,400}?)<\/span>/i.exec(tail);
|
|
3498
|
+
const snippet = snippetMatch ? decodeHtmlEntities(stripTags2(snippetMatch[1])).trim() : "";
|
|
3499
|
+
results.push({ title, url: rawUrl, snippet });
|
|
3500
|
+
}
|
|
3501
|
+
return results;
|
|
3502
|
+
}
|
|
3503
|
+
async function fetchHtml(url) {
|
|
3504
|
+
const controller2 = new AbortController();
|
|
3505
|
+
const timer = setTimeout(() => controller2.abort(), REQUEST_TIMEOUT_MS);
|
|
3506
|
+
try {
|
|
3507
|
+
const res = await fetch(url, {
|
|
3508
|
+
method: "GET",
|
|
3509
|
+
headers: {
|
|
3510
|
+
"User-Agent": UA,
|
|
3511
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9",
|
|
3512
|
+
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8"
|
|
3513
|
+
},
|
|
3514
|
+
signal: controller2.signal
|
|
3515
|
+
});
|
|
3516
|
+
if (!res.ok) {
|
|
3517
|
+
throw new NetworkError(`HTTP ${res.status} ${res.statusText}`, res.status);
|
|
3518
|
+
}
|
|
3519
|
+
return await res.text();
|
|
3520
|
+
} catch (err) {
|
|
3521
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
3522
|
+
throw new NetworkError(`Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s.`, void 0, err);
|
|
3523
|
+
}
|
|
3524
|
+
throw err;
|
|
3525
|
+
} finally {
|
|
3526
|
+
clearTimeout(timer);
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
function stripTags2(html) {
|
|
3530
|
+
return html.replace(/<[^>]+>/g, "").replace(/\s+/g, " ");
|
|
3531
|
+
}
|
|
3532
|
+
function decodeHtmlEntities(s) {
|
|
3533
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(///g, "/").replace(/ /g, " ");
|
|
3534
|
+
}
|
|
3535
|
+
function formatResults(query, engine, results) {
|
|
3536
|
+
const header = `Search results for "${query}" via ${engine} (${results.length} results):
|
|
3537
|
+
`;
|
|
3538
|
+
const body = results.map((r, i) => `${i + 1}. **${r.title}**
|
|
3539
|
+
URL: ${r.url}
|
|
3540
|
+
${decodeHtmlEntities(r.snippet) || "(no snippet extracted)"}`).join("\n\n");
|
|
3541
|
+
return header + "\n" + body;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3389
3544
|
// src/tools/builtin/save-last-response.ts
|
|
3390
3545
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
3391
3546
|
import { dirname as dirname3 } from "path";
|
|
@@ -3633,14 +3788,14 @@ function renderTodoList(todos) {
|
|
|
3633
3788
|
|
|
3634
3789
|
// src/tools/builtin/google-search.ts
|
|
3635
3790
|
var GOOGLE_SEARCH_API = "https://www.googleapis.com/customsearch/v1";
|
|
3636
|
-
var
|
|
3637
|
-
var
|
|
3638
|
-
var
|
|
3791
|
+
var REQUEST_TIMEOUT_MS2 = 15e3;
|
|
3792
|
+
var MAX_RESULTS2 = 10;
|
|
3793
|
+
var DEFAULT_RESULTS2 = 5;
|
|
3639
3794
|
var googleSearchContext = {};
|
|
3640
3795
|
var googleSearchTool = {
|
|
3641
3796
|
definition: {
|
|
3642
3797
|
name: "google_search",
|
|
3643
|
-
description: "
|
|
3798
|
+
description: "\u26A0\uFE0F NOT RECOMMENDED \u2014 uses Google Custom Search API which requires a paid API key. API keys have leaked in the wild causing tens of thousands of USD in unauthorized charges. PREFER `web_search` (keyless Bing/Google scraping, zero billing risk). This tool is disabled by default; user must set config.googleSearch.enabled=true to use it.",
|
|
3644
3799
|
parameters: {
|
|
3645
3800
|
query: {
|
|
3646
3801
|
type: "string",
|
|
@@ -3658,9 +3813,16 @@ var googleSearchTool = {
|
|
|
3658
3813
|
async execute(args) {
|
|
3659
3814
|
const query = String(args["query"] ?? "").trim();
|
|
3660
3815
|
if (!query) throw new ToolError("google_search", "query parameter is required");
|
|
3816
|
+
const enabledFlag = googleSearchContext.configManager?.get("googleSearch")?.enabled ?? false;
|
|
3817
|
+
if (!enabledFlag) {
|
|
3818
|
+
throw new ToolError(
|
|
3819
|
+
"google_search",
|
|
3820
|
+
'\u{1F6AB} google_search is disabled by default (v0.4.135+).\n\nWHY: Google Custom Search has no native daily-spend cap. Keys leak (search GitHub for "AIza" \u2014 thousands of public exposures), bots scrape them within hours, and the GCP bill lands days later. Multiple engineers have lost $10k+ USD this way.\n\nRECOMMENDED: use `web_search` instead \u2014 same use case, scrapes Bing/Google public pages, zero API key, zero billing risk.\n\nIF YOU INSIST: edit ~/.aicli/config.json and set `googleSearch.enabled = true`. ALSO go to GCP Console \u2192 Custom Search API \u2192 Quotas and set a hard daily request cap (e.g. 100/day) \u2014 that is the only real damage cap.'
|
|
3821
|
+
);
|
|
3822
|
+
}
|
|
3661
3823
|
const numResults = Math.min(
|
|
3662
|
-
Math.max(Math.floor(Number(args["num_results"] ??
|
|
3663
|
-
|
|
3824
|
+
Math.max(Math.floor(Number(args["num_results"] ?? DEFAULT_RESULTS2)), 1),
|
|
3825
|
+
MAX_RESULTS2
|
|
3664
3826
|
);
|
|
3665
3827
|
const { apiKey, cx } = resolveConfig();
|
|
3666
3828
|
const url = new URL(GOOGLE_SEARCH_API);
|
|
@@ -3669,7 +3831,7 @@ var googleSearchTool = {
|
|
|
3669
3831
|
url.searchParams.set("q", query);
|
|
3670
3832
|
url.searchParams.set("num", String(numResults));
|
|
3671
3833
|
const controller2 = new AbortController();
|
|
3672
|
-
const timeout = setTimeout(() => controller2.abort(),
|
|
3834
|
+
const timeout = setTimeout(() => controller2.abort(), REQUEST_TIMEOUT_MS2);
|
|
3673
3835
|
try {
|
|
3674
3836
|
const response = await fetch(url.toString(), {
|
|
3675
3837
|
method: "GET",
|
|
@@ -3697,10 +3859,10 @@ ${errorBody.slice(0, 500)}`,
|
|
|
3697
3859
|
);
|
|
3698
3860
|
}
|
|
3699
3861
|
const data = await response.json();
|
|
3700
|
-
return
|
|
3862
|
+
return formatResults2(query, data, numResults);
|
|
3701
3863
|
} catch (err) {
|
|
3702
3864
|
if (err instanceof Error && err.name === "AbortError") {
|
|
3703
|
-
throw new NetworkError(`Google Search request timed out (${
|
|
3865
|
+
throw new NetworkError(`Google Search request timed out (${REQUEST_TIMEOUT_MS2 / 1e3}s). Please check your network or proxy configuration.`, void 0, err);
|
|
3704
3866
|
}
|
|
3705
3867
|
throw err;
|
|
3706
3868
|
} finally {
|
|
@@ -3732,7 +3894,7 @@ function resolveConfig() {
|
|
|
3732
3894
|
}
|
|
3733
3895
|
return { apiKey, cx };
|
|
3734
3896
|
}
|
|
3735
|
-
function
|
|
3897
|
+
function formatResults2(query, data, _requested) {
|
|
3736
3898
|
const items = data.items ?? [];
|
|
3737
3899
|
if (items.length === 0) {
|
|
3738
3900
|
const info2 = data.searchInformation;
|
|
@@ -5015,6 +5177,7 @@ var ToolRegistry = class {
|
|
|
5015
5177
|
this.register(globFilesTool);
|
|
5016
5178
|
this.register(runInteractiveTool);
|
|
5017
5179
|
this.register(webFetchTool);
|
|
5180
|
+
this.register(webSearchTool);
|
|
5018
5181
|
this.register(saveLastResponseTool);
|
|
5019
5182
|
this.register(saveMemoryTool);
|
|
5020
5183
|
this.register(askUserTool);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5XL4HXY5.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PVZE6NWC.js";
|
|
15
15
|
import {
|
|
16
16
|
redactJson
|
|
17
17
|
} from "./chunk-7ZJN4KLV.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CONFIG_FILE_NAME,
|
|
9
9
|
HISTORY_DIR_NAME,
|
|
10
10
|
PLUGINS_DIR_NAME
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-PVZE6NWC.js";
|
|
12
12
|
|
|
13
13
|
// src/config/config-manager.ts
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -127,6 +127,18 @@ var ConfigSchema = z.object({
|
|
|
127
127
|
// API Key 通过 apiKeys['google-search'] 或 AICLI_API_KEY_GOOGLESEARCH 环境变量配置
|
|
128
128
|
// CX 也可通过 AICLI_GOOGLE_CX 环境变量覆盖
|
|
129
129
|
googleSearchEngineId: z.string().optional(),
|
|
130
|
+
// google_search 工具的安全开关(v0.4.135+)
|
|
131
|
+
// 默认 disabled。这个工具调用 Google Custom Search API,没有原生 daily-spend cap——
|
|
132
|
+
// 业内有多起 key 被盗后产生数万美元账单的真实案例。现在内置 web_search 工具走 Bing/Google
|
|
133
|
+
// 公开搜索页 scraping,零 key 零账单,是大多数场景下的默认选择。
|
|
134
|
+
// 仍想用 API 版?把 enabled 设为 true,并务必到 GCP Console 把 Custom Search Quota 设硬上限。
|
|
135
|
+
googleSearch: z.object({
|
|
136
|
+
enabled: z.boolean().default(false)
|
|
137
|
+
}).default({ enabled: false }),
|
|
138
|
+
// MCP (Model Context Protocol) 全局开关(v0.4.135+)
|
|
139
|
+
// false 时启动跳过 connectAll(),所有 MCP 服务器都不连,节省冷启动时间 + 工具定义 token。
|
|
140
|
+
// 对应你的 skills(whitelist 不依赖 MCP 工具时)完全不受影响。
|
|
141
|
+
mcpEnabled: z.boolean().default(true),
|
|
130
142
|
// MCP (Model Context Protocol) 服务器配置
|
|
131
143
|
// 声明外部 MCP 服务器,启动时自动连接、发现工具并注册
|
|
132
144
|
// 配置格式兼容 Claude Desktop(command + args + env)
|
|
@@ -2,25 +2,25 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfigDirUsage,
|
|
4
4
|
listRecentCrashes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BS6JUZPS.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderRegistry
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NCZWD2KK.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigManager
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-UJLTBN7R.js";
|
|
12
12
|
import {
|
|
13
13
|
getStatsSnapshot,
|
|
14
14
|
getTopFailingTools,
|
|
15
15
|
getTopUsedTools,
|
|
16
16
|
resetStats
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-P73ARSFY.js";
|
|
18
18
|
import "./chunk-2ZD3YTVM.js";
|
|
19
19
|
import {
|
|
20
20
|
DEV_STATE_FILE_NAME,
|
|
21
21
|
MEMORY_FILE_NAME,
|
|
22
22
|
VERSION
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-PVZE6NWC.js";
|
|
24
24
|
import "./chunk-PDX44BCA.js";
|
|
25
25
|
|
|
26
26
|
// src/diagnostics/doctor-cli.ts
|
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-OMB3XLCV.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -178,6 +178,18 @@ var ConfigSchema = z.object({
|
|
|
178
178
|
// API Key 通过 apiKeys['google-search'] 或 AICLI_API_KEY_GOOGLESEARCH 环境变量配置
|
|
179
179
|
// CX 也可通过 AICLI_GOOGLE_CX 环境变量覆盖
|
|
180
180
|
googleSearchEngineId: z.string().optional(),
|
|
181
|
+
// google_search 工具的安全开关(v0.4.135+)
|
|
182
|
+
// 默认 disabled。这个工具调用 Google Custom Search API,没有原生 daily-spend cap——
|
|
183
|
+
// 业内有多起 key 被盗后产生数万美元账单的真实案例。现在内置 web_search 工具走 Bing/Google
|
|
184
|
+
// 公开搜索页 scraping,零 key 零账单,是大多数场景下的默认选择。
|
|
185
|
+
// 仍想用 API 版?把 enabled 设为 true,并务必到 GCP Console 把 Custom Search Quota 设硬上限。
|
|
186
|
+
googleSearch: z.object({
|
|
187
|
+
enabled: z.boolean().default(false)
|
|
188
|
+
}).default({ enabled: false }),
|
|
189
|
+
// MCP (Model Context Protocol) 全局开关(v0.4.135+)
|
|
190
|
+
// false 时启动跳过 connectAll(),所有 MCP 服务器都不连,节省冷启动时间 + 工具定义 token。
|
|
191
|
+
// 对应你的 skills(whitelist 不依赖 MCP 工具时)完全不受影响。
|
|
192
|
+
mcpEnabled: z.boolean().default(true),
|
|
181
193
|
// MCP (Model Context Protocol) 服务器配置
|
|
182
194
|
// 声明外部 MCP 服务器,启动时自动连接、发现工具并注册
|
|
183
195
|
// 配置格式兼容 Claude Desktop(command + args + env)
|
|
@@ -7070,6 +7082,161 @@ var webFetchTool = {
|
|
|
7070
7082
|
}
|
|
7071
7083
|
};
|
|
7072
7084
|
|
|
7085
|
+
// src/tools/builtin/web-search.ts
|
|
7086
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
7087
|
+
var MAX_RESULTS = 10;
|
|
7088
|
+
var DEFAULT_RESULTS = 5;
|
|
7089
|
+
var UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36";
|
|
7090
|
+
var webSearchTool = {
|
|
7091
|
+
definition: {
|
|
7092
|
+
name: "web_search",
|
|
7093
|
+
description: 'Search the web using Bing or Google by scraping their public result pages. No API key required, no billing risk. Returns structured {title, url, snippet} for each result. Use this for fresh facts, news, or any "what does X say about Y" lookup. Prefer this over google_search (which needs a paid API key).',
|
|
7094
|
+
parameters: {
|
|
7095
|
+
query: {
|
|
7096
|
+
type: "string",
|
|
7097
|
+
description: "The search query string.",
|
|
7098
|
+
required: true
|
|
7099
|
+
},
|
|
7100
|
+
num_results: {
|
|
7101
|
+
type: "number",
|
|
7102
|
+
description: "Number of results to return (1-10, default 5).",
|
|
7103
|
+
required: false
|
|
7104
|
+
},
|
|
7105
|
+
engine: {
|
|
7106
|
+
type: "string",
|
|
7107
|
+
description: "Search engine: 'bing' (default for CN reachability), 'google', or 'auto' (try bing first, fall back to google on empty/error). Default 'auto'.",
|
|
7108
|
+
required: false
|
|
7109
|
+
}
|
|
7110
|
+
},
|
|
7111
|
+
dangerous: false
|
|
7112
|
+
},
|
|
7113
|
+
async execute(args) {
|
|
7114
|
+
const query = String(args["query"] ?? "").trim();
|
|
7115
|
+
if (!query) throw new ToolError("web_search", "query parameter is required");
|
|
7116
|
+
const numResults = Math.min(
|
|
7117
|
+
Math.max(Math.floor(Number(args["num_results"] ?? DEFAULT_RESULTS)), 1),
|
|
7118
|
+
MAX_RESULTS
|
|
7119
|
+
);
|
|
7120
|
+
const engine = String(args["engine"] ?? "auto").toLowerCase();
|
|
7121
|
+
if (!["bing", "google", "auto"].includes(engine)) {
|
|
7122
|
+
throw new ToolError("web_search", `engine must be one of: bing, google, auto (got: ${engine})`);
|
|
7123
|
+
}
|
|
7124
|
+
const order = engine === "auto" ? ["bing", "google"] : engine === "bing" ? ["bing"] : ["google"];
|
|
7125
|
+
const errors = [];
|
|
7126
|
+
for (const eng of order) {
|
|
7127
|
+
try {
|
|
7128
|
+
const results = eng === "bing" ? await searchBing(query, numResults) : await searchGoogle(query, numResults);
|
|
7129
|
+
if (results.length > 0) {
|
|
7130
|
+
return formatResults(query, eng, results);
|
|
7131
|
+
}
|
|
7132
|
+
errors.push(`${eng}: 0 results`);
|
|
7133
|
+
} catch (err) {
|
|
7134
|
+
errors.push(`${eng}: ${err instanceof Error ? err.message : String(err)}`);
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
throw new NetworkError(
|
|
7138
|
+
`web_search failed across all engines.
|
|
7139
|
+
${errors.map((e) => " - " + e).join("\n")}
|
|
7140
|
+
Tip: a CAPTCHA wall or a result-page redesign can cause this. Try web_fetch with a specific URL, or report at https://github.com/jinzhengdong/ai-cli/issues.`
|
|
7141
|
+
);
|
|
7142
|
+
}
|
|
7143
|
+
};
|
|
7144
|
+
async function searchBing(query, num) {
|
|
7145
|
+
const url = new URL("https://cn.bing.com/search");
|
|
7146
|
+
url.searchParams.set("q", query);
|
|
7147
|
+
url.searchParams.set("count", String(num));
|
|
7148
|
+
url.searchParams.set("mkt", "zh-CN");
|
|
7149
|
+
const html = await fetchHtml(url.toString());
|
|
7150
|
+
return parseBingResults(html, num);
|
|
7151
|
+
}
|
|
7152
|
+
function parseBingResults(html, maxResults) {
|
|
7153
|
+
if (/CaptchaRedirect|sysmsg/i.test(html) && !/b_algo/.test(html)) {
|
|
7154
|
+
throw new NetworkError('Bing returned a CAPTCHA / interstitial \u2014 try again later or use engine: "google".');
|
|
7155
|
+
}
|
|
7156
|
+
const results = [];
|
|
7157
|
+
const liRegex = /<li[^>]*class="[^"]*\bb_algo\b[^"]*"[^>]*>([\s\S]*?)<\/li>/gi;
|
|
7158
|
+
let match;
|
|
7159
|
+
while ((match = liRegex.exec(html)) !== null && results.length < maxResults) {
|
|
7160
|
+
const block = match[1];
|
|
7161
|
+
const titleMatch = /<h2[^>]*>[\s\S]*?<a[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<\/h2>/i.exec(block);
|
|
7162
|
+
if (!titleMatch) continue;
|
|
7163
|
+
const url = decodeHtmlEntities(titleMatch[1]);
|
|
7164
|
+
const title = decodeHtmlEntities(stripTags2(titleMatch[2])).trim();
|
|
7165
|
+
const snippetMatch = /<p[^>]*class="[^"]*b_(lineclamp\d*|paractl|algoSlug)[^"]*"[^>]*>([\s\S]*?)<\/p>/i.exec(block) ?? /<div[^>]*class="[^"]*b_caption[^"]*"[^>]*>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/i.exec(block);
|
|
7166
|
+
const snippet = snippetMatch ? decodeHtmlEntities(stripTags2(snippetMatch[snippetMatch.length - 1])).trim() : "";
|
|
7167
|
+
if (!url || !title) continue;
|
|
7168
|
+
results.push({ title, url, snippet });
|
|
7169
|
+
}
|
|
7170
|
+
return results;
|
|
7171
|
+
}
|
|
7172
|
+
async function searchGoogle(query, num) {
|
|
7173
|
+
const url = new URL("https://www.google.com/search");
|
|
7174
|
+
url.searchParams.set("q", query);
|
|
7175
|
+
url.searchParams.set("num", String(num));
|
|
7176
|
+
url.searchParams.set("hl", "en");
|
|
7177
|
+
const html = await fetchHtml(url.toString());
|
|
7178
|
+
return parseGoogleResults(html, num);
|
|
7179
|
+
}
|
|
7180
|
+
function parseGoogleResults(html, maxResults) {
|
|
7181
|
+
if (/CaptchaRedirect|\/sorry\/index/i.test(html)) {
|
|
7182
|
+
throw new NetworkError('Google returned a CAPTCHA wall \u2014 try again later or use engine: "bing".');
|
|
7183
|
+
}
|
|
7184
|
+
const results = [];
|
|
7185
|
+
const linkRegex = /<a[^>]+href="\/url\?q=([^&"]+)[^"]*"[^>]*>[\s\S]*?<h3[^>]*>([\s\S]*?)<\/h3>([\s\S]*?)(?=<a[^>]+href="\/url\?q=|<\/body>)/gi;
|
|
7186
|
+
let match;
|
|
7187
|
+
while ((match = linkRegex.exec(html)) !== null && results.length < maxResults) {
|
|
7188
|
+
const rawUrl = decodeHtmlEntities(decodeURIComponent(match[1]));
|
|
7189
|
+
const title = decodeHtmlEntities(stripTags2(match[2])).trim();
|
|
7190
|
+
const tail = match[3] ?? "";
|
|
7191
|
+
if (!rawUrl.startsWith("http")) continue;
|
|
7192
|
+
if (/google\.com\/(images|maps|search|webhp)/i.test(rawUrl)) continue;
|
|
7193
|
+
const snippetMatch = /<span[^>]*>([\s\S]{40,400}?)<\/span>/i.exec(tail);
|
|
7194
|
+
const snippet = snippetMatch ? decodeHtmlEntities(stripTags2(snippetMatch[1])).trim() : "";
|
|
7195
|
+
results.push({ title, url: rawUrl, snippet });
|
|
7196
|
+
}
|
|
7197
|
+
return results;
|
|
7198
|
+
}
|
|
7199
|
+
async function fetchHtml(url) {
|
|
7200
|
+
const controller2 = new AbortController();
|
|
7201
|
+
const timer = setTimeout(() => controller2.abort(), REQUEST_TIMEOUT_MS);
|
|
7202
|
+
try {
|
|
7203
|
+
const res = await fetch(url, {
|
|
7204
|
+
method: "GET",
|
|
7205
|
+
headers: {
|
|
7206
|
+
"User-Agent": UA,
|
|
7207
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9",
|
|
7208
|
+
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8"
|
|
7209
|
+
},
|
|
7210
|
+
signal: controller2.signal
|
|
7211
|
+
});
|
|
7212
|
+
if (!res.ok) {
|
|
7213
|
+
throw new NetworkError(`HTTP ${res.status} ${res.statusText}`, res.status);
|
|
7214
|
+
}
|
|
7215
|
+
return await res.text();
|
|
7216
|
+
} catch (err) {
|
|
7217
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
7218
|
+
throw new NetworkError(`Request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s.`, void 0, err);
|
|
7219
|
+
}
|
|
7220
|
+
throw err;
|
|
7221
|
+
} finally {
|
|
7222
|
+
clearTimeout(timer);
|
|
7223
|
+
}
|
|
7224
|
+
}
|
|
7225
|
+
function stripTags2(html) {
|
|
7226
|
+
return html.replace(/<[^>]+>/g, "").replace(/\s+/g, " ");
|
|
7227
|
+
}
|
|
7228
|
+
function decodeHtmlEntities(s) {
|
|
7229
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(///g, "/").replace(/ /g, " ");
|
|
7230
|
+
}
|
|
7231
|
+
function formatResults(query, engine, results) {
|
|
7232
|
+
const header = `Search results for "${query}" via ${engine} (${results.length} results):
|
|
7233
|
+
`;
|
|
7234
|
+
const body = results.map((r, i) => `${i + 1}. **${r.title}**
|
|
7235
|
+
URL: ${r.url}
|
|
7236
|
+
${decodeHtmlEntities(r.snippet) || "(no snippet extracted)"}`).join("\n\n");
|
|
7237
|
+
return header + "\n" + body;
|
|
7238
|
+
}
|
|
7239
|
+
|
|
7073
7240
|
// src/tools/builtin/save-last-response.ts
|
|
7074
7241
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
7075
7242
|
import { dirname as dirname4 } from "path";
|
|
@@ -7317,14 +7484,14 @@ function renderTodoList(todos) {
|
|
|
7317
7484
|
|
|
7318
7485
|
// src/tools/builtin/google-search.ts
|
|
7319
7486
|
var GOOGLE_SEARCH_API = "https://www.googleapis.com/customsearch/v1";
|
|
7320
|
-
var
|
|
7321
|
-
var
|
|
7322
|
-
var
|
|
7487
|
+
var REQUEST_TIMEOUT_MS2 = 15e3;
|
|
7488
|
+
var MAX_RESULTS2 = 10;
|
|
7489
|
+
var DEFAULT_RESULTS2 = 5;
|
|
7323
7490
|
var googleSearchContext = {};
|
|
7324
7491
|
var googleSearchTool = {
|
|
7325
7492
|
definition: {
|
|
7326
7493
|
name: "google_search",
|
|
7327
|
-
description: "
|
|
7494
|
+
description: "\u26A0\uFE0F NOT RECOMMENDED \u2014 uses Google Custom Search API which requires a paid API key. API keys have leaked in the wild causing tens of thousands of USD in unauthorized charges. PREFER `web_search` (keyless Bing/Google scraping, zero billing risk). This tool is disabled by default; user must set config.googleSearch.enabled=true to use it.",
|
|
7328
7495
|
parameters: {
|
|
7329
7496
|
query: {
|
|
7330
7497
|
type: "string",
|
|
@@ -7342,9 +7509,16 @@ var googleSearchTool = {
|
|
|
7342
7509
|
async execute(args) {
|
|
7343
7510
|
const query = String(args["query"] ?? "").trim();
|
|
7344
7511
|
if (!query) throw new ToolError("google_search", "query parameter is required");
|
|
7512
|
+
const enabledFlag = googleSearchContext.configManager?.get("googleSearch")?.enabled ?? false;
|
|
7513
|
+
if (!enabledFlag) {
|
|
7514
|
+
throw new ToolError(
|
|
7515
|
+
"google_search",
|
|
7516
|
+
'\u{1F6AB} google_search is disabled by default (v0.4.135+).\n\nWHY: Google Custom Search has no native daily-spend cap. Keys leak (search GitHub for "AIza" \u2014 thousands of public exposures), bots scrape them within hours, and the GCP bill lands days later. Multiple engineers have lost $10k+ USD this way.\n\nRECOMMENDED: use `web_search` instead \u2014 same use case, scrapes Bing/Google public pages, zero API key, zero billing risk.\n\nIF YOU INSIST: edit ~/.aicli/config.json and set `googleSearch.enabled = true`. ALSO go to GCP Console \u2192 Custom Search API \u2192 Quotas and set a hard daily request cap (e.g. 100/day) \u2014 that is the only real damage cap.'
|
|
7517
|
+
);
|
|
7518
|
+
}
|
|
7345
7519
|
const numResults = Math.min(
|
|
7346
|
-
Math.max(Math.floor(Number(args["num_results"] ??
|
|
7347
|
-
|
|
7520
|
+
Math.max(Math.floor(Number(args["num_results"] ?? DEFAULT_RESULTS2)), 1),
|
|
7521
|
+
MAX_RESULTS2
|
|
7348
7522
|
);
|
|
7349
7523
|
const { apiKey, cx } = resolveConfig();
|
|
7350
7524
|
const url = new URL(GOOGLE_SEARCH_API);
|
|
@@ -7353,7 +7527,7 @@ var googleSearchTool = {
|
|
|
7353
7527
|
url.searchParams.set("q", query);
|
|
7354
7528
|
url.searchParams.set("num", String(numResults));
|
|
7355
7529
|
const controller2 = new AbortController();
|
|
7356
|
-
const timeout = setTimeout(() => controller2.abort(),
|
|
7530
|
+
const timeout = setTimeout(() => controller2.abort(), REQUEST_TIMEOUT_MS2);
|
|
7357
7531
|
try {
|
|
7358
7532
|
const response = await fetch(url.toString(), {
|
|
7359
7533
|
method: "GET",
|
|
@@ -7381,10 +7555,10 @@ ${errorBody.slice(0, 500)}`,
|
|
|
7381
7555
|
);
|
|
7382
7556
|
}
|
|
7383
7557
|
const data = await response.json();
|
|
7384
|
-
return
|
|
7558
|
+
return formatResults2(query, data, numResults);
|
|
7385
7559
|
} catch (err) {
|
|
7386
7560
|
if (err instanceof Error && err.name === "AbortError") {
|
|
7387
|
-
throw new NetworkError(`Google Search request timed out (${
|
|
7561
|
+
throw new NetworkError(`Google Search request timed out (${REQUEST_TIMEOUT_MS2 / 1e3}s). Please check your network or proxy configuration.`, void 0, err);
|
|
7388
7562
|
}
|
|
7389
7563
|
throw err;
|
|
7390
7564
|
} finally {
|
|
@@ -7416,7 +7590,7 @@ function resolveConfig() {
|
|
|
7416
7590
|
}
|
|
7417
7591
|
return { apiKey, cx };
|
|
7418
7592
|
}
|
|
7419
|
-
function
|
|
7593
|
+
function formatResults2(query, data, _requested) {
|
|
7420
7594
|
const items = data.items ?? [];
|
|
7421
7595
|
if (items.length === 0) {
|
|
7422
7596
|
const info2 = data.searchInformation;
|
|
@@ -8699,6 +8873,7 @@ var ToolRegistry = class {
|
|
|
8699
8873
|
this.register(globFilesTool);
|
|
8700
8874
|
this.register(runInteractiveTool);
|
|
8701
8875
|
this.register(webFetchTool);
|
|
8876
|
+
this.register(webSearchTool);
|
|
8702
8877
|
this.register(saveLastResponseTool);
|
|
8703
8878
|
this.register(saveMemoryTool);
|
|
8704
8879
|
this.register(askUserTool);
|
|
@@ -12219,7 +12394,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
12219
12394
|
case "test": {
|
|
12220
12395
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
12221
12396
|
try {
|
|
12222
|
-
const { executeTests } = await import("./run-tests-
|
|
12397
|
+
const { executeTests } = await import("./run-tests-P436Z5DF.js");
|
|
12223
12398
|
const argStr = args.join(" ").trim();
|
|
12224
12399
|
let testArgs = {};
|
|
12225
12400
|
if (argStr) {
|
|
@@ -386,7 +386,7 @@ ${content}`);
|
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
389
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
389
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-WTBUOVNZ.js");
|
|
390
390
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
391
391
|
let interrupted = false;
|
|
392
392
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -16,12 +16,12 @@ import {
|
|
|
16
16
|
saveDevState,
|
|
17
17
|
sessionHasMeaningfulContent,
|
|
18
18
|
setupProxy
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SUJFSZ6U.js";
|
|
20
20
|
import {
|
|
21
21
|
getConfigDirUsage,
|
|
22
22
|
listRecentCrashes,
|
|
23
23
|
writeCrashLog
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-BS6JUZPS.js";
|
|
25
25
|
import {
|
|
26
26
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
27
27
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
looksLikeDocumentBody,
|
|
40
40
|
stripPseudoToolCalls,
|
|
41
41
|
stripToolCallReminder
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-NCZWD2KK.js";
|
|
43
43
|
import {
|
|
44
44
|
ConfigManager
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-UJLTBN7R.js";
|
|
46
46
|
import {
|
|
47
47
|
ToolExecutor,
|
|
48
48
|
ToolRegistry,
|
|
@@ -61,16 +61,16 @@ import {
|
|
|
61
61
|
spawnAgentContext,
|
|
62
62
|
theme,
|
|
63
63
|
undoStack
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-5XL4HXY5.js";
|
|
65
65
|
import "./chunk-3BICTI5M.js";
|
|
66
66
|
import "./chunk-2DXY7UGF.js";
|
|
67
|
-
import "./chunk-
|
|
67
|
+
import "./chunk-Y2IWJDJA.js";
|
|
68
68
|
import {
|
|
69
69
|
getStatsSnapshot,
|
|
70
70
|
getTopFailingTools,
|
|
71
71
|
getTopUsedTools,
|
|
72
72
|
installFlushOnExit
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-P73ARSFY.js";
|
|
74
74
|
import "./chunk-2ZD3YTVM.js";
|
|
75
75
|
import {
|
|
76
76
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
SKILLS_DIR_NAME,
|
|
94
94
|
VERSION,
|
|
95
95
|
buildUserIdentityPrompt
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-PVZE6NWC.js";
|
|
97
97
|
import {
|
|
98
98
|
formatGitContextForPrompt,
|
|
99
99
|
getGitContext,
|
|
@@ -1812,7 +1812,7 @@ No tools match "${filter}".
|
|
|
1812
1812
|
const { join: join6 } = await import("path");
|
|
1813
1813
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1814
1814
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1815
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1815
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-7LFVO52M.js");
|
|
1816
1816
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1817
1817
|
const cwd = process.cwd();
|
|
1818
1818
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2873,7 +2873,7 @@ ${hint}` : "")
|
|
|
2873
2873
|
usage: "/test [command|filter]",
|
|
2874
2874
|
async execute(args, ctx) {
|
|
2875
2875
|
try {
|
|
2876
|
-
const { executeTests } = await import("./run-tests-
|
|
2876
|
+
const { executeTests } = await import("./run-tests-7VI5TCNL.js");
|
|
2877
2877
|
const argStr = args.join(" ").trim();
|
|
2878
2878
|
let testArgs = {};
|
|
2879
2879
|
if (argStr) {
|
|
@@ -5429,8 +5429,12 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5429
5429
|
} catch {
|
|
5430
5430
|
}
|
|
5431
5431
|
})();
|
|
5432
|
-
const
|
|
5433
|
-
const
|
|
5432
|
+
const mcpEnabled = this.config.get("mcpEnabled") !== false;
|
|
5433
|
+
const globalMcpServers = mcpEnabled ? this.config.get("mcpServers") ?? {} : {};
|
|
5434
|
+
const projectMcpResult = mcpEnabled ? this.loadProjectMcpConfig() : null;
|
|
5435
|
+
if (!mcpEnabled) {
|
|
5436
|
+
process.stdout.write(theme.dim(" \u{1F50C} MCP: disabled (config.mcpEnabled=false)\n"));
|
|
5437
|
+
}
|
|
5434
5438
|
let projectMcpServers = {};
|
|
5435
5439
|
if (projectMcpResult) {
|
|
5436
5440
|
const { checkTrust } = await import("./project-trust-IFM7FXEV.js");
|
|
@@ -7323,7 +7327,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7323
7327
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7324
7328
|
process.exit(1);
|
|
7325
7329
|
}
|
|
7326
|
-
const { startWebServer } = await import("./server-
|
|
7330
|
+
const { startWebServer } = await import("./server-ELFHR6KD.js");
|
|
7327
7331
|
await startWebServer({ port, host: options.host });
|
|
7328
7332
|
});
|
|
7329
7333
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -7490,12 +7494,12 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7490
7494
|
console.log(footer + "\n");
|
|
7491
7495
|
});
|
|
7492
7496
|
program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
|
|
7493
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7497
|
+
const { runDoctorCli } = await import("./doctor-cli-4FQM4BHM.js");
|
|
7494
7498
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7495
7499
|
});
|
|
7496
7500
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
7497
7501
|
try {
|
|
7498
|
-
const batch = await import("./batch-
|
|
7502
|
+
const batch = await import("./batch-NOEJSHCZ.js");
|
|
7499
7503
|
switch (action) {
|
|
7500
7504
|
case "submit":
|
|
7501
7505
|
if (!arg) {
|
|
@@ -7538,7 +7542,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7538
7542
|
}
|
|
7539
7543
|
});
|
|
7540
7544
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
7541
|
-
const { startMcpServer } = await import("./server-
|
|
7545
|
+
const { startMcpServer } = await import("./server-33SKWAUV.js");
|
|
7542
7546
|
await startMcpServer({
|
|
7543
7547
|
allowDestructive: !!options.allowDestructive,
|
|
7544
7548
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7665,7 +7669,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7665
7669
|
}),
|
|
7666
7670
|
config.get("customProviders")
|
|
7667
7671
|
);
|
|
7668
|
-
const { startHub } = await import("./hub-
|
|
7672
|
+
const { startHub } = await import("./hub-JJF5BNY4.js");
|
|
7669
7673
|
await startHub(
|
|
7670
7674
|
{
|
|
7671
7675
|
topic: topic ?? "",
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5XL4HXY5.js";
|
|
5
5
|
import "./chunk-3BICTI5M.js";
|
|
6
6
|
import "./chunk-2DXY7UGF.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-Y2IWJDJA.js";
|
|
8
8
|
import {
|
|
9
9
|
getDangerLevel,
|
|
10
10
|
runTool,
|
|
11
11
|
schemaToJsonSchema
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-P73ARSFY.js";
|
|
13
13
|
import "./chunk-2ZD3YTVM.js";
|
|
14
14
|
import {
|
|
15
15
|
VERSION
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-PVZE6NWC.js";
|
|
17
17
|
import "./chunk-4BKXL7SM.js";
|
|
18
18
|
import "./chunk-7ZJN4KLV.js";
|
|
19
19
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
loadDevState,
|
|
15
15
|
persistToolRound,
|
|
16
16
|
setupProxy
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-SUJFSZ6U.js";
|
|
18
18
|
import {
|
|
19
19
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
20
20
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
@@ -28,10 +28,10 @@ import {
|
|
|
28
28
|
looksLikeDocumentBody,
|
|
29
29
|
stripPseudoToolCalls,
|
|
30
30
|
stripToolCallReminder
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-NCZWD2KK.js";
|
|
32
32
|
import {
|
|
33
33
|
ConfigManager
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-UJLTBN7R.js";
|
|
35
35
|
import {
|
|
36
36
|
ToolExecutor,
|
|
37
37
|
ToolRegistry,
|
|
@@ -49,14 +49,14 @@ import {
|
|
|
49
49
|
spawnAgentContext,
|
|
50
50
|
truncateOutput,
|
|
51
51
|
undoStack
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-5XL4HXY5.js";
|
|
53
53
|
import "./chunk-3BICTI5M.js";
|
|
54
54
|
import "./chunk-2DXY7UGF.js";
|
|
55
|
-
import "./chunk-
|
|
55
|
+
import "./chunk-Y2IWJDJA.js";
|
|
56
56
|
import {
|
|
57
57
|
getDangerLevel,
|
|
58
58
|
runTool
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-P73ARSFY.js";
|
|
60
60
|
import "./chunk-2ZD3YTVM.js";
|
|
61
61
|
import {
|
|
62
62
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
SKILLS_DIR_NAME,
|
|
77
77
|
VERSION,
|
|
78
78
|
buildUserIdentityPrompt
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-PVZE6NWC.js";
|
|
80
80
|
import {
|
|
81
81
|
formatGitContextForPrompt,
|
|
82
82
|
getGitContext,
|
|
@@ -2460,7 +2460,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2460
2460
|
case "test": {
|
|
2461
2461
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2462
2462
|
try {
|
|
2463
|
-
const { executeTests } = await import("./run-tests-
|
|
2463
|
+
const { executeTests } = await import("./run-tests-7VI5TCNL.js");
|
|
2464
2464
|
const argStr = args.join(" ").trim();
|
|
2465
2465
|
let testArgs = {};
|
|
2466
2466
|
if (argStr) {
|
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
googleSearchContext,
|
|
5
5
|
truncateOutput
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5XL4HXY5.js";
|
|
7
7
|
import "./chunk-3BICTI5M.js";
|
|
8
8
|
import "./chunk-2DXY7UGF.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-Y2IWJDJA.js";
|
|
10
10
|
import {
|
|
11
11
|
getDangerLevel,
|
|
12
12
|
runTool
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-P73ARSFY.js";
|
|
14
14
|
import "./chunk-2ZD3YTVM.js";
|
|
15
15
|
import {
|
|
16
16
|
SUBAGENT_ALLOWED_TOOLS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-PVZE6NWC.js";
|
|
18
18
|
import "./chunk-4BKXL7SM.js";
|
|
19
19
|
import "./chunk-7ZJN4KLV.js";
|
|
20
20
|
import "./chunk-KHYD3WXE.js";
|