gaoding-cli 1.0.0-alpha.7 → 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 (77) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +47 -60
  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 +11 -44
  6. package/dist/src/api/creative-client.d.ts +34 -0
  7. package/dist/src/api/creative-client.js +184 -0
  8. package/dist/src/api/dam-client.d.ts +0 -7
  9. package/dist/src/api/dam-client.js +0 -17
  10. package/dist/src/api/direct-client.d.ts +9 -2
  11. package/dist/src/api/direct-client.js +45 -18
  12. package/dist/src/api/hub-client.d.ts +11 -8
  13. package/dist/src/api/hub-client.js +17 -18
  14. package/dist/src/api/usage-client.d.ts +4 -4
  15. package/dist/src/api/usage-client.js +9 -49
  16. package/dist/src/auth/credential-store-v2.d.ts +0 -1
  17. package/dist/src/auth/credential-store-v2.js +0 -6
  18. package/dist/src/commands/auth.js +17 -53
  19. package/dist/src/commands/creative.d.ts +8 -0
  20. package/dist/src/commands/creative.js +178 -0
  21. package/dist/src/commands/dam.js +270 -127
  22. package/dist/src/commands/org.js +31 -47
  23. package/dist/src/commands/skills.js +33 -118
  24. package/dist/src/commands/update.js +11 -82
  25. package/dist/src/commands/usage.d.ts +1 -1
  26. package/dist/src/commands/usage.js +10 -21
  27. package/dist/src/commands/workflows.d.ts +1 -1
  28. package/dist/src/commands/workflows.js +299 -197
  29. package/dist/src/core/auth/auth-guard.d.ts +21 -0
  30. package/dist/src/core/auth/auth-guard.js +121 -0
  31. package/dist/src/core/auth/org-manager.d.ts +2 -1
  32. package/dist/src/core/auth/org-manager.js +61 -6
  33. package/dist/src/core/output/envelope.d.ts +1 -0
  34. package/dist/src/core/output/envelope.js +76 -6
  35. package/dist/src/creative/contract.d.ts +1060 -0
  36. package/dist/src/creative/contract.js +722 -0
  37. package/dist/src/creative/media.d.ts +19 -0
  38. package/dist/src/creative/media.js +83 -0
  39. package/dist/src/creative/protocol.d.ts +60 -0
  40. package/dist/src/creative/protocol.js +337 -0
  41. package/dist/src/io.d.ts +0 -2
  42. package/dist/src/io.js +0 -8
  43. package/dist/src/middleware/auth.d.ts +6 -2
  44. package/dist/src/middleware/auth.js +25 -63
  45. package/dist/src/middleware/error-handler.d.ts +8 -0
  46. package/dist/src/middleware/error-handler.js +61 -57
  47. package/dist/src/program.d.ts +1 -0
  48. package/dist/src/program.js +137 -122
  49. package/dist/src/registry/agent-contracts.d.ts +14 -34
  50. package/dist/src/registry/agent-contracts.js +209 -297
  51. package/dist/src/registry/direct-registry.d.ts +0 -5
  52. package/dist/src/registry/direct-registry.js +0 -19
  53. package/dist/src/registry/registry-client.d.ts +0 -21
  54. package/dist/src/registry/registry-client.js +1 -40
  55. package/dist/src/utils/capability-presenter.js +6 -29
  56. package/dist/src/utils/config.d.ts +2 -2
  57. package/dist/src/utils/config.js +1 -1
  58. package/dist/src/utils/help-verify.d.ts +1 -3
  59. package/dist/src/utils/help-verify.js +1 -25
  60. package/dist/src/utils/sensitive-path.js +1 -4
  61. package/package.json +4 -3
  62. package/skills/gd-cli/SKILL.md +13 -12
  63. package/skills/gd-cli/references/auth.md +9 -10
  64. package/skills/gd-cli/references/creative.md +47 -0
  65. package/skills/gd-cli/references/entitlement.md +3 -3
  66. package/skills/gd-cli/references/errors.md +10 -3
  67. package/skills/gd-cli/references/org.md +3 -3
  68. package/skills/gd-cli/references/sop.md +8 -8
  69. package/skills/gd-cli/references/update.md +4 -3
  70. package/skills/gd-cli/references/workflows.md +7 -6
  71. package/dist/src/commands/models.d.ts +0 -2
  72. package/dist/src/commands/models.js +0 -78
  73. package/dist/src/commands/tools.d.ts +0 -4
  74. package/dist/src/commands/tools.js +0 -383
  75. package/dist/src/utils/list-output-format.d.ts +0 -10
  76. package/dist/src/utils/list-output-format.js +0 -34
  77. package/skills/gd-cli/references/tools.md +0 -29
package/CHANGELOG.md CHANGED
@@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [1.0.0-alpha.9] - 2026-08-01
9
+
10
+ ### Changed
11
+
12
+ - 根命令仅保留 `--version` 和 `--help`,机器可读的 `--json` 收敛到确有脚本消费价值的叶子命令。
13
+ - `skills install` 与 `skills uninstall` 在未指定目标时默认处理全部 Agent,且不再二次确认;`update` 收敛为无选项动作。
14
+ - Creative 使用语义化的 `question_message_id`,并收紧输入、输出 Schema 与错误响应契约。
15
+ - Workflow 固定内部并发为 2,并由 CLI 选项显式授权敏感路径。
16
+
17
+ ### Removed
18
+
19
+ - 删除根级 `--format`、`--json`、`--no-input` 和 `--yes`,以及不再具有明确语义的重复输出选项。
20
+
21
+ ### Security
22
+
23
+ - DAM 公开结果改为白名单 DTO,并过滤私网地址、危险协议、userinfo 与敏感查询参数。
24
+ - 公共错误响应改为字段白名单,不再透传后端 `detail` 或内部 Tool/App 路由信息。
25
+
26
+ ## [1.0.0-alpha.8] - 2026-08-01
27
+
28
+ ### Added
29
+
30
+ - 新增统一 `creative` 创作入口及可发现的输入输出 Schema、调用示例和连续创作支持。
31
+ - 新增集中式鉴权前置层,按命令声明凭证或当前组织要求,并在请求前透明刷新当前组织授权。
32
+
33
+ ### Changed
34
+
35
+ - `org credits` 取代顶层 `usage`,组织绑定与刷新有效期不再作为公开概念展示。
36
+ - DAM 素材格式筛选统一使用 `--asset-format`,全局 `--format` 仅控制输出格式。
37
+
38
+ ### Removed
39
+
40
+ - 删除公开的 `tools`、`models` 以及顶层 `usage`、`manifest` 和 `examples` 命令。
41
+
42
+ ### Fixed
43
+
44
+ - 升级 `brace-expansion` 补丁版本,修复 production 依赖链中的高危拒绝服务漏洞。
45
+
8
46
  ## [1.0.0-alpha.7] - 2026-07-23
9
47
 
10
48
  ### Fixed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # gaoding-cli
2
2
 
3
- GD CLI 是稿定设计能力的命令行入口,为用户、脚本、CI 和 Agent 提供登录、组织切换、单项 AI Tool、多步骤 Workflow 和 DAM 素材管理能力。
3
+ GD CLI 是稿定设计能力的命令行入口,为用户、脚本、CI 和 Agent 提供认证、组织切换、统一 Creative 创作、多步骤 Workflow 和 DAM 素材管理。
4
4
 
5
5
  ## Requirements
6
6
 
@@ -9,91 +9,91 @@ GD CLI 是稿定设计能力的命令行入口,为用户、脚本、CI 和 Age
9
9
 
10
10
  ## Installation
11
11
 
12
- 默认使用全局安装:
13
-
14
12
  ```bash
15
13
  npm install -g gaoding-cli
16
14
  gd-cli skills install
17
15
  gd-cli auth login
18
16
  ```
19
17
 
20
- Agent 的安装与接入规则以[官方 Agent 安装文档](https://www.gaoding.com/cli/install.md)为准。
18
+ `npm install -g gaoding-cli` 只安装 CLI。执行 `gd-cli skills install` 才会安装 Agent Skill;不传参数时安装到全部已知 Agent target。详细规则见[官方 Agent 安装文档](https://www.gaoding.com/cli/install.md)
21
19
 
22
- 非交互 Agent 或 CI 需要显式指定目标并完成确认:
20
+ Agent 或 CI 中,可指定一个或多个 target;安装和卸载均为人类可读输出,用 `skills status --json` 检查机器状态:
23
21
 
24
22
  ```bash
25
- gd-cli skills install --agent codex --yes --format json
26
- gd-cli auth login --no-browser --format json
23
+ gd-cli skills install --agent codex
24
+ gd-cli skills status --json
25
+ gd-cli auth login --no-browser
27
26
  ```
28
27
 
29
- `npm install -g gaoding-cli` 只安装 CLI,不会修改任何 Agent 目录。只有显式执行 `gd-cli skills install` 才会安装 Agent Skill。
30
-
31
28
  ## Quick Start
32
29
 
33
30
  ```bash
34
- gd-cli auth status
35
-
36
- gd-cli org list
31
+ gd-cli auth status --json
32
+ gd-cli org list --json
37
33
  gd-cli org switch --org <org-id>
38
34
 
39
- gd-cli tools list
40
- gd-cli tools call image.cutout --image ./product.jpg --mode product
41
- gd-cli tools call text.title --brief "夏季运动鞋,轻量缓震,适合通勤"
35
+ gd-cli creative schema --json
36
+ gd-cli creative examples
37
+ gd-cli creative run --prompt "为夏季运动鞋生成一张户外通勤广告图" --json
42
38
 
43
- gd-cli workflows list
39
+ gd-cli workflows list --json
44
40
  gd-cli workflows run listing-gallery \
45
41
  --image ./product.jpg \
46
- --brief "夏季运动鞋,轻量缓震,适合通勤"
42
+ --brief "夏季运动鞋,轻量缓震,适合通勤" \
43
+ --json
47
44
 
48
- gd-cli dam upload ./product.jpg
45
+ gd-cli dam upload ./product.jpg --json
49
46
  ```
50
47
 
51
48
  ## Commands
52
49
 
50
+ 使用 `gd-cli --help` 查看一级命令,再使用 `gd-cli <command> --help` 查看子命令和选项。
51
+
53
52
  | Command | Purpose |
54
53
  | --- | --- |
55
- | `auth` | 登录、退出和查看本地认证状态 |
56
- | `org` | 查看和切换当前组织 |
57
- | `tools` | 调用单项 AI 创意能力 |
58
- | `workflows` | 运行多步骤创意生产流程 |
59
- | `skills` | 安装和管理 `gd-cli` Agent Skill |
60
- | `dam` | 上传、查询和删除 DAM 素材 |
61
- | `update` | 检查和升级全局 CLI |
62
- | `manifest` | 输出 Agent 可解析的能力清单 |
63
- | `examples` | 查看常用命令示例 |
54
+ | `auth login [--no-browser]` | 登录;输出面向人 |
55
+ | `auth logout` | 退出登录;输出面向人 |
56
+ | `auth status --json` | 查询认证状态 |
57
+ | `org list/current/credits --json` | 查询组织和稿豆余额 |
58
+ | `org switch [--org]` | 切换组织;输出面向人 |
59
+ | `creative run [--prompt|--input] [--json]` | 发起或继续创作 |
60
+ | `creative schema [--json]` | 查看创作 Schema |
61
+ | `creative examples` | 查看完整可运行示例 |
62
+ | `workflows list [--json]` | 列出 Workflow |
63
+ | `workflows schema <workflow-id> [--json]` | 查看 Workflow Schema |
64
+ | `workflows examples <workflow-id>` | 查看完整可运行示例 |
65
+ | `workflows run <workflow-id> [--json]` | 执行 Workflow |
66
+ | `skills install/uninstall [--agent <id> | --all]` | 管理 Agent Skill |
67
+ | `skills status --json` | 查询 Skill 状态 |
68
+ | `skills update` | 刷新已安装 Skill |
69
+ | `dam upload/list/search/get --json` | 管理和查询素材 |
70
+ | `dam delete` | 删除素材;输出面向人 |
71
+ | `update` | 检查并升级全局 CLI |
72
+
73
+ 默认不会因为 stdin/stdout 不是 TTY 而切换为 JSON。只有支持 `--json` 的叶命令在显式传入该选项时才输出机器可读结果。
64
74
 
65
75
  ## Agent And Script Usage
66
76
 
67
- 核心命令支持 `--format json`,便于脚本和 Agent 解析。Agent 自身有语言模型时,标题、正文、标签和 prompt 草稿可优先由 Agent 生成;`gd-cli` 负责上传、抠图、生图、生视频、高清化和完整 Workflow 交付。
68
-
69
- 单项能力使用 `tools call`:
77
+ Creative 使用 `--prompt` `--input`。媒体、结构化约束或连续会话输入使用 JSON 文件或 stdin:
70
78
 
71
79
  ```bash
72
- gd-cli tools call image.generate \
73
- --prompt "电商主图,白底,突出轻量缓震" \
74
- --image ./product.jpg \
75
- --ratio 1:1 \
76
- --format json
80
+ gd-cli creative run --prompt "为夏季运动鞋生成三条简洁的电商标题" --json
81
+ gd-cli creative run --input creative-request.json --json
82
+ cat creative-request.json | gd-cli creative run --input - --json
77
83
  ```
78
84
 
79
- 多步骤交付使用 `workflows run`:
85
+ 遇到 `finish_reason=requires_input` 时,回传结果中的 `conversation_id`、`question_message_id` 和 `answers`。完整字段由 `gd-cli creative schema --json` 定义。
80
86
 
81
- ```bash
82
- gd-cli workflows run listing-gallery \
83
- --image ./product.jpg \
84
- --brief "运动鞋上架素材包" \
85
- --output-dir ./output \
86
- --format json
87
- ```
87
+ Workflow 的可用场景可通过 `gd-cli workflows list --json` 查看;特定输入/输出通过 `gd-cli workflows schema <workflow-id> --json` 查看。
88
88
 
89
89
  ## Agent Skill
90
90
 
91
- `gd-cli skills install` 将静态 Skill 安装到 `~/.agents/skills/gd-cli`,再为选中的 Agent 创建 link。常用维护命令:
91
+ `gd-cli skills install` 将静态 Skill 安装到 `~/.agents/skills/gd-cli`,并为选择的 Agent 创建链接。常用维护命令:
92
92
 
93
93
  ```bash
94
- gd-cli skills status --format json
94
+ gd-cli skills status --json
95
95
  gd-cli skills update
96
- gd-cli skills uninstall --all --yes
96
+ gd-cli skills uninstall --all
97
97
  ```
98
98
 
99
99
  CLI 全局升级后,只在 canonical Skill 已安装时自动刷新它;本地项目安装、`npm link` 和 `npx` 运行不会修改全局 CLI。
@@ -105,23 +105,10 @@ npm install
105
105
  npm run build
106
106
  npm test
107
107
  npm run start -- --help
108
- ```
109
-
110
- 本地开发使用独立的 `gd-cli-dev`:
111
-
112
- ```bash
113
- npm run dev:setup
114
- npm run dev
115
- gd-cli-dev --help
116
- ```
117
-
118
- 默认 smoke test 不登录、不调用付费生成能力:
119
-
120
- ```bash
121
108
  npm run smoke:cli
122
109
  ```
123
110
 
124
- 真实接口测试会使用本机登录凭证,并可能消耗额度:
111
+ 真实接口 smoke 会使用本机登录凭证,并可能消耗额度:
125
112
 
126
113
  ```bash
127
114
  gd-cli auth login
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { createProgram } from "../src/program.js";
2
+ import { createProgram, parseProgram } from "../src/program.js";
3
3
  async function main() {
4
4
  const program = await createProgram();
5
- await program.parseAsync(process.argv);
5
+ await parseProgram(program, process.argv);
6
6
  }
7
7
  main().catch((err) => {
8
8
  console.error(err.message);
@@ -1,10 +1,7 @@
1
1
  import { HubClient } from "./hub-client.js";
2
2
  import type { TaskResult } from "./task-poller.js";
3
3
  interface RunOptions {
4
- async?: boolean;
5
- timeout?: number;
6
- outputDir?: string;
7
- concurrency?: number;
4
+ allowSensitivePath?: boolean;
8
5
  onStepStart?: (step: AppStepPublicRecord) => void;
9
6
  onStepComplete?: (step: AppStepPublicRecord, result?: TaskResult) => void;
10
7
  }
@@ -1,23 +1,5 @@
1
1
  import { DirectToolInvoker } from "./direct-tools.js";
2
2
  import { DirectApiError } from "./direct-client.js";
3
- /** 多步 App 含多次生图/对话,默认至少等待 10 分钟 */
4
- const APP_RUN_MIN_WAIT_SEC = 600;
5
- function resolveAppWaitTimeout(explicit, estimatedSeconds) {
6
- if (explicit !== undefined && Number.isFinite(explicit) && explicit > 0) {
7
- return Math.floor(explicit);
8
- }
9
- const est = Number(estimatedSeconds);
10
- if (Number.isFinite(est) && est > APP_RUN_MIN_WAIT_SEC) {
11
- return Math.ceil(est);
12
- }
13
- return APP_RUN_MIN_WAIT_SEC;
14
- }
15
- function resolveConcurrency(value) {
16
- const numeric = Number(value);
17
- if (!Number.isFinite(numeric) || numeric <= 0)
18
- return 2;
19
- return Math.max(1, Math.min(4, Math.floor(numeric)));
20
- }
21
3
  async function mapWithConcurrency(items, concurrency, worker) {
22
4
  let next = 0;
23
5
  const runners = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
@@ -170,15 +152,6 @@ export class AppRunner {
170
152
  void client;
171
153
  }
172
154
  async run(appId, params, options = {}) {
173
- if (options.async) {
174
- return {
175
- task_id: `app-${appId}-${Date.now()}`,
176
- status: "failed",
177
- message: "本地 App workflow 暂不支持 --async,请去掉 --async 直接运行。",
178
- };
179
- }
180
- void resolveAppWaitTimeout(options.timeout, undefined);
181
- void options.outputDir;
182
155
  try {
183
156
  if (appId === "listing-gallery")
184
157
  return await this.runListingGallery(params, options);
@@ -208,7 +181,7 @@ export class AppRunner {
208
181
  detail_image: "4:5",
209
182
  lifestyle_image: "4:5",
210
183
  });
211
- const prepared = await this.prepareProduct(ctx, image, allowSensitivePath(params));
184
+ const prepared = await this.prepareProduct(ctx, image, options.allowSensitivePath === true);
212
185
  const title = await this.generateTitle(ctx, brief);
213
186
  const titleText = outputString(title, "text", false) || brief;
214
187
  const promptPlan = await this.optimizePrompt(ctx, "prompt_plan", "生成图库素材规划", `为电商 Listing 图库生成素材规划:${brief}。品类判断:${profile.label}。需要覆盖白底主图、单卖点证明图、材质/结构细节图、生活方式图;${copyPlanningGuidance(copyPlan)}每张图只回答一个购买问题,不生成假认证和不可验证参数。`, prepared.cutoutUrl, `Listing 图库素材规划:主图、卖点图、细节图、生活方式图。品类:${profile.label}。商品卖点:${brief}`);
@@ -310,7 +283,7 @@ export class AppRunner {
310
283
  overlayCopy: overlayCopy.lifestyle_image,
311
284
  }),
312
285
  },
313
- ], options);
286
+ ]);
314
287
  return ctx.completed();
315
288
  }
316
289
  async runPdpAPlus(params, options) {
@@ -326,7 +299,7 @@ export class AppRunner {
326
299
  usage_module: "4:5",
327
300
  comparison_module: "1:1",
328
301
  });
329
- const prepared = await this.prepareProduct(ctx, image, allowSensitivePath(params));
302
+ const prepared = await this.prepareProduct(ctx, image, options.allowSensitivePath === true);
330
303
  const title = await this.generateTitle(ctx, brief);
331
304
  const titleText = outputString(title, "text", false) || brief;
332
305
  const promptPlan = await this.optimizePrompt(ctx, "prompt_plan", "生成详情页模块规划", `为电商详情页/A+模块生成购买说服顺序:${brief}。品类判断:${profile.label}。模块包含首屏、痛点解决、结构/细节证明、真实使用场景、对比规格;${copyPlanningGuidance(copyPlan)}不编造参数和认证。`, prepared.cutoutUrl, `详情页模块规划:首屏、痛点、结构细节、使用场景、对比规格。品类:${profile.label}。商品信息:${brief}`);
@@ -451,7 +424,7 @@ export class AppRunner {
451
424
  overlayCopy: overlayCopy.comparison_module,
452
425
  }),
453
426
  },
454
- ], options);
427
+ ]);
455
428
  return ctx.completed();
456
429
  }
457
430
  async runSocialSeedingPack(params, options) {
@@ -464,7 +437,7 @@ export class AppRunner {
464
437
  cover_image: "3:4",
465
438
  scene_image: "9:16",
466
439
  });
467
- const prepared = await this.prepareProduct(ctx, image, allowSensitivePath(params));
440
+ const prepared = await this.prepareProduct(ctx, image, options.allowSensitivePath === true);
468
441
  const title = await this.generateTitle(ctx, brief);
469
442
  const titleText = outputString(title, "text", false) || brief;
470
443
  const xhsCaption = buildXhsCaption(titleText, brief);
@@ -534,7 +507,7 @@ export class AppRunner {
534
507
  overlayCopy: overlayCopy.scene_image,
535
508
  }),
536
509
  },
537
- ], options);
510
+ ]);
538
511
  return ctx.completed();
539
512
  }
540
513
  async runCampaignKvPack(params, options) {
@@ -544,7 +517,7 @@ export class AppRunner {
544
517
  const ratios = parseRatioList(params.ratios ?? params.ratio, ["16:9", "1:1", "4:5"]);
545
518
  const profile = inferProductCategoryProfile(brief);
546
519
  const copyPlan = resolveCopyPlan(params, brief);
547
- const prepared = await this.prepareProduct(ctx, image, allowSensitivePath(params));
520
+ const prepared = await this.prepareProduct(ctx, image, options.allowSensitivePath === true);
548
521
  const title = await this.generateTitle(ctx, brief);
549
522
  const titleText = outputString(title, "text", false) || brief;
550
523
  const promptPlan = await this.optimizePrompt(ctx, "prompt_plan", "生成 Campaign KV 主视觉提示词", `为新品 Campaign KV 生成${copyPlan.mode === "no-text" ? "无字主视觉" : "可直接投放主视觉"}提示词:${brief}。品类判断:${profile.label}。要求一个清晰记忆符号,可裁切到官网、社媒、电商活动和投放;${copyPlanningGuidance(copyPlan)}不改 logo、不生成假促销标。`, prepared.cutoutUrl, copyPlan.mode === "no-text"
@@ -595,11 +568,11 @@ export class AppRunner {
595
568
  overlayCopy: String(overlayCopy[key] ?? ""),
596
569
  }),
597
570
  };
598
- }), options);
571
+ }));
599
572
  return ctx.completed();
600
573
  }
601
- async generateImageJobs(ctx, jobs, options) {
602
- await mapWithConcurrency(jobs, resolveConcurrency(options.concurrency), async (job) => {
574
+ async generateImageJobs(ctx, jobs) {
575
+ await mapWithConcurrency(jobs, 2, async (job) => {
603
576
  const result = await this.generateImage(ctx, job.key, job.stepName, job.prompt, job.image, job.ratio, job.model);
604
577
  ctx.outputs[job.key] = result.outputs;
605
578
  ctx.addAsset(job.label, job.key, result);
@@ -752,9 +725,8 @@ function normalizeAppStepError(error, step) {
752
725
  : "business",
753
726
  message: `${step.step_name} 执行失败:${friendlyErrorMessage(rawMessage)}`,
754
727
  raw_message: rawMessage,
755
- hint: "可根据失败步骤单独调用对应 Tool 验证输入,也可以调整图片或 brief 后重试 App。",
728
+ hint: "请调整图片或 brief 后重试当前 Workflow;内部步骤由 Workflow 自动编排。",
756
729
  next_steps: [
757
- `单独验证该步骤:gd-cli tools call ${step.tool}`,
758
730
  "调整输入后重试原 workflows run 命令。",
759
731
  ],
760
732
  };
@@ -1160,11 +1132,6 @@ function optionalString(value) {
1160
1132
  const normalized = value.trim();
1161
1133
  return normalized ? normalized : undefined;
1162
1134
  }
1163
- function allowSensitivePath(params) {
1164
- return (params.allow_sensitive_path === true ||
1165
- params.allowSensitivePath === true ||
1166
- params["allow-sensitive-path"] === true);
1167
- }
1168
1135
  function outputString(result, key, required = true) {
1169
1136
  const outputs = result.outputs;
1170
1137
  const value = outputs?.[key];
@@ -0,0 +1,34 @@
1
+ import { DamClient, type DamUploadOptions } from "./dam-client.js";
2
+ import { type DirectRequestOptions } from "./direct-client.js";
3
+ import { type CreativeAgentMessage, type CreativeAgentRequest } from "../creative/protocol.js";
4
+ import { type CreativeInput, type CreativeResult } from "../creative/contract.js";
5
+ export declare const CREATIVE_COMPLETION_PATH: "/ai-agent/v1/thread/completion";
6
+ export interface CreativeStreamClient {
7
+ postStream(path: string, body?: unknown, options?: DirectRequestOptions): Promise<Response>;
8
+ }
9
+ export interface CreativeUploadClient {
10
+ uploadLocalAsset(file: string, options?: DamUploadOptions): Promise<Awaited<ReturnType<DamClient["uploadLocalAsset"]>>>;
11
+ }
12
+ export interface CreativeClientDeps {
13
+ api?: CreativeStreamClient;
14
+ dam?: CreativeUploadClient;
15
+ idFactory?: () => string;
16
+ }
17
+ export declare class CreativeClient {
18
+ private readonly api;
19
+ private readonly dam;
20
+ private readonly idFactory;
21
+ constructor(deps?: CreativeClientDeps);
22
+ run(value: unknown): Promise<CreativeResult>;
23
+ }
24
+ /**
25
+ * Consume the Editor completion body without exposing transport events to the
26
+ * CLI caller. The Editor currently emits JSON arrays, sometimes as adjacent
27
+ * JSON values and sometimes wrapped in `data:` SSE records, so both forms are
28
+ * accepted here.
29
+ */
30
+ export declare function parseCreativeSse(stream: ReadableStream<Uint8Array>): Promise<CreativeAgentMessage[]>;
31
+ export declare function buildCreativeRequestForTest(input: CreativeInput, request: CreativeAgentRequest): {
32
+ input: CreativeInput;
33
+ request: CreativeAgentRequest;
34
+ };
@@ -0,0 +1,184 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { DamClient } from "./dam-client.js";
3
+ import { DirectApiClient } from "./direct-client.js";
4
+ import { buildCreativeAgentRequest, normalizeCreativeMessages, } from "../creative/protocol.js";
5
+ import { validateCreativeInput } from "../creative/contract.js";
6
+ import { prepareCreativeMedia } from "../creative/media.js";
7
+ export const CREATIVE_COMPLETION_PATH = "/ai-agent/v1/thread/completion";
8
+ export class CreativeClient {
9
+ api;
10
+ dam;
11
+ idFactory;
12
+ constructor(deps = {}) {
13
+ this.api = deps.api ?? new DirectApiClient();
14
+ this.dam = deps.dam ?? new DamClient();
15
+ this.idFactory = deps.idFactory ?? randomUUID;
16
+ }
17
+ async run(value) {
18
+ const input = validateCreativeInput(value);
19
+ const uploader = (file, options) => this.dam.uploadLocalAsset(file, options);
20
+ const media = await prepareCreativeMedia(input.media ?? [], uploader);
21
+ const request = buildCreativeAgentRequest(input, media, {
22
+ local_thread_id: this.idFactory(),
23
+ local_message_id: this.idFactory(),
24
+ });
25
+ const response = await this.api.postStream(CREATIVE_COMPLETION_PATH, request, {
26
+ headers: { Accept: "text/event-stream" },
27
+ });
28
+ if (!response.body) {
29
+ throw new Error("Creative completion 没有返回流式响应");
30
+ }
31
+ const messages = await parseCreativeSse(response.body);
32
+ return normalizeCreativeMessages(messages, input.conversation_id ?? "");
33
+ }
34
+ }
35
+ /**
36
+ * Consume the Editor completion body without exposing transport events to the
37
+ * CLI caller. The Editor currently emits JSON arrays, sometimes as adjacent
38
+ * JSON values and sometimes wrapped in `data:` SSE records, so both forms are
39
+ * accepted here.
40
+ */
41
+ export async function parseCreativeSse(stream) {
42
+ const reader = stream.getReader();
43
+ const decoder = new TextDecoder();
44
+ let raw = "";
45
+ try {
46
+ while (true) {
47
+ const result = await reader.read();
48
+ if (result.done)
49
+ break;
50
+ raw += decoder.decode(result.value, { stream: true });
51
+ }
52
+ raw += decoder.decode();
53
+ }
54
+ finally {
55
+ reader.releaseLock();
56
+ }
57
+ const payloads = extractSsePayloads(raw);
58
+ const messages = [];
59
+ for (const payload of payloads) {
60
+ for (const value of parseJsonSequence(payload)) {
61
+ if (Array.isArray(value)) {
62
+ for (const item of value) {
63
+ if (isMessage(item))
64
+ messages.push(item);
65
+ }
66
+ }
67
+ else if (isMessage(value)) {
68
+ messages.push(value);
69
+ }
70
+ }
71
+ }
72
+ return messages;
73
+ }
74
+ function extractSsePayloads(raw) {
75
+ const normalized = raw.replace(/\r\n?/g, "\n");
76
+ const lines = normalized.split("\n");
77
+ const payloads = [];
78
+ let dataLines = [];
79
+ let foundDataLine = false;
80
+ const flush = () => {
81
+ if (dataLines.length > 0) {
82
+ payloads.push(dataLines.join("\n"));
83
+ dataLines = [];
84
+ }
85
+ };
86
+ for (const line of lines) {
87
+ if (line.startsWith("data:")) {
88
+ foundDataLine = true;
89
+ dataLines.push(line.slice(5).replace(/^ /, ""));
90
+ }
91
+ else if (line === "") {
92
+ flush();
93
+ }
94
+ else if (line.startsWith(":") || line.startsWith("event:") || line.startsWith("id:")) {
95
+ // SSE metadata/heartbeats do not contain completion messages.
96
+ continue;
97
+ }
98
+ else if (!foundDataLine) {
99
+ // The current backend may send raw JSON arrays without an SSE prefix.
100
+ dataLines.push(line);
101
+ }
102
+ else {
103
+ // A continuation line belongs to the current data record according to
104
+ // the SSE grammar.
105
+ dataLines.push(line);
106
+ }
107
+ }
108
+ flush();
109
+ return payloads;
110
+ }
111
+ function parseJsonSequence(payload) {
112
+ const values = [];
113
+ let index = 0;
114
+ while (index < payload.length) {
115
+ while (index < payload.length && /[\s,]/.test(payload[index] ?? ""))
116
+ index += 1;
117
+ if (index >= payload.length)
118
+ break;
119
+ const remaining = payload.slice(index).trim();
120
+ if (remaining === "[DONE]")
121
+ break;
122
+ const start = findJsonStart(payload, index);
123
+ if (start < 0)
124
+ break;
125
+ const end = findJsonEnd(payload, start);
126
+ if (end < 0)
127
+ break;
128
+ const text = payload.slice(start, end + 1);
129
+ try {
130
+ values.push(JSON.parse(text));
131
+ }
132
+ catch {
133
+ // A malformed event is ignored here; valid later events can still be
134
+ // delivered and the final normalizer will report an empty completion.
135
+ }
136
+ index = end + 1;
137
+ }
138
+ return values;
139
+ }
140
+ function findJsonStart(value, from) {
141
+ for (let index = from; index < value.length; index += 1) {
142
+ if (value[index] === "{" || value[index] === "[")
143
+ return index;
144
+ }
145
+ return -1;
146
+ }
147
+ function findJsonEnd(value, start) {
148
+ const stack = [];
149
+ let inString = false;
150
+ let escaped = false;
151
+ for (let index = start; index < value.length; index += 1) {
152
+ const char = value[index];
153
+ if (inString) {
154
+ if (escaped)
155
+ escaped = false;
156
+ else if (char === "\\")
157
+ escaped = true;
158
+ else if (char === '"')
159
+ inString = false;
160
+ continue;
161
+ }
162
+ if (char === '"') {
163
+ inString = true;
164
+ continue;
165
+ }
166
+ if (char === "{" || char === "[")
167
+ stack.push(char);
168
+ else if (char === "}" || char === "]") {
169
+ const opening = stack.pop();
170
+ if ((char === "}" && opening !== "{") || (char === "]" && opening !== "[")) {
171
+ return -1;
172
+ }
173
+ if (stack.length === 0)
174
+ return index;
175
+ }
176
+ }
177
+ return -1;
178
+ }
179
+ function isMessage(value) {
180
+ return !!value && typeof value === "object" && !Array.isArray(value);
181
+ }
182
+ export function buildCreativeRequestForTest(input, request) {
183
+ return { input, request };
184
+ }
@@ -42,7 +42,6 @@ export interface DamSearchOptions {
42
42
  pageSize?: number;
43
43
  page?: number;
44
44
  cursor?: string;
45
- raw?: boolean;
46
45
  allowEmptyKeyword?: boolean;
47
46
  }
48
47
  export interface DamSearchAsset {
@@ -74,12 +73,6 @@ export interface DamSearchResult {
74
73
  finish: boolean;
75
74
  next_cursor?: string;
76
75
  assets: DamSearchAsset[];
77
- debug?: {
78
- source: {
79
- endpoint: string;
80
- raw?: unknown;
81
- };
82
- };
83
76
  }
84
77
  interface DamCover {
85
78
  url?: string;
@@ -4,7 +4,6 @@ import { basename, extname, resolve } from "node:path";
4
4
  import OSS from "ali-oss";
5
5
  import sharp from "sharp";
6
6
  import { DirectApiClient, DirectApiError, unwrapEnvelope } from "./direct-client.js";
7
- import { isDebug, isVerbose } from "../utils/config.js";
8
7
  import { assertSafeUploadPath } from "../utils/sensitive-path.js";
9
8
  import { assertSafeHttpUrl } from "../utils/url-safety.js";
10
9
  import { redactSensitiveText } from "../utils/redact.js";
@@ -140,12 +139,9 @@ export class DamClient {
140
139
  try {
141
140
  const response = await this.client.post("/dam/asset/v2/search/simple", payload);
142
141
  return normalizeSearchResponse(response, {
143
- endpoint: "/dam/asset/v2/search/simple",
144
142
  query,
145
143
  repositoryIds,
146
144
  payload,
147
- includeDebug: options.raw === true || isVerbose() || isDebug(),
148
- includeRaw: options.raw === true,
149
145
  });
150
146
  }
151
147
  catch (error) {
@@ -153,12 +149,9 @@ export class DamClient {
153
149
  throw error;
154
150
  const response = await this.client.post("/dam/asset/search", payload);
155
151
  return normalizeSearchResponse(response, {
156
- endpoint: "/dam/asset/search",
157
152
  query,
158
153
  repositoryIds,
159
154
  payload,
160
- includeDebug: options.raw === true || isVerbose() || isDebug(),
161
- includeRaw: options.raw === true,
162
155
  });
163
156
  }
164
157
  }
@@ -307,16 +300,6 @@ function normalizeSearchResponse(response, context) {
307
300
  finish,
308
301
  next_cursor: nextCursor,
309
302
  assets: rawItems.map(normalizeSearchAsset).filter((item) => item.asset_id),
310
- ...(context.includeDebug
311
- ? {
312
- debug: {
313
- source: {
314
- endpoint: context.endpoint,
315
- ...(context.includeRaw ? { raw: response } : {}),
316
- },
317
- },
318
- }
319
- : {}),
320
303
  };
321
304
  }
322
305
  function extractSearchContainer(value) {