u1s1-cli 1.11.8 → 1.13.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/agent-setup.d.ts +19 -3
- package/dist/agent-setup.js +85 -10
- package/dist/api.js +42 -34
- package/dist/bench-report.js +12 -9
- package/dist/bench.js +34 -31
- package/dist/brand.d.ts +2 -1
- package/dist/brand.js +38 -12
- package/dist/config.d.ts +11 -1
- package/dist/config.js +25 -8
- package/dist/context-usage.js +12 -9
- package/dist/deploy.js +49 -45
- package/dist/device-auth.js +7 -5
- package/dist/error-humanize.d.ts +1 -0
- package/dist/error-humanize.js +18 -6
- package/dist/feedback.js +48 -31
- package/dist/i18n.d.ts +21 -0
- package/dist/i18n.js +46 -0
- package/dist/import/index.js +64 -28
- package/dist/import/skills.js +72 -41
- package/dist/import/util.js +3 -2
- package/dist/import/write.js +2 -1
- package/dist/index.js +140 -49
- package/dist/login.js +39 -28
- package/dist/loop.js +18 -12
- package/dist/mcp/client.js +15 -14
- package/dist/mcp/command.d.ts +2 -2
- package/dist/mcp/command.js +109 -69
- package/dist/mcp/config.d.ts +22 -6
- package/dist/mcp/config.js +0 -0
- package/dist/mcp/extension.js +5 -3
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +10 -5
- package/dist/model.js +11 -10
- package/dist/nudges.d.ts +8 -2
- package/dist/nudges.js +22 -3
- package/dist/search-tools.js +7 -6
- package/dist/shell-doctor.js +9 -8
- package/dist/subagent.js +5 -4
- package/dist/tools.js +53 -37
- package/dist/update.js +29 -28
- package/dist/usage.d.ts +1 -1
- package/dist/usage.js +96 -43
- package/dist/web.js +2 -1
- package/dist/workflow/runner.js +33 -29
- package/dist/workflow/templates.js +70 -45
- package/dist/workflow/tool.js +15 -12
- package/package.json +4 -4
- package/scripts/patch-pi.js +347 -278
- package/scripts/render-regression.mjs +55 -4
package/dist/loop.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
1
2
|
/**
|
|
2
3
|
* /loop —— 会话级定时循环执行提示词(对标 Claude Code 的 /loop)。
|
|
3
4
|
*
|
|
@@ -34,12 +35,16 @@ function parseIntervalMs(token) {
|
|
|
34
35
|
}
|
|
35
36
|
function formatInterval(ms) {
|
|
36
37
|
if (ms >= 3_600_000 && ms % 3_600_000 === 0) {
|
|
37
|
-
return `${ms / 3_600_000}
|
|
38
|
+
return tr(`${ms / 3_600_000}小时`, `${ms / 3_600_000}h`);
|
|
38
39
|
}
|
|
39
40
|
if (ms % 60_000 === 0) {
|
|
40
|
-
return `${ms / 60_000}
|
|
41
|
+
return tr(`${ms / 60_000}分钟`, `${ms / 60_000}m`);
|
|
41
42
|
}
|
|
42
|
-
return `${Math.round(ms / 1_000)}
|
|
43
|
+
return tr(`${Math.round(ms / 1_000)}秒`, `${Math.round(ms / 1_000)}s`);
|
|
44
|
+
}
|
|
45
|
+
/** 「每5分钟」/ "every 5m" */
|
|
46
|
+
function everyInterval(ms) {
|
|
47
|
+
return tr(`每${formatInterval(ms)}`, `every ${formatInterval(ms)}`);
|
|
43
48
|
}
|
|
44
49
|
function preview(text) {
|
|
45
50
|
return text.length > PROMPT_PREVIEW_MAX ? `${text.slice(0, PROMPT_PREVIEW_MAX)}…` : text;
|
|
@@ -86,7 +91,7 @@ function parseArgs(ui, raw) {
|
|
|
86
91
|
}
|
|
87
92
|
const prompt = rest.join(" ").trim();
|
|
88
93
|
if (!prompt) {
|
|
89
|
-
ui.notify("用法: /loop [间隔] <提示词>,如 /loop 5m 检查部署状态;停止用 /loop stop", "error");
|
|
94
|
+
ui.notify(tr("用法: /loop [间隔] <提示词>,如 /loop 5m 检查部署状态;停止用 /loop stop", "Usage: /loop [interval] <prompt>, e.g. /loop 5m check the build status; /loop stop to stop"), "error");
|
|
90
95
|
return null;
|
|
91
96
|
}
|
|
92
97
|
return { intervalMs: intervalMs ?? DEFAULT_INTERVAL_MS, prompt };
|
|
@@ -95,22 +100,22 @@ export function registerLoopCommand(pi) {
|
|
|
95
100
|
// 会话重置(/clear、新会话)时循环随之消亡——和 Claude Code 的会话级语义一致
|
|
96
101
|
pi.on("session_start", (_event, ctx) => stopLoop(ctx.ui));
|
|
97
102
|
pi.registerCommand("loop", {
|
|
98
|
-
description: "定时重复执行提示词,如 /loop 5m 检查部署状态;/loop stop 停止",
|
|
103
|
+
description: tr("定时重复执行提示词,如 /loop 5m 检查部署状态;/loop stop 停止", "Repeat a prompt on an interval, e.g. /loop 5m check the build status; /loop stop to stop"),
|
|
99
104
|
handler: async (args, ctx) => {
|
|
100
105
|
const input = args.trim();
|
|
101
106
|
if (!input) {
|
|
102
107
|
ctx.ui.notify(timer
|
|
103
|
-
? `🔁
|
|
104
|
-
: "用法: /loop [间隔] <提示词>,如 /loop 5m 检查部署状态", "info");
|
|
108
|
+
? tr(`🔁 当前循环:${everyInterval(activeIntervalMs)} · ${preview(activePrompt)}(/loop stop 停止)`, `🔁 Current loop: ${everyInterval(activeIntervalMs)} · ${preview(activePrompt)} (/loop stop to stop)`)
|
|
109
|
+
: tr("用法: /loop [间隔] <提示词>,如 /loop 5m 检查部署状态", "Usage: /loop [interval] <prompt>, e.g. /loop 5m check the build status"), "info");
|
|
105
110
|
return;
|
|
106
111
|
}
|
|
107
112
|
if (/^(stop|off|取消|停止)$/i.test(input)) {
|
|
108
113
|
if (!timer) {
|
|
109
|
-
ctx.ui.notify("没有正在运行的循环", "info");
|
|
114
|
+
ctx.ui.notify(tr("没有正在运行的循环", "No loop is running"), "info");
|
|
110
115
|
return;
|
|
111
116
|
}
|
|
112
117
|
stopLoop(ctx.ui);
|
|
113
|
-
ctx.ui.notify("⏹ 循环已停止", "info");
|
|
118
|
+
ctx.ui.notify(tr("⏹ 循环已停止", "⏹ Loop stopped"), "info");
|
|
114
119
|
return;
|
|
115
120
|
}
|
|
116
121
|
const parsed = parseArgs(ctx.ui, input);
|
|
@@ -128,14 +133,15 @@ export function registerLoopCommand(pi) {
|
|
|
128
133
|
});
|
|
129
134
|
}
|
|
130
135
|
catch (e) {
|
|
131
|
-
|
|
136
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
137
|
+
ctx.ui.notify(tr(`loop 执行失败: ${reason}`, `Loop run failed: ${reason}`), "error");
|
|
132
138
|
}
|
|
133
139
|
};
|
|
134
140
|
// 第一轮立刻跑:用户写完命令就想看到结果,不该干等一个间隔
|
|
135
141
|
fire();
|
|
136
142
|
timer = setInterval(fire, activeIntervalMs);
|
|
137
|
-
ctx.ui.setStatus(STATUS_KEY, `🔁
|
|
138
|
-
ctx.ui.notify(`🔁
|
|
143
|
+
ctx.ui.setStatus(STATUS_KEY, `🔁 ${everyInterval(activeIntervalMs)} · ${preview(activePrompt)}`);
|
|
144
|
+
ctx.ui.notify(tr(`🔁 已开始:现在先跑第一轮,之后${everyInterval(activeIntervalMs)}一次「${preview(activePrompt)}」`, `🔁 Started: running the first round now, then ${everyInterval(activeIntervalMs)}: "${preview(activePrompt)}"`), "info");
|
|
139
145
|
},
|
|
140
146
|
});
|
|
141
147
|
}
|
package/dist/mcp/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { VERSION } from "../config.js";
|
|
3
|
+
import { tr } from "../i18n.js";
|
|
3
4
|
/**
|
|
4
5
|
* 极简 MCP 客户端:只做 initialize / tools/list / tools/call 三件事,
|
|
5
6
|
* 支持 stdio(本机进程,按行 JSON-RPC)和 Streamable HTTP(POST JSON,
|
|
@@ -29,8 +30,8 @@ function withTimeout(promise, timeoutMs, signal, what) {
|
|
|
29
30
|
signal?.removeEventListener("abort", onAbort);
|
|
30
31
|
fn(v);
|
|
31
32
|
};
|
|
32
|
-
const onAbort = () => finish(reject)(new McpError(`${what}
|
|
33
|
-
const timer = setTimeout(() => finish(reject)(new McpError(`${what} 超过 ${Math.round(timeoutMs / 1000)}s
|
|
33
|
+
const onAbort = () => finish(reject)(new McpError(tr(`${what} 已取消`, `${what} was canceled`)));
|
|
34
|
+
const timer = setTimeout(() => finish(reject)(new McpError(tr(`${what} 超过 ${Math.round(timeoutMs / 1000)}s 未响应`, `${what} timed out after ${Math.round(timeoutMs / 1000)}s`))), timeoutMs);
|
|
34
35
|
promise.then(finish(resolve), finish(reject));
|
|
35
36
|
if (signal?.aborted)
|
|
36
37
|
onAbort();
|
|
@@ -92,12 +93,12 @@ class StdioTransport {
|
|
|
92
93
|
// spawn 失败(ENOENT 等)不会再有 exit 事件
|
|
93
94
|
if (child.pid === undefined)
|
|
94
95
|
process.removeListener("exit", onParentExit);
|
|
95
|
-
this.fail(new McpError(`启动 ${this.command} 失败:${err.message}`));
|
|
96
|
+
this.fail(new McpError(tr(`启动 ${this.command} 失败:${err.message}`, `Failed to start ${this.command}: ${err.message}`)));
|
|
96
97
|
});
|
|
97
98
|
child.on("exit", (code, sig) => {
|
|
98
99
|
process.removeListener("exit", onParentExit);
|
|
99
100
|
const tail = this.stderrTail.slice(-5).join("\n");
|
|
100
|
-
this.fail(new McpError(
|
|
101
|
+
this.fail(new McpError(`${tr("MCP 服务进程已退出", "MCP server process exited")}(${sig ?? `code ${code ?? 0}`})${tail ? `\n${tail}` : ""}`));
|
|
101
102
|
});
|
|
102
103
|
}
|
|
103
104
|
fail(err) {
|
|
@@ -146,7 +147,7 @@ class StdioTransport {
|
|
|
146
147
|
throw this.exited;
|
|
147
148
|
const stdin = this.child?.stdin;
|
|
148
149
|
if (!stdin || stdin.destroyed)
|
|
149
|
-
throw new McpError("MCP 服务进程 stdin 已关闭");
|
|
150
|
+
throw new McpError(tr("MCP 服务进程 stdin 已关闭", "MCP server process stdin is closed"));
|
|
150
151
|
stdin.write(`${JSON.stringify(msg)}\n`);
|
|
151
152
|
}
|
|
152
153
|
request(msg, timeoutMs, signal) {
|
|
@@ -161,7 +162,7 @@ class StdioTransport {
|
|
|
161
162
|
reject(err);
|
|
162
163
|
}
|
|
163
164
|
});
|
|
164
|
-
return withTimeout(promise, timeoutMs, signal, msg.method ?? "请求").finally(() => this.pending.delete(id));
|
|
165
|
+
return withTimeout(promise, timeoutMs, signal, msg.method ?? tr("请求", "request")).finally(() => this.pending.delete(id));
|
|
165
166
|
}
|
|
166
167
|
async notify(msg) {
|
|
167
168
|
this.write(msg);
|
|
@@ -170,7 +171,7 @@ class StdioTransport {
|
|
|
170
171
|
const child = this.child;
|
|
171
172
|
if (!child)
|
|
172
173
|
return;
|
|
173
|
-
this.fail(new McpError("MCP 连接已关闭"));
|
|
174
|
+
this.fail(new McpError(tr("MCP 连接已关闭", "MCP connection closed")));
|
|
174
175
|
try {
|
|
175
176
|
child.stdin?.end();
|
|
176
177
|
}
|
|
@@ -252,10 +253,10 @@ class HttpTransport {
|
|
|
252
253
|
}
|
|
253
254
|
catch (err) {
|
|
254
255
|
if (signal?.aborted)
|
|
255
|
-
throw new McpError(`${msg.method ?? "请求"}
|
|
256
|
+
throw new McpError(tr(`${msg.method ?? "请求"} 已取消`, `${msg.method ?? "request"} was canceled`));
|
|
256
257
|
if (ctrl.signal.aborted)
|
|
257
|
-
throw new McpError(`${msg.method ?? "请求"} 超过 ${Math.round(timeoutMs / 1000)}s
|
|
258
|
-
throw new McpError(`连接 ${this.url} 失败:${err.message}`);
|
|
258
|
+
throw new McpError(tr(`${msg.method ?? "请求"} 超过 ${Math.round(timeoutMs / 1000)}s 未响应`, `${msg.method ?? "request"} timed out after ${Math.round(timeoutMs / 1000)}s`));
|
|
259
|
+
throw new McpError(tr(`连接 ${this.url} 失败:${err.message}`, `Failed to connect to ${this.url}: ${err.message}`));
|
|
259
260
|
}
|
|
260
261
|
finally {
|
|
261
262
|
clearTimeout(timer);
|
|
@@ -270,7 +271,7 @@ class HttpTransport {
|
|
|
270
271
|
if (!resp.ok) {
|
|
271
272
|
const text = (await resp.text().catch(() => "")).slice(0, 300);
|
|
272
273
|
if (resp.status === 401 || resp.status === 403) {
|
|
273
|
-
throw new McpError(`服务拒绝访问(HTTP ${resp.status}),请检查 headers 里的鉴权信息${text ? `:${text}` : ""}`, resp.status);
|
|
274
|
+
throw new McpError(tr(`服务拒绝访问(HTTP ${resp.status}),请检查 headers 里的鉴权信息${text ? `:${text}` : ""}`, `Access denied by server (HTTP ${resp.status}); check the auth headers${text ? `: ${text}` : ""}`), resp.status);
|
|
274
275
|
}
|
|
275
276
|
throw new McpError(`HTTP ${resp.status}${text ? `:${text}` : ""}`, resp.status);
|
|
276
277
|
}
|
|
@@ -292,13 +293,13 @@ class HttpTransport {
|
|
|
292
293
|
return m;
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
|
-
throw new McpError(`服务没有返回 ${msg.method ?? "请求"} 的结果(content-type ${ctype || "unknown"})`);
|
|
296
|
+
throw new McpError(tr(`服务没有返回 ${msg.method ?? "请求"} 的结果(content-type ${ctype || "unknown"})`, `Server returned no result for ${msg.method ?? "request"} (content-type ${ctype || "unknown"})`));
|
|
296
297
|
}
|
|
297
298
|
async notify(msg) {
|
|
298
299
|
const resp = await this.post(msg, 10_000);
|
|
299
300
|
// 规范要求 202;有些实现回 200/204,都当成功。鉴权失败要冒出来
|
|
300
301
|
if (resp.status === 401 || resp.status === 403)
|
|
301
|
-
throw new McpError(`服务拒绝访问(HTTP ${resp.status})`, resp.status);
|
|
302
|
+
throw new McpError(tr(`服务拒绝访问(HTTP ${resp.status})`, `Access denied by server (HTTP ${resp.status})`), resp.status);
|
|
302
303
|
await resp.body?.cancel().catch(() => { });
|
|
303
304
|
}
|
|
304
305
|
async close() {
|
|
@@ -409,7 +410,7 @@ export class McpClient {
|
|
|
409
410
|
async rpc(method, params, timeoutMs, signal) {
|
|
410
411
|
const transport = this.transport;
|
|
411
412
|
if (!transport)
|
|
412
|
-
throw new McpError("尚未连接");
|
|
413
|
+
throw new McpError(tr("尚未连接", "Not connected"));
|
|
413
414
|
const id = this.nextId++;
|
|
414
415
|
const resp = await transport.request({ jsonrpc: "2.0", id, method, params }, timeoutMs, signal);
|
|
415
416
|
if (resp.error) {
|
package/dist/mcp/command.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type McpServerConfig } from "./config.js";
|
|
2
2
|
/**
|
|
3
|
-
* `u1s1 mcp` 子命令:管理自定义 MCP
|
|
4
|
-
* add
|
|
3
|
+
* `u1s1 mcp` 子命令:管理自定义 MCP 服务,写的是 pi 内置 MCP 读的 agent/mcp.json。
|
|
4
|
+
* add 时先连一次确认能用再落盘;对话里的连接、登录、停用交给 pi 的 /mcp。
|
|
5
5
|
*/
|
|
6
6
|
export declare function printMcpHelp(): void;
|
|
7
7
|
export declare class McpUsageError extends Error {
|
package/dist/mcp/command.js
CHANGED
|
@@ -2,14 +2,37 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { formatHomePath } from "../brand.js";
|
|
5
|
+
import { isEnglish, tr } from "../i18n.js";
|
|
5
6
|
import { McpClient } from "./client.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
7
|
+
import { loadMcpConfigDetailed, loadMcpToolCache, maskSecret, MCP_SERVER_NAME_RE, mcpConfigPath, migrateLegacyMcpConfig, normalizeServerConfig, parseKeyValue, saveMcpToolCache, updateMcpServers, } from "./config.js";
|
|
8
|
+
import { piMcpToolName } from "./tools.js";
|
|
8
9
|
/**
|
|
9
|
-
* `u1s1 mcp` 子命令:管理自定义 MCP
|
|
10
|
-
* add
|
|
10
|
+
* `u1s1 mcp` 子命令:管理自定义 MCP 服务,写的是 pi 内置 MCP 读的 agent/mcp.json。
|
|
11
|
+
* add 时先连一次确认能用再落盘;对话里的连接、登录、停用交给 pi 的 /mcp。
|
|
11
12
|
*/
|
|
12
13
|
export function printMcpHelp() {
|
|
14
|
+
if (isEnglish()) {
|
|
15
|
+
console.log("");
|
|
16
|
+
console.log(" Configure third-party MCP servers so their tools (search, databases, browsers…) are available in chat");
|
|
17
|
+
console.log("");
|
|
18
|
+
console.log(" Usage:");
|
|
19
|
+
console.log(" u1s1 mcp add <name> <command> [args...] Local command server (stdio), e.g.:");
|
|
20
|
+
console.log(" u1s1 mcp add tavily --env TAVILY_API_KEY=tvly-xxx npx -y tavily-mcp");
|
|
21
|
+
console.log(" u1s1 mcp add <name> --url <url> HTTP server (Streamable HTTP), e.g.:");
|
|
22
|
+
console.log(" u1s1 mcp add exa --url https://mcp.exa.ai/mcp --header \"Authorization: Bearer xxx\"");
|
|
23
|
+
console.log(" --env K=V / --header \"K: V\" can be repeated; --force saves even if connecting fails");
|
|
24
|
+
console.log(" u1s1 mcp list List configured servers and their tools");
|
|
25
|
+
console.log(" u1s1 mcp test <name> Connect once and list the tools it provides");
|
|
26
|
+
console.log(" u1s1 mcp remove <name> Remove a server");
|
|
27
|
+
console.log(" u1s1 mcp import [--dry-run] Import from Claude Code config (~/.claude.json, project .mcp.json)");
|
|
28
|
+
console.log("");
|
|
29
|
+
console.log(` Config is stored in ${formatHomePath(mcpConfigPath())} (same format as Claude Code's mcpServers; safe to edit by hand).`);
|
|
30
|
+
console.log(" It stays on this machine and is never uploaded. Tools are available from your next chat, named mcp__<name>__<tool>.");
|
|
31
|
+
console.log(" In chat, /mcp shows server status and lets you sign in (OAuth), reconnect, or disable a server.");
|
|
32
|
+
console.log(" Command servers run locally with your permissions; only add sources you trust.");
|
|
33
|
+
console.log("");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
13
36
|
console.log("");
|
|
14
37
|
console.log(" 配置第三方 MCP 服务,让它提供的工具(搜索、数据库、浏览器…)在对话里直接可用");
|
|
15
38
|
console.log("");
|
|
@@ -25,7 +48,8 @@ export function printMcpHelp() {
|
|
|
25
48
|
console.log(" u1s1 mcp import [--dry-run] 从 Claude Code 的配置(~/.claude.json、项目 .mcp.json)导入");
|
|
26
49
|
console.log("");
|
|
27
50
|
console.log(` 配置存在 ${formatHomePath(mcpConfigPath())}(与 Claude Code 的 mcpServers 同格式,可手改),`);
|
|
28
|
-
console.log(" 只在本机,不会上传。下次进对话工具即生效,名字形如
|
|
51
|
+
console.log(" 只在本机,不会上传。下次进对话工具即生效,名字形如 mcp__名称__工具。");
|
|
52
|
+
console.log(" 对话里输入 /mcp 可看连接状态,还能登录(OAuth)、重连、停用服务。");
|
|
29
53
|
console.log(" 命令型服务会以你的权限在本机运行,只添加可信来源。");
|
|
30
54
|
console.log("");
|
|
31
55
|
}
|
|
@@ -55,12 +79,12 @@ async function probe(name, server) {
|
|
|
55
79
|
}
|
|
56
80
|
function printTools(name, tools) {
|
|
57
81
|
if (tools.length === 0) {
|
|
58
|
-
console.log(" (该服务没有提供任何工具)");
|
|
82
|
+
console.log(tr(" (该服务没有提供任何工具)", " (this server provides no tools)"));
|
|
59
83
|
return;
|
|
60
84
|
}
|
|
61
85
|
for (const t of tools) {
|
|
62
86
|
const desc = t.description.replace(/\s+/g, " ").trim();
|
|
63
|
-
console.log(` · ${
|
|
87
|
+
console.log(` · ${piMcpToolName(name, t.name)}${desc ? ` ${desc.length > 80 ? `${desc.slice(0, 79)}…` : desc}` : ""}`);
|
|
64
88
|
}
|
|
65
89
|
}
|
|
66
90
|
function cacheTools(name, tools, serverName) {
|
|
@@ -86,24 +110,24 @@ function applyAddOption(arg, args, cursor, opts) {
|
|
|
86
110
|
else if (arg === "--url" || arg.startsWith("--url=")) {
|
|
87
111
|
opts.url = optionValue(arg, "--url=", args, cursor);
|
|
88
112
|
if (!opts.url)
|
|
89
|
-
fail("--url 后面要跟地址");
|
|
113
|
+
fail(tr("--url 后面要跟地址", "--url requires a URL"));
|
|
90
114
|
}
|
|
91
115
|
else if (arg === "--env" || arg === "-e" || arg.startsWith("--env=")) {
|
|
92
116
|
const raw = optionValue(arg, "--env=", args, cursor);
|
|
93
117
|
const kv = raw ? parseKeyValue(raw, "=") : undefined;
|
|
94
118
|
if (!kv)
|
|
95
|
-
fail(`--env 要写成 KEY=VALUE:${raw ?? ""}`);
|
|
119
|
+
fail(tr(`--env 要写成 KEY=VALUE:${raw ?? ""}`, `--env must be KEY=VALUE: ${raw ?? ""}`));
|
|
96
120
|
opts.env[kv[0]] = kv[1];
|
|
97
121
|
}
|
|
98
122
|
else if (arg === "--header" || arg === "-H" || arg.startsWith("--header=")) {
|
|
99
123
|
const raw = optionValue(arg, "--header=", args, cursor);
|
|
100
124
|
const kv = raw ? parseKeyValue(raw, ":") : undefined;
|
|
101
125
|
if (!kv)
|
|
102
|
-
fail(`--header 要写成 "Name: value":${raw ?? ""}`);
|
|
126
|
+
fail(tr(`--header 要写成 "Name: value":${raw ?? ""}`, `--header must be "Name: value": ${raw ?? ""}`));
|
|
103
127
|
opts.headers[kv[0]] = kv[1];
|
|
104
128
|
}
|
|
105
129
|
else if (arg.startsWith("-") && arg.length > 1) {
|
|
106
|
-
fail(`不认识的选项 ${arg}(命令自己的参数请放在命令后面,或用 -- 隔开)`);
|
|
130
|
+
fail(tr(`不认识的选项 ${arg}(命令自己的参数请放在命令后面,或用 -- 隔开)`, `Unknown option ${arg} (put the command's own arguments after the command, or separate them with --)`));
|
|
107
131
|
}
|
|
108
132
|
else {
|
|
109
133
|
opts.command = arg;
|
|
@@ -113,26 +137,26 @@ function applyAddOption(arg, args, cursor, opts) {
|
|
|
113
137
|
function serverFromAddOptions(name, opts) {
|
|
114
138
|
const { url, command, force } = opts;
|
|
115
139
|
if (url && command)
|
|
116
|
-
fail("--url 和命令只能二选一");
|
|
140
|
+
fail(tr("--url 和命令只能二选一", "Use either --url or a command, not both"));
|
|
117
141
|
if (url) {
|
|
118
142
|
if (!/^https?:\/\//i.test(url))
|
|
119
|
-
fail(`--url 必须是 http(s) 地址:${url}`);
|
|
143
|
+
fail(tr(`--url 必须是 http(s) 地址:${url}`, `--url must be an http(s) URL: ${url}`));
|
|
120
144
|
if (Object.keys(opts.env).length)
|
|
121
|
-
fail("HTTP 型服务不支持 --env,鉴权请用 --header");
|
|
145
|
+
fail(tr("HTTP 型服务不支持 --env,鉴权请用 --header", "HTTP servers don't support --env; use --header for auth"));
|
|
122
146
|
return { name, server: { type: "http", url, headers: opts.headers }, force };
|
|
123
147
|
}
|
|
124
148
|
if (!command)
|
|
125
|
-
fail("请给出启动命令(如 npx -y some-mcp-server)或 --url 地址");
|
|
149
|
+
fail(tr("请给出启动命令(如 npx -y some-mcp-server)或 --url 地址", "Provide a start command (e.g. npx -y some-mcp-server) or --url"));
|
|
126
150
|
if (Object.keys(opts.headers).length)
|
|
127
|
-
fail("命令型服务不支持 --header,请用 --env 传密钥");
|
|
151
|
+
fail(tr("命令型服务不支持 --header,请用 --env 传密钥", "Command servers don't support --header; pass secrets with --env"));
|
|
128
152
|
return { name, server: { type: "stdio", command, args: opts.commandArgs, env: opts.env }, force };
|
|
129
153
|
}
|
|
130
154
|
export function parseAddArgs(args) {
|
|
131
155
|
const name = args[0];
|
|
132
156
|
if (!name || name.startsWith("-"))
|
|
133
|
-
fail("请给服务起个名字,例:u1s1 mcp add tavily npx -y tavily-mcp");
|
|
157
|
+
fail(tr("请给服务起个名字,例:u1s1 mcp add tavily npx -y tavily-mcp", "Give the server a name, e.g. u1s1 mcp add tavily npx -y tavily-mcp"));
|
|
134
158
|
if (!MCP_SERVER_NAME_RE.test(name))
|
|
135
|
-
fail(`服务名只能用小写字母、数字、- 和 _,且以字母或数字开头(最长 32 位):${name}`);
|
|
159
|
+
fail(tr(`服务名只能用小写字母、数字、- 和 _,且以字母或数字开头(最长 32 位):${name}`, `Server names may only use lowercase letters, digits, - and _, must start with a letter or digit, and be at most 32 characters: ${name}`));
|
|
136
160
|
const opts = { commandArgs: [], env: {}, headers: {}, force: false };
|
|
137
161
|
const cursor = { i: 1 };
|
|
138
162
|
for (; cursor.i < args.length; cursor.i++) {
|
|
@@ -145,7 +169,7 @@ export function parseAddArgs(args) {
|
|
|
145
169
|
opts.command = args[cursor.i + 1];
|
|
146
170
|
opts.commandArgs.push(...args.slice(cursor.i + 2));
|
|
147
171
|
if (opts.command === undefined)
|
|
148
|
-
fail("-- 后面要跟命令");
|
|
172
|
+
fail(tr("-- 后面要跟命令", "-- must be followed by a command"));
|
|
149
173
|
break;
|
|
150
174
|
}
|
|
151
175
|
applyAddOption(a, args, cursor, opts);
|
|
@@ -154,10 +178,10 @@ export function parseAddArgs(args) {
|
|
|
154
178
|
}
|
|
155
179
|
async function addCommand(args) {
|
|
156
180
|
const { name, server, force } = parseAddArgs(args);
|
|
157
|
-
const config =
|
|
158
|
-
const existed = Boolean(config.mcpServers[name]);
|
|
159
|
-
console.log(`${existed ? "更新" : "添加"} MCP 服务 ${name}:${describeServer(server)}`);
|
|
160
|
-
console.log("连接中…");
|
|
181
|
+
const { config, disabled } = loadMcpConfigDetailed();
|
|
182
|
+
const existed = Boolean(config.mcpServers[name]) || disabled.includes(name);
|
|
183
|
+
console.log(tr(`${existed ? "更新" : "添加"} MCP 服务 ${name}:${describeServer(server)}`, `${existed ? "Updating" : "Adding"} MCP server ${name}: ${describeServer(server)}`));
|
|
184
|
+
console.log(tr("连接中…", "Connecting…"));
|
|
161
185
|
let tools = [];
|
|
162
186
|
let serverName;
|
|
163
187
|
let probed = false;
|
|
@@ -167,54 +191,69 @@ async function addCommand(args) {
|
|
|
167
191
|
}
|
|
168
192
|
catch (err) {
|
|
169
193
|
const message = err instanceof Error ? err.message : String(err);
|
|
170
|
-
if (!force)
|
|
171
|
-
|
|
172
|
-
|
|
194
|
+
if (!force) {
|
|
195
|
+
// 无 headers 的 HTTP 服务被拒,多半是要 OAuth 登录:先存下,进对话在 /mcp 里登
|
|
196
|
+
const oauthHint = server.type === "http" && !Object.keys(server.headers).length && /HTTP 40[13]/.test(message)
|
|
197
|
+
? tr("\n 如果这个服务用浏览器登录(OAuth),加 --force 保存,进对话后输入 /mcp 选它登录", "\n If this server signs in through the browser (OAuth), add --force to save it, then sign in from /mcp in chat")
|
|
198
|
+
: "";
|
|
199
|
+
fail(tr(`连接失败,未保存:${message}\n 确认命令/地址和密钥无误后重试;想先保存加 --force${oauthHint}`, `Connection failed; nothing saved: ${message}\n Check the command/URL and keys, then retry. To save anyway, add --force${oauthHint}`));
|
|
200
|
+
}
|
|
201
|
+
console.error(tr(`⚠ 连接失败:${message}\n 已按 --force 保存,进对话前请用 u1s1 mcp test ${name} 确认可用`, `⚠ Connection failed: ${message}\n Saved anyway (--force). Run u1s1 mcp test ${name} before using it in chat`));
|
|
173
202
|
}
|
|
174
|
-
|
|
175
|
-
saveMcpConfig(config);
|
|
203
|
+
updateMcpServers({ [name]: server });
|
|
176
204
|
if (probed) {
|
|
177
205
|
cacheTools(name, tools, serverName);
|
|
178
|
-
console.log(`✓ 已连接${serverName ? ` ${serverName}` : ""},提供 ${tools.length}
|
|
206
|
+
console.log(tr(`✓ 已连接${serverName ? ` ${serverName}` : ""},提供 ${tools.length} 个工具:`, `✓ Connected${serverName ? ` to ${serverName}` : ""}, ${tools.length} tool(s):`));
|
|
179
207
|
printTools(name, tools);
|
|
180
208
|
}
|
|
181
209
|
else {
|
|
182
210
|
dropCache(name);
|
|
183
211
|
}
|
|
184
|
-
console.log(`✓ 已保存到 ${formatHomePath(mcpConfigPath())}
|
|
185
|
-
if (server.type === "stdio")
|
|
186
|
-
console.log(" 提示:命令型服务会以你的权限在本机运行,只添加可信来源。");
|
|
212
|
+
console.log(tr(`✓ 已保存到 ${formatHomePath(mcpConfigPath())},下次进入对话即可使用`, `✓ Saved to ${formatHomePath(mcpConfigPath())}; available from your next chat`));
|
|
213
|
+
if (server.type === "stdio") {
|
|
214
|
+
console.log(tr(" 提示:命令型服务会以你的权限在本机运行,只添加可信来源。", " Note: command servers run locally with your permissions; only add sources you trust."));
|
|
215
|
+
}
|
|
187
216
|
}
|
|
188
217
|
function listCommand() {
|
|
189
|
-
const config =
|
|
218
|
+
const { config, invalid, disabled } = loadMcpConfigDetailed();
|
|
190
219
|
const names = Object.keys(config.mcpServers);
|
|
191
|
-
if (names.length === 0) {
|
|
192
|
-
console.log("还没有配置 MCP 服务。用 u1s1 mcp add 添加,或 u1s1 mcp import 从 Claude Code 导入。");
|
|
220
|
+
if (names.length === 0 && disabled.length === 0 && invalid.length === 0) {
|
|
221
|
+
console.log(tr("还没有配置 MCP 服务。用 u1s1 mcp add 添加,或 u1s1 mcp import 从 Claude Code 导入。", "No MCP servers configured yet. Add one with u1s1 mcp add, or import from Claude Code with u1s1 mcp import."));
|
|
193
222
|
return;
|
|
194
223
|
}
|
|
195
224
|
const cache = loadMcpToolCache();
|
|
196
|
-
|
|
225
|
+
const total = names.length + disabled.length + invalid.length;
|
|
226
|
+
console.log(tr(`已配置 ${total} 个 MCP 服务(${formatHomePath(mcpConfigPath())}):`, `${total} MCP server(s) configured (${formatHomePath(mcpConfigPath())}):`));
|
|
197
227
|
for (const name of names) {
|
|
198
228
|
const server = config.mcpServers[name];
|
|
199
229
|
const cached = cache.servers[name];
|
|
200
230
|
console.log("");
|
|
201
231
|
console.log(`${name} [${server.type}] ${describeServer(server)}`);
|
|
202
232
|
if (!cached) {
|
|
203
|
-
console.log(
|
|
233
|
+
console.log(tr(` 还没检测过工具清单,u1s1 mcp test ${name} 看看`, ` Tool list not checked yet; run u1s1 mcp test ${name}`));
|
|
204
234
|
continue;
|
|
205
235
|
}
|
|
206
|
-
|
|
236
|
+
const fetched = cached.fetchedAt.slice(0, 16).replace("T", " ");
|
|
237
|
+
console.log(tr(` ${cached.tools.length} 个工具(${fetched} 检测):`, ` ${cached.tools.length} tool(s) (checked ${fetched}):`));
|
|
207
238
|
printTools(name, cached.tools);
|
|
208
239
|
}
|
|
240
|
+
for (const name of disabled) {
|
|
241
|
+
console.log("");
|
|
242
|
+
console.log(tr(`${name} [已停用,对话里 /mcp 可重新启用]`, `${name} [disabled; re-enable it from /mcp in chat]`));
|
|
243
|
+
}
|
|
244
|
+
for (const name of invalid) {
|
|
245
|
+
console.log("");
|
|
246
|
+
console.log(tr(`${name} [配置无效,请检查这一条]`, `${name} [invalid entry; please check it]`));
|
|
247
|
+
}
|
|
209
248
|
}
|
|
210
249
|
async function testCommand(name) {
|
|
211
250
|
if (!name)
|
|
212
|
-
fail("用法:u1s1 mcp test 名称");
|
|
213
|
-
const config =
|
|
251
|
+
fail(tr("用法:u1s1 mcp test 名称", "Usage: u1s1 mcp test <name>"));
|
|
252
|
+
const { config } = loadMcpConfigDetailed();
|
|
214
253
|
const server = config.mcpServers[name];
|
|
215
254
|
if (!server)
|
|
216
|
-
fail(`没有叫 ${name} 的 MCP 服务,u1s1 mcp list
|
|
217
|
-
console.log(`连接 ${name}:${describeServer(server)}`);
|
|
255
|
+
fail(tr(`没有叫 ${name} 的 MCP 服务,u1s1 mcp list 看看已有的`, `No MCP server named ${name}; run u1s1 mcp list to see configured servers`));
|
|
256
|
+
console.log(tr(`连接 ${name}:${describeServer(server)}`, `Connecting to ${name}: ${describeServer(server)}`));
|
|
218
257
|
const started = Date.now();
|
|
219
258
|
let tools;
|
|
220
259
|
let serverName;
|
|
@@ -222,22 +261,23 @@ async function testCommand(name) {
|
|
|
222
261
|
({ tools, serverName } = await probe(name, server));
|
|
223
262
|
}
|
|
224
263
|
catch (err) {
|
|
225
|
-
|
|
264
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
265
|
+
fail(tr(`连接失败:${message}`, `Connection failed: ${message}`));
|
|
226
266
|
}
|
|
227
267
|
cacheTools(name, tools, serverName);
|
|
228
|
-
|
|
268
|
+
const ms = Date.now() - started;
|
|
269
|
+
console.log(tr(`✓ 连接成功${serverName ? `(${serverName})` : ""},${ms} ms,提供 ${tools.length} 个工具:`, `✓ Connected${serverName ? ` (${serverName})` : ""} in ${ms} ms, ${tools.length} tool(s):`));
|
|
229
270
|
printTools(name, tools);
|
|
230
271
|
}
|
|
231
272
|
function removeCommand(name) {
|
|
232
273
|
if (!name)
|
|
233
|
-
fail("用法:u1s1 mcp remove 名称");
|
|
234
|
-
const config =
|
|
235
|
-
if (!config.mcpServers[name])
|
|
236
|
-
fail(`没有叫 ${name} 的 MCP
|
|
237
|
-
|
|
238
|
-
saveMcpConfig(config);
|
|
274
|
+
fail(tr("用法:u1s1 mcp remove 名称", "Usage: u1s1 mcp remove <name>"));
|
|
275
|
+
const { config, disabled } = loadMcpConfigDetailed();
|
|
276
|
+
if (!config.mcpServers[name] && !disabled.includes(name))
|
|
277
|
+
fail(tr(`没有叫 ${name} 的 MCP 服务`, `No MCP server named ${name}`));
|
|
278
|
+
updateMcpServers({ [name]: undefined });
|
|
239
279
|
dropCache(name);
|
|
240
|
-
console.log(`✓ 已删除 ${name}`);
|
|
280
|
+
console.log(tr(`✓ 已删除 ${name}`, `✓ Removed ${name}`));
|
|
241
281
|
}
|
|
242
282
|
/** Claude Code 的 MCP 配置:~/.claude.json(用户级 + 各项目)与项目 .mcp.json */
|
|
243
283
|
export function collectClaudeMcpServers(home = homedir(), cwd = process.cwd()) {
|
|
@@ -253,11 +293,11 @@ export function collectClaudeMcpServers(home = homedir(), cwd = process.cwd()) {
|
|
|
253
293
|
continue;
|
|
254
294
|
const server = normalizeServerConfig(raw);
|
|
255
295
|
if (!server) {
|
|
256
|
-
unsupported.push(`${name}(${source})`);
|
|
296
|
+
unsupported.push(tr(`${name}(${source})`, `${name} (${source})`));
|
|
257
297
|
continue;
|
|
258
298
|
}
|
|
259
299
|
if (!MCP_SERVER_NAME_RE.test(name)) {
|
|
260
|
-
unsupported.push(`${name}(${source},名字不合规)`);
|
|
300
|
+
unsupported.push(tr(`${name}(${source},名字不合规)`, `${name} (${source}, invalid name)`));
|
|
261
301
|
continue;
|
|
262
302
|
}
|
|
263
303
|
seen.add(key);
|
|
@@ -282,7 +322,7 @@ export function collectClaudeMcpServers(home = homedir(), cwd = process.cwd()) {
|
|
|
282
322
|
if (projects && typeof projects === "object") {
|
|
283
323
|
const entry = projects[resolve(cwd)];
|
|
284
324
|
if (entry && typeof entry === "object")
|
|
285
|
-
take(entry["mcpServers"], "~/.claude.json 项目配置");
|
|
325
|
+
take(entry["mcpServers"], tr("~/.claude.json 项目配置", "~/.claude.json project config"));
|
|
286
326
|
}
|
|
287
327
|
take(user?.["mcpServers"], "~/.claude.json");
|
|
288
328
|
return { candidates, unsupported };
|
|
@@ -291,32 +331,30 @@ async function importCommand(args) {
|
|
|
291
331
|
const dryRun = args.includes("--dry-run");
|
|
292
332
|
const { candidates, unsupported } = collectClaudeMcpServers();
|
|
293
333
|
for (const u of unsupported)
|
|
294
|
-
console.log(`⚠ 跳过 ${u}:只支持命令型(stdio)和 HTTP
|
|
334
|
+
console.log(tr(`⚠ 跳过 ${u}:只支持命令型(stdio)和 HTTP 型服务`, `⚠ Skipped ${u}: only command (stdio) and HTTP servers are supported`));
|
|
295
335
|
if (candidates.length === 0) {
|
|
296
|
-
console.log("没有在 Claude Code 的配置里找到可导入的 MCP 服务。");
|
|
336
|
+
console.log(tr("没有在 Claude Code 的配置里找到可导入的 MCP 服务。", "No importable MCP servers found in Claude Code's config."));
|
|
297
337
|
return;
|
|
298
338
|
}
|
|
299
|
-
const config =
|
|
300
|
-
console.log(`找到 ${candidates.length} 个 MCP
|
|
339
|
+
const { config, disabled } = loadMcpConfigDetailed();
|
|
340
|
+
console.log(tr(`找到 ${candidates.length} 个 MCP 服务:`, `Found ${candidates.length} MCP server(s):`));
|
|
301
341
|
for (const c of candidates) {
|
|
302
|
-
const tag = config.mcpServers[c.name] ? "(已存在,将覆盖)" : "";
|
|
342
|
+
const tag = config.mcpServers[c.name] || disabled.includes(c.name) ? tr("(已存在,将覆盖)", "(exists, will be overwritten)") : "";
|
|
303
343
|
console.log(` ${c.name} ${describeServer(c.server)} ← ${c.source} ${tag}`);
|
|
304
344
|
}
|
|
305
345
|
if (dryRun) {
|
|
306
|
-
console.log("--dry-run:未写盘");
|
|
346
|
+
console.log(tr("--dry-run:未写盘", "--dry-run: nothing written"));
|
|
307
347
|
return;
|
|
308
348
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
saveMcpConfig(config);
|
|
312
|
-
console.log(`✓ 已保存到 ${formatHomePath(mcpConfigPath())}`);
|
|
349
|
+
updateMcpServers(Object.fromEntries(candidates.map((c) => [c.name, c.server])));
|
|
350
|
+
console.log(tr(`✓ 已保存到 ${formatHomePath(mcpConfigPath())}`, `✓ Saved to ${formatHomePath(mcpConfigPath())}`));
|
|
313
351
|
let failed = 0;
|
|
314
352
|
for (const c of candidates) {
|
|
315
|
-
process.stdout.write(`连接 ${c.name}… `);
|
|
353
|
+
process.stdout.write(tr(`连接 ${c.name}… `, `Connecting to ${c.name}… `));
|
|
316
354
|
try {
|
|
317
355
|
const { tools, serverName } = await probe(c.name, c.server);
|
|
318
356
|
cacheTools(c.name, tools, serverName);
|
|
319
|
-
console.log(`✓ ${tools.length}
|
|
357
|
+
console.log(tr(`✓ ${tools.length} 个工具`, `✓ ${tools.length} tool(s)`));
|
|
320
358
|
}
|
|
321
359
|
catch (err) {
|
|
322
360
|
failed += 1;
|
|
@@ -324,12 +362,14 @@ async function importCommand(args) {
|
|
|
324
362
|
console.log(`✗ ${(err instanceof Error ? err.message : String(err)).split("\n")[0]}`);
|
|
325
363
|
}
|
|
326
364
|
}
|
|
327
|
-
if (failed)
|
|
328
|
-
console.log(`${failed} 个服务连接失败,进对话前请用 u1s1 mcp test 名称 排查(失败的服务不会影响其他工具)`);
|
|
365
|
+
if (failed) {
|
|
366
|
+
console.log(tr(`${failed} 个服务连接失败,进对话前请用 u1s1 mcp test 名称 排查(失败的服务不会影响其他工具)`, `${failed} server(s) failed to connect; run u1s1 mcp test <name> before chatting (failed servers don't affect other tools)`));
|
|
367
|
+
}
|
|
329
368
|
}
|
|
330
369
|
export async function mcpCommand(args) {
|
|
331
370
|
const sub = args[0];
|
|
332
371
|
try {
|
|
372
|
+
migrateLegacyMcpConfig();
|
|
333
373
|
if (!sub || sub === "help" || sub === "-h" || sub === "--help") {
|
|
334
374
|
printMcpHelp();
|
|
335
375
|
return;
|
|
@@ -344,7 +384,7 @@ export async function mcpCommand(args) {
|
|
|
344
384
|
return removeCommand(args[1]);
|
|
345
385
|
if (sub === "import")
|
|
346
386
|
return await importCommand(args.slice(1));
|
|
347
|
-
fail(`不认识的子命令 ${sub},u1s1 mcp --help
|
|
387
|
+
fail(tr(`不认识的子命令 ${sub},u1s1 mcp --help 看用法`, `Unknown subcommand ${sub}; see u1s1 mcp --help`));
|
|
348
388
|
}
|
|
349
389
|
catch (err) {
|
|
350
390
|
if (err instanceof McpUsageError) {
|
package/dist/mcp/config.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 自定义 MCP 服务配置:~/.u1s1/mcp.json
|
|
3
|
-
*
|
|
4
|
-
* writePrivateFile(0600),并且永远不上传、不进遥测。
|
|
2
|
+
* 自定义 MCP 服务配置:~/.u1s1/agent/mcp.json,即 pi 内置 MCP 读的用户级配置,
|
|
3
|
+
* 形状与 Claude Code 的 mcpServers 一致,方便手改或从别的工具照抄。里面可能有
|
|
4
|
+
* API Key(env / headers),所以走 writePrivateFile(0600),并且永远不上传、不进遥测。
|
|
5
|
+
* pi 的 /mcp 会往条目里写 exposure、enabled 等字段,这里改写时逐条保留原样。
|
|
5
6
|
*/
|
|
6
7
|
export interface McpStdioServer {
|
|
7
8
|
type: "stdio";
|
|
@@ -32,9 +33,11 @@ export interface McpToolCache {
|
|
|
32
33
|
version: 1;
|
|
33
34
|
servers: Record<string, McpCachedServer>;
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
+
/** u1s1 mcp add 收的服务名:比 pi 的规则更严,工具名前缀短且全小写。 */
|
|
36
37
|
export declare const MCP_SERVER_NAME_RE: RegExp;
|
|
37
38
|
export declare function mcpConfigPath(): string;
|
|
39
|
+
/** ≤1.12 的配置位置,启动时迁到 mcpConfigPath()。 */
|
|
40
|
+
export declare function legacyMcpConfigPath(): string;
|
|
38
41
|
export declare function mcpCachePath(): string;
|
|
39
42
|
/**
|
|
40
43
|
* 把一条 mcpServers 记录规整成内部形状。兼容 Claude Code 的写法:
|
|
@@ -42,13 +45,26 @@ export declare function mcpCachePath(): string;
|
|
|
42
45
|
* SSE 传输)不支持,返回 undefined 让调用方提示。
|
|
43
46
|
*/
|
|
44
47
|
export declare function normalizeServerConfig(raw: unknown): McpServerConfig | undefined;
|
|
48
|
+
/** enabled:false(在 /mcp 里停用)的服务不进 config,名字放进 disabled。 */
|
|
45
49
|
export declare function parseMcpConfig(raw: unknown): {
|
|
46
50
|
config: McpConfig;
|
|
47
51
|
invalid: string[];
|
|
52
|
+
disabled: string[];
|
|
48
53
|
};
|
|
49
54
|
export declare function loadMcpConfig(path?: string): McpConfig;
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
export declare function loadMcpConfigDetailed(path?: string): ReturnType<typeof parseMcpConfig>;
|
|
56
|
+
/**
|
|
57
|
+
* 改写 mcpServers:value 为 undefined 即删除。其余顶层字段与没动到的条目原样保留;
|
|
58
|
+
* 覆盖已有条目时只换传输字段(命令/地址/env/headers),description、exposure 等留着。
|
|
59
|
+
*/
|
|
60
|
+
export declare function updateMcpServers(changes: Record<string, McpServerConfig | undefined>, path?: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* 把 ≤1.12 的 ~/.u1s1/mcp.json 并进 pi 读的 agent/mcp.json(同名以新文件为准),
|
|
63
|
+
* 旧文件改名留底。条目原样搬(补上 direct,保持原来工具直接给模型),格式本来就一致;
|
|
64
|
+
* sse 等 pi 不支持的条目由 pi 报错跳过。
|
|
65
|
+
* 返回搬过去的服务名;没有旧文件时什么也不做。
|
|
66
|
+
*/
|
|
67
|
+
export declare function migrateLegacyMcpConfig(legacyPath?: string, path?: string): string[];
|
|
52
68
|
export declare function loadMcpToolCache(path?: string): McpToolCache;
|
|
53
69
|
export declare function saveMcpToolCache(cache: McpToolCache, path?: string): void;
|
|
54
70
|
/** 工具列表是否变化(名称 + 参数结构),用来决定要不要提示重启。 */
|
package/dist/mcp/config.js
CHANGED
|
Binary file
|