tyc-cli 0.3.7 → 0.3.9
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/CHANGELOG.md +9 -0
- package/README.md +16 -10
- package/dist/catalog.json +332 -170
- package/dist/commands/capabilities.js +1 -2
- package/dist/commands/category.js +2 -3
- package/dist/commands/init.js +35 -11
- package/dist/commands/login.js +185 -81
- package/dist/commands/output.js +2 -4
- package/dist/config.js +1 -2
- package/dist/index.js +13 -4
- package/dist/oauth.js +129 -25
- package/dist/oauthPending.js +3 -2
- package/dist/registry.js +1 -1
- package/dist/utils/history.js +68 -0
- package/dist/utils/jsonToMarkdown.js +134 -26
- package/dist/utils/personnelChanges.js +74 -0
- package/package.json +1 -1
|
@@ -25,8 +25,7 @@ export function registerCompanyCapabilitiesCommand(companyCmd, program) {
|
|
|
25
25
|
}
|
|
26
26
|
catch (err) {
|
|
27
27
|
const msg = err instanceof Error ? err.message : String(err);
|
|
28
|
-
|
|
29
|
-
process.exit(1);
|
|
28
|
+
throw new Error(`请求失败: ${msg}`, { cause: err });
|
|
30
29
|
}
|
|
31
30
|
});
|
|
32
31
|
}
|
|
@@ -36,7 +36,7 @@ function bindMethod(catCmd, tool, program) {
|
|
|
36
36
|
// 都能直观看到分层信息;徽章不影响 Agent 对 description 的语义理解。
|
|
37
37
|
let methodCmd = catCmd
|
|
38
38
|
.command(tool.cliMethod)
|
|
39
|
-
.description(`[${tool.layer}] ${tool.description}
|
|
39
|
+
.description(`[${tool.layer}] ${tool.description} 调用额度:成功且返回有效结果计 1 次;报错、全部无结果和系统异常计 0 次。`);
|
|
40
40
|
if (positional) {
|
|
41
41
|
methodCmd = methodCmd.argument(`<${positional.name}>`, positional.description);
|
|
42
42
|
}
|
|
@@ -63,8 +63,7 @@ function bindMethod(catCmd, tool, program) {
|
|
|
63
63
|
}
|
|
64
64
|
catch (err) {
|
|
65
65
|
const msg = err instanceof Error ? err.message : String(err);
|
|
66
|
-
|
|
67
|
-
process.exit(1);
|
|
66
|
+
throw new Error(`请求失败: ${msg}`, { cause: err });
|
|
68
67
|
}
|
|
69
68
|
});
|
|
70
69
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { DEFAULT_MCP_URL, defaultCoreURL, loadConfig,
|
|
2
|
-
import { verifyCoreEndpoint } from "../coreClient.js";
|
|
1
|
+
import { DEFAULT_MCP_URL, defaultCoreURL, loadConfig, saveConfig, } from "../config.js";
|
|
2
|
+
import { verifyCoreAuthEndpoint, verifyCoreEndpoint } from "../coreClient.js";
|
|
3
|
+
import { printLoginSuccessBanner } from "../logo.js";
|
|
3
4
|
export function registerInitCommand(program) {
|
|
4
5
|
program
|
|
5
6
|
.command("init")
|
|
6
|
-
.description("配置 endpoint / Authorization(保存到 ~/.tyc/config.json
|
|
7
|
+
.description("配置 endpoint / Authorization(保存到 ~/.tyc/config.json,并校验配置)")
|
|
7
8
|
.option("--authorization <token>", "tyc OpenAPI Authorization(写入 headers.Authorization)")
|
|
8
9
|
.option("--url <url>", `MCP endpoint(默认 ${DEFAULT_MCP_URL})`)
|
|
9
10
|
.option("--core-url <url>", "Shared Core HTTP endpoint(默认从 --url 推导 /v1/core/tools/call)")
|
|
@@ -52,22 +53,45 @@ export function registerInitCommand(program) {
|
|
|
52
53
|
}
|
|
53
54
|
if (resetOAuth)
|
|
54
55
|
delete cfg.oauth;
|
|
56
|
+
const persistedAuthorization = cfg.headers.Authorization?.trim();
|
|
55
57
|
saveConfig(cfg);
|
|
56
|
-
|
|
58
|
+
const verbose = !!program.opts().verbose;
|
|
59
|
+
if (verbose) {
|
|
60
|
+
console.error(`> config saved to ~/.tyc/config.json (url=${cfg.url}, coreUrl=${cfg.coreUrl})`);
|
|
61
|
+
}
|
|
57
62
|
if (opts.verify === false) {
|
|
63
|
+
console.log(`已保存 ~/.tyc/config.json (url=${cfg.url}, coreUrl=${cfg.coreUrl})`);
|
|
58
64
|
return;
|
|
59
65
|
}
|
|
60
66
|
try {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
const verifyConfig = {
|
|
68
|
+
url: cfg.url,
|
|
69
|
+
coreUrl: cfg.coreUrl || defaultCoreURL(cfg.url),
|
|
70
|
+
headers: { ...(cfg.headers || {}) },
|
|
71
|
+
};
|
|
72
|
+
if (!verifyConfig.headers.Authorization && process.env.TYC_AUTHORIZATION) {
|
|
73
|
+
verifyConfig.headers.Authorization = process.env.TYC_AUTHORIZATION;
|
|
74
|
+
}
|
|
75
|
+
if (verifyConfig.headers.Authorization?.trim()) {
|
|
76
|
+
await verifyCoreAuthEndpoint(verifyConfig, verbose);
|
|
77
|
+
if (verbose) {
|
|
78
|
+
console.error("> Shared Core auth check passed");
|
|
79
|
+
}
|
|
80
|
+
if (persistedAuthorization) {
|
|
81
|
+
printLoginSuccessBanner();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
console.log("Authorization 校验通过(来自 TYC_AUTHORIZATION;未写入 ~/.tyc/config.json)");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
await verifyCoreEndpoint(verifyConfig, verbose);
|
|
89
|
+
console.log("Shared Core endpoint 校验通过");
|
|
90
|
+
}
|
|
65
91
|
}
|
|
66
92
|
catch (err) {
|
|
67
93
|
const msg = err instanceof Error ? err.message : String(err);
|
|
68
|
-
|
|
69
|
-
console.error("配置已保存;确认 --url 可达后重新运行 tyc init,或加 --no-verify 跳过校验。");
|
|
70
|
-
process.exit(1);
|
|
94
|
+
throw new Error(`配置校验失败:${msg}\n配置已保存;确认 --url 可达且 Authorization 有效后重新运行 tyc init,或加 --no-verify 跳过校验。`, { cause: err });
|
|
71
95
|
}
|
|
72
96
|
});
|
|
73
97
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_MCP_URL, applyOAuthTokenToConfig, defaultCoreURL, loadConfig, resolveConfig, saveConfig, } from "../config.js";
|
|
2
2
|
import { verifyCoreAuthEndpoint } from "../coreClient.js";
|
|
3
|
-
import { buildAuthorizationURL, buildCliCallbackRedirectUri, createPKCE, discoverAuthorizationServer, discoverProtectedResourceMetadata, exchangeAuthorizationCode, knownOAuthDefaultsForMcpURL, openBrowser, parseAuthorizationCallbackCode, randomState, registerDynamicOAuthClient, startCallbackServer, } from "../oauth.js";
|
|
3
|
+
import { buildAuthorizationURL, buildCliCallbackRedirectUri, createPKCE, DEVICE_CODE_GRANT_TYPE, discoverAuthorizationServer, discoverProtectedResourceMetadata, exchangeAuthorizationCode, exchangeDeviceCode, knownOAuthDefaultsForMcpURL, OAuthTokenEndpointError, openBrowser, parseAuthorizationCallbackCode, randomState, registerDynamicOAuthClient, requestDeviceAuthorization, startCallbackServer, } from "../oauth.js";
|
|
4
4
|
import { clearPendingOAuthLogin, loadPendingOAuthLogin, savePendingOAuthLogin, } from "../oauthPending.js";
|
|
5
5
|
import { printLoginSuccessBanner } from "../logo.js";
|
|
6
6
|
function parsePort(raw) {
|
|
@@ -45,6 +45,15 @@ async function verifySavedOAuthLogin(verify, verbose) {
|
|
|
45
45
|
}
|
|
46
46
|
printLoginSuccessBanner();
|
|
47
47
|
}
|
|
48
|
+
function isPendingDeviceLogin(pending) {
|
|
49
|
+
return pending.version === 2;
|
|
50
|
+
}
|
|
51
|
+
function isPendingPKCELogin(pending) {
|
|
52
|
+
return pending.version === 1;
|
|
53
|
+
}
|
|
54
|
+
function sleep(ms) {
|
|
55
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
|
+
}
|
|
48
57
|
async function completePendingOAuthLogin(pending, callbackToken, verify, verbose) {
|
|
49
58
|
const code = parseAuthorizationCallbackCode(callbackToken, pending.state);
|
|
50
59
|
if (verbose) {
|
|
@@ -68,6 +77,63 @@ async function completePendingOAuthLogin(pending, callbackToken, verify, verbose
|
|
|
68
77
|
clearPendingOAuthLogin(verbose);
|
|
69
78
|
await verifySavedOAuthLogin(verify, verbose);
|
|
70
79
|
}
|
|
80
|
+
async function completePendingDeviceLogin(pending, verify, verbose) {
|
|
81
|
+
if (pending.expiresAt <= Date.now()) {
|
|
82
|
+
clearPendingOAuthLogin(verbose);
|
|
83
|
+
throw new Error("OAuth device 授权已过期,请重新运行 tyc login --no-block。");
|
|
84
|
+
}
|
|
85
|
+
let intervalMs = Math.max(1, pending.interval || 5) * 1000;
|
|
86
|
+
const deadline = Date.now() + 30_000;
|
|
87
|
+
for (;;) {
|
|
88
|
+
try {
|
|
89
|
+
if (verbose) {
|
|
90
|
+
console.error("> polling OAuth device token endpoint");
|
|
91
|
+
}
|
|
92
|
+
const token = await exchangeDeviceCode({
|
|
93
|
+
tokenEndpoint: pending.tokenEndpoint,
|
|
94
|
+
clientId: pending.clientId,
|
|
95
|
+
clientSecret: pending.clientSecret,
|
|
96
|
+
deviceCode: pending.deviceCode,
|
|
97
|
+
resource: pending.resource,
|
|
98
|
+
});
|
|
99
|
+
saveOAuthTokenConfig(pending.mcpURL, token, {
|
|
100
|
+
tokenEndpoint: pending.tokenEndpoint,
|
|
101
|
+
clientId: pending.clientId,
|
|
102
|
+
clientSecret: pending.clientSecret,
|
|
103
|
+
resource: pending.resource,
|
|
104
|
+
scope: pending.scope,
|
|
105
|
+
}, verbose);
|
|
106
|
+
clearPendingOAuthLogin(verbose);
|
|
107
|
+
await verifySavedOAuthLogin(verify, verbose);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (!(err instanceof OAuthTokenEndpointError)) {
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
if (err.error === "authorization_pending" || err.error === "slow_down") {
|
|
115
|
+
if (err.error === "slow_down") {
|
|
116
|
+
intervalMs += 5_000;
|
|
117
|
+
}
|
|
118
|
+
if (Date.now() + intervalMs > deadline) {
|
|
119
|
+
throw new Error("授权尚未完成。请在网页输入 6 位验证码并确认后,再运行 tyc login --resume。");
|
|
120
|
+
}
|
|
121
|
+
await sleep(intervalMs);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (["expired_token", "access_denied", "invalid_grant"].includes(err.error)) {
|
|
125
|
+
clearPendingOAuthLogin(verbose);
|
|
126
|
+
}
|
|
127
|
+
if (err.error === "expired_token") {
|
|
128
|
+
throw new Error("OAuth device 授权已过期,请重新运行 tyc login --no-block。");
|
|
129
|
+
}
|
|
130
|
+
if (err.error === "access_denied") {
|
|
131
|
+
throw new Error("OAuth device 授权已被拒绝,请重新运行 tyc login --no-block。");
|
|
132
|
+
}
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
71
137
|
export function registerLoginCommand(program) {
|
|
72
138
|
program
|
|
73
139
|
.command("login")
|
|
@@ -81,21 +147,40 @@ export function registerLoginCommand(program) {
|
|
|
81
147
|
.option("--resource-metadata-url <url>", "手动指定 MCP protected resource metadata URL")
|
|
82
148
|
.option("--authorization-endpoint <url>", "手动指定 OAuth authorization endpoint")
|
|
83
149
|
.option("--token-endpoint <url>", "手动指定 OAuth token endpoint")
|
|
150
|
+
.option("--device-authorization-endpoint <url>", "手动指定 OAuth device authorization endpoint")
|
|
84
151
|
.option("--redirect-host <host>", "本地回调 host(默认 localhost)")
|
|
85
152
|
.option("--redirect-port <port>", "本地回调端口(默认 7078)")
|
|
86
153
|
.option("--callback-path <path>", "本地回调路径(默认 /oauth/callback)")
|
|
87
154
|
.option("--callback-token <code-or-url>", "继续非阻塞登录:传入授权回调 code 或包含 code 的完整 callback URL")
|
|
88
155
|
.option("--token <code-or-url>", "同 --callback-token(兼容别名;仍需传授权回调 code)")
|
|
156
|
+
.option("--resume", "继续 RFC 8628 device flow 非阻塞登录")
|
|
89
157
|
.option("--no-open", "不自动打开浏览器,只打印授权 URL")
|
|
90
|
-
.option("--no-block", "
|
|
158
|
+
.option("--no-block", "打印 Device Flow 授权 URL 和 6 位验证码并保存 pending 状态后立即退出")
|
|
91
159
|
.option("--no-verify", "保存 token 后跳过 shared core 鉴权校验")
|
|
92
160
|
.action(async (opts) => {
|
|
93
161
|
const verbose = !!program.opts().verbose;
|
|
94
162
|
const callbackToken = pickCallbackToken(opts);
|
|
163
|
+
if (opts.resume) {
|
|
164
|
+
if (callbackToken) {
|
|
165
|
+
throw new Error("--resume 不能与 --callback-token/--token 同时使用。");
|
|
166
|
+
}
|
|
167
|
+
const pending = loadPendingOAuthLogin();
|
|
168
|
+
if (!pending) {
|
|
169
|
+
throw new Error("未找到待完成的 OAuth device 登录状态。请先运行 tyc login --no-block。");
|
|
170
|
+
}
|
|
171
|
+
if (!isPendingDeviceLogin(pending)) {
|
|
172
|
+
throw new Error("当前待完成的是旧版 callback 登录,请使用 tyc login --callback-token <code-or-url>。");
|
|
173
|
+
}
|
|
174
|
+
await completePendingDeviceLogin(pending, opts.verify !== false && pending.verify !== false, verbose);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
95
177
|
if (callbackToken) {
|
|
96
178
|
const pending = loadPendingOAuthLogin();
|
|
97
179
|
if (!pending) {
|
|
98
|
-
throw new Error("未找到待完成的 OAuth 登录状态。请先运行 tyc login --no-
|
|
180
|
+
throw new Error("未找到待完成的 OAuth 登录状态。请先运行 tyc login --no-block。");
|
|
181
|
+
}
|
|
182
|
+
if (!isPendingPKCELogin(pending)) {
|
|
183
|
+
throw new Error("当前待完成的是 device 登录,请在网页确认后运行 tyc login --resume。");
|
|
99
184
|
}
|
|
100
185
|
if (verbose) {
|
|
101
186
|
console.error(`> loaded pending OAuth login from ~/.tyc/oauth_pending.json (url=${pending.mcpURL})`);
|
|
@@ -104,9 +189,6 @@ export function registerLoginCommand(program) {
|
|
|
104
189
|
return;
|
|
105
190
|
}
|
|
106
191
|
const noBlock = opts.block === false;
|
|
107
|
-
if (noBlock && opts.open !== false) {
|
|
108
|
-
throw new Error("--no-block 需要与 --no-open 一起使用。");
|
|
109
|
-
}
|
|
110
192
|
const current = loadConfig() || {};
|
|
111
193
|
const mcpURL = opts.url || process.env.TYC_MCP_ENDPOINT || current.url || DEFAULT_MCP_URL;
|
|
112
194
|
const knownDefaults = knownOAuthDefaultsForMcpURL(mcpURL);
|
|
@@ -158,6 +240,7 @@ export function registerLoginCommand(program) {
|
|
|
158
240
|
endpoints = {
|
|
159
241
|
authorizationEndpoint: opts.authorizationEndpoint,
|
|
160
242
|
tokenEndpoint: opts.tokenEndpoint,
|
|
243
|
+
deviceAuthorizationEndpoint: opts.deviceAuthorizationEndpoint,
|
|
161
244
|
issuer,
|
|
162
245
|
};
|
|
163
246
|
}
|
|
@@ -166,11 +249,16 @@ export function registerLoginCommand(program) {
|
|
|
166
249
|
endpoints.authorizationEndpoint =
|
|
167
250
|
opts.authorizationEndpoint || endpoints.authorizationEndpoint;
|
|
168
251
|
endpoints.tokenEndpoint = opts.tokenEndpoint || endpoints.tokenEndpoint;
|
|
252
|
+
endpoints.deviceAuthorizationEndpoint =
|
|
253
|
+
opts.deviceAuthorizationEndpoint || endpoints.deviceAuthorizationEndpoint;
|
|
169
254
|
}
|
|
170
255
|
resource ||= endpoints.resourceDocumentation || mcpURL;
|
|
171
256
|
if (verbose) {
|
|
172
257
|
console.error(`> authorization endpoint: ${endpoints.authorizationEndpoint}`);
|
|
173
258
|
console.error(`> token endpoint: ${endpoints.tokenEndpoint}`);
|
|
259
|
+
if (endpoints.deviceAuthorizationEndpoint) {
|
|
260
|
+
console.error(`> device authorization endpoint: ${endpoints.deviceAuthorizationEndpoint}`);
|
|
261
|
+
}
|
|
174
262
|
if (endpoints.registrationEndpoint) {
|
|
175
263
|
console.error(`> registration endpoint: ${endpoints.registrationEndpoint}`);
|
|
176
264
|
}
|
|
@@ -187,98 +275,114 @@ export function registerLoginCommand(program) {
|
|
|
187
275
|
state,
|
|
188
276
|
timeoutMs: 5 * 60 * 1000,
|
|
189
277
|
})).redirectUri;
|
|
190
|
-
|
|
191
|
-
if (!
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
try {
|
|
200
|
-
registeredClient = await registerDynamicOAuthClient({
|
|
278
|
+
try {
|
|
279
|
+
if (!clientId) {
|
|
280
|
+
if (!endpoints.registrationEndpoint) {
|
|
281
|
+
throw new Error("OAuth metadata 未提供 registration_endpoint,请用 --client-id 指定预注册客户端。");
|
|
282
|
+
}
|
|
283
|
+
if (verbose) {
|
|
284
|
+
console.error("> registering OAuth client via Dynamic Client Registration");
|
|
285
|
+
}
|
|
286
|
+
const registeredClient = await registerDynamicOAuthClient({
|
|
201
287
|
registrationEndpoint: endpoints.registrationEndpoint,
|
|
202
288
|
clientName: "tyc-cli",
|
|
203
289
|
redirectUris: [redirectUri],
|
|
290
|
+
grantTypes: noBlock
|
|
291
|
+
? ["authorization_code", "refresh_token", DEVICE_CODE_GRANT_TYPE]
|
|
292
|
+
: undefined,
|
|
293
|
+
responseTypes: ["code"],
|
|
204
294
|
tokenEndpointAuthMethod: "none",
|
|
205
295
|
});
|
|
296
|
+
clientId = registeredClient.clientId;
|
|
297
|
+
clientSecret ||= registeredClient.clientSecret;
|
|
298
|
+
if (verbose) {
|
|
299
|
+
console.error(`> registered client_id: ${clientId}`);
|
|
300
|
+
}
|
|
206
301
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
302
|
+
if (noBlock) {
|
|
303
|
+
if (!endpoints.deviceAuthorizationEndpoint) {
|
|
304
|
+
throw new Error("OAuth metadata 未提供 device_authorization_endpoint,请升级授权服务或使用 --device-authorization-endpoint 指定。");
|
|
305
|
+
}
|
|
306
|
+
const device = await requestDeviceAuthorization({
|
|
307
|
+
deviceAuthorizationEndpoint: endpoints.deviceAuthorizationEndpoint,
|
|
308
|
+
clientId,
|
|
309
|
+
clientSecret,
|
|
310
|
+
scope,
|
|
311
|
+
resource,
|
|
312
|
+
});
|
|
313
|
+
savePendingOAuthLogin({
|
|
314
|
+
version: 2,
|
|
315
|
+
flow: "device",
|
|
316
|
+
createdAt: Date.now(),
|
|
317
|
+
mcpURL,
|
|
318
|
+
tokenEndpoint: endpoints.tokenEndpoint,
|
|
319
|
+
clientId,
|
|
320
|
+
clientSecret,
|
|
321
|
+
deviceCode: device.device_code,
|
|
322
|
+
userCode: device.user_code,
|
|
323
|
+
verificationUri: device.verification_uri,
|
|
324
|
+
expiresAt: Date.now() + device.expires_in * 1000,
|
|
325
|
+
interval: device.interval || 5,
|
|
326
|
+
resource,
|
|
327
|
+
scope,
|
|
328
|
+
verify: opts.verify !== false,
|
|
329
|
+
});
|
|
330
|
+
console.error("请在浏览器打开以下 URL 完成登录:");
|
|
331
|
+
console.error(device.verification_uri);
|
|
332
|
+
console.error("");
|
|
333
|
+
console.error(`验证码:${device.user_code}`);
|
|
334
|
+
console.error("");
|
|
335
|
+
console.error("在网页输入 6 位验证码并确认授权后,运行:");
|
|
336
|
+
console.error("tyc login --resume");
|
|
337
|
+
return;
|
|
210
338
|
}
|
|
211
|
-
|
|
212
|
-
|
|
339
|
+
const authorizationURL = buildAuthorizationURL({
|
|
340
|
+
authorizationEndpoint: endpoints.authorizationEndpoint,
|
|
341
|
+
clientId,
|
|
342
|
+
redirectUri,
|
|
343
|
+
scope,
|
|
344
|
+
state,
|
|
345
|
+
codeChallenge: pkce.codeChallenge,
|
|
346
|
+
resource,
|
|
347
|
+
});
|
|
213
348
|
if (verbose) {
|
|
214
|
-
console.error(`>
|
|
349
|
+
console.error(`> OAuth callback: ${redirectUri}`);
|
|
215
350
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
createdAt: Date.now(),
|
|
233
|
-
mcpURL,
|
|
351
|
+
if (opts.open === false) {
|
|
352
|
+
console.error("请在浏览器打开以下 URL 完成登录:");
|
|
353
|
+
console.error(authorizationURL);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
console.error("正在打开浏览器完成 OAuth 登录...");
|
|
357
|
+
openBrowser(authorizationURL);
|
|
358
|
+
}
|
|
359
|
+
if (!callback) {
|
|
360
|
+
throw new Error("OAuth callback server not initialized");
|
|
361
|
+
}
|
|
362
|
+
const code = await callback.waitForCode();
|
|
363
|
+
if (verbose) {
|
|
364
|
+
console.error("> authorization code received; exchanging access token");
|
|
365
|
+
}
|
|
366
|
+
const token = await exchangeAuthorizationCode({
|
|
234
367
|
tokenEndpoint: endpoints.tokenEndpoint,
|
|
235
368
|
clientId,
|
|
236
369
|
clientSecret,
|
|
370
|
+
code,
|
|
237
371
|
redirectUri,
|
|
238
372
|
codeVerifier: pkce.codeVerifier,
|
|
239
373
|
resource,
|
|
240
|
-
state,
|
|
241
|
-
verify: opts.verify !== false,
|
|
242
374
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (opts.open === false) {
|
|
252
|
-
console.error("请在浏览器打开以下 URL 完成登录:");
|
|
253
|
-
console.error(authorizationURL);
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
console.error("正在打开浏览器完成 OAuth 登录...");
|
|
257
|
-
openBrowser(authorizationURL);
|
|
258
|
-
}
|
|
259
|
-
if (!callback) {
|
|
260
|
-
throw new Error("OAuth callback server not initialized");
|
|
375
|
+
saveOAuthTokenConfig(mcpURL, token, {
|
|
376
|
+
tokenEndpoint: endpoints.tokenEndpoint,
|
|
377
|
+
clientId,
|
|
378
|
+
clientSecret,
|
|
379
|
+
resource,
|
|
380
|
+
}, verbose);
|
|
381
|
+
clearPendingOAuthLogin(verbose);
|
|
382
|
+
await verifySavedOAuthLogin(opts.verify !== false, verbose);
|
|
261
383
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
console.error("> authorization code received; exchanging access token");
|
|
384
|
+
finally {
|
|
385
|
+
callback?.close();
|
|
265
386
|
}
|
|
266
|
-
const token = await exchangeAuthorizationCode({
|
|
267
|
-
tokenEndpoint: endpoints.tokenEndpoint,
|
|
268
|
-
clientId,
|
|
269
|
-
clientSecret,
|
|
270
|
-
code,
|
|
271
|
-
redirectUri,
|
|
272
|
-
codeVerifier: pkce.codeVerifier,
|
|
273
|
-
resource,
|
|
274
|
-
});
|
|
275
|
-
saveOAuthTokenConfig(mcpURL, token, {
|
|
276
|
-
tokenEndpoint: endpoints.tokenEndpoint,
|
|
277
|
-
clientId,
|
|
278
|
-
clientSecret,
|
|
279
|
-
resource,
|
|
280
|
-
}, verbose);
|
|
281
|
-
clearPendingOAuthLogin(verbose);
|
|
282
|
-
await verifySavedOAuthLogin(opts.verify !== false, verbose);
|
|
283
387
|
});
|
|
284
388
|
}
|
package/dist/commands/output.js
CHANGED
|
@@ -3,13 +3,11 @@ import { applyTruncation, resolveOptionalInt, TRUNCATE_DEFAULTS, } from "../util
|
|
|
3
3
|
export function emitToolResult(result, opts, toolName) {
|
|
4
4
|
if (result.isError) {
|
|
5
5
|
const errText = extractText(result) || "未知业务错误";
|
|
6
|
-
|
|
7
|
-
process.exit(1);
|
|
6
|
+
throw new Error(errText);
|
|
8
7
|
}
|
|
9
8
|
const text = extractText(result);
|
|
10
9
|
if (text === null) {
|
|
11
|
-
|
|
12
|
-
process.exit(1);
|
|
10
|
+
throw new Error("tools/call 返回无可解析内容");
|
|
13
11
|
}
|
|
14
12
|
let payload;
|
|
15
13
|
try {
|
package/dist/config.js
CHANGED
|
@@ -109,8 +109,7 @@ export function resolveConfig() {
|
|
|
109
109
|
headers.Authorization = process.env.TYC_AUTHORIZATION;
|
|
110
110
|
}
|
|
111
111
|
if (!headers.Authorization) {
|
|
112
|
-
|
|
113
|
-
process.exit(1);
|
|
112
|
+
throw new Error("未配置 Authorization。请先运行:tyc init --authorization YOUR_API_KEY");
|
|
114
113
|
}
|
|
115
114
|
return { url, coreUrl, headers, oauth: cfg.oauth ? { ...cfg.oauth } : undefined };
|
|
116
115
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from "commander";
|
|
2
|
+
import { Command, CommanderError } from "commander";
|
|
3
3
|
import { registerInitCommand } from "./commands/init.js";
|
|
4
4
|
import { registerLoginCommand } from "./commands/login.js";
|
|
5
5
|
import { registerCategoryCommands } from "./commands/category.js";
|
|
@@ -67,8 +67,9 @@ ${renderCategoryLines()}
|
|
|
67
67
|
初始化与登录
|
|
68
68
|
|
|
69
69
|
tyc login OAuth 浏览器登录
|
|
70
|
-
tyc login --no-
|
|
71
|
-
tyc login --
|
|
70
|
+
tyc login --no-block 打印 Device Flow URL 和 6 位验证码后立即退出
|
|
71
|
+
tyc login --resume 继续非阻塞 Device Flow 登录
|
|
72
|
+
tyc login --callback-token <CODE_OR_CALLBACK_URL> 继续旧版 callback OAuth 登录
|
|
72
73
|
tyc login --url <MCP_URL> 登录本地、预发或自托管 MCP
|
|
73
74
|
tyc init --authorization <KEY> 使用 API Key 兼容路径
|
|
74
75
|
tyc init --url <MCP_URL> --authorization <KEY> 配置本地或自托管服务
|
|
@@ -92,6 +93,7 @@ function renderPriorityLines() {
|
|
|
92
93
|
return lines.join("\n");
|
|
93
94
|
}
|
|
94
95
|
const program = new Command()
|
|
96
|
+
.exitOverride()
|
|
95
97
|
.name("tyc")
|
|
96
98
|
.description(`天眼查 AI CLI:${getTotalCount()} 个商业数据工具 · L0=${getLayerCount("L0")} L1=${getLayerCount("L1")} L2=${getLayerCount("L2")} L3=${getLayerCount("L3")} · 面向 Agent 的 MCP 工具网关`)
|
|
97
99
|
.version(VERSION, "-V, --version", "输出版本号")
|
|
@@ -124,7 +126,14 @@ registerLoginCommand(program);
|
|
|
124
126
|
registerLayerCommands(program);
|
|
125
127
|
registerCategoryCommands(program);
|
|
126
128
|
program.parseAsync(process.argv).catch((err) => {
|
|
129
|
+
// Commander has already printed help/version/argument errors. Preserve its
|
|
130
|
+
// exit status without printing twice or interrupting pending stream writes.
|
|
131
|
+
if (err instanceof CommanderError) {
|
|
132
|
+
process.exitCode = err.exitCode;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
127
135
|
const msg = err instanceof Error ? err.message : String(err);
|
|
128
136
|
console.error(msg);
|
|
129
|
-
|
|
137
|
+
// Let Node finish asynchronous I/O and teardown (including fetch on Windows).
|
|
138
|
+
process.exitCode = 1;
|
|
130
139
|
});
|