gaoding-cli 1.0.0-alpha.8 → 1.0.0-alpha.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +47 -64
  3. package/dist/bin/gd-cli.js +2 -2
  4. package/dist/src/api/app-runner.d.ts +1 -4
  5. package/dist/src/api/app-runner.js +10 -42
  6. package/dist/src/api/dam-client.d.ts +0 -7
  7. package/dist/src/api/dam-client.js +0 -17
  8. package/dist/src/commands/auth.js +5 -41
  9. package/dist/src/commands/creative.js +37 -45
  10. package/dist/src/commands/dam.js +248 -110
  11. package/dist/src/commands/org.js +17 -39
  12. package/dist/src/commands/skills.js +24 -114
  13. package/dist/src/commands/update.js +10 -85
  14. package/dist/src/commands/usage.js +4 -17
  15. package/dist/src/commands/workflows.d.ts +1 -1
  16. package/dist/src/commands/workflows.js +283 -199
  17. package/dist/src/core/output/envelope.d.ts +1 -0
  18. package/dist/src/core/output/envelope.js +76 -6
  19. package/dist/src/creative/contract.d.ts +28 -80
  20. package/dist/src/creative/contract.js +23 -44
  21. package/dist/src/creative/protocol.js +6 -6
  22. package/dist/src/io.d.ts +0 -2
  23. package/dist/src/io.js +0 -8
  24. package/dist/src/middleware/error-handler.d.ts +7 -1
  25. package/dist/src/middleware/error-handler.js +59 -54
  26. package/dist/src/program.d.ts +1 -0
  27. package/dist/src/program.js +138 -41
  28. package/dist/src/registry/agent-contracts.d.ts +14 -26
  29. package/dist/src/registry/agent-contracts.js +214 -64
  30. package/dist/src/utils/capability-presenter.js +6 -29
  31. package/dist/src/utils/config.d.ts +2 -2
  32. package/dist/src/utils/config.js +1 -1
  33. package/dist/src/utils/sensitive-path.js +1 -4
  34. package/package.json +2 -1
  35. package/skills/gd-cli/SKILL.md +6 -6
  36. package/skills/gd-cli/references/auth.md +3 -10
  37. package/skills/gd-cli/references/creative.md +11 -11
  38. package/skills/gd-cli/references/entitlement.md +2 -2
  39. package/skills/gd-cli/references/errors.md +4 -4
  40. package/skills/gd-cli/references/org.md +3 -3
  41. package/skills/gd-cli/references/sop.md +5 -5
  42. package/skills/gd-cli/references/update.md +4 -3
  43. package/skills/gd-cli/references/workflows.md +6 -5
  44. package/dist/src/utils/list-output-format.d.ts +0 -10
  45. package/dist/src/utils/list-output-format.js +0 -34
@@ -3,7 +3,6 @@ export const CREATIVE_SCHEMA_VERSION = "creative/v1";
3
3
  export const CREATIVE_INPUT_SCHEMA = {
4
4
  $schema: "https://json-schema.org/draft/2020-12/schema",
5
5
  $id: "https://www.gaoding.com/cli/schemas/creative-input-v1.json",
6
- title: "Creative Input",
7
6
  description: "发起或继续一次稿定 Creative 创作所需的完整输入。",
8
7
  type: "object",
9
8
  additionalProperties: false,
@@ -19,7 +18,6 @@ export const CREATIVE_INPUT_SCHEMA = {
19
18
  description: "本次创作使用的输入素材;媒体不能脱离 prompt 或 answers 单独提交。",
20
19
  items: {
21
20
  type: "object",
22
- description: "一份带有明确用途的输入素材。",
23
21
  additionalProperties: false,
24
22
  required: ["source", "role"],
25
23
  properties: {
@@ -63,7 +61,7 @@ export const CREATIVE_INPUT_SCHEMA = {
63
61
  minLength: 1,
64
62
  description: "继续已有创作或回答追问时使用的会话标识;首次请求和独立的新创作不传。",
65
63
  },
66
- last_tool_message_id: {
64
+ question_message_id: {
67
65
  type: "string",
68
66
  minLength: 1,
69
67
  description: "正在回答或跳过的追问消息标识,原样使用上一次 requires_input 输出中的值。",
@@ -74,7 +72,6 @@ export const CREATIVE_INPUT_SCHEMA = {
74
72
  description: "对上一次 requires_input 输出中一个或多个问题的结构化回答。",
75
73
  items: {
76
74
  type: "object",
77
- description: "对一条 GD Agent 追问的回答。",
78
75
  additionalProperties: false,
79
76
  required: ["question", "values"],
80
77
  properties: {
@@ -90,7 +87,6 @@ export const CREATIVE_INPUT_SCHEMA = {
90
87
  items: {
91
88
  type: "string",
92
89
  minLength: 1,
93
- description: "一项非空的选择值或自定义回答。",
94
90
  },
95
91
  },
96
92
  },
@@ -98,22 +94,15 @@ export const CREATIVE_INPUT_SCHEMA = {
98
94
  },
99
95
  },
100
96
  anyOf: [
101
- {
102
- description: "普通新创作或连续编辑必须提供 prompt。",
103
- required: ["prompt"],
104
- },
105
- {
106
- description: "回答追问时 answers 可以替代 prompt,但必须同时携带两个连续对话标识。",
107
- required: ["answers", "conversation_id", "last_tool_message_id"],
108
- },
97
+ { required: ["prompt"] },
98
+ { required: ["answers"] },
109
99
  ],
110
100
  dependentRequired: {
111
- answers: ["conversation_id", "last_tool_message_id"],
112
- last_tool_message_id: ["conversation_id"],
101
+ answers: ["conversation_id", "question_message_id"],
102
+ question_message_id: ["conversation_id"],
113
103
  },
114
104
  allOf: [
115
105
  {
116
- description: "first_frame 最多出现一次。",
117
106
  properties: {
118
107
  media: {
119
108
  description: "用于检查首帧数量的素材列表。",
@@ -133,7 +122,6 @@ export const CREATIVE_INPUT_SCHEMA = {
133
122
  },
134
123
  },
135
124
  {
136
- description: "last_frame 最多出现一次。",
137
125
  properties: {
138
126
  media: {
139
127
  description: "用于检查尾帧数量的素材列表。",
@@ -157,7 +145,6 @@ export const CREATIVE_INPUT_SCHEMA = {
157
145
  export const CREATIVE_OUTPUT_SCHEMA = {
158
146
  $schema: "https://json-schema.org/draft/2020-12/schema",
159
147
  $id: "https://www.gaoding.com/cli/schemas/creative-output-v1.json",
160
- title: "Creative Output",
161
148
  description: "creative run 的统一最终输出;中间事件和内部调用过程不属于本 Schema。",
162
149
  type: "object",
163
150
  additionalProperties: false,
@@ -170,11 +157,9 @@ export const CREATIVE_OUTPUT_SCHEMA = {
170
157
  },
171
158
  data: {
172
159
  description: "status 为 completed 时存在的 Creative 最终结果;failed 时为 null。",
173
- oneOf: [{ $ref: "#/$defs/result" }, { type: "null" }],
174
160
  },
175
161
  error: {
176
162
  description: "status 为 failed 时存在的结构化错误;completed 时为 null。",
177
- oneOf: [{ $ref: "#/$defs/error" }, { type: "null" }],
178
163
  },
179
164
  meta: {
180
165
  type: "object",
@@ -195,7 +180,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
195
180
  },
196
181
  oneOf: [
197
182
  {
198
- description: "成功完成或需要使用者继续回答的结果。",
199
183
  properties: {
200
184
  status: { const: "completed", description: "成功状态。" },
201
185
  data: { $ref: "#/$defs/result", description: "Creative 结果。" },
@@ -203,7 +187,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
203
187
  },
204
188
  },
205
189
  {
206
- description: "校验、认证、业务或网络失败的结果。",
207
190
  properties: {
208
191
  status: { const: "failed", description: "失败状态。" },
209
192
  data: { type: "null", description: "失败时没有 Creative 结果。" },
@@ -214,7 +197,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
214
197
  $defs: {
215
198
  result: {
216
199
  type: "object",
217
- description: "GD Agent 本轮的最终结果。",
218
200
  additionalProperties: false,
219
201
  required: ["conversation_id", "finish_reason", "message", "outputs"],
220
202
  properties: {
@@ -235,9 +217,9 @@ export const CREATIVE_OUTPUT_SCHEMA = {
235
217
  outputs: {
236
218
  type: "array",
237
219
  description: "本轮最终产出的文本、结构化数据或媒体。",
238
- items: { $ref: "#/$defs/output", description: "一项 Creative 最终产出。" },
220
+ items: { $ref: "#/$defs/output" },
239
221
  },
240
- last_tool_message_id: {
222
+ question_message_id: {
241
223
  type: "string",
242
224
  minLength: 1,
243
225
  description: "requires_input 时必填,并在下一次请求中原样回传。",
@@ -257,11 +239,11 @@ export const CREATIVE_OUTPUT_SCHEMA = {
257
239
  },
258
240
  },
259
241
  },
260
- then: { required: ["last_tool_message_id", "questions"] },
242
+ then: { required: ["question_message_id", "questions"] },
261
243
  else: {
262
244
  not: {
263
245
  anyOf: [
264
- { required: ["last_tool_message_id"] },
246
+ { required: ["question_message_id"] },
265
247
  { required: ["questions"] },
266
248
  ],
267
249
  },
@@ -271,7 +253,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
271
253
  },
272
254
  question_group: {
273
255
  type: "object",
274
- description: "GD Agent 在本轮提出的一组问题。",
275
256
  additionalProperties: false,
276
257
  required: ["title", "questions"],
277
258
  properties: {
@@ -285,7 +266,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
285
266
  description: "需要使用者回答的一个或多个问题。",
286
267
  items: {
287
268
  type: "object",
288
- description: "一条 GD Agent 追问。",
289
269
  additionalProperties: false,
290
270
  required: ["question", "options", "allow_multiple"],
291
271
  properties: {
@@ -299,7 +279,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
299
279
  description: "推荐选项,可以为空;label 不是严格枚举。",
300
280
  items: {
301
281
  type: "object",
302
- description: "一项推荐回答。",
303
282
  additionalProperties: false,
304
283
  required: ["label"],
305
284
  properties: {
@@ -321,11 +300,9 @@ export const CREATIVE_OUTPUT_SCHEMA = {
321
300
  },
322
301
  },
323
302
  output: {
324
- description: "文本、JSON、图片、视频、音频或文件结果。",
325
303
  oneOf: [
326
304
  {
327
305
  type: "object",
328
- description: "文本结果。",
329
306
  additionalProperties: false,
330
307
  required: ["type", "text"],
331
308
  properties: {
@@ -335,7 +312,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
335
312
  },
336
313
  {
337
314
  type: "object",
338
- description: "可机器解析的结构化结果。",
339
315
  additionalProperties: false,
340
316
  required: ["type", "value"],
341
317
  properties: {
@@ -345,7 +321,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
345
321
  },
346
322
  {
347
323
  type: "object",
348
- description: "最终媒体或文件结果。",
349
324
  additionalProperties: false,
350
325
  required: ["type", "url", "mime_type"],
351
326
  properties: {
@@ -396,7 +371,6 @@ export const CREATIVE_OUTPUT_SCHEMA = {
396
371
  },
397
372
  error: {
398
373
  type: "object",
399
- description: "Creative 失败时的稳定错误信息。",
400
374
  additionalProperties: false,
401
375
  required: ["code", "type", "message"],
402
376
  properties: {
@@ -440,6 +414,7 @@ export const CREATIVE_EXAMPLES = {
440
414
  {
441
415
  name: "text_creation",
442
416
  description: "纯文本创作",
417
+ command: 'gd-cli creative run --prompt "为一款轻量缓震跑鞋写三条电商主图标题,语言简洁有力。" --json',
443
418
  input: {
444
419
  prompt: "为一款轻量缓震跑鞋写三条电商主图标题,语言简洁有力。",
445
420
  },
@@ -447,6 +422,7 @@ export const CREATIVE_EXAMPLES = {
447
422
  {
448
423
  name: "image_with_reference",
449
424
  description: "使用参考图创作图片",
425
+ command: "gd-cli creative run --input creative-request.json --json",
450
426
  input: {
451
427
  prompt: "以产品为主体生成一张户外晨跑场景广告图,保持鞋款外观和配色。",
452
428
  media: [
@@ -464,6 +440,7 @@ export const CREATIVE_EXAMPLES = {
464
440
  {
465
441
  name: "video_with_first_and_last_frames",
466
442
  description: "使用首尾帧创作视频",
443
+ command: "gd-cli creative run --input creative-request.json --json",
467
444
  input: {
468
445
  prompt: "生成从清晨城市街道过渡到终点冲线的运动广告视频,镜头运动自然。",
469
446
  media: [
@@ -486,6 +463,7 @@ export const CREATIVE_EXAMPLES = {
486
463
  {
487
464
  name: "continue_creation",
488
465
  description: "继续修改已有创作",
466
+ command: "gd-cli creative run --input creative-request.json --json",
489
467
  input: {
490
468
  conversation_id: "conversation_123",
491
469
  prompt: "保留主体和构图,把整体风格调整得更克制,并降低背景饱和度。",
@@ -494,9 +472,10 @@ export const CREATIVE_EXAMPLES = {
494
472
  {
495
473
  name: "answer_questions",
496
474
  description: "回答 GD Agent 的结构化追问",
475
+ command: "gd-cli creative run --input creative-request.json --json",
497
476
  input: {
498
477
  conversation_id: "conversation_123",
499
- last_tool_message_id: "message_456",
478
+ question_message_id: "message_456",
500
479
  answers: [
501
480
  {
502
481
  question: "希望采用什么视觉风格?",
@@ -519,7 +498,7 @@ const INPUT_KEYS = new Set([
519
498
  "media",
520
499
  "parameters",
521
500
  "conversation_id",
522
- "last_tool_message_id",
501
+ "question_message_id",
523
502
  "answers",
524
503
  ]);
525
504
  const PARAMETER_KEYS = new Set(["ratio", "resolution", "duration_seconds"]);
@@ -573,14 +552,14 @@ export function validateCreativeInput(value) {
573
552
  const conversationId = Object.hasOwn(input, "conversation_id")
574
553
  ? requireNonEmptyString(input.conversation_id, "conversation_id")
575
554
  : undefined;
576
- const lastToolMessageId = Object.hasOwn(input, "last_tool_message_id")
577
- ? requireNonEmptyString(input.last_tool_message_id, "last_tool_message_id")
555
+ const questionMessageId = Object.hasOwn(input, "question_message_id")
556
+ ? requireNonEmptyString(input.question_message_id, "question_message_id")
578
557
  : undefined;
579
558
  if (!hasPrompt && !hasAnswers) {
580
559
  invalid("prompt", "普通创作必须提供非空 prompt;回答追问时可以改为提供 answers");
581
560
  }
582
- if (lastToolMessageId && !conversationId) {
583
- invalid("last_tool_message_id", "last_tool_message_id 必须与 conversation_id 一起使用");
561
+ if (questionMessageId && !conversationId) {
562
+ invalid("question_message_id", "question_message_id 必须与 conversation_id 一起使用");
584
563
  }
585
564
  if (Object.hasOwn(input, "media"))
586
565
  validateMedia(input.media);
@@ -588,8 +567,8 @@ export function validateCreativeInput(value) {
588
567
  validateParameters(input.parameters);
589
568
  if (hasAnswers) {
590
569
  validateAnswers(input.answers);
591
- if (!conversationId || !lastToolMessageId) {
592
- invalid("answers", "answers 必须同时携带 conversation_id 和 last_tool_message_id");
570
+ if (!conversationId || !questionMessageId) {
571
+ invalid("answers", "answers 必须同时携带 conversation_id 和 question_message_id");
593
572
  }
594
573
  }
595
574
  if (prompt === undefined && !hasAnswers) {
@@ -736,7 +715,7 @@ function invalid(path, message) {
736
715
  code: "PARAM_INVALID",
737
716
  type: "validation",
738
717
  message,
739
- hint: "请运行 gd-cli creative schema --format json 查看完整输入结构。",
718
+ hint: "请运行 gd-cli creative schema --json 查看完整输入结构。",
740
719
  retryable: false,
741
720
  detail: { path },
742
721
  });
@@ -29,9 +29,9 @@ export function buildCreativeAgentRequest(input, media = [], ids) {
29
29
  ? buildAnswerContent(input, promptItems)
30
30
  : buildCreationContent(input, promptItems);
31
31
  const extra = {};
32
- if (input.conversation_id && input.last_tool_message_id) {
33
- extra.lastToolMessageId = input.last_tool_message_id;
34
- extra.last_tool_message_id = input.last_tool_message_id;
32
+ if (input.conversation_id && input.question_message_id) {
33
+ extra.lastToolMessageId = input.question_message_id;
34
+ extra.last_tool_message_id = input.question_message_id;
35
35
  }
36
36
  if (isAnswer) {
37
37
  const questions = input.answers.map(toEditorAnswer);
@@ -145,9 +145,9 @@ export function normalizeCreativeMessages(messages, fallbackConversationId = "")
145
145
  }
146
146
  if (ask) {
147
147
  const questionData = parseAskUserQuestion(ask);
148
- const lastToolMessageId = stringValue(ask.message_id ?? ask.messageId) ||
148
+ const questionMessageId = stringValue(ask.message_id ?? ask.messageId) ||
149
149
  stringValue(ask.extra?.last_tool_message_id ?? ask.extra?.lastToolMessageId);
150
- if (!lastToolMessageId) {
150
+ if (!questionMessageId) {
151
151
  invalidAgentResponse("GD Agent 追问结果缺少追问消息标识");
152
152
  }
153
153
  if (questionData.questions.length === 0 ||
@@ -159,7 +159,7 @@ export function normalizeCreativeMessages(messages, fallbackConversationId = "")
159
159
  finish_reason: "requires_input",
160
160
  message: textParts.at(-1) ?? questionData.title,
161
161
  outputs: dedupeOutputs(outputs),
162
- last_tool_message_id: lastToolMessageId,
162
+ question_message_id: questionMessageId,
163
163
  questions: questionData,
164
164
  };
165
165
  }
package/dist/src/io.d.ts CHANGED
@@ -6,8 +6,6 @@ export declare class IOStreams {
6
6
  readonly stdoutIsTTY: boolean;
7
7
  readonly stderrIsTTY: boolean;
8
8
  constructor();
9
- /** Agent / CI:stdout 非 TTY 时默认 JSON */
10
- prefersJsonOutput(explicitFormat?: string): boolean;
11
9
  /** 授权等人机交互场景 */
12
10
  isInteractiveAuth(): boolean;
13
11
  }
package/dist/src/io.js CHANGED
@@ -10,14 +10,6 @@ export class IOStreams {
10
10
  this.stdoutIsTTY = !!process.stdout.isTTY;
11
11
  this.stderrIsTTY = !!process.stderr.isTTY;
12
12
  }
13
- /** Agent / CI:stdout 非 TTY 时默认 JSON */
14
- prefersJsonOutput(explicitFormat) {
15
- if (explicitFormat && explicitFormat !== "json")
16
- return false;
17
- if (explicitFormat === "json")
18
- return true;
19
- return !this.stdoutIsTTY;
20
- }
21
13
  /** 授权等人机交互场景 */
22
14
  isInteractiveAuth() {
23
15
  return this.stdoutIsTTY && this.stdinIsTTY;
@@ -1,5 +1,11 @@
1
- import { type CliErrorBody } from "../core/output/envelope.js";
1
+ import type { Command } from "commander";
2
+ import { type CliErrorBody, type ResultEnvelope } from "../core/output/envelope.js";
2
3
  type ActionHandler = (...args: any[]) => Promise<void>;
4
+ type JsonFailureProjector = (error: CliErrorBody) => ResultEnvelope<null>;
3
5
  export declare function withErrorHandler(handler: ActionHandler): ActionHandler;
6
+ export declare function shouldEmitJsonError(args: unknown[]): boolean;
7
+ export declare function setJsonFailureProjector(command: Command, projector: JsonFailureProjector): void;
8
+ export declare function jsonFailureEnvelopeFor(command: Command | undefined, error: unknown): ResultEnvelope<null>;
9
+ export declare function emitJsonFailure(command: Command | undefined, error: unknown): void;
4
10
  export declare function toCliErrorBody(error: unknown): CliErrorBody;
5
11
  export {};
@@ -1,11 +1,12 @@
1
1
  import { ApiError } from "../api/hub-client.js";
2
2
  import { DirectApiError } from "../api/direct-client.js";
3
- import { failedEnvelope, emitJson } from "../core/output/envelope.js";
3
+ import { failedEnvelope, emitJson, publicCliErrorBody, } from "../core/output/envelope.js";
4
4
  import { CliUsageError } from "../core/output/cli-error.js";
5
5
  import { isVerbose, isDebug } from "../utils/config.js";
6
6
  import { isTransientNetworkError } from "../utils/transient-network-error.js";
7
7
  import { detectEntitlementIssue, entitlementCliError, ENTITLEMENT_PRICING_URL, resolveEntitlementPricingUrl, } from "../utils/entitlement.js";
8
8
  import { redactSensitiveText, redactSensitiveValue } from "../utils/redact.js";
9
+ const jsonFailureProjectors = new WeakMap();
9
10
  const ERROR_GUIDES = {
10
11
  AUTH_MISSING: "请先登录:\n gd-cli auth login",
11
12
  AUTH_EXPIRED: "凭证已过期,请重新登录:\n gd-cli auth login",
@@ -28,7 +29,7 @@ export function withErrorHandler(handler) {
28
29
  }
29
30
  catch (error) {
30
31
  if (shouldEmitJsonError(args)) {
31
- emitJson(failedEnvelope(redactSensitiveValue(toCliErrorBody(error))));
32
+ emitJsonFailure(commandFromArgs(args), error);
32
33
  process.exit(1);
33
34
  }
34
35
  if (error instanceof CliUsageError) {
@@ -80,22 +81,26 @@ export function withErrorHandler(handler) {
80
81
  }
81
82
  };
82
83
  }
83
- function shouldEmitJsonError(args) {
84
- let current = args.find(isCommandLike);
85
- while (current) {
86
- if (!isCommandLike(current))
87
- return false;
88
- const format = current.opts().format;
89
- const json = current.opts().json;
90
- if (json === true)
91
- return true;
92
- if (format === "json")
93
- return true;
94
- if (format)
95
- return false;
96
- current = current.parent;
97
- }
98
- return !process.stdout.isTTY;
84
+ export function shouldEmitJsonError(args) {
85
+ const command = commandFromArgs(args);
86
+ return command?.opts().json === true;
87
+ }
88
+ export function setJsonFailureProjector(command, projector) {
89
+ jsonFailureProjectors.set(command, projector);
90
+ }
91
+ export function jsonFailureEnvelopeFor(command, error) {
92
+ const body = redactSensitiveValue(toCliErrorBody(error));
93
+ const projector = command ? jsonFailureProjectors.get(command) : undefined;
94
+ if (projector)
95
+ return projector(body);
96
+ const commandName = command ? publicCommandName(command) : "";
97
+ return failedEnvelope(body, commandName ? { command: commandName } : undefined);
98
+ }
99
+ export function emitJsonFailure(command, error) {
100
+ emitJson(jsonFailureEnvelopeFor(command, error));
101
+ }
102
+ function commandFromArgs(args) {
103
+ return [...args].reverse().find(isCommandLike);
99
104
  }
100
105
  function isCommandLike(value) {
101
106
  return (!!value &&
@@ -104,6 +109,9 @@ function isCommandLike(value) {
104
109
  typeof value.opts === "function");
105
110
  }
106
111
  export function toCliErrorBody(error) {
112
+ return publicCliErrorBody(toCliErrorBodyInternal(error));
113
+ }
114
+ function toCliErrorBodyInternal(error) {
107
115
  if (error instanceof CliUsageError) {
108
116
  return error.body;
109
117
  }
@@ -127,38 +135,40 @@ export function toCliErrorBody(error) {
127
135
  });
128
136
  if (entitlement)
129
137
  return redactSensitiveValue(entitlementCliError(entitlement, error.body));
130
- if (isToolRouteUnavailableMessage(parsed.message ?? error.message)) {
131
- return toolRouteUnavailableCliError(parsed.message ?? error.message, redactSensitiveValue(error.body));
138
+ if (parsed.message && isToolRouteUnavailableMessage(parsed.message)) {
139
+ return toolRouteUnavailableCliError(parsed.message, redactSensitiveValue(error.body));
132
140
  }
133
141
  return {
134
142
  code: parsed.code ?? `HTTP_${error.statusCode}`,
135
143
  type: error.statusCode === 401 ? "auth" : "business",
136
144
  message: parsed.message
137
145
  ? normalizeBusinessMessage(parsed.message)
138
- : redactSensitiveText(error.message),
146
+ : publicApiFailureMessage(error.statusCode),
139
147
  hint: redactSensitiveText(parsed.hint ?? directApiHint(parsed, error.url) ?? ""),
140
148
  retryable: false,
141
149
  detail: redactSensitiveValue(error.body),
142
150
  };
143
151
  }
144
152
  if (error instanceof ApiError) {
145
- const parsed = parseJsonObject(error.body);
146
- const code = stringField(parsed, "error_code") ?? stringField(parsed, "error") ?? "API_ERROR";
147
- const message = stringField(parsed, "message") ?? error.message;
153
+ const parsedBody = parseJsonObject(error.body);
154
+ const parsed = parseDirectApiErrorBody(parsedBody ?? error.body);
155
+ const code = parsed.code ?? "API_ERROR";
156
+ const message = parsed.message ?? publicApiFailureMessage(error.statusCode);
148
157
  const entitlement = detectEntitlementIssue({
149
158
  code,
150
159
  message,
151
- detail: parsed ?? error.body,
160
+ detail: parsedBody ?? error.body,
152
161
  });
153
- if (entitlement)
154
- return redactSensitiveValue(entitlementCliError(entitlement, parsed ?? error.body));
162
+ if (entitlement) {
163
+ return redactSensitiveValue(entitlementCliError(entitlement, parsedBody ?? error.body));
164
+ }
155
165
  return {
156
166
  code,
157
167
  type: code.startsWith("AUTH") ? "auth" : "business",
158
168
  message: redactSensitiveText(message),
159
- hint: redactSensitiveText(stringField(parsed, "suggestion") ?? errorGuide(code) ?? ""),
169
+ hint: redactSensitiveText(parsed.hint ?? errorGuide(code) ?? ""),
160
170
  retryable: false,
161
- detail: redactSensitiveValue(parsed ?? error.body),
171
+ detail: redactSensitiveValue(parsedBody ?? error.body),
162
172
  };
163
173
  }
164
174
  if (error instanceof Error) {
@@ -209,32 +219,10 @@ function printCliUsageError(body) {
209
219
  console.error(`\n 错误码: ${body.code}`);
210
220
  if (body.reason)
211
221
  console.error(` 原因: ${body.reason}`);
212
- const detail = body.detail && typeof body.detail === "object" && !Array.isArray(body.detail)
213
- ? body.detail
214
- : undefined;
215
- const appId = body.app_id ?? stringField(detail, "app_id");
216
- const toolId = body.tool_id ?? stringField(detail, "tool_id");
217
- if (appId)
218
- console.error(` Workflow: ${appId}`);
219
- if (toolId)
220
- console.error(` Tool: ${toolId}`);
221
- const missingTools = Array.isArray(body.missing_tools)
222
- ? body.missing_tools
223
- .map((item) => typeof item === "string"
224
- ? item
225
- : stringField(item, "id") ?? "")
226
- .filter(Boolean)
227
- : [];
228
- if (missingTools.length > 0) {
229
- console.error(` 缺失内部能力: ${missingTools.join(", ")}`);
230
- }
231
222
  if (body.hint)
232
223
  console.error(`\n 说明: ${body.hint}`);
233
224
  if (body.next_command)
234
225
  console.error(`\n 下一步: ${body.next_command}`);
235
- const listCommand = stringField(detail, "list_command");
236
- if (listCommand)
237
- console.error(` 查看状态: ${listCommand}`);
238
226
  console.error("");
239
227
  }
240
228
  function parseDirectApiErrorBody(body) {
@@ -249,12 +237,29 @@ function parseDirectApiErrorBody(body) {
249
237
  code: stringField(nestedError, "error_code") ??
250
238
  stringField(nestedError, "code") ??
251
239
  stringField(value, "error_code") ??
252
- stringField(value, "code"),
240
+ stringField(value, "code") ??
241
+ stringField(value, "error"),
253
242
  errorName: stringField(nestedError, "error_name") ??
254
243
  stringField(value, "error_name"),
255
244
  message: stringField(nestedError, "message") ?? stringField(value, "message"),
245
+ hint: stringField(nestedError, "suggestion") ??
246
+ stringField(nestedError, "hint") ??
247
+ stringField(value, "suggestion") ??
248
+ stringField(value, "hint"),
256
249
  };
257
250
  }
251
+ function publicApiFailureMessage(statusCode) {
252
+ return `业务请求失败(HTTP ${statusCode})`;
253
+ }
254
+ function publicCommandName(command) {
255
+ const names = [];
256
+ let current = command;
257
+ while (current.parent) {
258
+ names.unshift(current.name());
259
+ current = current.parent;
260
+ }
261
+ return names.join(" ");
262
+ }
258
263
  function parseJsonObject(value) {
259
264
  try {
260
265
  const parsed = JSON.parse(value);
@@ -366,7 +371,7 @@ function toolRouteUnavailableCliError(message, detail) {
366
371
  type: "business",
367
372
  message: normalizeToolRouteUnavailableMessage(message),
368
373
  reason: "tool-route-unavailable",
369
- hint: "当前 Tool 的平台生成路由不可用。Agent 应停止重试,不要切换模型、环境、团队或调用内部 raw.dify;请保留本次输入并联系平台确认能力配置。",
374
+ hint: "当前能力的生成路由不可用。请停止重试,不要切换模型、环境或团队;请保留本次输入并联系平台确认能力配置。",
370
375
  retryable: false,
371
376
  detail,
372
377
  };
@@ -385,7 +390,7 @@ function isToolRouteUnavailableMessage(message) {
385
390
  function normalizeToolRouteUnavailableMessage(message) {
386
391
  const normalized = normalizeBusinessMessage(message);
387
392
  if (/没有可用的工具|tool-intent 没有返回|tool intent 没有返回/i.test(normalized)) {
388
- return "当前 Tool 的平台生成路由不可用,未发起生成任务。";
393
+ return "当前能力的生成路由不可用,未发起生成任务。";
389
394
  }
390
395
  return normalized;
391
396
  }
@@ -1,2 +1,3 @@
1
1
  import { Command } from "commander";
2
2
  export declare function createProgram(): Promise<Command>;
3
+ export declare function parseProgram(program: Command, argv?: readonly string[]): Promise<void>;