gaoding-cli 1.0.0-alpha.8 → 1.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +47 -64
- 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 +10 -42
- package/dist/src/api/dam-client.d.ts +0 -7
- package/dist/src/api/dam-client.js +0 -17
- package/dist/src/commands/auth.js +5 -41
- package/dist/src/commands/creative.js +37 -45
- package/dist/src/commands/dam.js +248 -110
- package/dist/src/commands/org.js +17 -39
- package/dist/src/commands/skills.js +24 -114
- package/dist/src/commands/update.js +10 -85
- package/dist/src/commands/usage.js +4 -17
- package/dist/src/commands/workflows.d.ts +1 -1
- package/dist/src/commands/workflows.js +283 -199
- 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 +28 -80
- package/dist/src/creative/contract.js +23 -44
- package/dist/src/creative/protocol.js +6 -6
- package/dist/src/io.d.ts +0 -2
- package/dist/src/io.js +0 -8
- package/dist/src/middleware/error-handler.d.ts +7 -1
- package/dist/src/middleware/error-handler.js +59 -54
- package/dist/src/program.d.ts +1 -0
- package/dist/src/program.js +138 -41
- package/dist/src/registry/agent-contracts.d.ts +14 -26
- package/dist/src/registry/agent-contracts.js +214 -64
- 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/sensitive-path.js +1 -4
- package/package.json +2 -1
- package/skills/gd-cli/SKILL.md +6 -6
- package/skills/gd-cli/references/auth.md +3 -10
- package/skills/gd-cli/references/creative.md +11 -11
- package/skills/gd-cli/references/entitlement.md +2 -2
- package/skills/gd-cli/references/errors.md +4 -4
- package/skills/gd-cli/references/org.md +3 -3
- package/skills/gd-cli/references/sop.md +5 -5
- package/skills/gd-cli/references/update.md +4 -3
- package/skills/gd-cli/references/workflows.md +6 -5
- package/dist/src/utils/list-output-format.d.ts +0 -10
- package/dist/src/utils/list-output-format.js +0 -34
package/dist/src/program.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command,
|
|
1
|
+
import { Command, CommanderError } from "commander";
|
|
2
2
|
import { CLI_VERSION } from "./utils/config.js";
|
|
3
3
|
import { registerAuthCommand } from "./commands/auth.js";
|
|
4
4
|
import { registerOrgCommand } from "./commands/org.js";
|
|
@@ -8,21 +8,16 @@ import { registerDamCommand } from "./commands/dam.js";
|
|
|
8
8
|
import { registerUpdateCommand } from "./commands/update.js";
|
|
9
9
|
import { registerSkillsCommand } from "./commands/skills.js";
|
|
10
10
|
import { maybeNotifyUpdate } from "./update/notifier.js";
|
|
11
|
-
import { setStaticHelp } from "./utils/static-help.js";
|
|
12
11
|
import { installAuthPreflight } from "./middleware/auth.js";
|
|
12
|
+
import { CliUsageError } from "./core/output/cli-error.js";
|
|
13
|
+
import { emitJsonFailure } from "./middleware/error-handler.js";
|
|
13
14
|
export async function createProgram() {
|
|
14
15
|
const program = new Command();
|
|
15
16
|
program
|
|
16
17
|
.name("gd-cli")
|
|
17
18
|
.usage("<command> [options]")
|
|
18
19
|
.description("GD CLI — 让稿定成为 Agent 的创意生产引擎")
|
|
19
|
-
.version(CLI_VERSION)
|
|
20
|
-
.addOption(new Option("-f, --format <format>", "输出格式: human / table / json / text").choices(["json", "human", "table", "text"]))
|
|
21
|
-
.addOption(new Option("--json", "等同于 --format json,推荐 Agent 和脚本使用"))
|
|
22
|
-
.addOption(new Option("--no-input", "禁止交互,适合 CI / Agent"))
|
|
23
|
-
.addOption(new Option("--yes", "跳过确认"))
|
|
24
|
-
.addOption(new Option("--verbose", "输出详细日志").hideHelp().default(false));
|
|
25
|
-
setStaticHelp(program, TOP_LEVEL_HELP);
|
|
20
|
+
.version(CLI_VERSION);
|
|
26
21
|
registerAuthCommand(program);
|
|
27
22
|
registerOrgCommand(program);
|
|
28
23
|
registerCreativeCommand(program);
|
|
@@ -36,35 +31,137 @@ export async function createProgram() {
|
|
|
36
31
|
});
|
|
37
32
|
return program;
|
|
38
33
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
34
|
+
export async function parseProgram(program, argv = process.argv) {
|
|
35
|
+
const userArgs = argv.slice(2);
|
|
36
|
+
const jsonLeaf = resolveExplicitJsonLeaf(program, userArgs);
|
|
37
|
+
const capturedErrors = [];
|
|
38
|
+
const configuredCommands = allCommands(program).map((command) => {
|
|
39
|
+
const output = command.configureOutput();
|
|
40
|
+
const writeErr = output.writeErr ?? ((text) => process.stderr.write(text));
|
|
41
|
+
command.configureOutput({
|
|
42
|
+
writeErr: (text) => capturedErrors.push({ text, write: writeErr }),
|
|
43
|
+
});
|
|
44
|
+
command.exitOverride();
|
|
45
|
+
return { command, writeErr };
|
|
46
|
+
});
|
|
47
|
+
let actionStarted = false;
|
|
48
|
+
program.hook("preAction", () => {
|
|
49
|
+
actionStarted = true;
|
|
50
|
+
});
|
|
51
|
+
try {
|
|
52
|
+
await program.parseAsync([...argv]);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error instanceof CommanderError && error.exitCode === 0)
|
|
56
|
+
return;
|
|
57
|
+
if (!actionStarted && jsonLeaf) {
|
|
58
|
+
emitJsonFailure(jsonLeaf, parseFailure(error, jsonLeaf));
|
|
59
|
+
process.exitCode = error instanceof CommanderError
|
|
60
|
+
? Math.max(1, error.exitCode)
|
|
61
|
+
: 1;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const captured of capturedErrors)
|
|
65
|
+
captured.write(captured.text);
|
|
66
|
+
if (error instanceof CommanderError) {
|
|
67
|
+
process.exitCode = error.exitCode;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
for (const { command, writeErr } of configuredCommands) {
|
|
74
|
+
command.configureOutput({ writeErr });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function resolveExplicitJsonLeaf(program, args) {
|
|
79
|
+
let current = program;
|
|
80
|
+
let index = 0;
|
|
81
|
+
let commandIndex = -1;
|
|
82
|
+
while (current.commands.length > 0) {
|
|
83
|
+
let nextCommand;
|
|
84
|
+
while (index < args.length) {
|
|
85
|
+
const token = args[index];
|
|
86
|
+
if (token === "--")
|
|
87
|
+
return undefined;
|
|
88
|
+
if (token.startsWith("-")) {
|
|
89
|
+
index += optionWidth(current, args, index);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
nextCommand = current.commands.find((candidate) => candidate.name() === token || candidate.aliases().includes(token));
|
|
93
|
+
if (!nextCommand)
|
|
94
|
+
return undefined;
|
|
95
|
+
commandIndex = index;
|
|
96
|
+
index += 1;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
if (!nextCommand)
|
|
100
|
+
return undefined;
|
|
101
|
+
current = nextCommand;
|
|
102
|
+
}
|
|
103
|
+
if (commandIndex < 0 ||
|
|
104
|
+
!current.options.some((option) => option.long === "--json")) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
return hasExplicitJsonOption(current, args.slice(commandIndex + 1))
|
|
108
|
+
? current
|
|
109
|
+
: undefined;
|
|
110
|
+
}
|
|
111
|
+
function hasExplicitJsonOption(command, args) {
|
|
112
|
+
for (let index = 0; index < args.length;) {
|
|
113
|
+
const token = args[index];
|
|
114
|
+
if (token === "--")
|
|
115
|
+
return false;
|
|
116
|
+
if (token === "--json")
|
|
117
|
+
return true;
|
|
118
|
+
index += optionWidth(command, args, index);
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
function optionWidth(command, args, index) {
|
|
123
|
+
const token = args[index];
|
|
124
|
+
const flag = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
125
|
+
const option = command.options.find((candidate) => candidate.long === flag || candidate.short === flag);
|
|
126
|
+
if (!option || token.includes("="))
|
|
127
|
+
return 1;
|
|
128
|
+
if (option.required)
|
|
129
|
+
return index + 1 < args.length ? 2 : 1;
|
|
130
|
+
if (option.optional &&
|
|
131
|
+
index + 1 < args.length &&
|
|
132
|
+
!args[index + 1].startsWith("-")) {
|
|
133
|
+
return 2;
|
|
134
|
+
}
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
function parseFailure(error, command) {
|
|
138
|
+
const missingCodes = new Set([
|
|
139
|
+
"commander.missingArgument",
|
|
140
|
+
"commander.optionMissingArgument",
|
|
141
|
+
"commander.missingMandatoryOptionValue",
|
|
142
|
+
]);
|
|
143
|
+
const code = error instanceof CommanderError && missingCodes.has(error.code)
|
|
144
|
+
? "PARAM_MISSING"
|
|
145
|
+
: "PARAM_INVALID";
|
|
146
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
147
|
+
const message = rawMessage.replace(/^error:\s*/i, "").trim() || "参数不合法";
|
|
148
|
+
return new CliUsageError({
|
|
149
|
+
code,
|
|
150
|
+
type: "validation",
|
|
151
|
+
message,
|
|
152
|
+
hint: `运行 gd-cli ${publicCommandName(command)} --help 查看参数说明。`,
|
|
153
|
+
retryable: false,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function publicCommandName(command) {
|
|
157
|
+
const names = [];
|
|
158
|
+
let current = command;
|
|
159
|
+
while (current.parent) {
|
|
160
|
+
names.unshift(current.name());
|
|
161
|
+
current = current.parent;
|
|
162
|
+
}
|
|
163
|
+
return names.join(" ");
|
|
164
|
+
}
|
|
165
|
+
function allCommands(root) {
|
|
166
|
+
return [root, ...root.commands.flatMap(allCommands)];
|
|
167
|
+
}
|
|
@@ -1,35 +1,23 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { ParamSpec } from "./types.js";
|
|
2
|
+
export declare const PUBLIC_WORKFLOW_MEDIA_PATTERN = "^kv_\\d+_\\d+$";
|
|
3
|
+
export interface PublicWorkflowOutputDefinition {
|
|
4
|
+
textFields: readonly string[];
|
|
5
|
+
mediaFields: readonly string[];
|
|
6
|
+
overlayFields: readonly string[];
|
|
7
|
+
ratioFields: readonly string[];
|
|
8
|
+
ratios: "record" | "array";
|
|
9
|
+
sellingPoints?: boolean;
|
|
10
|
+
mediaPattern?: string;
|
|
11
|
+
}
|
|
3
12
|
export interface JsonSchemaObject {
|
|
4
13
|
type: "object";
|
|
5
14
|
properties: Record<string, Record<string, unknown>>;
|
|
6
15
|
required: string[];
|
|
7
16
|
additionalProperties?: boolean;
|
|
8
|
-
|
|
9
|
-
export interface CapabilityManifestCommand {
|
|
10
|
-
id: string;
|
|
11
|
-
type: "workflow";
|
|
12
|
-
category: string;
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
canonical_command: string;
|
|
16
|
-
input_schema_command?: string;
|
|
17
|
-
examples_command?: string;
|
|
18
|
-
output: "json";
|
|
19
|
-
safe_for_agent: boolean;
|
|
20
|
-
source: CapabilitySource;
|
|
21
|
-
status: CapabilityStatus;
|
|
22
|
-
policy: CapabilityPolicy;
|
|
23
|
-
}
|
|
24
|
-
export interface CapabilityManifest {
|
|
25
|
-
name: "gd-cli";
|
|
26
|
-
version: string;
|
|
27
|
-
description: string;
|
|
28
|
-
commands: CapabilityManifestCommand[];
|
|
17
|
+
patternProperties?: Record<string, Record<string, unknown>>;
|
|
29
18
|
}
|
|
30
19
|
export declare function buildInputJsonSchema(params: ParamSpec[], extraProperties?: Record<string, Record<string, unknown>>): JsonSchemaObject;
|
|
31
|
-
export declare function
|
|
20
|
+
export declare function resolvePublicWorkflowOutputDefinition(appId: string): PublicWorkflowOutputDefinition;
|
|
21
|
+
export declare function buildOutputJsonSchema(appId: string): JsonSchemaObject;
|
|
32
22
|
export declare function buildWorkflowSchema(appId: string): Record<string, unknown>;
|
|
33
23
|
export declare function buildWorkflowExamples(appId: string): Record<string, unknown>;
|
|
34
|
-
export declare function buildWorkflowManifest(): CapabilityManifest;
|
|
35
|
-
export declare function rowsForWorkflowManifest(manifest: CapabilityManifest): Record<string, string>[];
|
|
@@ -1,6 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { resolveAppSpec } from "./direct-registry.js";
|
|
2
|
+
export const PUBLIC_WORKFLOW_MEDIA_PATTERN = "^kv_\\d+_\\d+$";
|
|
3
|
+
const PUBLIC_WORKFLOW_OUTPUT_DEFINITIONS = {
|
|
4
|
+
"listing-gallery": {
|
|
5
|
+
textFields: ["text", "title_text", "delivery_copy", "prompt_plan"],
|
|
6
|
+
mediaFields: [
|
|
7
|
+
"main_image",
|
|
8
|
+
"selling_point_image",
|
|
9
|
+
"detail_image",
|
|
10
|
+
"lifestyle_image",
|
|
11
|
+
],
|
|
12
|
+
overlayFields: [
|
|
13
|
+
"selling_point_image",
|
|
14
|
+
"detail_image",
|
|
15
|
+
"lifestyle_image",
|
|
16
|
+
],
|
|
17
|
+
ratioFields: [
|
|
18
|
+
"main_image",
|
|
19
|
+
"selling_point_image",
|
|
20
|
+
"detail_image",
|
|
21
|
+
"lifestyle_image",
|
|
22
|
+
],
|
|
23
|
+
ratios: "record",
|
|
24
|
+
},
|
|
25
|
+
"pdp-a-plus": {
|
|
26
|
+
textFields: ["text", "title_text", "delivery_copy", "prompt_plan"],
|
|
27
|
+
mediaFields: [
|
|
28
|
+
"hero_module",
|
|
29
|
+
"pain_point_module",
|
|
30
|
+
"structure_module",
|
|
31
|
+
"usage_module",
|
|
32
|
+
"comparison_module",
|
|
33
|
+
],
|
|
34
|
+
overlayFields: [
|
|
35
|
+
"hero_module",
|
|
36
|
+
"pain_point_module",
|
|
37
|
+
"structure_module",
|
|
38
|
+
"usage_module",
|
|
39
|
+
"comparison_module",
|
|
40
|
+
],
|
|
41
|
+
ratioFields: [
|
|
42
|
+
"hero_module",
|
|
43
|
+
"pain_point_module",
|
|
44
|
+
"structure_module",
|
|
45
|
+
"usage_module",
|
|
46
|
+
"comparison_module",
|
|
47
|
+
],
|
|
48
|
+
ratios: "record",
|
|
49
|
+
sellingPoints: true,
|
|
50
|
+
},
|
|
51
|
+
"social-seeding-pack": {
|
|
52
|
+
textFields: [
|
|
53
|
+
"text",
|
|
54
|
+
"title_text",
|
|
55
|
+
"xhs_caption",
|
|
56
|
+
"cover_prompt",
|
|
57
|
+
"scene_prompt",
|
|
58
|
+
],
|
|
59
|
+
mediaFields: ["cover_image", "scene_image"],
|
|
60
|
+
overlayFields: ["cover_image", "scene_image"],
|
|
61
|
+
ratioFields: ["cover_image", "scene_image"],
|
|
62
|
+
ratios: "record",
|
|
63
|
+
},
|
|
64
|
+
"campaign-kv-pack": {
|
|
65
|
+
textFields: ["text", "title_text", "delivery_copy", "prompt_plan"],
|
|
66
|
+
mediaFields: [],
|
|
67
|
+
overlayFields: [],
|
|
68
|
+
ratioFields: [],
|
|
69
|
+
ratios: "array",
|
|
70
|
+
mediaPattern: PUBLIC_WORKFLOW_MEDIA_PATTERN,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
4
73
|
export function buildInputJsonSchema(params, extraProperties = {}) {
|
|
5
74
|
const properties = { ...extraProperties };
|
|
6
75
|
const required = [];
|
|
@@ -24,28 +93,52 @@ export function buildInputJsonSchema(params, extraProperties = {}) {
|
|
|
24
93
|
type: "object",
|
|
25
94
|
properties,
|
|
26
95
|
required,
|
|
27
|
-
additionalProperties:
|
|
96
|
+
additionalProperties: false,
|
|
28
97
|
};
|
|
29
98
|
}
|
|
30
|
-
export function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
99
|
+
export function resolvePublicWorkflowOutputDefinition(appId) {
|
|
100
|
+
const definition = PUBLIC_WORKFLOW_OUTPUT_DEFINITIONS[appId];
|
|
101
|
+
if (!definition)
|
|
102
|
+
throw new Error(`未找到 Workflow 输出契约: ${appId}`);
|
|
103
|
+
return definition;
|
|
104
|
+
}
|
|
105
|
+
export function buildOutputJsonSchema(appId) {
|
|
106
|
+
const definition = resolvePublicWorkflowOutputDefinition(appId);
|
|
107
|
+
const properties = Object.fromEntries(definition.textFields.map((field) => [
|
|
108
|
+
field,
|
|
109
|
+
stringSchema(workflowTextDescription(field)),
|
|
110
|
+
]));
|
|
111
|
+
properties.copy_plan = copyPlanSchema();
|
|
112
|
+
properties.overlay_copy = namedStringRecordSchema(definition.overlayFields, definition.mediaPattern);
|
|
113
|
+
properties.category_profile = categoryProfileSchema();
|
|
114
|
+
properties.ratios = definition.ratios === "array"
|
|
115
|
+
? stringArraySchema("本次生成的画面比例列表", "^\\d+:\\d+$")
|
|
116
|
+
: namedStringRecordSchema(definition.ratioFields);
|
|
117
|
+
properties.assets = workflowAssetsSchema();
|
|
118
|
+
if (definition.sellingPoints) {
|
|
119
|
+
properties.selling_points = stringArraySchema("从 brief 提取的公开卖点列表");
|
|
120
|
+
}
|
|
121
|
+
for (const field of definition.mediaFields) {
|
|
122
|
+
properties[field] = workflowMediaSchema(`${field} 生成结果`);
|
|
37
123
|
}
|
|
38
124
|
return {
|
|
39
125
|
type: "object",
|
|
40
126
|
properties,
|
|
41
127
|
required: [],
|
|
42
|
-
additionalProperties:
|
|
128
|
+
additionalProperties: false,
|
|
129
|
+
...(definition.mediaPattern
|
|
130
|
+
? {
|
|
131
|
+
patternProperties: {
|
|
132
|
+
[definition.mediaPattern]: workflowMediaSchema("Campaign KV 生成结果"),
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
: {}),
|
|
43
136
|
};
|
|
44
137
|
}
|
|
45
138
|
export function buildWorkflowSchema(appId) {
|
|
46
139
|
const spec = resolveAppSpec(appId);
|
|
47
140
|
if (!spec)
|
|
48
|
-
throw new Error(
|
|
141
|
+
throw new Error(`未找到 Workflow: ${appId}`);
|
|
49
142
|
const input = sampleInput(spec.input ?? []);
|
|
50
143
|
return {
|
|
51
144
|
id: spec.id,
|
|
@@ -54,23 +147,119 @@ export function buildWorkflowSchema(appId) {
|
|
|
54
147
|
title: spec.name,
|
|
55
148
|
description: spec.description,
|
|
56
149
|
canonical_command: `gd-cli workflows run ${spec.id}`,
|
|
57
|
-
schema_command: `gd-cli workflows schema ${spec.id} --
|
|
58
|
-
examples_command: `gd-cli workflows examples ${spec.id}
|
|
150
|
+
schema_command: `gd-cli workflows schema ${spec.id} --json`,
|
|
151
|
+
examples_command: `gd-cli workflows examples ${spec.id}`,
|
|
59
152
|
input_schema: buildInputJsonSchema(spec.input ?? []),
|
|
60
|
-
output_schema: buildOutputJsonSchema(spec.
|
|
153
|
+
output_schema: buildOutputJsonSchema(spec.id),
|
|
61
154
|
sample_input: input,
|
|
62
155
|
deliverables: spec.outputs ?? ["manifest.json", "README.md", "assets/"],
|
|
63
156
|
stdin: {
|
|
64
157
|
supported: true,
|
|
65
|
-
command: `cat brief.json | gd-cli workflows run ${spec.id} - --
|
|
158
|
+
command: `cat brief.json | gd-cli workflows run ${spec.id} --input - --json`,
|
|
66
159
|
content_type: "application/json",
|
|
67
160
|
},
|
|
68
161
|
};
|
|
69
162
|
}
|
|
163
|
+
function workflowMediaSchema(description) {
|
|
164
|
+
return {
|
|
165
|
+
type: "object",
|
|
166
|
+
description,
|
|
167
|
+
properties: {
|
|
168
|
+
url: stringSchema("主结果 URL"),
|
|
169
|
+
mime_type: stringSchema("主结果 MIME 类型"),
|
|
170
|
+
urls: stringArraySchema("全部结果 URL"),
|
|
171
|
+
},
|
|
172
|
+
required: [],
|
|
173
|
+
additionalProperties: false,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function workflowAssetsSchema() {
|
|
177
|
+
return {
|
|
178
|
+
type: "array",
|
|
179
|
+
description: "按语义角色汇总的公开图片清单",
|
|
180
|
+
items: {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
label: stringSchema("交付物显示名称"),
|
|
184
|
+
role: stringSchema("交付物语义角色"),
|
|
185
|
+
type: { type: "string", enum: ["image"], description: "媒体类型" },
|
|
186
|
+
url: stringSchema("交付物 URL"),
|
|
187
|
+
},
|
|
188
|
+
required: ["label", "role", "type", "url"],
|
|
189
|
+
additionalProperties: false,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function copyPlanSchema() {
|
|
194
|
+
return {
|
|
195
|
+
type: "object",
|
|
196
|
+
description: "本次 Workflow 使用的画内文案策略",
|
|
197
|
+
properties: {
|
|
198
|
+
mode: {
|
|
199
|
+
type: "string",
|
|
200
|
+
enum: ["layout-copy", "render-text", "no-text"],
|
|
201
|
+
description: "最终文案模式",
|
|
202
|
+
},
|
|
203
|
+
render_text: { type: "boolean", description: "是否生成画内文字" },
|
|
204
|
+
image_model: stringSchema("显式选择的生图模型"),
|
|
205
|
+
},
|
|
206
|
+
required: ["mode", "render_text"],
|
|
207
|
+
additionalProperties: false,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function categoryProfileSchema() {
|
|
211
|
+
return {
|
|
212
|
+
type: "object",
|
|
213
|
+
description: "根据 brief 推断的公开品类策略",
|
|
214
|
+
properties: {
|
|
215
|
+
id: stringSchema("品类策略 ID"),
|
|
216
|
+
label: stringSchema("品类显示名称"),
|
|
217
|
+
guidance: stringSchema("品类创作指导"),
|
|
218
|
+
},
|
|
219
|
+
required: ["id", "label", "guidance"],
|
|
220
|
+
additionalProperties: false,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function namedStringRecordSchema(fields, pattern) {
|
|
224
|
+
return {
|
|
225
|
+
type: "object",
|
|
226
|
+
properties: Object.fromEntries(fields.map((field) => [field, stringSchema(`${field} 对应值`)])),
|
|
227
|
+
required: [],
|
|
228
|
+
additionalProperties: false,
|
|
229
|
+
...(pattern
|
|
230
|
+
? { patternProperties: { [pattern]: stringSchema("比例对应值") } }
|
|
231
|
+
: {}),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function stringArraySchema(description, pattern) {
|
|
235
|
+
return {
|
|
236
|
+
type: "array",
|
|
237
|
+
description,
|
|
238
|
+
items: {
|
|
239
|
+
type: "string",
|
|
240
|
+
...(pattern ? { pattern } : {}),
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function stringSchema(description) {
|
|
245
|
+
return { type: "string", description };
|
|
246
|
+
}
|
|
247
|
+
function workflowTextDescription(field) {
|
|
248
|
+
const descriptions = {
|
|
249
|
+
text: "面向用户的 Workflow 总说明",
|
|
250
|
+
title_text: "生成标题",
|
|
251
|
+
delivery_copy: "交付说明或渠道文案",
|
|
252
|
+
prompt_plan: "公开素材或主视觉规划",
|
|
253
|
+
xhs_caption: "小红书正文与标签",
|
|
254
|
+
cover_prompt: "封面图提示词",
|
|
255
|
+
scene_prompt: "场景图提示词",
|
|
256
|
+
};
|
|
257
|
+
return descriptions[field] ?? field;
|
|
258
|
+
}
|
|
70
259
|
export function buildWorkflowExamples(appId) {
|
|
71
260
|
const spec = resolveAppSpec(appId);
|
|
72
261
|
if (!spec)
|
|
73
|
-
throw new Error(
|
|
262
|
+
throw new Error(`未找到 Workflow: ${appId}`);
|
|
74
263
|
const input = sampleInput(spec.input ?? []);
|
|
75
264
|
const curatedExamples = curatedAppExamples(spec.id);
|
|
76
265
|
const agentInput = firstExampleInput(curatedExamples) ?? input;
|
|
@@ -82,21 +271,15 @@ export function buildWorkflowExamples(appId) {
|
|
|
82
271
|
]),
|
|
83
272
|
{
|
|
84
273
|
description: "Agent / 脚本推荐:stdin JSON",
|
|
85
|
-
command: `cat brief.json | gd-cli workflows run ${spec.id} - --
|
|
274
|
+
command: `cat brief.json | gd-cli workflows run ${spec.id} --input - --json`,
|
|
86
275
|
input_json: agentInput,
|
|
87
276
|
},
|
|
88
277
|
{
|
|
89
278
|
description: "Agent / 脚本推荐:JSON 文件",
|
|
90
|
-
command: `gd-cli workflows run ${spec.id} --input brief.json --
|
|
279
|
+
command: `gd-cli workflows run ${spec.id} --input brief.json --json`,
|
|
91
280
|
input_json: agentInput,
|
|
92
281
|
},
|
|
93
282
|
];
|
|
94
|
-
if (spec.supports_batch) {
|
|
95
|
-
examples.push({
|
|
96
|
-
description: "批量任务 dry-run 预检",
|
|
97
|
-
command: `gd-cli workflows run ${spec.id} --input ./products.csv --assets-dir ./images --dry-run --format json`,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
283
|
return {
|
|
101
284
|
id: spec.id,
|
|
102
285
|
type: "workflow",
|
|
@@ -106,39 +289,6 @@ export function buildWorkflowExamples(appId) {
|
|
|
106
289
|
examples,
|
|
107
290
|
};
|
|
108
291
|
}
|
|
109
|
-
export function buildWorkflowManifest() {
|
|
110
|
-
const commands = DIRECT_APPS.map(workflowManifestCommand);
|
|
111
|
-
return {
|
|
112
|
-
name: "gd-cli",
|
|
113
|
-
version: CLI_VERSION,
|
|
114
|
-
description: "Gaoding Workflow capabilities for agents",
|
|
115
|
-
commands,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
export function rowsForWorkflowManifest(manifest) {
|
|
119
|
-
return manifest.commands.map((command) => ({
|
|
120
|
-
id: command.id,
|
|
121
|
-
type: command.type,
|
|
122
|
-
分类: command.category,
|
|
123
|
-
名称: command.title,
|
|
124
|
-
command: command.canonical_command,
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
function workflowManifestCommand(spec) {
|
|
128
|
-
return {
|
|
129
|
-
id: spec.id,
|
|
130
|
-
type: "workflow",
|
|
131
|
-
category: spec.category,
|
|
132
|
-
title: spec.name,
|
|
133
|
-
description: spec.description,
|
|
134
|
-
canonical_command: `gd-cli workflows run ${spec.id}`,
|
|
135
|
-
input_schema_command: `gd-cli workflows schema ${spec.id}`,
|
|
136
|
-
examples_command: `gd-cli workflows examples ${spec.id}`,
|
|
137
|
-
output: "json",
|
|
138
|
-
safe_for_agent: true,
|
|
139
|
-
...capabilityMetadata("app", spec.id),
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
292
|
function buildFlagCommand(prefix, id, params) {
|
|
143
293
|
const pieces = [prefix, id];
|
|
144
294
|
for (const param of params) {
|
|
@@ -146,7 +296,7 @@ function buildFlagCommand(prefix, id, params) {
|
|
|
146
296
|
continue;
|
|
147
297
|
pieces.push(param.cli_flag, quoteShell(String(sampleValue(param))));
|
|
148
298
|
}
|
|
149
|
-
pieces.push("--
|
|
299
|
+
pieces.push("--json");
|
|
150
300
|
return pieces.join(" ");
|
|
151
301
|
}
|
|
152
302
|
function sampleInput(params) {
|
|
@@ -187,7 +337,7 @@ function sampleValue(param) {
|
|
|
187
337
|
function curatedAppExamples(appId) {
|
|
188
338
|
if (appId === "listing-gallery") {
|
|
189
339
|
return [
|
|
190
|
-
scenarioExample("生成一套可上架的商品图库素材,包含白底主图、卖点图、细节图和生活方式图。", "gd-cli workflows run listing-gallery --image ./sku_001.jpg --brief \"夏季轻薄防晒衣,透气面料,适合户外通勤;卖点图短文案:轻薄防晒 通勤无负担\" --copy-mode render-text --ratio 1:1
|
|
340
|
+
scenarioExample("生成一套可上架的商品图库素材,包含白底主图、卖点图、细节图和生活方式图。", "gd-cli workflows run listing-gallery --image ./sku_001.jpg --brief \"夏季轻薄防晒衣,透气面料,适合户外通勤;卖点图短文案:轻薄防晒 通勤无负担\" --copy-mode render-text --ratio 1:1 --json", {
|
|
191
341
|
image: "./sku_001.jpg",
|
|
192
342
|
brief: "夏季轻薄防晒衣,透气面料,适合户外通勤;卖点图短文案:轻薄防晒 通勤无负担",
|
|
193
343
|
copy_mode: "render-text",
|
|
@@ -197,7 +347,7 @@ function curatedAppExamples(appId) {
|
|
|
197
347
|
}
|
|
198
348
|
if (appId === "pdp-a-plus") {
|
|
199
349
|
return [
|
|
200
|
-
scenarioExample("生成详情页/A+模块素材,按购买疑虑组织首屏、痛点、结构、使用和规格模块。", "gd-cli workflows run pdp-a-plus --image ./air-purifier.jpg --brief \"桌面空气净化器,静音,滤芯可更换,适合卧室;首屏短文案:静音净化 安心入睡\" --copy-mode render-text --ratio 4:5
|
|
350
|
+
scenarioExample("生成详情页/A+模块素材,按购买疑虑组织首屏、痛点、结构、使用和规格模块。", "gd-cli workflows run pdp-a-plus --image ./air-purifier.jpg --brief \"桌面空气净化器,静音,滤芯可更换,适合卧室;首屏短文案:静音净化 安心入睡\" --copy-mode render-text --ratio 4:5 --json", {
|
|
201
351
|
image: "./air-purifier.jpg",
|
|
202
352
|
brief: "桌面空气净化器,静音,滤芯可更换,适合卧室;首屏短文案:静音净化 安心入睡",
|
|
203
353
|
copy_mode: "render-text",
|
|
@@ -207,7 +357,7 @@ function curatedAppExamples(appId) {
|
|
|
207
357
|
}
|
|
208
358
|
if (appId === "social-seeding-pack") {
|
|
209
359
|
return [
|
|
210
|
-
scenarioExample("生成小红书种草图文素材,包含封面图、场景图、标题、正文和标签。", "gd-cli workflows run social-seeding-pack --image ./serum.jpg --brief \"屏障修护精华,清爽不黏,适合通勤包分享;封面短文案:通勤包里的清爽修护\" --copy-mode render-text --ratio 3:4
|
|
360
|
+
scenarioExample("生成小红书种草图文素材,包含封面图、场景图、标题、正文和标签。", "gd-cli workflows run social-seeding-pack --image ./serum.jpg --brief \"屏障修护精华,清爽不黏,适合通勤包分享;封面短文案:通勤包里的清爽修护\" --copy-mode render-text --ratio 3:4 --json", {
|
|
211
361
|
image: "./serum.jpg",
|
|
212
362
|
brief: "屏障修护精华,清爽不黏,适合通勤包分享;封面短文案:通勤包里的清爽修护",
|
|
213
363
|
copy_mode: "render-text",
|
|
@@ -217,7 +367,7 @@ function curatedAppExamples(appId) {
|
|
|
217
367
|
}
|
|
218
368
|
if (appId === "campaign-kv-pack") {
|
|
219
369
|
return [
|
|
220
|
-
scenarioExample("生成 Campaign KV 多渠道素材,包含横版、方图、竖图和渠道裁切建议。", "gd-cli workflows run campaign-kv-pack --image ./running-shoes.jpg --brief \"城市跑鞋新品 Campaign,轻量缓震,面向通勤跑者;主标题:轻跑进城\" --copy-mode render-text --ratios 16:9,1:1,4:5
|
|
370
|
+
scenarioExample("生成 Campaign KV 多渠道素材,包含横版、方图、竖图和渠道裁切建议。", "gd-cli workflows run campaign-kv-pack --image ./running-shoes.jpg --brief \"城市跑鞋新品 Campaign,轻量缓震,面向通勤跑者;主标题:轻跑进城\" --copy-mode render-text --ratios 16:9,1:1,4:5 --json", {
|
|
221
371
|
image: "./running-shoes.jpg",
|
|
222
372
|
brief: "城市跑鞋新品 Campaign,轻量缓震,面向通勤跑者;主标题:轻跑进城",
|
|
223
373
|
copy_mode: "render-text",
|