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.
- package/CHANGELOG.md +38 -0
- package/README.md +47 -60
- package/dist/bin/gd-cli.js +2 -2
- package/dist/src/api/app-runner.d.ts +1 -4
- package/dist/src/api/app-runner.js +11 -44
- package/dist/src/api/creative-client.d.ts +34 -0
- package/dist/src/api/creative-client.js +184 -0
- package/dist/src/api/dam-client.d.ts +0 -7
- package/dist/src/api/dam-client.js +0 -17
- package/dist/src/api/direct-client.d.ts +9 -2
- package/dist/src/api/direct-client.js +45 -18
- package/dist/src/api/hub-client.d.ts +11 -8
- package/dist/src/api/hub-client.js +17 -18
- package/dist/src/api/usage-client.d.ts +4 -4
- package/dist/src/api/usage-client.js +9 -49
- package/dist/src/auth/credential-store-v2.d.ts +0 -1
- package/dist/src/auth/credential-store-v2.js +0 -6
- package/dist/src/commands/auth.js +17 -53
- package/dist/src/commands/creative.d.ts +8 -0
- package/dist/src/commands/creative.js +178 -0
- package/dist/src/commands/dam.js +270 -127
- package/dist/src/commands/org.js +31 -47
- package/dist/src/commands/skills.js +33 -118
- package/dist/src/commands/update.js +11 -82
- package/dist/src/commands/usage.d.ts +1 -1
- package/dist/src/commands/usage.js +10 -21
- package/dist/src/commands/workflows.d.ts +1 -1
- package/dist/src/commands/workflows.js +299 -197
- package/dist/src/core/auth/auth-guard.d.ts +21 -0
- package/dist/src/core/auth/auth-guard.js +121 -0
- package/dist/src/core/auth/org-manager.d.ts +2 -1
- package/dist/src/core/auth/org-manager.js +61 -6
- package/dist/src/core/output/envelope.d.ts +1 -0
- package/dist/src/core/output/envelope.js +76 -6
- package/dist/src/creative/contract.d.ts +1060 -0
- package/dist/src/creative/contract.js +722 -0
- package/dist/src/creative/media.d.ts +19 -0
- package/dist/src/creative/media.js +83 -0
- package/dist/src/creative/protocol.d.ts +60 -0
- package/dist/src/creative/protocol.js +337 -0
- package/dist/src/io.d.ts +0 -2
- package/dist/src/io.js +0 -8
- package/dist/src/middleware/auth.d.ts +6 -2
- package/dist/src/middleware/auth.js +25 -63
- package/dist/src/middleware/error-handler.d.ts +8 -0
- package/dist/src/middleware/error-handler.js +61 -57
- package/dist/src/program.d.ts +1 -0
- package/dist/src/program.js +137 -122
- package/dist/src/registry/agent-contracts.d.ts +14 -34
- package/dist/src/registry/agent-contracts.js +209 -297
- package/dist/src/registry/direct-registry.d.ts +0 -5
- package/dist/src/registry/direct-registry.js +0 -19
- package/dist/src/registry/registry-client.d.ts +0 -21
- package/dist/src/registry/registry-client.js +1 -40
- package/dist/src/utils/capability-presenter.js +6 -29
- package/dist/src/utils/config.d.ts +2 -2
- package/dist/src/utils/config.js +1 -1
- package/dist/src/utils/help-verify.d.ts +1 -3
- package/dist/src/utils/help-verify.js +1 -25
- package/dist/src/utils/sensitive-path.js +1 -4
- package/package.json +4 -3
- package/skills/gd-cli/SKILL.md +13 -12
- package/skills/gd-cli/references/auth.md +9 -10
- package/skills/gd-cli/references/creative.md +47 -0
- package/skills/gd-cli/references/entitlement.md +3 -3
- package/skills/gd-cli/references/errors.md +10 -3
- package/skills/gd-cli/references/org.md +3 -3
- package/skills/gd-cli/references/sop.md +8 -8
- package/skills/gd-cli/references/update.md +4 -3
- package/skills/gd-cli/references/workflows.md +7 -6
- package/dist/src/commands/models.d.ts +0 -2
- package/dist/src/commands/models.js +0 -78
- package/dist/src/commands/tools.d.ts +0 -4
- package/dist/src/commands/tools.js +0 -383
- package/dist/src/utils/list-output-format.d.ts +0 -10
- package/dist/src/utils/list-output-format.js +0 -34
- 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,
|
|
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,
|
|
12
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
20
|
-
|
|
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
|
|
19
|
+
const workflows = program
|
|
30
20
|
.command("workflows")
|
|
31
21
|
.usage("<command> [options]")
|
|
32
|
-
.description("完整创意场景 Workflows")
|
|
33
|
-
|
|
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(
|
|
42
|
-
|
|
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),
|
|
34
|
+
formatOutput(rowsForAppList(publicItems), "table");
|
|
51
35
|
}
|
|
52
36
|
}));
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
+
setAuthRequirement(schema, "none");
|
|
53
|
+
const examples = workflows
|
|
85
54
|
.command("examples <workflow-id>")
|
|
86
55
|
.description("查看 Workflow 调用示例")
|
|
87
|
-
.action(withErrorHandler(async (appId
|
|
88
|
-
const cmd = command;
|
|
56
|
+
.action(withErrorHandler(async (appId) => {
|
|
89
57
|
const payload = buildWorkflowExamples(String(appId));
|
|
90
|
-
|
|
91
|
-
if (format === "json") {
|
|
92
|
-
formatOutput(payload, "json");
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
printCapabilityExamples(payload);
|
|
96
|
-
}
|
|
58
|
+
printCapabilityExamples(payload);
|
|
97
59
|
}));
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.
|
|
101
|
-
.
|
|
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("--
|
|
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("--
|
|
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("--
|
|
132
|
-
.option("--timeout <seconds>", "同步等待超时", "600")
|
|
133
|
-
.allowUnknownOption(true)
|
|
75
|
+
.option("--json", "输出机器可读 JSON")
|
|
134
76
|
.allowExcessArguments(false);
|
|
135
|
-
callCmd.action(withErrorHandler(async (appId,
|
|
136
|
-
await runAppCall(appId,
|
|
77
|
+
callCmd.action(withErrorHandler(async (appId, options) => {
|
|
78
|
+
await runAppCall(appId, options);
|
|
137
79
|
}));
|
|
138
|
-
|
|
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,
|
|
82
|
+
export async function runAppCall(appId, opts) {
|
|
142
83
|
const spec = resolveAppSpec(appId);
|
|
143
84
|
if (!spec)
|
|
144
|
-
throw new Error(
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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,
|
|
102
|
+
formatOutput(payload, "human");
|
|
173
103
|
}
|
|
174
104
|
return;
|
|
175
105
|
}
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
253
|
-
|
|
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
|
-
|
|
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
|
|
267
|
-
hasReferenceImage: !appNeedsReferenceImage(spec) || Boolean(firstReferenceImage(params.image
|
|
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
|
|
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(
|
|
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
|
|
439
|
+
function workflowFlagParams(opts) {
|
|
322
440
|
const params = {};
|
|
323
|
-
for (const [
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (
|
|
333
|
-
params[
|
|
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
|
|
339
|
-
|
|
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
|
|
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
|
-
|
|
362
|
-
|
|
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} --
|
|
365
|
-
examples_command: `gd-cli workflows examples ${app.id}
|
|
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
|
+
}
|