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
@@ -1,181 +1,109 @@
1
1
  import { AppRunner } from "../api/app-runner.js";
2
2
  import { withErrorHandler } from "../middleware/error-handler.js";
3
3
  import { formatOutput, rowsForAppList } from "../middleware/output.js";
4
- import { resolveInvokeOutputFormat, resolveListOutputFormat, } from "../utils/list-output-format.js";
5
4
  import { resolveAppActivityLabel } from "../utils/tool-display.js";
6
5
  import { createSpinner } from "../utils/spinner.js";
7
- import { appendAppRunQuickExample } from "../utils/help-verify.js";
8
6
  import { writeAppDeliverables } from "../utils/write-app-deliverables.js";
9
- import { emitJson, wrapEnvelope, shouldEmitEnvelope } from "../core/output/envelope.js";
7
+ import { emitJson, failedEnvelope, publicCliErrorBody, wrapEnvelope, } from "../core/output/envelope.js";
10
8
  import { DIRECT_APPS, resolveAppSpec, } from "../registry/direct-registry.js";
11
- import { buildWorkflowExamples, buildWorkflowSchema, buildManifest, rowsForManifest, } from "../registry/agent-contracts.js";
12
- import { applySetEntries, collectArg, readJsonInput } from "../utils/input-json.js";
13
- import { setStaticHelp } from "../utils/static-help.js";
9
+ import { buildWorkflowExamples, buildWorkflowSchema, PUBLIC_WORKFLOW_MEDIA_PATTERN, resolvePublicWorkflowOutputDefinition, } from "../registry/agent-contracts.js";
10
+ import { readJsonInput } from "../utils/input-json.js";
14
11
  import { printCapabilityExamples, printCapabilitySchema, } from "../utils/capability-presenter.js";
15
- import { capabilityMetadata } from "../utils/capability-metadata.js";
12
+ import { CliUsageError } from "../core/output/cli-error.js";
16
13
  import { assertReferenceImageAvailable, firstReferenceImage, } from "../utils/reference-image.js";
17
14
  import { buildEcommerceInputGuidance } from "../utils/ecommerce-input-guidance.js";
18
15
  import { resolveSafeOutputDir } from "../utils/output-path.js";
19
- const INTERNAL_OPTS = new Set([
20
- "outputDir",
21
- "save",
22
- "async",
23
- "timeout",
24
- "dryRun",
25
- "set",
26
- "asset",
27
- ]);
16
+ import { setAuthRequirement } from "../middleware/auth.js";
17
+ const PUBLIC_WORKFLOW_MEDIA_KEY = new RegExp(PUBLIC_WORKFLOW_MEDIA_PATTERN);
28
18
  export function registerWorkflowsCommand(program) {
29
- const apps = program
19
+ const workflows = program
30
20
  .command("workflows")
31
21
  .usage("<command> [options]")
32
- .description("完整创意场景 Workflows")
33
- .configureHelp({ showGlobalOptions: true });
34
- setStaticHelp(apps, WORKFLOWS_HELP);
35
- apps
22
+ .description("完整创意场景 Workflows");
23
+ const list = workflows
36
24
  .command("list")
37
- .alias("ls")
38
25
  .description("列出内置 Workflows")
26
+ .option("--json", "输出机器可读 JSON")
39
27
  .action(withErrorHandler(async (_options, command) => {
40
28
  const cmd = command;
41
- const publicItems = DIRECT_APPS.map(toPublicAppPayload);
42
- const format = resolveListOutputFormat(cmd);
43
- if (shouldEmitEnvelope(format)) {
29
+ const publicItems = DIRECT_APPS.map(toPublicWorkflowPayload);
30
+ if (cmd.opts().json === true) {
44
31
  emitJson(wrapEnvelope({ workflows: publicItems }, { command: "workflows list" }));
45
32
  }
46
- else if (format === "json") {
47
- formatOutput(publicItems, format);
48
- }
49
33
  else {
50
- formatOutput(rowsForAppList(publicItems), format);
34
+ formatOutput(rowsForAppList(publicItems), "table");
51
35
  }
52
36
  }));
53
- apps
54
- .command("info <workflow-id>")
55
- .description("查看 Workflow 详情")
56
- .action(withErrorHandler(async (appId, _opts, command) => {
57
- const cmd = command;
58
- const detail = resolveAppSpec(String(appId));
59
- if (!detail)
60
- throw new Error(`未找到应用: ${String(appId)}`);
61
- const payload = toPublicAppPayload(detail);
62
- const format = cmd.parent?.parent?.opts().format ?? "json";
63
- if (shouldEmitEnvelope(format)) {
64
- emitJson(wrapEnvelope(payload, { command: "workflows info", workflow_id: appId }));
65
- }
66
- else {
67
- formatOutput(payload, format);
68
- }
69
- }));
70
- apps
37
+ setAuthRequirement(list, "none");
38
+ const schema = workflows
71
39
  .command("schema <workflow-id>")
72
40
  .description("查看 Workflow 输入/输出 JSON Schema")
41
+ .option("--json", "输出完整 JSON Schema")
73
42
  .action(withErrorHandler(async (appId, _opts, command) => {
74
43
  const cmd = command;
75
44
  const payload = buildWorkflowSchema(String(appId));
76
- const format = resolveListOutputFormat(cmd);
77
- if (format === "json") {
45
+ if (cmd.opts().json === true) {
78
46
  formatOutput(payload, "json");
79
47
  }
80
48
  else {
81
49
  printCapabilitySchema(payload);
82
50
  }
83
51
  }));
84
- apps
52
+ setAuthRequirement(schema, "none");
53
+ const examples = workflows
85
54
  .command("examples <workflow-id>")
86
55
  .description("查看 Workflow 调用示例")
87
- .action(withErrorHandler(async (appId, _opts, command) => {
88
- const cmd = command;
56
+ .action(withErrorHandler(async (appId) => {
89
57
  const payload = buildWorkflowExamples(String(appId));
90
- const format = resolveListOutputFormat(cmd);
91
- if (format === "json") {
92
- formatOutput(payload, "json");
93
- }
94
- else {
95
- printCapabilityExamples(payload);
96
- }
58
+ printCapabilityExamples(payload);
97
59
  }));
98
- apps
99
- .command("manifest")
100
- .description("输出 Workflows 机器可读能力清单")
101
- .action((_opts, command) => {
102
- const manifest = buildManifest("workflows");
103
- const format = resolveListOutputFormat(command);
104
- formatOutput(format === "json" ? manifest : rowsForManifest(manifest), format);
105
- });
106
- const callCmd = apps
107
- .command("run <workflow-id> [input]")
108
- .usage("<workflow-id> [input] [options]")
60
+ setAuthRequirement(examples, "none");
61
+ const callCmd = workflows
62
+ .command("run <workflow-id>")
63
+ .usage("<workflow-id> [options]")
109
64
  .description("运行 Workflow(场景编排)")
110
65
  .option("--image <path>", "输入图片路径")
111
- .option("--images <paths>", "多张图片(逗号分隔)")
112
- .option("--prompt <text>", "文字描述 / brief")
113
- .option("--brief <text>", "同 --prompt")
114
- .option("--platforms <list>", "目标平台(逗号分隔)")
115
- .option("--style <style>", "风格")
66
+ .option("--brief <text>", "创作需求说明")
116
67
  .option("--ratio <ratio>", "画面比例")
117
68
  .option("--ratios <list>", "多比例输出列表,如 16:9,1:1,4:5")
118
69
  .option("--copy-mode <mode>", "文案模式: auto / render-text / layout-copy / no-text / ask")
119
70
  .option("--model <code-or-name>", "生图模型 code / 名称 / auto")
120
- .option("--duration <value>", "视频时长参数")
121
- .option("--input <path>", "从 JSON 文件读取输入;非 .json 文件作为 Workflow input 参数")
122
- .option("--set <key=value>", "直接传入单个字段,可重复", collectArg)
123
- .option("--asset <id-or-url>", "传入 DAM asset_id 或 CDN URL,可重复", collectArg)
124
- .option("--assets-dir <dir>", "商品图片目录")
125
- .option("--count <n>", "目标产出数量", parseInt)
126
- .option("--concurrency <n>", "并发数", parseInt)
71
+ .option("--input <path>", "从 JSON 文件读取完整输入;传 - 表示读取 stdin")
127
72
  .option("--dry-run", "只输出计划,不实际调用业务接口", false)
128
- .option("--save <dir>", "同 --output-dir")
129
73
  .option("-o, --output-dir <dir>", "结果输出目录", "./output")
130
74
  .option("--allow-sensitive-path", "确认上传默认受保护的本地路径", false)
131
- .option("--async", "异步模式", false)
132
- .option("--timeout <seconds>", "同步等待超时", "600")
133
- .allowUnknownOption(true)
75
+ .option("--json", "输出机器可读 JSON")
134
76
  .allowExcessArguments(false);
135
- callCmd.action(withErrorHandler(async (appId, input, options, command) => {
136
- await runAppCall(appId, input, options, command);
77
+ callCmd.action(withErrorHandler(async (appId, options) => {
78
+ await runAppCall(appId, options);
137
79
  }));
138
- appendAppRunQuickExample(callCmd, "gd-cli workflows run");
139
- callCmd.addHelpText("afterAll", WORKFLOW_RUN_HELP);
80
+ setAuthRequirement(callCmd, (command) => command.opts().dryRun === true ? "none" : "current-org");
140
81
  }
141
- export async function runAppCall(appId, inputRef, opts, cmd) {
82
+ export async function runAppCall(appId, opts) {
142
83
  const spec = resolveAppSpec(appId);
143
84
  if (!spec)
144
- throw new Error(`未找到应用: ${appId}`);
145
- const inputOption = optionalString(opts.input);
146
- const inputOptionIsJson = inputOption ? shouldReadJsonInput(inputOption) : false;
147
- const inputArgIsJson = inputRef ? shouldReadJsonInput(inputRef) : false;
148
- let params = {};
149
- if (inputArgIsJson && inputRef) {
150
- params = { ...params, ...(await readJsonInput(inputRef)) };
151
- }
152
- if (inputOptionIsJson && inputOption) {
153
- params = { ...params, ...(await readJsonInput(inputOption)) };
154
- }
155
- params = {
156
- ...params,
157
- ...extractAppParams(cmd, opts, { skipInput: inputOptionIsJson }),
85
+ throw new Error(`未找到 Workflow: ${appId}`);
86
+ const inputRef = optionalString(opts.input);
87
+ const inputParams = inputRef
88
+ ? stripSensitiveWorkflowInput(await readJsonInput(inputRef))
89
+ : {};
90
+ const params = {
91
+ ...inputParams,
92
+ ...workflowFlagParams(opts),
158
93
  };
159
- if (inputRef && !inputArgIsJson)
160
- params.input = inputRef;
161
- applySetEntries(params, opts.set);
162
- applyAssetEntries(params, opts.asset);
163
- if (opts.save)
164
- opts.outputDir = opts.save;
94
+ validateWorkflowInput(spec, params);
95
+ const json = opts.json === true;
165
96
  if (opts.dryRun) {
166
97
  const payload = buildAppDryRunPlan(spec.id, params, opts);
167
- const format = resolveInvokeOutputFormat(cmd);
168
- if (shouldEmitEnvelope(format)) {
98
+ if (json) {
169
99
  emitJson(wrapEnvelope(payload, { command: "workflows run", workflow_id: spec.id }));
170
100
  }
171
101
  else {
172
- formatOutput(payload, format);
102
+ formatOutput(payload, "human");
173
103
  }
174
104
  return;
175
105
  }
176
- if (!opts.async) {
177
- resolveSafeOutputDir(String(opts.outputDir ?? "./output"));
178
- }
106
+ resolveSafeOutputDir(String(opts.outputDir ?? "./output"));
179
107
  assertAppReferenceImageAvailable(spec, params);
180
108
  const label = await resolveAppActivityLabel(spec.id);
181
109
  const spinner = createSpinner(`${label} · 处理中…`);
@@ -185,10 +113,7 @@ export async function runAppCall(appId, inputRef, opts, cmd) {
185
113
  let result;
186
114
  try {
187
115
  result = await runner.run(spec.id, params, {
188
- async: !!opts.async,
189
- timeout: parseInt(String(opts.timeout)),
190
- outputDir: opts.outputDir,
191
- concurrency: typeof opts.concurrency === "number" ? opts.concurrency : undefined,
116
+ allowSensitivePath: opts.allowSensitivePath === true,
192
117
  onStepStart: (step) => {
193
118
  if (process.stderr.isTTY)
194
119
  spinner.text = `${label} · ${step.step_name}…`;
@@ -221,7 +146,7 @@ export async function runAppCall(appId, inputRef, opts, cmd) {
221
146
  spinner.fail(`${label} · 失败`);
222
147
  throw error;
223
148
  }
224
- if (result.status === "completed" && result.outputs && !opts.async) {
149
+ if (result.status === "completed" && result.outputs) {
225
150
  try {
226
151
  const pack = await writeAppDeliverables({
227
152
  appId: spec.id,
@@ -249,13 +174,205 @@ export async function runAppCall(appId, inputRef, opts, cmd) {
249
174
  else
250
175
  spinner.stop();
251
176
  }
252
- const format = resolveInvokeOutputFormat(cmd);
253
- if (shouldEmitEnvelope(format)) {
254
- emitJson(wrapEnvelope(result, { command: "workflows run", workflow_id: spec.id }));
177
+ if (json) {
178
+ emitPublicWorkflowJson(spec.id, result);
255
179
  }
256
180
  else {
257
- formatOutput(result, format, { activityLabel: label });
181
+ formatPublicWorkflowHuman(spec.id, result, label);
258
182
  }
183
+ if (result.status === "failed") {
184
+ process.exitCode = 1;
185
+ }
186
+ }
187
+ function emitPublicWorkflowJson(workflowId, result) {
188
+ const meta = { command: "workflows run", workflow_id: workflowId };
189
+ if (result.status === "failed") {
190
+ const envelope = failedEnvelope(projectPublicWorkflowError(result.error), meta);
191
+ envelope.task_id = result.task_id;
192
+ emitJson(envelope);
193
+ return;
194
+ }
195
+ const envelope = wrapEnvelope(projectPublicWorkflowResult(workflowId, result), meta);
196
+ envelope.task_id = result.task_id;
197
+ emitJson(envelope);
198
+ }
199
+ function formatPublicWorkflowHuman(workflowId, result, activityLabel) {
200
+ if (result.status === "failed") {
201
+ formatOutput({
202
+ status: "failed",
203
+ task_id: result.task_id,
204
+ error: projectPublicWorkflowError(result.error),
205
+ }, "human", { activityLabel });
206
+ return;
207
+ }
208
+ const projected = projectPublicWorkflowResult(workflowId, result);
209
+ formatOutput({
210
+ status: "completed",
211
+ task_id: result.task_id,
212
+ outputs: projected.outputs,
213
+ deliverable_dir: projected.deliverable_dir,
214
+ deliverable_zip: projected.deliverable_zip,
215
+ deliverable_readme: projected.deliverable_readme,
216
+ }, "human", { activityLabel });
217
+ }
218
+ function projectPublicWorkflowResult(workflowId, result) {
219
+ return {
220
+ workflow_id: workflowId,
221
+ outputs: projectPublicWorkflowOutputs(workflowId, result.outputs),
222
+ ...(result.deliverable_dir ? { deliverable_dir: result.deliverable_dir } : {}),
223
+ ...(result.deliverable_zip ? { deliverable_zip: result.deliverable_zip } : {}),
224
+ ...(result.deliverable_readme ? { deliverable_readme: result.deliverable_readme } : {}),
225
+ };
226
+ }
227
+ function projectPublicWorkflowOutputs(workflowId, value) {
228
+ if (!value || typeof value !== "object" || Array.isArray(value))
229
+ return {};
230
+ const definition = resolvePublicWorkflowOutputDefinition(workflowId);
231
+ return Object.fromEntries(Object.entries(value)
232
+ .flatMap(([key, item]) => {
233
+ const projected = projectPublicWorkflowOutput(definition, key, item);
234
+ return projected === undefined ? [] : [[key, projected]];
235
+ }));
236
+ }
237
+ function projectPublicWorkflowOutput(definition, key, value) {
238
+ if (definition.textFields.includes(key))
239
+ return publicString(value);
240
+ if (definition.mediaFields.includes(key) ||
241
+ (definition.mediaPattern !== undefined && isPublicKvKey(key))) {
242
+ return projectPublicWorkflowDeliverable(value);
243
+ }
244
+ if (key === "assets")
245
+ return projectPublicWorkflowAssets(value);
246
+ if (key === "copy_plan")
247
+ return projectPublicCopyPlan(value);
248
+ if (key === "overlay_copy") {
249
+ return projectPublicNamedStringRecord(value, definition.overlayFields, definition.mediaPattern !== undefined);
250
+ }
251
+ if (key === "category_profile")
252
+ return projectPublicCategoryProfile(value);
253
+ if (key === "ratios")
254
+ return projectPublicWorkflowRatios(definition, value);
255
+ if (key === "selling_points" && definition.sellingPoints) {
256
+ return publicStringArray(value);
257
+ }
258
+ return undefined;
259
+ }
260
+ function projectPublicWorkflowAssets(value) {
261
+ if (!Array.isArray(value))
262
+ return [];
263
+ return value
264
+ .filter((item) => item && typeof item === "object" && !Array.isArray(item))
265
+ .map((item) => {
266
+ const asset = item;
267
+ return compactPublicRecord({
268
+ label: publicString(asset.label),
269
+ role: publicString(asset.role),
270
+ type: publicString(asset.type),
271
+ url: publicString(asset.url),
272
+ });
273
+ });
274
+ }
275
+ function projectPublicWorkflowDeliverable(value) {
276
+ if (!value || typeof value !== "object" || Array.isArray(value))
277
+ return undefined;
278
+ const deliverable = value;
279
+ return compactPublicRecord({
280
+ url: publicString(deliverable.url),
281
+ mime_type: publicString(deliverable.mime_type),
282
+ urls: publicStringArray(deliverable.urls),
283
+ });
284
+ }
285
+ function projectPublicCopyPlan(value) {
286
+ if (!value || typeof value !== "object" || Array.isArray(value))
287
+ return undefined;
288
+ const plan = value;
289
+ return compactPublicRecord({
290
+ mode: publicString(plan.mode),
291
+ render_text: typeof plan.render_text === "boolean" ? plan.render_text : undefined,
292
+ image_model: publicString(plan.image_model),
293
+ });
294
+ }
295
+ function projectPublicCategoryProfile(value) {
296
+ if (!value || typeof value !== "object" || Array.isArray(value))
297
+ return undefined;
298
+ const profile = value;
299
+ return compactPublicRecord({
300
+ id: publicString(profile.id),
301
+ label: publicString(profile.label),
302
+ guidance: publicString(profile.guidance),
303
+ });
304
+ }
305
+ function projectPublicWorkflowRatios(definition, value) {
306
+ if (definition.ratios === "array") {
307
+ return Array.isArray(value) ? publicStringArray(value) : undefined;
308
+ }
309
+ return projectPublicNamedStringRecord(value, definition.ratioFields);
310
+ }
311
+ function projectPublicNamedStringRecord(value, allowedKeys, allowDynamicKv = false) {
312
+ if (!value || typeof value !== "object" || Array.isArray(value))
313
+ return undefined;
314
+ const entries = Object.entries(value)
315
+ .flatMap(([key, item]) => (allowedKeys.includes(key) || (allowDynamicKv && isPublicKvKey(key))) &&
316
+ typeof item === "string"
317
+ ? [[key, item]]
318
+ : []);
319
+ return Object.fromEntries(entries);
320
+ }
321
+ function isPublicKvKey(key) {
322
+ return PUBLIC_WORKFLOW_MEDIA_KEY.test(key);
323
+ }
324
+ function projectPublicWorkflowError(value) {
325
+ if (typeof value === "string") {
326
+ return { code: "WORKFLOW_FAILED", type: "business", message: value };
327
+ }
328
+ const error = value && typeof value === "object" && !Array.isArray(value)
329
+ ? value
330
+ : {};
331
+ const type = publicErrorType(error.type);
332
+ return publicCliErrorBody({
333
+ code: publicString(error.code) ?? "WORKFLOW_FAILED",
334
+ type,
335
+ message: publicString(error.message) ?? "Workflow 执行失败",
336
+ reason: publicString(error.reason),
337
+ hint: publicString(error.hint),
338
+ retryable: typeof error.retryable === "boolean" ? error.retryable : undefined,
339
+ diagnostic_context: error.diagnostic_context && typeof error.diagnostic_context === "object" &&
340
+ !Array.isArray(error.diagnostic_context)
341
+ ? error.diagnostic_context
342
+ : undefined,
343
+ next_command: publicString(error.next_command),
344
+ next_steps: publicStringArray(error.next_steps),
345
+ pricing_url: publicString(error.pricing_url),
346
+ user_action_required: publicString(error.user_action_required),
347
+ forbidden_actions: publicStringArray(error.forbidden_actions),
348
+ allow_org_check: typeof error.allow_org_check === "boolean" ? error.allow_org_check : undefined,
349
+ agent_message_template: publicString(error.agent_message_template),
350
+ });
351
+ }
352
+ function publicErrorType(value) {
353
+ return value === "business" ||
354
+ value === "auth" ||
355
+ value === "network" ||
356
+ value === "validation" ||
357
+ value === "unknown"
358
+ ? value
359
+ : "unknown";
360
+ }
361
+ function publicString(value) {
362
+ return typeof value === "string" && value ? value : undefined;
363
+ }
364
+ function publicStringArray(value) {
365
+ if (!Array.isArray(value))
366
+ return undefined;
367
+ const items = value.filter((item) => typeof item === "string");
368
+ return items.length > 0 ? items : undefined;
369
+ }
370
+ function compactPublicRecord(value) {
371
+ return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
372
+ }
373
+ function stripSensitiveWorkflowInput(input) {
374
+ const { allow_sensitive_path: _allowSensitivePath, "allow-sensitive-path": _allowSensitivePathKebab, ...safeInput } = input;
375
+ return safeInput;
259
376
  }
260
377
  function buildAppDryRunPlan(appId, params, opts) {
261
378
  const spec = resolveAppSpec(appId);
@@ -263,16 +380,14 @@ function buildAppDryRunPlan(appId, params, opts) {
263
380
  throw new Error(`未找到应用: ${appId}`);
264
381
  const inputGuidance = buildEcommerceInputGuidance({
265
382
  appId: spec.id,
266
- brief: params.brief ?? params.prompt,
267
- hasReferenceImage: !appNeedsReferenceImage(spec) || Boolean(firstReferenceImage(params.image ?? params.images)),
383
+ brief: params.brief,
384
+ hasReferenceImage: !appNeedsReferenceImage(spec) || Boolean(firstReferenceImage(params.image)),
268
385
  });
269
386
  return {
270
387
  workflow: spec.id,
271
388
  dry_run: true,
272
389
  description: spec.description,
273
390
  inputs: params,
274
- required_tools: spec.required_tools,
275
- asset_operations: spec.asset_operations ?? [],
276
391
  outputs: spec.outputs ?? ["manifest.json", "README.md", "assets/"],
277
392
  estimated_duration: spec.estimated_duration,
278
393
  supports_batch: spec.supports_batch ?? false,
@@ -287,7 +402,7 @@ function buildAppDryRunPlan(appId, params, opts) {
287
402
  function assertAppReferenceImageAvailable(spec, params) {
288
403
  if (!appNeedsReferenceImage(spec))
289
404
  return;
290
- assertReferenceImageAvailable(params.image ?? params.images, {
405
+ assertReferenceImageAvailable(params.image, {
291
406
  context: `${spec.id} / ${spec.name}`,
292
407
  });
293
408
  }
@@ -305,11 +420,14 @@ function stepResultUrl(stepResult) {
305
420
  }
306
421
  function buildNextAppCommand(appId, params, opts) {
307
422
  const pieces = ["gd-cli", "workflows", "run", appId];
308
- for (const [key, value] of Object.entries({ ...params, ...opts })) {
309
- if (INTERNAL_OPTS.has(key) || value === undefined || value === false)
310
- continue;
423
+ for (const [key, value] of Object.entries(params)) {
311
424
  pieces.push(`--${kebabCase(key)}`, quoteShell(String(value)));
312
425
  }
426
+ if (opts.allowSensitivePath === true)
427
+ pieces.push("--allow-sensitive-path");
428
+ if (opts.outputDir && opts.outputDir !== "./output") {
429
+ pieces.push("--output-dir", quoteShell(String(opts.outputDir)));
430
+ }
313
431
  return pieces.join(" ");
314
432
  }
315
433
  function kebabCase(key) {
@@ -318,25 +436,47 @@ function kebabCase(key) {
318
436
  function quoteShell(value) {
319
437
  return /^[\w./:=,-]+$/.test(value) ? value : `"${value.replace(/"/g, '\\"')}"`;
320
438
  }
321
- function extractAppParams(command, opts, options = {}) {
439
+ function workflowFlagParams(opts) {
322
440
  const params = {};
323
- for (const [key, value] of Object.entries(opts)) {
324
- if (key === "input" && options.skipInput)
325
- continue;
326
- if (!INTERNAL_OPTS.has(key) && value !== undefined && value !== false) {
327
- params[key] = value;
328
- }
329
- }
330
- const rawArgs = command.args.slice(1);
331
- for (let i = 0; i < rawArgs.length; i += 2) {
332
- if (rawArgs[i]?.startsWith("--")) {
333
- params[rawArgs[i].replace(/^--/, "")] = rawArgs[i + 1];
334
- }
441
+ for (const [option, field] of [
442
+ ["image", "image"],
443
+ ["brief", "brief"],
444
+ ["ratio", "ratio"],
445
+ ["ratios", "ratios"],
446
+ ["copyMode", "copy_mode"],
447
+ ["model", "model"],
448
+ ]) {
449
+ const value = optionalString(opts[option]);
450
+ if (value !== undefined)
451
+ params[field] = value;
335
452
  }
336
453
  return params;
337
454
  }
338
- function shouldReadJsonInput(value) {
339
- return value === "-" || /\.json$/i.test(value);
455
+ function validateWorkflowInput(spec, params) {
456
+ const known = new Set(spec.input.map((param) => param.name));
457
+ const unknown = Object.keys(params).filter((key) => !known.has(key));
458
+ if (unknown.length > 0) {
459
+ throw new CliUsageError({
460
+ code: "PARAM_INVALID",
461
+ type: "validation",
462
+ message: `Workflow 输入不支持字段: ${unknown.join(", ")}`,
463
+ hint: `运行 gd-cli workflows schema ${spec.id} --json 查看完整输入结构。`,
464
+ retryable: false,
465
+ });
466
+ }
467
+ const missing = spec.input
468
+ .filter((param) => param.required)
469
+ .map((param) => param.name)
470
+ .filter((name) => typeof params[name] !== "string" || !String(params[name]).trim());
471
+ if (missing.length > 0) {
472
+ throw new CliUsageError({
473
+ code: "PARAM_MISSING",
474
+ type: "validation",
475
+ message: `Workflow 缺少必填输入: ${missing.join(", ")}`,
476
+ hint: `运行 gd-cli workflows schema ${spec.id} 查看输入说明。`,
477
+ retryable: false,
478
+ });
479
+ }
340
480
  }
341
481
  function optionalString(value) {
342
482
  if (typeof value !== "string")
@@ -344,55 +484,17 @@ function optionalString(value) {
344
484
  const trimmed = value.trim();
345
485
  return trimmed ? trimmed : undefined;
346
486
  }
347
- function applyAssetEntries(target, entries) {
348
- if (!Array.isArray(entries) || entries.length === 0)
349
- return;
350
- const assets = entries.map(String).filter(Boolean);
351
- if (assets.length === 0)
352
- return;
353
- target.assets = assets;
354
- if (!target.image && assets.length === 1)
355
- target.image = assets[0];
356
- if (!target.images && assets.length > 1)
357
- target.images = assets;
358
- }
359
- function toPublicAppPayload(app) {
487
+ function toPublicWorkflowPayload(app) {
360
488
  return {
361
- ...app,
362
- ...capabilityMetadata("app", app.id),
489
+ id: app.id,
490
+ name: app.name,
491
+ description: app.description,
492
+ category: app.category,
493
+ estimated_duration: app.estimated_duration,
494
+ deliverables: app.outputs ?? [],
495
+ consumes_quota: app.consumes_quota ?? false,
363
496
  canonical_command: `gd-cli workflows run ${app.id}`,
364
- schema_command: `gd-cli workflows schema ${app.id} --format json`,
365
- examples_command: `gd-cli workflows examples ${app.id} --format json`,
497
+ schema_command: `gd-cli workflows schema ${app.id} --json`,
498
+ examples_command: `gd-cli workflows examples ${app.id}`,
366
499
  };
367
500
  }
368
- const WORKFLOWS_HELP = `
369
- gd-cli workflows <command> [options]
370
-
371
- 用于运行完整业务场景,例如商品图库素材包、详情页/A+模块素材包、小红书种草图文包。
372
- 一个 Workflow 通常会编排多个 Tools,并输出一组可交付物料。
373
-
374
- 常用命令:
375
- list/ls 列出内置 Workflows
376
- info <workflow-id> 查看 Workflow 详情
377
- run <workflow-id> 运行 Workflow,适合 Agent / 脚本
378
- manifest 输出 Workflows 能力清单
379
- schema <workflow-id> 查看 Workflow 输入/输出 Schema
380
- examples <workflow-id> 查看 Workflow 调用示例
381
-
382
- 示例:
383
- gd-cli workflows list
384
- gd-cli workflows info listing-gallery
385
- gd-cli workflows schema pdp-a-plus
386
- gd-cli workflows run social-seeding-pack --input brief.json --format json
387
- `;
388
- const WORKFLOW_RUN_HELP = `
389
-
390
- JSON 输入:
391
- gd-cli workflows run listing-gallery --input brief.json --format json
392
- cat brief.json | gd-cli workflows run social-seeding-pack - --format json
393
- gd-cli workflows run campaign-kv-pack --set brief="城市跑鞋新品 Campaign" --set image=./sku.png --format json
394
-
395
- 说明:
396
- --input <file> 传入 .json 时作为参数对象读取;其他文件类型会作为 Workflow 的 input 字段。
397
- --dry-run 只校验输入和执行计划,不真正生成。
398
- `;
@@ -0,0 +1,21 @@
1
+ import { CredentialStoreV2 } from "../../auth/credential-store-v2.js";
2
+ import type { CredentialsV2, OrgBinding } from "./types.js";
3
+ export type AuthRequirement = "none" | "credential" | "current-org";
4
+ export interface AuthGuardOptions {
5
+ store?: CredentialStoreV2;
6
+ now?: () => Date;
7
+ refreshCurrentOrg?: (organization: OrgBinding) => Promise<void>;
8
+ onRefreshWarning?: (error: unknown) => void;
9
+ }
10
+ export interface AuthGuardLike {
11
+ ensure(requirement: AuthRequirement): Promise<CredentialsV2 | null>;
12
+ }
13
+ export declare class AuthGuard {
14
+ private readonly store;
15
+ private readonly now;
16
+ private readonly refreshCurrentOrg;
17
+ private readonly onRefreshWarning;
18
+ constructor(options?: AuthGuardOptions);
19
+ ensure(requirement: AuthRequirement): Promise<CredentialsV2 | null>;
20
+ private clearCurrentOrganization;
21
+ }