@24klynx/tools 0.1.2 → 0.1.5

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/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { ToolError } from "@24klynx/core";
2
- import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
1
+ import { NotImplementedError, ToolError } from "@24klynx/core";
2
+ import { mkdir, readFile, readdir, stat } from "node:fs/promises";
3
+ import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
3
4
  import { dirname, join, relative, resolve } from "node:path";
4
5
  import { exec, execFile, spawn } from "node:child_process";
5
6
  import { promisify } from "node:util";
6
- import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from "node:fs";
7
7
  import { randomUUID } from "node:crypto";
8
- import { homedir } from "node:os";
8
+ import { homedir, tmpdir } from "node:os";
9
9
  //#region src/availability.ts
10
10
  function evalAlways() {
11
11
  return { available: true };
@@ -166,7 +166,7 @@ function createToolRegistry() {
166
166
  *
167
167
  * Limits: 2000 lines per call, binary files return MIME + base64.
168
168
  */
169
- const descriptor$33 = {
169
+ const descriptor$38 = {
170
170
  name: "read_file",
171
171
  description: "读取文件内容。支持 offset/limit 分页。二进制和图片文件以 base64 编码数据加 MIME 类型返回。",
172
172
  inputSchema: {
@@ -233,13 +233,23 @@ const TEXT_EXTENSIONS = new Set([
233
233
  ".proto",
234
234
  ".vue",
235
235
  ".svelte",
236
- ".astro"
236
+ ".astro",
237
+ ""
238
+ ]);
239
+ /** Common files without extensions that should be treated as text. */
240
+ const TEXT_FILENAMES = new Set([
241
+ "dockerfile",
242
+ "makefile",
243
+ "license",
244
+ "changelog"
237
245
  ]);
238
246
  function isTextExtension(filePath) {
239
247
  const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
240
- return TEXT_EXTENSIONS.has(ext);
248
+ if (TEXT_EXTENSIONS.has(ext)) return true;
249
+ const basename = filePath.slice(filePath.lastIndexOf("/") + 1).toLowerCase();
250
+ return TEXT_FILENAMES.has(basename);
241
251
  }
242
- const handler$30 = { async handle(invocation, signal) {
252
+ const handler$31 = { async handle(invocation, signal) {
243
253
  const { file_path, offset, limit } = invocation.payload;
244
254
  const startTime = Date.now();
245
255
  if (signal.aborted) return {
@@ -337,7 +347,7 @@ function guessMime(filePath) {
337
347
  * Creates parent directories automatically. Overwrites existing files
338
348
  * without asking (permission pipeline handles safety).
339
349
  */
340
- const descriptor$32 = {
350
+ const descriptor$37 = {
341
351
  name: "write_file",
342
352
  description: "创建新文件或完全覆盖已有文件。父目录不存在时会自动创建。",
343
353
  inputSchema: {
@@ -360,7 +370,7 @@ const descriptor$32 = {
360
370
  executor: "core:write_file",
361
371
  owner: "core"
362
372
  };
363
- const handler$29 = { async handle(invocation, signal) {
373
+ const handler$30 = { async handle(invocation, signal) {
364
374
  const { file_path, content } = invocation.payload;
365
375
  const startTime = Date.now();
366
376
  if (signal.aborted) return {
@@ -370,7 +380,9 @@ const handler$29 = { async handle(invocation, signal) {
370
380
  };
371
381
  try {
372
382
  await mkdir(dirname(file_path), { recursive: true });
373
- await writeFile(file_path, content, "utf-8");
383
+ const tmpPath = file_path + ".tmp";
384
+ writeFileSync(tmpPath, content, "utf-8");
385
+ renameSync(tmpPath, file_path);
374
386
  return {
375
387
  success: true,
376
388
  content: `已写入 ${content.length} 字节到 ${file_path}`,
@@ -393,7 +405,7 @@ const handler$29 = { async handle(invocation, signal) {
393
405
  * This is the primary editing tool — LLMs should use it instead of write_file
394
406
  * for targeted changes.
395
407
  */
396
- const descriptor$31 = {
408
+ const descriptor$36 = {
397
409
  name: "edit_file",
398
410
  description: "在文件中执行精确字符串替换。old_string 必须在文件中精确匹配(包括空格和缩进),除非设置 replace_all 为 true。",
399
411
  inputSchema: {
@@ -428,7 +440,7 @@ const descriptor$31 = {
428
440
  executor: "core:edit_file",
429
441
  owner: "core"
430
442
  };
431
- const handler$28 = { async handle(invocation, signal) {
443
+ const handler$29 = { async handle(invocation, signal) {
432
444
  const { file_path, old_string, new_string, replace_all } = invocation.payload;
433
445
  const startTime = Date.now();
434
446
  if (signal.aborted) return {
@@ -454,7 +466,10 @@ const handler$28 = { async handle(invocation, signal) {
454
466
  content: `old_string 在 ${file_path} 中出现了 ${count} 次。请设置 replace_all: true 替换所有匹配项,或提供更多上下文使匹配唯一。`,
455
467
  metadata: { durationMs: Date.now() - startTime }
456
468
  };
457
- await writeFile(file_path, replace_all ? original.replaceAll(old_string, new_string) : original.replace(old_string, new_string), "utf-8");
469
+ const updated = replace_all ? original.replaceAll(old_string, new_string) : original.replace(old_string, new_string);
470
+ const tmpPath = file_path + ".tmp";
471
+ writeFileSync(tmpPath, updated, "utf-8");
472
+ renameSync(tmpPath, file_path);
458
473
  return {
459
474
  success: true,
460
475
  content: `已在 ${file_path} 中替换 ${replace_all ? count : 1} 处`,
@@ -491,7 +506,7 @@ function countOccurrences$1(haystack, needle) {
491
506
  *
492
507
  * Returns sorted absolute paths. Default excludes: node_modules, .git, dist, build.
493
508
  */
494
- const descriptor$30 = {
509
+ const descriptor$35 = {
495
510
  name: "glob",
496
511
  description: "用 glob 模式匹配文件。返回排序后的绝对路径。支持 ** 递归匹配、* 通配符。",
497
512
  inputSchema: {
@@ -526,7 +541,7 @@ const DEFAULT_EXCLUDE = new Set([
526
541
  "venv"
527
542
  ]);
528
543
  const MAX_RESULTS = 1e4;
529
- const handler$27 = { async handle(invocation, signal) {
544
+ const handler$28 = { async handle(invocation, signal) {
530
545
  const { pattern, path: rootPath } = invocation.payload;
531
546
  const startTime = Date.now();
532
547
  const base = rootPath ? resolve(rootPath) : process.cwd();
@@ -620,13 +635,13 @@ function matchSegment(name, seg) {
620
635
  //#endregion
621
636
  //#region src/builtin/files/grep.ts
622
637
  /**
623
- * grep — Regular expression content search (ripgrep-backed).
638
+ * grep — 基于 ripgrep 的正则内容搜索工具。
624
639
  *
625
- * Falls back to a pure-JS implementation when rg is not available.
626
- * Default head_limit=250 to prevent overwhelming output.
640
+ * ripgrep (rg) 为必需依赖。未安装时给出各平台安装命令。
641
+ * 输出有默认行数(250)和字节数(50KB)限制,防止 LLM 上下文溢出。
627
642
  */
628
643
  promisify(execFile);
629
- const descriptor$29 = {
644
+ const descriptor$34 = {
630
645
  name: "grep",
631
646
  description: "使用正则表达式搜索文件内容。返回匹配行及可选的上下文。优先使用 ripgrep。",
632
647
  inputSchema: {
@@ -750,7 +765,7 @@ function buildGrepResult(collected, limit, byteTruncated, startTime) {
750
765
  /**
751
766
  * Classify an error thrown during ripgrep execution and return the
752
767
  * appropriate {@link ToolResult}, or `null` if the caller should
753
- * fall through to the JS fallback.
768
+ * fall through to return the "rg not installed" error.
754
769
  */
755
770
  function classifyRgError(err, signal, startTime) {
756
771
  if (err.code === "ENOENT") return null;
@@ -776,7 +791,7 @@ function classifyRgError(err, signal, startTime) {
776
791
  metadata: { durationMs: Date.now() - startTime }
777
792
  };
778
793
  }
779
- const handler$26 = { async handle(invocation, signal) {
794
+ const handler$27 = { async handle(invocation, signal) {
780
795
  const { pattern, path, glob, output_mode, "-n": showLineNum, "-i": caseInsensitive, "-C": context, head_limit } = invocation.payload;
781
796
  const startTime = Date.now();
782
797
  if (signal.aborted) return {
@@ -807,7 +822,7 @@ const handler$26 = { async handle(invocation, signal) {
807
822
  }
808
823
  return {
809
824
  success: false,
810
- content: "ripgrep (rg) 未安装。请安装 ripgrep 以支持 grep 功能: https://github.com/BurntSushi/ripgrep",
825
+ content: "ripgrep (rg) 未安装,grep 功能依赖 ripgrep。安装方式:Windows: choco install ripgrep 或 winget install BurntSushi.ripgrep.MSVC、macOS: brew install ripgrep、Linux: apt install ripgrep 或 dnf install ripgrep。详见: https://github.com/BurntSushi/ripgrep",
811
826
  metadata: { durationMs: Date.now() - startTime }
812
827
  };
813
828
  } };
@@ -954,7 +969,7 @@ function isUrlAllowed(url) {
954
969
  reason: `域名 "${host}" 不在允许列表中。如需访问请联系用户确认。`
955
970
  };
956
971
  }
957
- const descriptor$28 = {
972
+ const descriptor$33 = {
958
973
  name: "web_fetch",
959
974
  description: "从 URL 获取内容并以文本形式返回。HTTP 自动升级为 HTTPS。跨域重定向会返回给调用方而非自动跟随。每个 URL 的结果缓存 15 分钟。HTML 内容会转换为纯文本。",
960
975
  inputSchema: {
@@ -1089,7 +1104,7 @@ function buildFetchError(err, startTime) {
1089
1104
  metadata: { durationMs: Date.now() - startTime }
1090
1105
  };
1091
1106
  }
1092
- const handler$25 = { async handle(invocation, signal) {
1107
+ const handler$26 = { async handle(invocation, signal) {
1093
1108
  const { url, maxChars } = invocation.payload;
1094
1109
  const charLimit = maxChars ?? 5e4;
1095
1110
  const startTime = Date.now();
@@ -1162,7 +1177,7 @@ const handler$25 = { async handle(invocation, signal) {
1162
1177
  } };
1163
1178
  //#endregion
1164
1179
  //#region src/builtin/files/web-search.ts
1165
- const descriptor$27 = {
1180
+ const descriptor$32 = {
1166
1181
  name: "web_search",
1167
1182
  description: "搜索网页并返回包含标题、URL 和摘要的结果。支持域名白名单和黑名单过滤。",
1168
1183
  inputSchema: {
@@ -1286,7 +1301,7 @@ function cacheKey(query, allowed, blocked) {
1286
1301
  if (blocked?.length) parts.push("block:" + blocked.sort().join(","));
1287
1302
  return parts.join("|");
1288
1303
  }
1289
- const handler$24 = { async handle(invocation, signal) {
1304
+ const handler$25 = { async handle(invocation, signal) {
1290
1305
  const { query, allowed_domains, blocked_domains } = invocation.payload;
1291
1306
  const startTime = Date.now();
1292
1307
  if (signal.aborted) return {
@@ -1348,7 +1363,7 @@ const handler$24 = { async handle(invocation, signal) {
1348
1363
  } };
1349
1364
  //#endregion
1350
1365
  //#region src/builtin/files/todo-write.ts
1351
- const descriptor$26 = {
1366
+ const descriptor$31 = {
1352
1367
  name: "todo_write",
1353
1368
  description: "创建和更新任务列表以跟踪进度。每次调用会替换整个列表。每项任务必须包含 content、status 和 activeForm。",
1354
1369
  inputSchema: {
@@ -1392,7 +1407,7 @@ const descriptor$26 = {
1392
1407
  executor: "core:todo_write",
1393
1408
  owner: "core"
1394
1409
  };
1395
- const handler$23 = { async handle(invocation, _signal) {
1410
+ const handler$24 = { async handle(invocation, _signal) {
1396
1411
  const { todos } = invocation.payload;
1397
1412
  const startTime = Date.now();
1398
1413
  if (!Array.isArray(todos)) return {
@@ -1432,6 +1447,117 @@ const handler$23 = { async handle(invocation, _signal) {
1432
1447
  };
1433
1448
  } };
1434
1449
  //#endregion
1450
+ //#region src/builtin/files/bash.ts
1451
+ /**
1452
+ * bash — 跨平台执行 Shell 命令。
1453
+ *
1454
+ * Unix (Linux/macOS) 上使用 `bash -c` 执行,
1455
+ * Windows 上使用 `cmd /c` 执行(PowerShell 由独立的 powershell 工具处理)。
1456
+ * 默认 30 秒超时,stdout/stderr 各截断至 10KB。
1457
+ */
1458
+ /** stdout/stderr 最大输出长度(字节),超出部分截断并标记。 */
1459
+ const MAX_OUTPUT_LENGTH = 1e4;
1460
+ const descriptor$30 = {
1461
+ name: "bash",
1462
+ description: "执行 Shell 命令。在 Unix (Linux/macOS) 上使用 bash -c,在 Windows 上使用 cmd /c。返回 stdout 和 stderr。默认 30 秒超时,输出超出 10KB 会被截断。",
1463
+ inputSchema: {
1464
+ type: "object",
1465
+ properties: {
1466
+ command: {
1467
+ type: "string",
1468
+ description: "要执行的 Shell 命令"
1469
+ },
1470
+ timeout: {
1471
+ type: "number",
1472
+ description: "超时时间(毫秒),默认 30000",
1473
+ default: 3e4
1474
+ }
1475
+ },
1476
+ required: ["command"]
1477
+ },
1478
+ kind: "ExecutesCode",
1479
+ safety: "RequiresApproval",
1480
+ availability: { type: "always" },
1481
+ executor: "core:bash",
1482
+ owner: "core"
1483
+ };
1484
+ const handler$23 = { async handle(invocation, signal) {
1485
+ const { command, timeout } = invocation.payload;
1486
+ const startTime = Date.now();
1487
+ if (signal.aborted) return {
1488
+ success: false,
1489
+ content: "操作已取消",
1490
+ metadata: { durationMs: Date.now() - startTime }
1491
+ };
1492
+ if (!command || command.trim().length === 0) return {
1493
+ success: false,
1494
+ content: "请输入要执行的命令。",
1495
+ metadata: { durationMs: Date.now() - startTime }
1496
+ };
1497
+ const timeoutMs = timeout ?? 3e4;
1498
+ const shellCmd = buildShellCommand(command);
1499
+ return new Promise((resolve) => {
1500
+ let aborted = false;
1501
+ const onAbort = () => {
1502
+ aborted = true;
1503
+ };
1504
+ signal.addEventListener("abort", onAbort, { once: true });
1505
+ exec(shellCmd, {
1506
+ timeout: timeoutMs,
1507
+ windowsHide: true
1508
+ }, (err, stdout, stderr) => {
1509
+ signal.removeEventListener("abort", onAbort);
1510
+ if (aborted) {
1511
+ resolve({
1512
+ success: false,
1513
+ content: "操作已取消",
1514
+ metadata: { durationMs: Date.now() - startTime }
1515
+ });
1516
+ return;
1517
+ }
1518
+ if (err) {
1519
+ resolve({
1520
+ success: false,
1521
+ content: err.code === "ETIMEDOUT" || err.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? `命令执行超时(${timeoutMs}ms)` : `命令执行失败 (exit ${err.code ?? "unknown"}): ${err.message}\n\nstderr:\n${stderr}`,
1522
+ metadata: { durationMs: Date.now() - startTime }
1523
+ });
1524
+ return;
1525
+ }
1526
+ const truncatedStdout = truncate(stdout);
1527
+ const truncatedStderr = truncate(stderr);
1528
+ const parts = [];
1529
+ if (truncatedStdout.text) parts.push(`stdout:\n${truncatedStdout.text}`);
1530
+ if (truncatedStderr.text) parts.push(`stderr:\n${truncatedStderr.text}`);
1531
+ const output = parts.join("\n\n") || "(无输出)";
1532
+ const wasTruncated = truncatedStdout.truncated || truncatedStderr.truncated;
1533
+ resolve({
1534
+ success: true,
1535
+ content: output,
1536
+ metadata: {
1537
+ durationMs: Date.now() - startTime,
1538
+ truncated: wasTruncated
1539
+ }
1540
+ });
1541
+ });
1542
+ });
1543
+ } };
1544
+ /** 根据平台构建 Shell 命令字符串。 */
1545
+ function buildShellCommand(command) {
1546
+ if (process.platform === "win32") return `cmd /c "${command.replace(/"/g, "\\\"")}"`;
1547
+ return `bash -c '${command.replace(/'/g, `'\\''`)}'`;
1548
+ }
1549
+ /** 截断超长输出,末尾追加截断提示。 */
1550
+ function truncate(raw) {
1551
+ if (raw.length <= MAX_OUTPUT_LENGTH) return {
1552
+ text: raw,
1553
+ truncated: false
1554
+ };
1555
+ return {
1556
+ text: raw.slice(0, MAX_OUTPUT_LENGTH) + `\n...(截断,原 ${raw.length} 字节,仅显示前 ${MAX_OUTPUT_LENGTH} 字节)`,
1557
+ truncated: true
1558
+ };
1559
+ }
1560
+ //#endregion
1435
1561
  //#region src/builtin/files/powershell.ts
1436
1562
  /**
1437
1563
  * powershell — 在 Windows 上执行 PowerShell 命令。
@@ -1439,7 +1565,7 @@ const handler$23 = { async handle(invocation, _signal) {
1439
1565
  * 仅在 Windows 平台可用。使用 child_process.exec 执行,
1440
1566
  * 默认 30 秒超时。返回 stdout 和 stderr。
1441
1567
  */
1442
- const descriptor$25 = {
1568
+ const descriptor$29 = {
1443
1569
  name: "powershell",
1444
1570
  description: "在 Windows 上执行 PowerShell 命令。返回 stdout 和 stderr。仅 Windows 平台可用。命令以 -NoProfile 模式运行。",
1445
1571
  inputSchema: {
@@ -1484,6 +1610,16 @@ const handler$22 = { async handle(invocation, signal) {
1484
1610
  content: "请输入要执行的 PowerShell 命令。",
1485
1611
  metadata: { durationMs: Date.now() - startTime }
1486
1612
  };
1613
+ if (/\$\(/.test(command)) return {
1614
+ success: false,
1615
+ content: "命令包含不安全的子表达式 `$(`。请使用安全的替代方式。",
1616
+ metadata: { durationMs: Date.now() - startTime }
1617
+ };
1618
+ if (/`/.test(command)) return {
1619
+ success: false,
1620
+ content: "命令包含不安全的转义符 `` ` ``。请使用安全的替代方式。",
1621
+ metadata: { durationMs: Date.now() - startTime }
1622
+ };
1487
1623
  const timeoutMs = timeout ?? 3e4;
1488
1624
  const escapedCommand = command.replace(/"/g, "\\\"");
1489
1625
  return new Promise((resolve) => {
@@ -1535,7 +1671,7 @@ const handler$22 = { async handle(invocation, signal) {
1535
1671
  * .ipynb 文件结构为 JSON: { cells: [{ cell_type, source, ... }], ... }
1536
1672
  * source 字段可以是字符串或字符串数组,统一按字符串数组处理。
1537
1673
  */
1538
- const descriptor$24 = {
1674
+ const descriptor$28 = {
1539
1675
  name: "NotebookEditTool",
1540
1676
  description: "编辑 Jupyter notebook (.ipynb) 文件中的单元格。支持插入、替换、删除和列出代码与 Markdown 单元格。",
1541
1677
  inputSchema: {
@@ -1740,7 +1876,7 @@ const handler$21 = { async handle(invocation, signal) {
1740
1876
  } };
1741
1877
  //#endregion
1742
1878
  //#region src/builtin/files/secret-scan.ts
1743
- const descriptor$23 = {
1879
+ const descriptor$27 = {
1744
1880
  name: "SecretScanner",
1745
1881
  description: "扫描文件内容以查找潜在的密钥、令牌和凭证。在写入操作前使用此工具检查敏感信息。检测模式包括:私钥、GitHub token、OpenAI key、Google API key、JWT、通用 API key、密码赋值。",
1746
1882
  inputSchema: {
@@ -1862,7 +1998,7 @@ const handler$20 = { async handle(invocation, signal) {
1862
1998
  * 此工具默认隐藏(需设置 flag "lsp_enabled" 才会暴露)。
1863
1999
  * 当 IDE 连接后将提供完整的 LSP 集成,目前提供接口契约层。
1864
2000
  */
1865
- const descriptor$22 = {
2001
+ const descriptor$26 = {
1866
2002
  name: "LSPTool",
1867
2003
  description: "查询语言服务器协议(LSP)以获取诊断、类型信息、跳转定义等。支持 diagnostics、hover、definition、references、format 等常见 LSP 操作。",
1868
2004
  inputSchema: {
@@ -2020,7 +2156,7 @@ function countOccurrences(str, char) {
2020
2156
  */
2021
2157
  /** 活跃的 REPL 会话映射,key 为 session UUID。 */
2022
2158
  const activeSessions = /* @__PURE__ */ new Map();
2023
- const descriptor$21 = {
2159
+ const descriptor$25 = {
2024
2160
  name: "REPLTool",
2025
2161
  description: "在持久化 REPL 会话中执行代码。启动运行时(Node.js/Python/Bash)并保持状态在多次调用之间。支持 start(启动)、eval(执行)、stop(停止)、status(状态)四种操作。",
2026
2162
  inputSchema: {
@@ -2243,7 +2379,7 @@ function handleStatus$1() {
2243
2379
  }
2244
2380
  //#endregion
2245
2381
  //#region src/builtin/agent/agent.ts
2246
- const descriptor$20 = {
2382
+ const descriptor$24 = {
2247
2383
  name: "agent",
2248
2384
  description: "启动子 Agent 自主处理复杂多步骤任务。每种子 Agent 类型拥有不同能力和可用工具。子 Agent 将最终结果返回给父 Agent。",
2249
2385
  inputSchema: {
@@ -2314,7 +2450,7 @@ const handler$17 = { async handle(invocation, signal) {
2314
2450
  } };
2315
2451
  //#endregion
2316
2452
  //#region src/builtin/agent/task.ts
2317
- const descriptor$19 = {
2453
+ const descriptor$23 = {
2318
2454
  name: "task",
2319
2455
  description: "管理后台任务——创建、列表、获取、更新或停止任务。任务持久化到 SQLite,会话重启后仍存在。适用于跨多个会话的长时间运行操作。",
2320
2456
  inputSchema: {
@@ -2532,7 +2668,7 @@ function mockDispatch(action, taskId, taskType, taskPayload, taskStatus, startTi
2532
2668
  const handler$16 = buildHandler(null);
2533
2669
  //#endregion
2534
2670
  //#region src/builtin/agent/team-create.ts
2535
- const descriptor$18 = {
2671
+ const descriptor$22 = {
2536
2672
  name: "team_create",
2537
2673
  description: "创建多 Agent 协作团队。每个成员拥有独立的角色、工具集和模型。团队通过可配置的策略协作完成工作(默认:共识模式)。",
2538
2674
  inputSchema: {
@@ -2589,30 +2725,16 @@ const descriptor$18 = {
2589
2725
  };
2590
2726
  const handler$15 = { async handle(invocation, signal) {
2591
2727
  const { name, members, strategy } = invocation.payload;
2592
- const startTime = Date.now();
2593
2728
  if (signal.aborted) return {
2594
2729
  success: false,
2595
2730
  content: "团队创建已取消",
2596
- metadata: { durationMs: Date.now() - startTime }
2597
- };
2598
- const strat = strategy ?? "consensus";
2599
- const memberList = members.map((m) => ` - ${m.name} (${m.role})${m.model ? ` [${m.model}]` : ""}`).join("\n");
2600
- return {
2601
- success: true,
2602
- content: [
2603
- `团队已创建:${name}`,
2604
- `策略:${strat}`,
2605
- `成员(${members.length} 人):`,
2606
- memberList,
2607
- "",
2608
- "[Phase 4 集成:通过 @24klynx/agent 子 Agent 通道实现真实团队编排]"
2609
- ].join("\n"),
2610
- metadata: { durationMs: Date.now() - startTime }
2731
+ metadata: { durationMs: 0 }
2611
2732
  };
2733
+ throw new NotImplementedError(`团队 "${name ?? "未命名"}" 创建失败:团队协作引擎将在 Phase 4 实现。当前不支持多 Agent 团队编排(${members?.length ?? 0} 名成员,策略:${strategy ?? "consensus"})。`);
2612
2734
  } };
2613
2735
  //#endregion
2614
2736
  //#region src/builtin/agent/team-delete.ts
2615
- const descriptor$17 = {
2737
+ const descriptor$21 = {
2616
2738
  name: "team_delete",
2617
2739
  description: "删除多 Agent 协作团队。移除团队前会终止所有正在执行的成员任务。",
2618
2740
  inputSchema: {
@@ -2634,25 +2756,16 @@ const descriptor$17 = {
2634
2756
  };
2635
2757
  const handler$14 = { async handle(invocation, signal) {
2636
2758
  const { team_id } = invocation.payload;
2637
- const startTime = Date.now();
2638
2759
  if (signal.aborted) return {
2639
2760
  success: false,
2640
2761
  content: "团队删除已取消",
2641
- metadata: { durationMs: Date.now() - startTime }
2642
- };
2643
- return {
2644
- success: true,
2645
- content: [
2646
- `团队已删除:${team_id}`,
2647
- "所有成员任务已终止。",
2648
- "[Phase 4 集成:通过 @24klynx/agent 实现真实团队生命周期管理]"
2649
- ].join("\n"),
2650
- metadata: { durationMs: Date.now() - startTime }
2762
+ metadata: { durationMs: 0 }
2651
2763
  };
2764
+ throw new NotImplementedError(`团队 "${team_id}" 删除失败:团队协作引擎将在 Phase 4 实现。当前不支持多 Agent 团队生命周期管理。`);
2652
2765
  } };
2653
2766
  //#endregion
2654
2767
  //#region src/builtin/agent/verify-plan.ts
2655
- const descriptor$16 = {
2768
+ const descriptor$20 = {
2656
2769
  name: "verify_plan_execution",
2657
2770
  description: "验证计划执行是否匹配其规范。逐一检查每个检查点的预期输出与实际输出是否一致。在实施计划后使用此工具,确保无遗漏。",
2658
2771
  inputSchema: {
@@ -2730,7 +2843,7 @@ const handler$13 = { async handle(invocation, signal) {
2730
2843
  } };
2731
2844
  //#endregion
2732
2845
  //#region src/builtin/agent/remote-trigger.ts
2733
- const descriptor$15 = {
2846
+ const descriptor$19 = {
2734
2847
  name: "remote_trigger",
2735
2848
  description: "通过发送 HTTP 请求(webhook / CI 回调)触发远程任务。支持 GET 和 POST 方法,可自定义请求头和请求体。默认超时 30 秒。",
2736
2849
  inputSchema: {
@@ -2915,7 +3028,7 @@ function isValidCron(cron) {
2915
3028
  });
2916
3029
  }
2917
3030
  init$1();
2918
- const descriptor$14 = {
3031
+ const descriptor$18 = {
2919
3032
  name: "ScheduleCronTool",
2920
3033
  description: "使用 cron 语法安排定时任务。任务在指定时间或间隔触发。支持一次性提醒和循环计划。标准 cron 格式:分 时 日 月 周。也支持 @hourly、@daily、@weekly 别名。",
2921
3034
  inputSchema: {
@@ -3060,7 +3173,7 @@ function persist() {
3060
3173
  writeFileSync(STORAGE_FILE, JSON.stringify(Array.from(workflows.values()), null, 2));
3061
3174
  }
3062
3175
  init();
3063
- const descriptor$13 = {
3176
+ const descriptor$17 = {
3064
3177
  name: "WorkflowTool",
3065
3178
  description: "定义并执行多步骤工作流。每个步骤可以是一个工具调用,步骤之间可以有依赖关系。支持 define(定义)、run(运行)、status(查看状态)、list(列出所有)四种操作。",
3066
3179
  inputSchema: {
@@ -3167,7 +3280,13 @@ function handleDefine(name, steps) {
3167
3280
  content: `工作流已定义。ID:${id}\n名称:${name}\n步骤:\n${steps.map((s, i) => ` ${i + 1}. ${s.name} — 调用 ${s.toolName}`).join("\n")}`
3168
3281
  };
3169
3282
  }
3170
- /** 运行工作流:返回步骤列表供 agent 按顺序执行。 */
3283
+ /**
3284
+ * 运行工作流:返回步骤指令供 Agent 循环按序执行。
3285
+ *
3286
+ * 本工具是"指令生成器"而非"执行引擎"——
3287
+ * 它输出清晰的步骤文本,由 Agent 循环(loop.ts)负责依次调用各步骤指定的工具。
3288
+ * 这样设计是为了让每一步的工具调用都经过权限检查和用户审批流程。
3289
+ */
3171
3290
  function handleRun(workflowId) {
3172
3291
  if (!workflowId) return {
3173
3292
  success: false,
@@ -3235,7 +3354,7 @@ function handleList() {
3235
3354
  }
3236
3355
  //#endregion
3237
3356
  //#region src/builtin/agent/tungsten.ts
3238
- const descriptor$12 = {
3357
+ const descriptor$16 = {
3239
3358
  name: "TungstenTool",
3240
3359
  description: "重型复合工具:并行调度多个子 Agent 处理复杂任务的各个部分,然后综合结果。支持 parallel(并行)、pipeline(流水线)、debate(辩论)三种策略。适用于代码审查、多模块重构、全面调研等大规模任务。",
3241
3360
  inputSchema: {
@@ -3343,7 +3462,14 @@ function decomposeTask(task, maxAgents) {
3343
3462
  suggestedAgentRole: "主执行 Agent"
3344
3463
  }];
3345
3464
  }
3346
- /** 根据策略生成执行计划文本。 */
3465
+ /**
3466
+ * 根据策略生成执行计划文本。
3467
+ *
3468
+ * 本工具是"任务规划器"而非"执行引擎"——
3469
+ * 它将复杂任务拆解为子任务并输出结构化指令,
3470
+ * 实际的子 Agent spawn 由 Agent 工具(agent.ts)负责。
3471
+ * Agent 循环读取此计划后逐一创建子 Agent 并收集结果。
3472
+ */
3347
3473
  function buildExecutionPlan(task, subtasks, maxAgents, strategy) {
3348
3474
  const planLines = [
3349
3475
  "═══════════════════════════════════════",
@@ -3394,7 +3520,7 @@ function strategyLabel(strategy) {
3394
3520
  }
3395
3521
  //#endregion
3396
3522
  //#region src/builtin/mode/enter-plan-mode.ts
3397
- const descriptor$11 = {
3523
+ const descriptor$15 = {
3398
3524
  name: "enter_plan_mode",
3399
3525
  description: "进入计划模式 — 切换为只读模式,Agent 只能读取文件和输出设计方案。所有写入/编辑/执行工具将自动被拒绝。在进行重大架构变更前使用此模式,以便在实施前获得用户对方案的认可。",
3400
3526
  inputSchema: {
@@ -3428,7 +3554,7 @@ const handler$8 = { async handle(_invocation, signal) {
3428
3554
  } };
3429
3555
  //#endregion
3430
3556
  //#region src/builtin/mode/exit-plan-mode.ts
3431
- const descriptor$10 = {
3557
+ const descriptor$14 = {
3432
3558
  name: "exit_plan_mode",
3433
3559
  description: "退出计划模式,返回普通模式(写入工具重新启用)。计划方案将在执行前展示给用户审批。",
3434
3560
  inputSchema: {
@@ -3461,7 +3587,7 @@ const handler$7 = { async handle(_invocation, signal) {
3461
3587
  } };
3462
3588
  //#endregion
3463
3589
  //#region src/builtin/mode/enter-worktree.ts
3464
- const descriptor$9 = {
3590
+ const descriptor$13 = {
3465
3591
  name: "enter_worktree",
3466
3592
  description: "创建新的 git worktree 或进入已有 worktree 进行隔离工作。Worktree 存放在 .claude/worktrees/ 目录下。使用 name 参数创建新 worktree,使用 path 参数进入已有 worktree。",
3467
3593
  inputSchema: {
@@ -3525,7 +3651,7 @@ const handler$6 = { async handle(invocation, signal) {
3525
3651
  } };
3526
3652
  //#endregion
3527
3653
  //#region src/builtin/mode/exit-worktree.ts
3528
- const descriptor$8 = {
3654
+ const descriptor$12 = {
3529
3655
  name: "exit_worktree",
3530
3656
  description: "退出 git worktree 并返回原始目录。使用 'keep' 保留 worktree,或使用 'remove' 删除(如有未提交变更需搭配 discard_changes)。",
3531
3657
  inputSchema: {
@@ -3587,7 +3713,7 @@ const handler$5 = { async handle(invocation, signal) {
3587
3713
  * - list: 列出所有配置项
3588
3714
  * - path: 返回配置文件路径
3589
3715
  */
3590
- const descriptor$7 = {
3716
+ const descriptor$11 = {
3591
3717
  name: "ConfigTool",
3592
3718
  description: "读取或修改 Lynx 配置。可以查看当前配置值或设置新的配置项。支持四种操作:get(获取单个配置项)、set(设置配置项)、list(列出所有配置项)、path(查看配置文件路径)。",
3593
3719
  inputSchema: {
@@ -3722,7 +3848,7 @@ const handler$4 = { async handle(invocation, signal) {
3722
3848
  } };
3723
3849
  //#endregion
3724
3850
  //#region src/builtin/interact/ask-user-question.ts
3725
- const descriptor$6 = {
3851
+ const descriptor$10 = {
3726
3852
  name: "ask_user_question",
3727
3853
  description: "向用户提出一个或多个澄清性问题并等待回答。支持单选、多选以及自由文本的「其他」选项。当您被一个只有用户才能做决定的问题卡住时使用。",
3728
3854
  inputSchema: {
@@ -3809,7 +3935,7 @@ const handler$3 = { async handle(invocation, signal) {
3809
3935
  } };
3810
3936
  //#endregion
3811
3937
  //#region src/builtin/interact/brief.ts
3812
- const descriptor$5 = {
3938
+ const descriptor$9 = {
3813
3939
  name: "brief",
3814
3940
  description: "生成当前对话上下文的结构化摘要简报。适用于进度检查点、会话间交接、或向用户提供状态更新。",
3815
3941
  inputSchema: {
@@ -3869,7 +3995,7 @@ const handler$2 = { async handle(invocation, signal) {
3869
3995
  } };
3870
3996
  //#endregion
3871
3997
  //#region src/builtin/interact/synthetic-output.ts
3872
- const descriptor$4 = {
3998
+ const descriptor$8 = {
3873
3999
  name: "synthetic_output",
3874
4000
  description: "生成符合 JSON Schema 的结构化输出。用于在子 Agent 和父 Agent 之间传递带类型的数据。如果输出无法通过 schema 校验,LLM 会自动重试。",
3875
4001
  inputSchema: {
@@ -3913,7 +4039,7 @@ const handler$1 = { async handle(invocation, signal) {
3913
4039
  } };
3914
4040
  //#endregion
3915
4041
  //#region src/builtin/interact/sleep.ts
3916
- const descriptor$3 = {
4042
+ const descriptor$7 = {
3917
4043
  name: "sleep",
3918
4044
  description: "暂停执行指定秒数。用于速率限制退避、等待外部事件或轮询间隔。最长 300 秒。必须提供原因。",
3919
4045
  inputSchema: {
@@ -3972,7 +4098,7 @@ const handler = { async handle(invocation, signal) {
3972
4098
  } };
3973
4099
  //#endregion
3974
4100
  //#region src/builtin/memory/memory-write.ts
3975
- const descriptor$1 = {
4101
+ const descriptor$3 = {
3976
4102
  name: "memory_write",
3977
4103
  description: "管理持久化记忆。支持以下操作:create/update — 写入或更新一条记忆;delete — 按名称删除;search — 全文搜索记忆(按相关度排序);compact — 去重压缩相似条目(Jaccard 相似度 > 0.8);forget — 按 glob 模式批量删除匹配的记忆;export — 导出全部记忆为 JSON 字符串;import — 从 JSON 字符串批量导入记忆(跳过同名条目);merge — 合并另一个 memory 目录中的记忆文件。当用户要求记住某事、搜索记忆、清理重复记忆或迁移记忆时使用。",
3978
4104
  inputSchema: {
@@ -4190,9 +4316,291 @@ function createMemoryWriteHandler(memoryManager) {
4190
4316
  } };
4191
4317
  }
4192
4318
  //#endregion
4193
- //#region src/builtin/mcp/mcp-auth.ts
4319
+ //#region src/builtin/files/tool-search.ts
4320
+ const descriptor$6 = {
4321
+ name: "ToolSearchTool",
4322
+ description: "按名称或描述搜索可用的工具。返回匹配工具的摘要信息,包括工具名、用途和安全等级。",
4323
+ inputSchema: {
4324
+ type: "object",
4325
+ properties: { query: {
4326
+ type: "string",
4327
+ description: "搜索关键词(大小写不敏感)"
4328
+ } },
4329
+ required: ["query"]
4330
+ },
4331
+ kind: "ReadOnly",
4332
+ safety: "Safe",
4333
+ availability: { type: "always" },
4334
+ executor: "core:tool_search",
4335
+ owner: "core"
4336
+ };
4337
+ /**
4338
+ * 创建 ToolSearchTool 的 handler。
4339
+ *
4340
+ * 工厂函数接收获取所有工具描述符的函数,返回 handler。
4341
+ * 这样可以在不引入循环依赖的情况下注入工具列表。
4342
+ *
4343
+ * @param getAllTools — 返回所有已注册 ToolDescriptor 的函数
4344
+ */
4345
+ function createToolSearchHandler(getAllTools) {
4346
+ return { async handle(invocation, signal) {
4347
+ const { query } = invocation.payload;
4348
+ const startTime = Date.now();
4349
+ if (signal.aborted) return {
4350
+ success: false,
4351
+ content: "操作已取消",
4352
+ metadata: { durationMs: Date.now() - startTime }
4353
+ };
4354
+ if (!query || query.trim().length === 0) return {
4355
+ success: false,
4356
+ content: "请输入搜索关键词。",
4357
+ metadata: { durationMs: Date.now() - startTime }
4358
+ };
4359
+ const lowerQuery = query.trim().toLowerCase();
4360
+ const matches = getAllTools().filter((tool) => {
4361
+ const nameLower = tool.name.toLowerCase();
4362
+ const descLower = tool.description.toLowerCase();
4363
+ return nameLower.includes(lowerQuery) || descLower.includes(lowerQuery);
4364
+ });
4365
+ if (matches.length === 0) return {
4366
+ success: true,
4367
+ content: `未找到与 "${query.trim()}" 匹配的工具。`,
4368
+ metadata: { durationMs: Date.now() - startTime }
4369
+ };
4370
+ const lines = matches.map((tool) => {
4371
+ const safetyLabel = safetyToLabel(tool.safety);
4372
+ return `- **${tool.name}** [${safetyLabel}]\n ${tool.description}`;
4373
+ });
4374
+ return {
4375
+ success: true,
4376
+ content: `找到 ${matches.length} 个匹配的工具:\n\n${lines.join("\n\n")}`,
4377
+ metadata: { durationMs: Date.now() - startTime }
4378
+ };
4379
+ } };
4380
+ }
4381
+ /** 将 safety 枚举值转为中文标签。 */
4382
+ function safetyToLabel(safety) {
4383
+ switch (safety) {
4384
+ case "Safe": return "安全";
4385
+ case "WorkspaceSafe": return "工作区安全";
4386
+ case "RequiresApproval": return "需审批";
4387
+ case "Dangerous": return "危险";
4388
+ default: return safety;
4389
+ }
4390
+ }
4391
+ //#endregion
4392
+ //#region src/builtin/mcp/call-tool.ts
4194
4393
  /** 工具描述符 — 注册到 ToolRegistry 的静态元数据。 */
4394
+ const descriptor$2 = {
4395
+ name: "mcp__call_tool",
4396
+ description: "直接调用已连接的 MCP 服务器的工具。使用 serverName 和 toolName 指定目标工具。",
4397
+ inputSchema: {
4398
+ type: "object",
4399
+ properties: {
4400
+ serverName: {
4401
+ type: "string",
4402
+ description: "MCP 服务器名称"
4403
+ },
4404
+ toolName: {
4405
+ type: "string",
4406
+ description: "原始工具名(非命名空间格式)"
4407
+ },
4408
+ arguments: {
4409
+ type: "object",
4410
+ description: "传递给工具的参数"
4411
+ }
4412
+ },
4413
+ required: ["serverName", "toolName"]
4414
+ },
4415
+ kind: "ExecutesCode",
4416
+ safety: "RequiresApproval",
4417
+ availability: { type: "always" },
4418
+ executor: "core:mcp_call_tool",
4419
+ owner: "core"
4420
+ };
4421
+ /**
4422
+ * 创建 mcp__call_tool 的 handler,绑定到给定的 McpManager。
4423
+ *
4424
+ * 工厂模式 — McpManager 在 bootstrap 时注入,
4425
+ * 因此 lynx-tools 无需依赖 lynx-agent。
4426
+ */
4427
+ function createMcpCallToolHandler(mcpManager) {
4428
+ return { async handle(invocation, signal) {
4429
+ const { serverName, toolName, arguments: toolArgs } = invocation.payload;
4430
+ if (!serverName || typeof serverName !== "string") return {
4431
+ success: false,
4432
+ content: "缺少必需参数 serverName"
4433
+ };
4434
+ if (!toolName || typeof toolName !== "string") return {
4435
+ success: false,
4436
+ content: "缺少必需参数 toolName"
4437
+ };
4438
+ const namespacedName = `mcp__${serverName}__${toolName}`;
4439
+ if (signal.aborted) return {
4440
+ success: false,
4441
+ content: "操作已取消"
4442
+ };
4443
+ try {
4444
+ const result = await mcpManager.callTool(namespacedName, toolArgs ?? {});
4445
+ if (result.isError) return {
4446
+ success: false,
4447
+ content: result.content
4448
+ };
4449
+ return {
4450
+ success: true,
4451
+ content: result.content
4452
+ };
4453
+ } catch (err) {
4454
+ return {
4455
+ success: false,
4456
+ content: `MCP 工具调用失败:${err.message}`
4457
+ };
4458
+ }
4459
+ } };
4460
+ }
4461
+ //#endregion
4462
+ //#region src/builtin/mcp/list-resources.ts
4463
+ /** 工具描述符。 */
4195
4464
  const descriptor = {
4465
+ name: "ListMcpResourcesTool",
4466
+ description: "列出已连接 MCP 服务器提供的资源。可指定 server 名称进行过滤。",
4467
+ inputSchema: {
4468
+ type: "object",
4469
+ properties: { server: {
4470
+ type: "string",
4471
+ description: "过滤特定 MCP 服务器(可选)"
4472
+ } }
4473
+ },
4474
+ kind: "ReadOnly",
4475
+ safety: "Safe",
4476
+ availability: { type: "always" },
4477
+ executor: "core:mcp_list_resources",
4478
+ owner: "core"
4479
+ };
4480
+ /**
4481
+ * 创建 ListMcpResourcesTool 的 handler,绑定到给定的 McpManager。
4482
+ *
4483
+ * 工厂模式 — McpManager 在 bootstrap 时注入。
4484
+ */
4485
+ function createListMcpResourcesHandler(mcpManager) {
4486
+ return { async handle(invocation, _signal) {
4487
+ const { server } = invocation.payload;
4488
+ if (!mcpManager.hasResourceCapability()) return {
4489
+ success: true,
4490
+ content: "当前没有已连接且支持 resources 协议的 MCP 服务器。"
4491
+ };
4492
+ let resources = mcpManager.getAllResources();
4493
+ if (server && typeof server === "string") {
4494
+ resources = resources.filter((r) => r.server === server);
4495
+ if (resources.length === 0) return {
4496
+ success: true,
4497
+ content: `服务器 "${server}" 未提供任何资源,或未连接。`
4498
+ };
4499
+ }
4500
+ if (resources.length === 0) return {
4501
+ success: true,
4502
+ content: "已连接的 MCP 服务器未提供任何资源。"
4503
+ };
4504
+ const lines = resources.map((r) => {
4505
+ const parts = [`- **${r.name}**`];
4506
+ parts.push(`(server: ${r.server})`);
4507
+ parts.push(`uri: \`${r.uri}\``);
4508
+ if (r.mimeType) parts.push(`mimeType: ${r.mimeType}`);
4509
+ if (r.description) parts.push(`${r.description}`);
4510
+ return parts.join(" \n ");
4511
+ });
4512
+ return {
4513
+ success: true,
4514
+ content: `已连接 MCP 服务器资源列表(共 ${resources.length} 项):\n\n${lines.join("\n")}`
4515
+ };
4516
+ } };
4517
+ }
4518
+ //#endregion
4519
+ //#region src/builtin/mcp/read-resource.ts
4520
+ /**
4521
+ * ReadMcpResourceTool — 通过 URI 读取 MCP 资源的内容。
4522
+ *
4523
+ * 文本内容直接返回,二进制内容保存到临时文件并返回文件路径。
4524
+ */
4525
+ /** 工具描述符。 */
4526
+ const descriptor$4 = {
4527
+ name: "ReadMcpResourceTool",
4528
+ description: "通过 URI 读取 MCP 资源的内容。二进制资源将保存到临时文件并返回文件路径。",
4529
+ inputSchema: {
4530
+ type: "object",
4531
+ properties: {
4532
+ server: {
4533
+ type: "string",
4534
+ description: "MCP 服务器名称"
4535
+ },
4536
+ uri: {
4537
+ type: "string",
4538
+ description: "资源 URI"
4539
+ }
4540
+ },
4541
+ required: ["server", "uri"]
4542
+ },
4543
+ kind: "ReadOnly",
4544
+ safety: "Safe",
4545
+ availability: { type: "always" },
4546
+ executor: "core:mcp_read_resource",
4547
+ owner: "core"
4548
+ };
4549
+ /**
4550
+ * 创建 ReadMcpResourceTool 的 handler,绑定到给定的 McpManager。
4551
+ *
4552
+ * 工厂模式 — McpManager 在 bootstrap 时注入。
4553
+ */
4554
+ function createReadMcpResourceHandler(mcpManager) {
4555
+ return { async handle(invocation, _signal) {
4556
+ const { server, uri } = invocation.payload;
4557
+ if (!server || typeof server !== "string") return {
4558
+ success: false,
4559
+ content: "缺少必需参数 server"
4560
+ };
4561
+ if (!uri || typeof uri !== "string") return {
4562
+ success: false,
4563
+ content: "缺少必需参数 uri"
4564
+ };
4565
+ try {
4566
+ const contents = (await mcpManager.readResource(server, uri)).contents;
4567
+ if (!contents || contents.length === 0) return {
4568
+ success: true,
4569
+ content: `资源 "${uri}" 返回了空内容。`
4570
+ };
4571
+ const textContents = [];
4572
+ const binaryContents = [];
4573
+ for (const item of contents) {
4574
+ const c = item;
4575
+ if (c.text !== void 0) textContents.push(c.text);
4576
+ else if (c.blob !== void 0) {
4577
+ const tmpDir = join(tmpdir(), "lynx-mcp-resources");
4578
+ mkdirSync(tmpDir, { recursive: true });
4579
+ const filePath = join(tmpDir, uri.replace(/[^a-zA-Z0-9._-]/g, "_").slice(-64) || "resource");
4580
+ writeFileSync(filePath, Buffer.from(c.blob, "base64"));
4581
+ const mimeLabel = c.mimeType ? ` (${c.mimeType})` : "";
4582
+ binaryContents.push(`二进制内容${mimeLabel}已保存到:${filePath}`);
4583
+ }
4584
+ }
4585
+ const parts = [];
4586
+ if (textContents.length > 0) parts.push(textContents.join("\n---\n"));
4587
+ if (binaryContents.length > 0) parts.push(binaryContents.join("\n"));
4588
+ return {
4589
+ success: true,
4590
+ content: parts.join("\n\n") || "(空内容)"
4591
+ };
4592
+ } catch (err) {
4593
+ return {
4594
+ success: false,
4595
+ content: `读取 MCP 资源失败:${err.message}`
4596
+ };
4597
+ }
4598
+ } };
4599
+ }
4600
+ //#endregion
4601
+ //#region src/builtin/mcp/mcp-auth.ts
4602
+ /** 工具描述符 — 注册到 ToolRegistry 的静态元数据。 */
4603
+ const descriptor$1 = {
4196
4604
  name: "McpAuthTool",
4197
4605
  description: "触发 MCP 服务器的重新认证流程(OAuth 或 XAA)。用于在工具调用失败并返回认证错误时。",
4198
4606
  inputSchema: {
@@ -4240,7 +4648,7 @@ function createMcpAuthHandler(mcpOps) {
4240
4648
  }
4241
4649
  //#endregion
4242
4650
  //#region src/builtin/interact/send-message.ts
4243
- const descriptor$2 = {
4651
+ const descriptor$5 = {
4244
4652
  name: "SendMessageTool",
4245
4653
  description: "通过配置的消息通道发送消息(飞书等)。用于向用户发送通知或进度摘要。需要提前配置消息通道。",
4246
4654
  inputSchema: {
@@ -4309,127 +4717,131 @@ function createSendMessageHandler(sender) {
4309
4717
  /** All built‑in (descriptor, handler) pairs in registration order. */
4310
4718
  const BUILTIN_TOOLS = [
4311
4719
  {
4312
- descriptor: descriptor$33,
4720
+ descriptor: descriptor$38,
4721
+ handler: handler$31
4722
+ },
4723
+ {
4724
+ descriptor: descriptor$37,
4313
4725
  handler: handler$30
4314
4726
  },
4315
4727
  {
4316
- descriptor: descriptor$32,
4728
+ descriptor: descriptor$36,
4317
4729
  handler: handler$29
4318
4730
  },
4319
4731
  {
4320
- descriptor: descriptor$31,
4732
+ descriptor: descriptor$35,
4321
4733
  handler: handler$28
4322
4734
  },
4323
4735
  {
4324
- descriptor: descriptor$30,
4736
+ descriptor: descriptor$34,
4325
4737
  handler: handler$27
4326
4738
  },
4327
4739
  {
4328
- descriptor: descriptor$29,
4740
+ descriptor: descriptor$33,
4329
4741
  handler: handler$26
4330
4742
  },
4331
4743
  {
4332
- descriptor: descriptor$28,
4744
+ descriptor: descriptor$32,
4333
4745
  handler: handler$25
4334
4746
  },
4335
4747
  {
4336
- descriptor: descriptor$27,
4748
+ descriptor: descriptor$31,
4337
4749
  handler: handler$24
4338
4750
  },
4339
4751
  {
4340
- descriptor: descriptor$26,
4752
+ descriptor: descriptor$30,
4341
4753
  handler: handler$23
4342
4754
  },
4343
4755
  {
4344
- descriptor: descriptor$25,
4756
+ descriptor: descriptor$29,
4345
4757
  handler: handler$22
4346
4758
  },
4347
4759
  {
4348
- descriptor: descriptor$24,
4760
+ descriptor: descriptor$28,
4349
4761
  handler: handler$21
4350
4762
  },
4351
4763
  {
4352
- descriptor: descriptor$23,
4764
+ descriptor: descriptor$27,
4353
4765
  handler: handler$20
4354
4766
  },
4355
4767
  {
4356
- descriptor: descriptor$22,
4768
+ descriptor: descriptor$26,
4357
4769
  handler: handler$19
4358
4770
  },
4359
4771
  {
4360
- descriptor: descriptor$21,
4772
+ descriptor: descriptor$25,
4361
4773
  handler: handler$18
4362
4774
  },
4363
4775
  {
4364
- descriptor: descriptor$20,
4776
+ descriptor: descriptor$24,
4365
4777
  handler: handler$17
4366
4778
  },
4367
4779
  {
4368
- descriptor: descriptor$19,
4780
+ descriptor: descriptor$23,
4369
4781
  handler: handler$16
4370
4782
  },
4371
4783
  {
4372
- descriptor: descriptor$18,
4784
+ descriptor: descriptor$22,
4373
4785
  handler: handler$15
4374
4786
  },
4375
4787
  {
4376
- descriptor: descriptor$17,
4788
+ descriptor: descriptor$21,
4377
4789
  handler: handler$14
4378
4790
  },
4379
4791
  {
4380
- descriptor: descriptor$16,
4792
+ descriptor: descriptor$20,
4381
4793
  handler: handler$13
4382
4794
  },
4383
4795
  {
4384
- descriptor: descriptor$15,
4796
+ descriptor: descriptor$19,
4385
4797
  handler: handler$12
4386
4798
  },
4387
4799
  {
4388
- descriptor: descriptor$14,
4800
+ descriptor: descriptor$18,
4389
4801
  handler: handler$11
4390
4802
  },
4391
4803
  {
4392
- descriptor: descriptor$13,
4804
+ descriptor: descriptor$17,
4393
4805
  handler: handler$10
4394
4806
  },
4395
4807
  {
4396
- descriptor: descriptor$12,
4808
+ descriptor: descriptor$16,
4397
4809
  handler: handler$9
4398
4810
  },
4399
4811
  {
4400
- descriptor: descriptor$11,
4812
+ descriptor: descriptor$15,
4401
4813
  handler: handler$8
4402
4814
  },
4403
4815
  {
4404
- descriptor: descriptor$10,
4816
+ descriptor: descriptor$14,
4405
4817
  handler: handler$7
4406
4818
  },
4407
4819
  {
4408
- descriptor: descriptor$9,
4820
+ descriptor: descriptor$13,
4409
4821
  handler: handler$6
4410
4822
  },
4411
4823
  {
4412
- descriptor: descriptor$8,
4824
+ descriptor: descriptor$12,
4413
4825
  handler: handler$5
4414
4826
  },
4415
4827
  {
4416
- descriptor: descriptor$7,
4828
+ descriptor: descriptor$11,
4417
4829
  handler: handler$4
4418
4830
  },
4419
4831
  {
4420
- descriptor: descriptor$6,
4832
+ descriptor: descriptor$10,
4421
4833
  handler: handler$3
4422
4834
  },
4423
4835
  {
4424
- descriptor: descriptor$5,
4836
+ descriptor: descriptor$9,
4425
4837
  handler: handler$2
4426
4838
  },
4427
4839
  {
4428
- descriptor: descriptor$4,
4840
+ descriptor: descriptor$8,
4429
4841
  handler: handler$1
4430
4842
  },
4431
4843
  {
4432
- descriptor: descriptor$3,
4844
+ descriptor: descriptor$7,
4433
4845
  handler
4434
4846
  }
4435
4847
  ];
@@ -5002,6 +5414,6 @@ function redactSecrets(text) {
5002
5414
  return result;
5003
5415
  }
5004
5416
  //#endregion
5005
- export { SAFETY_LABELS, buildToolPlan, classifySensitivity as classifyPath, createMcpAuthHandler, createMemoryWriteHandler, createSendMessageHandler, createTaskHandler, createToolRegistry, escalateForSensitivePaths, evaluateAvailability, injectTaskManager, isBlockedCommand, isHeadlessSafe, isTrustedCommand, isPathSafe as isWithinWorkspace, listBuiltinDescriptors, descriptor as mcpAuthDescriptor, descriptor$1 as memoryWriteDescriptor, needsApproval, redactSecrets, registerBuiltinTools, sanitizeUnicode, descriptor$2 as sendMessageDescriptor };
5417
+ export { SAFETY_LABELS, buildToolPlan, classifySensitivity as classifyPath, createListMcpResourcesHandler, createMcpAuthHandler, createMcpCallToolHandler, createMemoryWriteHandler, createReadMcpResourceHandler, createSendMessageHandler, createTaskHandler, createToolRegistry, createToolSearchHandler, escalateForSensitivePaths, evaluateAvailability, injectTaskManager, isBlockedCommand, isHeadlessSafe, isTrustedCommand, isPathSafe as isWithinWorkspace, listBuiltinDescriptors, descriptor as listMcpResourcesDescriptor, descriptor$1 as mcpAuthDescriptor, descriptor$2 as mcpCallToolDescriptor, descriptor$3 as memoryWriteDescriptor, needsApproval, descriptor$4 as readMcpResourceDescriptor, redactSecrets, registerBuiltinTools, sanitizeUnicode, descriptor$5 as sendMessageDescriptor, descriptor$6 as toolSearchDescriptor };
5006
5418
 
5007
5419
  //# sourceMappingURL=index.mjs.map