gaoding-cli 1.0.0-alpha.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/CHANGELOG.md +88 -0
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/SECURITY.md +34 -0
- package/dist/bin/gd-cli.d.ts +2 -0
- package/dist/bin/gd-cli.js +10 -0
- package/dist/src/api/app-runner.d.ts +33 -0
- package/dist/src/api/app-runner.js +1177 -0
- package/dist/src/api/dam-client.d.ts +111 -0
- package/dist/src/api/dam-client.js +897 -0
- package/dist/src/api/direct-auth.d.ts +3 -0
- package/dist/src/api/direct-auth.js +11 -0
- package/dist/src/api/direct-client.d.ts +27 -0
- package/dist/src/api/direct-client.js +151 -0
- package/dist/src/api/direct-tools.d.ts +43 -0
- package/dist/src/api/direct-tools.js +1155 -0
- package/dist/src/api/hub-client.d.ts +20 -0
- package/dist/src/api/hub-client.js +99 -0
- package/dist/src/api/sso-client.d.ts +60 -0
- package/dist/src/api/sso-client.js +140 -0
- package/dist/src/api/task-poller.d.ts +38 -0
- package/dist/src/api/task-poller.js +72 -0
- package/dist/src/api/tool-invoker.d.ts +12 -0
- package/dist/src/api/tool-invoker.js +11 -0
- package/dist/src/api/usage-client.d.ts +39 -0
- package/dist/src/api/usage-client.js +179 -0
- package/dist/src/auth/credential-store-v2.d.ts +12 -0
- package/dist/src/auth/credential-store-v2.js +59 -0
- package/dist/src/commands/auth.d.ts +2 -0
- package/dist/src/commands/auth.js +191 -0
- package/dist/src/commands/dam.d.ts +2 -0
- package/dist/src/commands/dam.js +293 -0
- package/dist/src/commands/models.d.ts +2 -0
- package/dist/src/commands/models.js +78 -0
- package/dist/src/commands/org.d.ts +2 -0
- package/dist/src/commands/org.js +137 -0
- package/dist/src/commands/skills.d.ts +2 -0
- package/dist/src/commands/skills.js +213 -0
- package/dist/src/commands/tools.d.ts +4 -0
- package/dist/src/commands/tools.js +383 -0
- package/dist/src/commands/update.d.ts +2 -0
- package/dist/src/commands/update.js +167 -0
- package/dist/src/commands/usage.d.ts +7 -0
- package/dist/src/commands/usage.js +43 -0
- package/dist/src/commands/workflows.d.ts +3 -0
- package/dist/src/commands/workflows.js +398 -0
- package/dist/src/core/auth/auth-provider.d.ts +8 -0
- package/dist/src/core/auth/auth-provider.js +12 -0
- package/dist/src/core/auth/device-oauth-provider.d.ts +12 -0
- package/dist/src/core/auth/device-oauth-provider.js +124 -0
- package/dist/src/core/auth/org-manager.d.ts +26 -0
- package/dist/src/core/auth/org-manager.js +224 -0
- package/dist/src/core/auth/signature.d.ts +19 -0
- package/dist/src/core/auth/signature.js +33 -0
- package/dist/src/core/auth/types.d.ts +52 -0
- package/dist/src/core/auth/types.js +3 -0
- package/dist/src/core/output/cli-error.d.ts +5 -0
- package/dist/src/core/output/cli-error.js +8 -0
- package/dist/src/core/output/detector.d.ts +5 -0
- package/dist/src/core/output/detector.js +14 -0
- package/dist/src/core/output/engine.d.ts +32 -0
- package/dist/src/core/output/engine.js +77 -0
- package/dist/src/core/output/envelope.d.ts +40 -0
- package/dist/src/core/output/envelope.js +119 -0
- package/dist/src/core/output/index.d.ts +4 -0
- package/dist/src/core/output/index.js +4 -0
- package/dist/src/core/output/live-display.d.ts +15 -0
- package/dist/src/core/output/live-display.js +111 -0
- package/dist/src/core/output/result-card.d.ts +18 -0
- package/dist/src/core/output/result-card.js +39 -0
- package/dist/src/core/prompt/index.d.ts +31 -0
- package/dist/src/core/prompt/index.js +36 -0
- package/dist/src/io.d.ts +14 -0
- package/dist/src/io.js +31 -0
- package/dist/src/middleware/auth.d.ts +3 -0
- package/dist/src/middleware/auth.js +74 -0
- package/dist/src/middleware/error-handler.d.ts +3 -0
- package/dist/src/middleware/error-handler.js +431 -0
- package/dist/src/middleware/interactive-params.d.ts +14 -0
- package/dist/src/middleware/interactive-params.js +53 -0
- package/dist/src/middleware/output.d.ts +14 -0
- package/dist/src/middleware/output.js +546 -0
- package/dist/src/models/model-catalog.d.ts +26 -0
- package/dist/src/models/model-catalog.js +216 -0
- package/dist/src/program.d.ts +2 -0
- package/dist/src/program.js +152 -0
- package/dist/src/registry/agent-contracts.d.ts +43 -0
- package/dist/src/registry/agent-contracts.js +483 -0
- package/dist/src/registry/app-loader.d.ts +2 -0
- package/dist/src/registry/app-loader.js +70 -0
- package/dist/src/registry/direct-registry.d.ts +11 -0
- package/dist/src/registry/direct-registry.js +234 -0
- package/dist/src/registry/registry-cache.d.ts +10 -0
- package/dist/src/registry/registry-cache.js +52 -0
- package/dist/src/registry/registry-client.d.ts +28 -0
- package/dist/src/registry/registry-client.js +50 -0
- package/dist/src/registry/types.d.ts +69 -0
- package/dist/src/registry/types.js +1 -0
- package/dist/src/tty/auth-presenter.d.ts +3 -0
- package/dist/src/tty/auth-presenter.js +21 -0
- package/dist/src/update/install-source.d.ts +19 -0
- package/dist/src/update/install-source.js +139 -0
- package/dist/src/update/notifier.d.ts +2 -0
- package/dist/src/update/notifier.js +59 -0
- package/dist/src/update/update-checker.d.ts +22 -0
- package/dist/src/update/update-checker.js +110 -0
- package/dist/src/update/version.d.ts +9 -0
- package/dist/src/update/version.js +52 -0
- package/dist/src/utils/agent-skill-installer.d.ts +57 -0
- package/dist/src/utils/agent-skill-installer.js +389 -0
- package/dist/src/utils/capability-metadata.d.ts +18 -0
- package/dist/src/utils/capability-metadata.js +88 -0
- package/dist/src/utils/capability-presenter.d.ts +4 -0
- package/dist/src/utils/capability-presenter.js +190 -0
- package/dist/src/utils/config.d.ts +16 -0
- package/dist/src/utils/config.js +54 -0
- package/dist/src/utils/credential-permissions.d.ts +2 -0
- package/dist/src/utils/credential-permissions.js +22 -0
- package/dist/src/utils/ecommerce-input-guidance.d.ts +15 -0
- package/dist/src/utils/ecommerce-input-guidance.js +85 -0
- package/dist/src/utils/endpoints.d.ts +52 -0
- package/dist/src/utils/endpoints.js +258 -0
- package/dist/src/utils/enrich-upload-params.d.ts +6 -0
- package/dist/src/utils/enrich-upload-params.js +11 -0
- package/dist/src/utils/entitlement.d.ts +17 -0
- package/dist/src/utils/entitlement.js +146 -0
- package/dist/src/utils/gd-home.d.ts +7 -0
- package/dist/src/utils/gd-home.js +26 -0
- package/dist/src/utils/help-verify.d.ts +9 -0
- package/dist/src/utils/help-verify.js +41 -0
- package/dist/src/utils/input-json.d.ts +3 -0
- package/dist/src/utils/input-json.js +61 -0
- package/dist/src/utils/list-output-format.d.ts +10 -0
- package/dist/src/utils/list-output-format.js +34 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.js +19 -0
- package/dist/src/utils/matting-compose.d.ts +10 -0
- package/dist/src/utils/matting-compose.js +45 -0
- package/dist/src/utils/open-browser.d.ts +1 -0
- package/dist/src/utils/open-browser.js +4 -0
- package/dist/src/utils/output-path.d.ts +5 -0
- package/dist/src/utils/output-path.js +70 -0
- package/dist/src/utils/redact.d.ts +3 -0
- package/dist/src/utils/redact.js +96 -0
- package/dist/src/utils/reference-image.d.ts +8 -0
- package/dist/src/utils/reference-image.js +43 -0
- package/dist/src/utils/resolve-app-local-images.d.ts +8 -0
- package/dist/src/utils/resolve-app-local-images.js +84 -0
- package/dist/src/utils/sensitive-path.d.ts +6 -0
- package/dist/src/utils/sensitive-path.js +69 -0
- package/dist/src/utils/settings-store.d.ts +42 -0
- package/dist/src/utils/settings-store.js +50 -0
- package/dist/src/utils/sleep.d.ts +1 -0
- package/dist/src/utils/sleep.js +3 -0
- package/dist/src/utils/spinner.d.ts +2 -0
- package/dist/src/utils/spinner.js +4 -0
- package/dist/src/utils/static-help.d.ts +2 -0
- package/dist/src/utils/static-help.js +3 -0
- package/dist/src/utils/tool-display.d.ts +10 -0
- package/dist/src/utils/tool-display.js +55 -0
- package/dist/src/utils/transient-network-error.d.ts +4 -0
- package/dist/src/utils/transient-network-error.js +40 -0
- package/dist/src/utils/url-safety.d.ts +6 -0
- package/dist/src/utils/url-safety.js +67 -0
- package/dist/src/utils/write-app-deliverables.d.ts +18 -0
- package/dist/src/utils/write-app-deliverables.js +386 -0
- package/package.json +91 -0
- package/skills/gd-cli/SKILL.md +57 -0
- package/skills/gd-cli/references/auth.md +31 -0
- package/skills/gd-cli/references/deliverables.md +22 -0
- package/skills/gd-cli/references/entitlement.md +21 -0
- package/skills/gd-cli/references/errors.md +19 -0
- package/skills/gd-cli/references/org.md +18 -0
- package/skills/gd-cli/references/sop.md +25 -0
- package/skills/gd-cli/references/tools.md +29 -0
- package/skills/gd-cli/references/update.md +16 -0
- package/skills/gd-cli/references/workflows.md +22 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { ApiError } from "../api/hub-client.js";
|
|
2
|
+
import { DirectApiError } from "../api/direct-client.js";
|
|
3
|
+
import { failedEnvelope, emitJson } from "../core/output/envelope.js";
|
|
4
|
+
import { CliUsageError } from "../core/output/cli-error.js";
|
|
5
|
+
import { isVerbose, isDebug } from "../utils/config.js";
|
|
6
|
+
import { isTransientNetworkError } from "../utils/transient-network-error.js";
|
|
7
|
+
import { detectEntitlementIssue, entitlementCliError, ENTITLEMENT_PRICING_URL, resolveEntitlementPricingUrl, } from "../utils/entitlement.js";
|
|
8
|
+
import { redactSensitiveText, redactSensitiveValue } from "../utils/redact.js";
|
|
9
|
+
const ERROR_GUIDES = {
|
|
10
|
+
AUTH_MISSING: "请先登录:\n gd-cli auth login",
|
|
11
|
+
AUTH_EXPIRED: "凭证已过期,请重新登录:\n gd-cli auth login",
|
|
12
|
+
AUTH_REFRESH_FAILED: "凭证刷新失败:\n gd-cli auth login",
|
|
13
|
+
AUTH_SCOPE_DENIED: "权限不足,请重新授权",
|
|
14
|
+
ORG_BIND_EXPIRED: "组织绑定已过期:\n gd-cli org switch",
|
|
15
|
+
ORG_INVALID: "当前组织无效:\n gd-cli org list",
|
|
16
|
+
PARAM_MISSING: "查看命令帮助:\n gd-cli <command> --help",
|
|
17
|
+
PARAM_INVALID: "参数值不合法,请检查参数格式",
|
|
18
|
+
TOOL_NOT_FOUND: "工具不存在:\n gd-cli tools ls",
|
|
19
|
+
APP_NOT_FOUND: "Workflow 不存在:\n gd-cli workflows ls",
|
|
20
|
+
TASK_NOT_FOUND: "任务不存在或已过期",
|
|
21
|
+
RATE_LIMITED: "请求过于频繁,请稍后重试",
|
|
22
|
+
QUOTA_EXCEEDED: `权益不足,请购买或升级后重试:\n ${ENTITLEMENT_PRICING_URL}`,
|
|
23
|
+
ENTITLEMENT_INSUFFICIENT: `权益不足,请购买或升级后重试:\n ${ENTITLEMENT_PRICING_URL}`,
|
|
24
|
+
};
|
|
25
|
+
export function withErrorHandler(handler) {
|
|
26
|
+
return async (...args) => {
|
|
27
|
+
try {
|
|
28
|
+
await handler(...args);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (shouldEmitJsonError(args)) {
|
|
32
|
+
emitJson(failedEnvelope(redactSensitiveValue(toCliErrorBody(error))));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (error instanceof CliUsageError) {
|
|
36
|
+
printCliUsageError(redactSensitiveValue(error.body));
|
|
37
|
+
}
|
|
38
|
+
else if (error instanceof DirectApiError) {
|
|
39
|
+
handleDirectApiError(error);
|
|
40
|
+
}
|
|
41
|
+
else if (error instanceof ApiError) {
|
|
42
|
+
handleApiError(error);
|
|
43
|
+
}
|
|
44
|
+
else if (error instanceof Error) {
|
|
45
|
+
const safeMessage = redactSensitiveText(error.message);
|
|
46
|
+
if (isRateLimitMessage(safeMessage)) {
|
|
47
|
+
console.error("Error: 请求过于频繁,已被平台限流。");
|
|
48
|
+
console.error("\n 请稍后重试,或减少并发和连续生成次数。\n");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
if (isMediaResourceDownloadError(safeMessage)) {
|
|
52
|
+
console.error(`Error: ${normalizeMediaResourceMessage(safeMessage)}`);
|
|
53
|
+
console.error("\n 请换用可访问的 HTTPS 图片 URL;视频首帧优先使用已验证可访问的图片结果 URL,或先去掉 --image 运行文生视频。\n");
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
if (isToolRouteUnavailableMessage(safeMessage)) {
|
|
57
|
+
printToolRouteUnavailableError(safeMessage);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const entitlement = detectEntitlementIssue({
|
|
61
|
+
message: safeMessage,
|
|
62
|
+
detail: error,
|
|
63
|
+
});
|
|
64
|
+
if (entitlement) {
|
|
65
|
+
printEntitlementError(entitlement.message, entitlement.hint, entitlement.diagnostic_context);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const lines = safeMessage.split("\n");
|
|
69
|
+
console.error(`Error: ${lines[0] ?? ""}`);
|
|
70
|
+
for (let i = 1; i < lines.length; i++) {
|
|
71
|
+
console.error(lines[i]);
|
|
72
|
+
}
|
|
73
|
+
if (isVerbose() || isDebug()) {
|
|
74
|
+
console.error(redactSensitiveText(error.stack ?? ""));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.error(`Error: ${redactSensitiveText(String(error))}`);
|
|
79
|
+
}
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function shouldEmitJsonError(args) {
|
|
85
|
+
let current = args.find(isCommandLike);
|
|
86
|
+
while (current) {
|
|
87
|
+
if (!isCommandLike(current))
|
|
88
|
+
return false;
|
|
89
|
+
const format = current.opts().format;
|
|
90
|
+
const json = current.opts().json;
|
|
91
|
+
if (json === true)
|
|
92
|
+
return true;
|
|
93
|
+
if (format === "json")
|
|
94
|
+
return true;
|
|
95
|
+
if (format)
|
|
96
|
+
return false;
|
|
97
|
+
current = current.parent;
|
|
98
|
+
}
|
|
99
|
+
return !process.stdout.isTTY;
|
|
100
|
+
}
|
|
101
|
+
function isCommandLike(value) {
|
|
102
|
+
return (!!value &&
|
|
103
|
+
typeof value === "object" &&
|
|
104
|
+
"opts" in value &&
|
|
105
|
+
typeof value.opts === "function");
|
|
106
|
+
}
|
|
107
|
+
function toCliErrorBody(error) {
|
|
108
|
+
if (error instanceof CliUsageError) {
|
|
109
|
+
return error.body;
|
|
110
|
+
}
|
|
111
|
+
if (error instanceof DirectApiError) {
|
|
112
|
+
const parsed = parseDirectApiErrorBody(error.body);
|
|
113
|
+
if (error.statusCode === 429) {
|
|
114
|
+
return {
|
|
115
|
+
code: "RATE_LIMITED",
|
|
116
|
+
type: "business",
|
|
117
|
+
message: "请求过于频繁,已被平台限流。",
|
|
118
|
+
hint: ERROR_GUIDES.RATE_LIMITED,
|
|
119
|
+
retryable: true,
|
|
120
|
+
detail: redactSensitiveValue(error.body),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const entitlement = detectEntitlementIssue({
|
|
124
|
+
code: parsed.code,
|
|
125
|
+
errorName: parsed.errorName,
|
|
126
|
+
message: parsed.message,
|
|
127
|
+
detail: redactSensitiveValue(error.body),
|
|
128
|
+
});
|
|
129
|
+
if (entitlement)
|
|
130
|
+
return redactSensitiveValue(entitlementCliError(entitlement, error.body));
|
|
131
|
+
if (isToolRouteUnavailableMessage(parsed.message ?? error.message)) {
|
|
132
|
+
return toolRouteUnavailableCliError(parsed.message ?? error.message, redactSensitiveValue(error.body));
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
code: parsed.code ?? `HTTP_${error.statusCode}`,
|
|
136
|
+
type: error.statusCode === 401 ? "auth" : "business",
|
|
137
|
+
message: parsed.message
|
|
138
|
+
? normalizeBusinessMessage(parsed.message)
|
|
139
|
+
: redactSensitiveText(error.message),
|
|
140
|
+
hint: redactSensitiveText(parsed.hint ?? directApiHint(parsed, error.url) ?? ""),
|
|
141
|
+
retryable: false,
|
|
142
|
+
detail: redactSensitiveValue(error.body),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (error instanceof ApiError) {
|
|
146
|
+
const parsed = parseJsonObject(error.body);
|
|
147
|
+
const code = stringField(parsed, "error_code") ?? stringField(parsed, "error") ?? "API_ERROR";
|
|
148
|
+
const message = stringField(parsed, "message") ?? error.message;
|
|
149
|
+
const entitlement = detectEntitlementIssue({
|
|
150
|
+
code,
|
|
151
|
+
message,
|
|
152
|
+
detail: parsed ?? error.body,
|
|
153
|
+
});
|
|
154
|
+
if (entitlement)
|
|
155
|
+
return redactSensitiveValue(entitlementCliError(entitlement, parsed ?? error.body));
|
|
156
|
+
return {
|
|
157
|
+
code,
|
|
158
|
+
type: code.startsWith("AUTH") ? "auth" : "business",
|
|
159
|
+
message: redactSensitiveText(message),
|
|
160
|
+
hint: redactSensitiveText(stringField(parsed, "suggestion") ?? errorGuide(code) ?? ""),
|
|
161
|
+
retryable: false,
|
|
162
|
+
detail: redactSensitiveValue(parsed ?? error.body),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (error instanceof Error) {
|
|
166
|
+
if (isRateLimitMessage(error.message)) {
|
|
167
|
+
return {
|
|
168
|
+
code: "RATE_LIMITED",
|
|
169
|
+
type: "business",
|
|
170
|
+
message: "请求过于频繁,已被平台限流。",
|
|
171
|
+
hint: ERROR_GUIDES.RATE_LIMITED,
|
|
172
|
+
retryable: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (isMediaResourceDownloadError(error.message)) {
|
|
176
|
+
return {
|
|
177
|
+
code: "MEDIA_RESOURCE_UNREACHABLE",
|
|
178
|
+
type: "business",
|
|
179
|
+
message: normalizeMediaResourceMessage(redactSensitiveText(error.message)),
|
|
180
|
+
hint: "请换用可访问的 HTTPS 图片 URL;视频首帧优先使用已验证可访问的图片结果 URL,或先去掉 --image 运行文生视频。",
|
|
181
|
+
retryable: false,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const retryable = isTransientNetworkError(error);
|
|
185
|
+
const entitlement = detectEntitlementIssue({
|
|
186
|
+
message: redactSensitiveText(error.message),
|
|
187
|
+
detail: error,
|
|
188
|
+
});
|
|
189
|
+
if (entitlement)
|
|
190
|
+
return entitlementCliError(entitlement);
|
|
191
|
+
if (isToolRouteUnavailableMessage(error.message)) {
|
|
192
|
+
return toolRouteUnavailableCliError(redactSensitiveText(error.message));
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
code: retryable ? "NETWORK_TRANSIENT" : "ERROR",
|
|
196
|
+
type: retryable ? "network" : "unknown",
|
|
197
|
+
message: redactSensitiveText(error.message),
|
|
198
|
+
retryable,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
code: "ERROR",
|
|
203
|
+
type: "unknown",
|
|
204
|
+
message: redactSensitiveText(String(error)),
|
|
205
|
+
retryable: false,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function printCliUsageError(body) {
|
|
209
|
+
console.error(`Error: ${body.message}`);
|
|
210
|
+
console.error(`\n 错误码: ${body.code}`);
|
|
211
|
+
if (body.reason)
|
|
212
|
+
console.error(` 原因: ${body.reason}`);
|
|
213
|
+
const detail = body.detail && typeof body.detail === "object" && !Array.isArray(body.detail)
|
|
214
|
+
? body.detail
|
|
215
|
+
: undefined;
|
|
216
|
+
const appId = body.app_id ?? stringField(detail, "app_id");
|
|
217
|
+
const toolId = body.tool_id ?? stringField(detail, "tool_id");
|
|
218
|
+
if (appId)
|
|
219
|
+
console.error(` Workflow: ${appId}`);
|
|
220
|
+
if (toolId)
|
|
221
|
+
console.error(` Tool: ${toolId}`);
|
|
222
|
+
const missingTools = Array.isArray(body.missing_tools)
|
|
223
|
+
? body.missing_tools
|
|
224
|
+
.map((item) => typeof item === "string"
|
|
225
|
+
? item
|
|
226
|
+
: stringField(item, "id") ?? "")
|
|
227
|
+
.filter(Boolean)
|
|
228
|
+
: [];
|
|
229
|
+
if (missingTools.length > 0) {
|
|
230
|
+
console.error(` 缺失 Tool: ${missingTools.join(", ")}`);
|
|
231
|
+
}
|
|
232
|
+
if (body.hint)
|
|
233
|
+
console.error(`\n 说明: ${body.hint}`);
|
|
234
|
+
if (body.next_command)
|
|
235
|
+
console.error(`\n 下一步: ${body.next_command}`);
|
|
236
|
+
const listCommand = stringField(detail, "list_command");
|
|
237
|
+
if (listCommand)
|
|
238
|
+
console.error(` 查看状态: ${listCommand}`);
|
|
239
|
+
console.error("");
|
|
240
|
+
}
|
|
241
|
+
function parseDirectApiErrorBody(body) {
|
|
242
|
+
const parsed = typeof body === "string" ? parseJsonObject(body) : body;
|
|
243
|
+
if (!parsed || typeof parsed !== "object")
|
|
244
|
+
return {};
|
|
245
|
+
const value = parsed;
|
|
246
|
+
const nestedError = value.error && typeof value.error === "object"
|
|
247
|
+
? value.error
|
|
248
|
+
: undefined;
|
|
249
|
+
return {
|
|
250
|
+
code: stringField(nestedError, "error_code") ??
|
|
251
|
+
stringField(nestedError, "code") ??
|
|
252
|
+
stringField(value, "error_code") ??
|
|
253
|
+
stringField(value, "code"),
|
|
254
|
+
errorName: stringField(nestedError, "error_name") ??
|
|
255
|
+
stringField(value, "error_name"),
|
|
256
|
+
message: stringField(nestedError, "message") ?? stringField(value, "message"),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function parseJsonObject(value) {
|
|
260
|
+
try {
|
|
261
|
+
const parsed = JSON.parse(value);
|
|
262
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
263
|
+
? parsed
|
|
264
|
+
: undefined;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function stringField(value, key) {
|
|
271
|
+
const field = value?.[key];
|
|
272
|
+
return typeof field === "string" && field ? field : undefined;
|
|
273
|
+
}
|
|
274
|
+
function handleApiError(error) {
|
|
275
|
+
let parsed = {};
|
|
276
|
+
try {
|
|
277
|
+
parsed = JSON.parse(error.body);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
parsed = { message: error.body };
|
|
281
|
+
}
|
|
282
|
+
const errorCode = parsed.error_code ?? parsed.error ?? "";
|
|
283
|
+
const message = redactSensitiveText(parsed.message ?? error.message);
|
|
284
|
+
const entitlement = detectEntitlementIssue({
|
|
285
|
+
code: errorCode,
|
|
286
|
+
message,
|
|
287
|
+
detail: parsed,
|
|
288
|
+
});
|
|
289
|
+
if (entitlement) {
|
|
290
|
+
printEntitlementError(entitlement.message, entitlement.hint, entitlement.diagnostic_context);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
console.error(`Error: ${message}`);
|
|
294
|
+
const guide = redactSensitiveText(parsed.suggestion ?? errorGuide(errorCode) ?? "");
|
|
295
|
+
if (guide) {
|
|
296
|
+
console.error(`\n ${guide}\n`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function handleDirectApiError(error) {
|
|
300
|
+
const parsed = parseDirectApiErrorBody(error.body);
|
|
301
|
+
const entitlement = detectEntitlementIssue({
|
|
302
|
+
code: parsed.code,
|
|
303
|
+
errorName: parsed.errorName,
|
|
304
|
+
message: parsed.message,
|
|
305
|
+
detail: error.body,
|
|
306
|
+
});
|
|
307
|
+
if (entitlement) {
|
|
308
|
+
printEntitlementError(entitlement.message, entitlement.hint, entitlement.diagnostic_context);
|
|
309
|
+
if (isVerbose() || isDebug()) {
|
|
310
|
+
const code = parsed.errorName ?? parsed.code;
|
|
311
|
+
const codeSuffix = code ? ` · ${code}` : "";
|
|
312
|
+
console.error(`\nHTTP ${error.statusCode}${codeSuffix}`);
|
|
313
|
+
console.error(`请求: ${redactSensitiveText(error.url)}`);
|
|
314
|
+
console.error(JSON.stringify(redactSensitiveValue(error.body), null, 2));
|
|
315
|
+
console.error(redactSensitiveText(error.stack ?? ""));
|
|
316
|
+
}
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const message = redactSensitiveText(normalizeBusinessMessage(parsed.message ?? error.message));
|
|
320
|
+
if (isToolRouteUnavailableMessage(message)) {
|
|
321
|
+
printToolRouteUnavailableError(message);
|
|
322
|
+
if (isVerbose() || isDebug()) {
|
|
323
|
+
const code = parsed.errorName ?? parsed.code;
|
|
324
|
+
const codeSuffix = code ? ` · ${code}` : "";
|
|
325
|
+
console.error(`\nHTTP ${error.statusCode}${codeSuffix}`);
|
|
326
|
+
console.error(`请求: ${redactSensitiveText(error.url)}`);
|
|
327
|
+
console.error(JSON.stringify(redactSensitiveValue(error.body), null, 2));
|
|
328
|
+
console.error(redactSensitiveText(error.stack ?? ""));
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (error.statusCode === 429 || isRateLimitMessage(message)) {
|
|
333
|
+
console.error("Error: 请求过于频繁,已被平台限流。");
|
|
334
|
+
console.error("\n 请稍后重试,或减少并发和连续生成次数。\n");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
console.error(`Error: ${message}`);
|
|
338
|
+
const hint = redactSensitiveText(directApiHint(parsed, error.url) ?? "");
|
|
339
|
+
if (hint) {
|
|
340
|
+
console.error(`\n ${hint}\n`);
|
|
341
|
+
}
|
|
342
|
+
if (isVerbose() || isDebug()) {
|
|
343
|
+
const code = parsed.errorName ?? parsed.code;
|
|
344
|
+
const codeSuffix = code ? ` · ${code}` : "";
|
|
345
|
+
console.error(`\nHTTP ${error.statusCode}${codeSuffix}`);
|
|
346
|
+
console.error(`请求: ${redactSensitiveText(error.url)}`);
|
|
347
|
+
console.error(JSON.stringify(redactSensitiveValue(error.body), null, 2));
|
|
348
|
+
console.error(redactSensitiveText(error.stack ?? ""));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function printEntitlementError(message, hint, diagnosticContext) {
|
|
352
|
+
console.error(`Error: ${redactSensitiveText(message)}`);
|
|
353
|
+
if ((isVerbose() || isDebug()) && diagnosticContext && Object.keys(diagnosticContext).length > 0) {
|
|
354
|
+
console.error(`\n 诊断上下文: ${formatDiagnosticContext(redactSensitiveValue(diagnosticContext))}`);
|
|
355
|
+
}
|
|
356
|
+
console.error(`\n ${redactSensitiveText(hint)}\n`);
|
|
357
|
+
}
|
|
358
|
+
function formatDiagnosticContext(context) {
|
|
359
|
+
return Object.entries(context)
|
|
360
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== "")
|
|
361
|
+
.map(([key, value]) => `${key}=${redactSensitiveText(Array.isArray(value) ? value.join(",") : String(value))}`)
|
|
362
|
+
.join(" ");
|
|
363
|
+
}
|
|
364
|
+
function toolRouteUnavailableCliError(message, detail) {
|
|
365
|
+
return {
|
|
366
|
+
code: "TOOL_ROUTE_UNAVAILABLE",
|
|
367
|
+
type: "business",
|
|
368
|
+
message: normalizeToolRouteUnavailableMessage(message),
|
|
369
|
+
reason: "tool-route-unavailable",
|
|
370
|
+
hint: "当前 Tool 的平台生成路由不可用。Agent 应停止重试,不要切换模型、环境、团队或调用内部 raw.dify;请保留本次输入并联系平台确认能力配置。",
|
|
371
|
+
retryable: false,
|
|
372
|
+
detail,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function printToolRouteUnavailableError(message) {
|
|
376
|
+
const body = toolRouteUnavailableCliError(message);
|
|
377
|
+
console.error(`Error: ${body.message}`);
|
|
378
|
+
console.error(`\n 错误码: ${body.code}`);
|
|
379
|
+
console.error(` 原因: ${body.reason}`);
|
|
380
|
+
console.error(`\n 说明: ${body.hint}\n`);
|
|
381
|
+
}
|
|
382
|
+
function isToolRouteUnavailableMessage(message) {
|
|
383
|
+
return /没有可用的工具|tool-intent 没有返回|tool intent 没有返回|工具路由|模型清单为空|平台.*未开通.*生成|暂未开通的生成通道/i
|
|
384
|
+
.test(message);
|
|
385
|
+
}
|
|
386
|
+
function normalizeToolRouteUnavailableMessage(message) {
|
|
387
|
+
const normalized = normalizeBusinessMessage(message);
|
|
388
|
+
if (/没有可用的工具|tool-intent 没有返回|tool intent 没有返回/i.test(normalized)) {
|
|
389
|
+
return "当前 Tool 的平台生成路由不可用,未发起生成任务。";
|
|
390
|
+
}
|
|
391
|
+
return normalized;
|
|
392
|
+
}
|
|
393
|
+
function normalizeBusinessMessage(message) {
|
|
394
|
+
if (message === "资产已位于回收站, 不允许访问") {
|
|
395
|
+
return "资产已位于回收站,无法访问";
|
|
396
|
+
}
|
|
397
|
+
return message.replace(/, /g, ",");
|
|
398
|
+
}
|
|
399
|
+
function isRateLimitMessage(message) {
|
|
400
|
+
return /429|Too Many Requests|rate.?limit|请求过于频繁|限流|频率/i.test(message);
|
|
401
|
+
}
|
|
402
|
+
function isMediaResourceDownloadError(message) {
|
|
403
|
+
return /resource download failed|image_url.*not valid|content\[\d+\]\.image_url|参考图.*下载|参考图.*视频生成服务|媒体.*下载失败|图片.*下载失败/i
|
|
404
|
+
.test(message);
|
|
405
|
+
}
|
|
406
|
+
function normalizeMediaResourceMessage(message) {
|
|
407
|
+
if (/^参考图/.test(message))
|
|
408
|
+
return message;
|
|
409
|
+
return "参考图无法被生成服务下载。";
|
|
410
|
+
}
|
|
411
|
+
function directApiHint(parsed, url) {
|
|
412
|
+
if (parsed.message === "资产已位于回收站, 不允许访问") {
|
|
413
|
+
return "该素材已被删除到回收站;请在 DAM 中恢复后再访问,或重新上传获取新的 asset_id。";
|
|
414
|
+
}
|
|
415
|
+
if (parsed.errorName === "commons.NOT_FOUND" || parsed.code === "404") {
|
|
416
|
+
return "请确认 asset_id 是否存在、是否属于当前组织,或是否已被删除。";
|
|
417
|
+
}
|
|
418
|
+
if (parsed.errorName === "cmc.ORG_EMPTY_ERROR" || parsed.code === "11040022") {
|
|
419
|
+
return "当前请求缺少业务组织上下文;请先确认已执行 gd-cli org switch,并联系网关/DAM 同学检查组织透传。";
|
|
420
|
+
}
|
|
421
|
+
if (/\/dam\/asset\//.test(url)) {
|
|
422
|
+
return "可使用 gd-cli dam upload <file> 重新上传,或检查当前组织下是否有该素材。";
|
|
423
|
+
}
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
function errorGuide(code) {
|
|
427
|
+
if (code === "QUOTA_EXCEEDED" || code === "ENTITLEMENT_INSUFFICIENT") {
|
|
428
|
+
return `权益不足,请购买或升级后重试:\n ${resolveEntitlementPricingUrl()}`;
|
|
429
|
+
}
|
|
430
|
+
return ERROR_GUIDES[code];
|
|
431
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ParamDef {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
type: "string" | "number" | "boolean" | "select";
|
|
5
|
+
required: boolean;
|
|
6
|
+
choices?: {
|
|
7
|
+
name: string;
|
|
8
|
+
value: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}[];
|
|
11
|
+
default?: unknown;
|
|
12
|
+
validate?: (value: string) => string | true;
|
|
13
|
+
}
|
|
14
|
+
export declare function withInteractiveParams(requiredParams: ParamDef[], optionalParams?: ParamDef[]): (options: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Prompt } from "../core/prompt/index.js";
|
|
2
|
+
export function withInteractiveParams(requiredParams, optionalParams = []) {
|
|
3
|
+
return async (options) => {
|
|
4
|
+
if (!process.stdout.isTTY)
|
|
5
|
+
return options;
|
|
6
|
+
const result = { ...options };
|
|
7
|
+
for (const param of requiredParams) {
|
|
8
|
+
if (result[param.name] !== undefined && result[param.name] !== "")
|
|
9
|
+
continue;
|
|
10
|
+
if (param.type === "select" && param.choices) {
|
|
11
|
+
result[param.name] = await Prompt.select({
|
|
12
|
+
message: param.description,
|
|
13
|
+
choices: param.choices,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
else if (param.type === "boolean") {
|
|
17
|
+
result[param.name] = await Prompt.confirm(param.description, param.default);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
result[param.name] = await Prompt.text({
|
|
21
|
+
message: `${param.description} (${param.name})`,
|
|
22
|
+
default: param.default,
|
|
23
|
+
validate: param.validate,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (optionalParams.length > 0) {
|
|
28
|
+
const hasOptionalSet = optionalParams.some((p) => result[p.name] !== undefined);
|
|
29
|
+
if (!hasOptionalSet) {
|
|
30
|
+
const customize = await Prompt.confirm("是否自定义可选参数?", false);
|
|
31
|
+
if (customize) {
|
|
32
|
+
for (const param of optionalParams) {
|
|
33
|
+
if (param.type === "select" && param.choices) {
|
|
34
|
+
result[param.name] = await Prompt.select({
|
|
35
|
+
message: param.description,
|
|
36
|
+
choices: param.choices,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const val = await Prompt.text({
|
|
41
|
+
message: `${param.description} (${param.name},留空跳过)`,
|
|
42
|
+
default: param.default,
|
|
43
|
+
});
|
|
44
|
+
if (val)
|
|
45
|
+
result[param.name] = val;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** 人类可读输出时的业务上下文(工具/应用展示名) */
|
|
2
|
+
export interface HumanFormatContext {
|
|
3
|
+
/** 如「AI 生图」「电商主图」 */
|
|
4
|
+
activityLabel?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function formatOutput(data: unknown, format?: string, humanCtx?: HumanFormatContext): void;
|
|
7
|
+
/** TTY 默认:展示任务/工具结果中的链接与交付物说明,非原始 JSON */
|
|
8
|
+
export declare function printHumanTaskResult(data: unknown, ctx?: HumanFormatContext): void;
|
|
9
|
+
/** 工具列表:扁平列,避免把整份 spec 打进表格 */
|
|
10
|
+
export declare function rowsForToolList(items: unknown[]): Record<string, string>[];
|
|
11
|
+
/** 应用列表 */
|
|
12
|
+
export declare function rowsForAppList(items: unknown[]): Record<string, string>[];
|
|
13
|
+
/** 搜索结果(Tool + App 混合) */
|
|
14
|
+
export declare function rowsForSearchList(items: unknown[]): Record<string, string>[];
|