gaoding-cli 1.0.0-alpha.5
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 +88 -0
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/SECURITY.md +34 -0
- package/dist/bin/gd-cli.d.ts +2 -0
- package/dist/bin/gd-cli.js +10 -0
- package/dist/src/api/app-runner.d.ts +33 -0
- package/dist/src/api/app-runner.js +1177 -0
- package/dist/src/api/dam-client.d.ts +111 -0
- package/dist/src/api/dam-client.js +897 -0
- package/dist/src/api/direct-auth.d.ts +3 -0
- package/dist/src/api/direct-auth.js +11 -0
- package/dist/src/api/direct-client.d.ts +27 -0
- package/dist/src/api/direct-client.js +151 -0
- package/dist/src/api/direct-tools.d.ts +43 -0
- package/dist/src/api/direct-tools.js +1155 -0
- package/dist/src/api/hub-client.d.ts +20 -0
- package/dist/src/api/hub-client.js +99 -0
- package/dist/src/api/sso-client.d.ts +60 -0
- package/dist/src/api/sso-client.js +140 -0
- package/dist/src/api/task-poller.d.ts +38 -0
- package/dist/src/api/task-poller.js +72 -0
- package/dist/src/api/tool-invoker.d.ts +12 -0
- package/dist/src/api/tool-invoker.js +11 -0
- package/dist/src/api/usage-client.d.ts +39 -0
- package/dist/src/api/usage-client.js +179 -0
- package/dist/src/auth/credential-store-v2.d.ts +12 -0
- package/dist/src/auth/credential-store-v2.js +59 -0
- package/dist/src/commands/auth.d.ts +2 -0
- package/dist/src/commands/auth.js +191 -0
- package/dist/src/commands/dam.d.ts +2 -0
- package/dist/src/commands/dam.js +293 -0
- package/dist/src/commands/models.d.ts +2 -0
- package/dist/src/commands/models.js +78 -0
- package/dist/src/commands/org.d.ts +2 -0
- package/dist/src/commands/org.js +137 -0
- package/dist/src/commands/skills.d.ts +2 -0
- package/dist/src/commands/skills.js +213 -0
- package/dist/src/commands/tools.d.ts +4 -0
- package/dist/src/commands/tools.js +383 -0
- package/dist/src/commands/update.d.ts +2 -0
- package/dist/src/commands/update.js +167 -0
- package/dist/src/commands/usage.d.ts +7 -0
- package/dist/src/commands/usage.js +43 -0
- package/dist/src/commands/workflows.d.ts +3 -0
- package/dist/src/commands/workflows.js +398 -0
- package/dist/src/core/auth/auth-provider.d.ts +8 -0
- package/dist/src/core/auth/auth-provider.js +12 -0
- package/dist/src/core/auth/device-oauth-provider.d.ts +12 -0
- package/dist/src/core/auth/device-oauth-provider.js +124 -0
- package/dist/src/core/auth/org-manager.d.ts +26 -0
- package/dist/src/core/auth/org-manager.js +224 -0
- package/dist/src/core/auth/signature.d.ts +19 -0
- package/dist/src/core/auth/signature.js +33 -0
- package/dist/src/core/auth/types.d.ts +52 -0
- package/dist/src/core/auth/types.js +3 -0
- package/dist/src/core/output/cli-error.d.ts +5 -0
- package/dist/src/core/output/cli-error.js +8 -0
- package/dist/src/core/output/detector.d.ts +5 -0
- package/dist/src/core/output/detector.js +14 -0
- package/dist/src/core/output/engine.d.ts +32 -0
- package/dist/src/core/output/engine.js +77 -0
- package/dist/src/core/output/envelope.d.ts +40 -0
- package/dist/src/core/output/envelope.js +119 -0
- package/dist/src/core/output/index.d.ts +4 -0
- package/dist/src/core/output/index.js +4 -0
- package/dist/src/core/output/live-display.d.ts +15 -0
- package/dist/src/core/output/live-display.js +111 -0
- package/dist/src/core/output/result-card.d.ts +18 -0
- package/dist/src/core/output/result-card.js +39 -0
- package/dist/src/core/prompt/index.d.ts +31 -0
- package/dist/src/core/prompt/index.js +36 -0
- package/dist/src/io.d.ts +14 -0
- package/dist/src/io.js +31 -0
- package/dist/src/middleware/auth.d.ts +3 -0
- package/dist/src/middleware/auth.js +74 -0
- package/dist/src/middleware/error-handler.d.ts +3 -0
- package/dist/src/middleware/error-handler.js +431 -0
- package/dist/src/middleware/interactive-params.d.ts +14 -0
- package/dist/src/middleware/interactive-params.js +53 -0
- package/dist/src/middleware/output.d.ts +14 -0
- package/dist/src/middleware/output.js +546 -0
- package/dist/src/models/model-catalog.d.ts +26 -0
- package/dist/src/models/model-catalog.js +216 -0
- package/dist/src/program.d.ts +2 -0
- package/dist/src/program.js +152 -0
- package/dist/src/registry/agent-contracts.d.ts +43 -0
- package/dist/src/registry/agent-contracts.js +483 -0
- package/dist/src/registry/app-loader.d.ts +2 -0
- package/dist/src/registry/app-loader.js +70 -0
- package/dist/src/registry/direct-registry.d.ts +11 -0
- package/dist/src/registry/direct-registry.js +234 -0
- package/dist/src/registry/registry-cache.d.ts +10 -0
- package/dist/src/registry/registry-cache.js +52 -0
- package/dist/src/registry/registry-client.d.ts +28 -0
- package/dist/src/registry/registry-client.js +50 -0
- package/dist/src/registry/types.d.ts +69 -0
- package/dist/src/registry/types.js +1 -0
- package/dist/src/tty/auth-presenter.d.ts +3 -0
- package/dist/src/tty/auth-presenter.js +21 -0
- package/dist/src/update/install-source.d.ts +19 -0
- package/dist/src/update/install-source.js +139 -0
- package/dist/src/update/notifier.d.ts +2 -0
- package/dist/src/update/notifier.js +59 -0
- package/dist/src/update/update-checker.d.ts +22 -0
- package/dist/src/update/update-checker.js +110 -0
- package/dist/src/update/version.d.ts +9 -0
- package/dist/src/update/version.js +52 -0
- package/dist/src/utils/agent-skill-installer.d.ts +57 -0
- package/dist/src/utils/agent-skill-installer.js +389 -0
- package/dist/src/utils/capability-metadata.d.ts +18 -0
- package/dist/src/utils/capability-metadata.js +88 -0
- package/dist/src/utils/capability-presenter.d.ts +4 -0
- package/dist/src/utils/capability-presenter.js +190 -0
- package/dist/src/utils/config.d.ts +16 -0
- package/dist/src/utils/config.js +54 -0
- package/dist/src/utils/credential-permissions.d.ts +2 -0
- package/dist/src/utils/credential-permissions.js +22 -0
- package/dist/src/utils/ecommerce-input-guidance.d.ts +15 -0
- package/dist/src/utils/ecommerce-input-guidance.js +85 -0
- package/dist/src/utils/endpoints.d.ts +52 -0
- package/dist/src/utils/endpoints.js +258 -0
- package/dist/src/utils/enrich-upload-params.d.ts +6 -0
- package/dist/src/utils/enrich-upload-params.js +11 -0
- package/dist/src/utils/entitlement.d.ts +17 -0
- package/dist/src/utils/entitlement.js +146 -0
- package/dist/src/utils/gd-home.d.ts +7 -0
- package/dist/src/utils/gd-home.js +26 -0
- package/dist/src/utils/help-verify.d.ts +9 -0
- package/dist/src/utils/help-verify.js +41 -0
- package/dist/src/utils/input-json.d.ts +3 -0
- package/dist/src/utils/input-json.js +61 -0
- package/dist/src/utils/list-output-format.d.ts +10 -0
- package/dist/src/utils/list-output-format.js +34 -0
- package/dist/src/utils/logger.d.ts +6 -0
- package/dist/src/utils/logger.js +19 -0
- package/dist/src/utils/matting-compose.d.ts +10 -0
- package/dist/src/utils/matting-compose.js +45 -0
- package/dist/src/utils/open-browser.d.ts +1 -0
- package/dist/src/utils/open-browser.js +4 -0
- package/dist/src/utils/output-path.d.ts +5 -0
- package/dist/src/utils/output-path.js +70 -0
- package/dist/src/utils/redact.d.ts +3 -0
- package/dist/src/utils/redact.js +96 -0
- package/dist/src/utils/reference-image.d.ts +8 -0
- package/dist/src/utils/reference-image.js +43 -0
- package/dist/src/utils/resolve-app-local-images.d.ts +8 -0
- package/dist/src/utils/resolve-app-local-images.js +84 -0
- package/dist/src/utils/sensitive-path.d.ts +6 -0
- package/dist/src/utils/sensitive-path.js +69 -0
- package/dist/src/utils/settings-store.d.ts +42 -0
- package/dist/src/utils/settings-store.js +50 -0
- package/dist/src/utils/sleep.d.ts +1 -0
- package/dist/src/utils/sleep.js +3 -0
- package/dist/src/utils/spinner.d.ts +2 -0
- package/dist/src/utils/spinner.js +4 -0
- package/dist/src/utils/static-help.d.ts +2 -0
- package/dist/src/utils/static-help.js +3 -0
- package/dist/src/utils/tool-display.d.ts +10 -0
- package/dist/src/utils/tool-display.js +55 -0
- package/dist/src/utils/transient-network-error.d.ts +4 -0
- package/dist/src/utils/transient-network-error.js +40 -0
- package/dist/src/utils/url-safety.d.ts +6 -0
- package/dist/src/utils/url-safety.js +67 -0
- package/dist/src/utils/write-app-deliverables.d.ts +18 -0
- package/dist/src/utils/write-app-deliverables.js +386 -0
- package/package.json +91 -0
- package/skills/gd-cli/SKILL.md +57 -0
- package/skills/gd-cli/references/auth.md +31 -0
- package/skills/gd-cli/references/deliverables.md +22 -0
- package/skills/gd-cli/references/entitlement.md +21 -0
- package/skills/gd-cli/references/errors.md +19 -0
- package/skills/gd-cli/references/org.md +18 -0
- package/skills/gd-cli/references/sop.md +25 -0
- package/skills/gd-cli/references/tools.md +29 -0
- package/skills/gd-cli/references/update.md +16 -0
- package/skills/gd-cli/references/workflows.md +22 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, join } from "node:path";
|
|
4
|
+
import { ZipArchive } from "archiver";
|
|
5
|
+
import { createUniqueOutputDir, resolveSafeOutputDir } from "./output-path.js";
|
|
6
|
+
import { redactSensitiveText } from "./redact.js";
|
|
7
|
+
import { assertSafeHttpUrl } from "./url-safety.js";
|
|
8
|
+
function pad2(n) {
|
|
9
|
+
return n < 10 ? `0${n}` : String(n);
|
|
10
|
+
}
|
|
11
|
+
function nowStamp() {
|
|
12
|
+
const d = new Date();
|
|
13
|
+
return `${d.getFullYear()}${pad2(d.getMonth() + 1)}${pad2(d.getDate())}-${pad2(d.getHours())}${pad2(d.getMinutes())}${pad2(d.getSeconds())}`;
|
|
14
|
+
}
|
|
15
|
+
function slug(s) {
|
|
16
|
+
return s.replace(/[^a-zA-Z0-9\u4e00-\u9fa5._-]+/g, "-").replace(/^-+|-+$/g, "") || "app";
|
|
17
|
+
}
|
|
18
|
+
function shortId(taskId) {
|
|
19
|
+
return taskId.replace(/-/g, "").slice(0, 8);
|
|
20
|
+
}
|
|
21
|
+
/** 从单步工具 outputs 中提取可读文本(chat 的 text、Dify raw_content 等) */
|
|
22
|
+
function extractReadableText(outputs) {
|
|
23
|
+
if (outputs == null)
|
|
24
|
+
return null;
|
|
25
|
+
if (typeof outputs === "string")
|
|
26
|
+
return outputs.trim() || null;
|
|
27
|
+
if (typeof outputs !== "object")
|
|
28
|
+
return String(outputs);
|
|
29
|
+
const o = outputs;
|
|
30
|
+
if (typeof o.text === "string" && o.text.trim())
|
|
31
|
+
return o.text.trim();
|
|
32
|
+
if (typeof o.message === "string" && o.message.trim())
|
|
33
|
+
return o.message.trim();
|
|
34
|
+
const raw = o.raw_content;
|
|
35
|
+
if (Array.isArray(raw)) {
|
|
36
|
+
const parts = [];
|
|
37
|
+
for (const item of raw) {
|
|
38
|
+
if (!item || typeof item !== "object")
|
|
39
|
+
continue;
|
|
40
|
+
const it = item;
|
|
41
|
+
if (it.type === "text" && typeof it.text === "string")
|
|
42
|
+
parts.push(it.text);
|
|
43
|
+
}
|
|
44
|
+
if (parts.length)
|
|
45
|
+
return parts.join("\n\n");
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function collectHttpsUrls(val, acc, depth = 0) {
|
|
50
|
+
if (depth > 12)
|
|
51
|
+
return;
|
|
52
|
+
if (val == null)
|
|
53
|
+
return;
|
|
54
|
+
if (typeof val === "string" && /^https?:\/\//.test(val)) {
|
|
55
|
+
acc.add(val);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(val)) {
|
|
59
|
+
for (const x of val)
|
|
60
|
+
collectHttpsUrls(x, acc, depth + 1);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (typeof val === "object") {
|
|
64
|
+
const o = val;
|
|
65
|
+
for (const k of ["url", "uri"]) {
|
|
66
|
+
const v = o[k];
|
|
67
|
+
if (typeof v === "string" && /^https?:\/\//.test(v))
|
|
68
|
+
acc.add(v);
|
|
69
|
+
}
|
|
70
|
+
for (const v of Object.values(o))
|
|
71
|
+
collectHttpsUrls(v, acc, depth + 1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function labelForOutputKey(key) {
|
|
75
|
+
const map = {
|
|
76
|
+
product: "原始商品图",
|
|
77
|
+
cutout: "透明底商品图",
|
|
78
|
+
mask: "抠图 Mask",
|
|
79
|
+
mask_url: "抠图 Mask",
|
|
80
|
+
hero: "商品主图",
|
|
81
|
+
main_image: "商品主图",
|
|
82
|
+
selling_point_image: "卖点图",
|
|
83
|
+
detail_image: "细节图",
|
|
84
|
+
lifestyle_image: "生活方式图",
|
|
85
|
+
cover_image: "小红书封面图",
|
|
86
|
+
xhs: "小红书种草图",
|
|
87
|
+
xhs_seed_image: "小红书种草图",
|
|
88
|
+
hero_module: "首屏模块",
|
|
89
|
+
pain_point_module: "痛点模块",
|
|
90
|
+
structure_module: "结构细节模块",
|
|
91
|
+
usage_module: "使用场景模块",
|
|
92
|
+
comparison_module: "对比规格模块",
|
|
93
|
+
scene: "生成场景图",
|
|
94
|
+
scene_image: "场景图",
|
|
95
|
+
video: "生成视频",
|
|
96
|
+
source: "原始素材",
|
|
97
|
+
uploaded: "上传后的素材",
|
|
98
|
+
listing: "上架素材",
|
|
99
|
+
poster: "商品海报",
|
|
100
|
+
};
|
|
101
|
+
return map[key.toLowerCase()] ?? key;
|
|
102
|
+
}
|
|
103
|
+
function collectLabeledUrls(outputs) {
|
|
104
|
+
if (!outputs || typeof outputs !== "object" || Array.isArray(outputs)) {
|
|
105
|
+
const urls = new Set();
|
|
106
|
+
collectHttpsUrls(outputs, urls);
|
|
107
|
+
return [...urls].map((url) => ({ label: "资源", url }));
|
|
108
|
+
}
|
|
109
|
+
const o = outputs;
|
|
110
|
+
const labeled = [];
|
|
111
|
+
const seen = new Set();
|
|
112
|
+
const push = (label, url) => {
|
|
113
|
+
if (typeof url !== "string" || !/^https?:\/\//.test(url) || seen.has(url))
|
|
114
|
+
return;
|
|
115
|
+
seen.add(url);
|
|
116
|
+
labeled.push({ label, url });
|
|
117
|
+
};
|
|
118
|
+
if (Array.isArray(o.assets)) {
|
|
119
|
+
for (const item of o.assets) {
|
|
120
|
+
if (!item || typeof item !== "object")
|
|
121
|
+
continue;
|
|
122
|
+
const asset = item;
|
|
123
|
+
push(typeof asset.label === "string" && asset.label.trim() ? asset.label.trim() : "资源", asset.url);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (const [key, value] of Object.entries(o)) {
|
|
127
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
128
|
+
push(labelForOutputKey(key), value.url);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const urls = new Set();
|
|
132
|
+
collectHttpsUrls(outputs, urls);
|
|
133
|
+
for (const url of urls) {
|
|
134
|
+
push("资源", url);
|
|
135
|
+
}
|
|
136
|
+
return labeled;
|
|
137
|
+
}
|
|
138
|
+
function collectTextSections(outputs) {
|
|
139
|
+
if (!outputs || typeof outputs !== "object" || Array.isArray(outputs))
|
|
140
|
+
return [];
|
|
141
|
+
const o = outputs;
|
|
142
|
+
const sections = [];
|
|
143
|
+
const push = (label, value) => {
|
|
144
|
+
if (typeof value !== "string")
|
|
145
|
+
return;
|
|
146
|
+
const text = value.trim();
|
|
147
|
+
if (!text)
|
|
148
|
+
return;
|
|
149
|
+
sections.push({ label, text });
|
|
150
|
+
};
|
|
151
|
+
push("标题", o.title_text);
|
|
152
|
+
push("小红书种草文案", o.xhs_caption);
|
|
153
|
+
push("交付说明", o.delivery_copy);
|
|
154
|
+
push("商品主图提示词", o.main_image_prompt);
|
|
155
|
+
push("小红书种草图提示词", o.xhs_seed_prompt);
|
|
156
|
+
push("素材规划", o.prompt_plan);
|
|
157
|
+
push("文案模式", formatObjectText(o.copy_plan));
|
|
158
|
+
push("图上/后期文案建议", formatObjectText(o.overlay_copy));
|
|
159
|
+
if (sections.length === 0)
|
|
160
|
+
push("文案与说明", extractReadableText(outputs));
|
|
161
|
+
return sections;
|
|
162
|
+
}
|
|
163
|
+
function formatObjectText(value) {
|
|
164
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
165
|
+
return undefined;
|
|
166
|
+
const entries = Object.entries(value)
|
|
167
|
+
.filter(([, item]) => item !== undefined && item !== null && String(item).trim())
|
|
168
|
+
.map(([key, item]) => `- ${key}: ${String(item)}`);
|
|
169
|
+
return entries.length > 0 ? entries.join("\n") : undefined;
|
|
170
|
+
}
|
|
171
|
+
function extFromUrl(u) {
|
|
172
|
+
try {
|
|
173
|
+
const path = new URL(u).pathname.toLowerCase();
|
|
174
|
+
const m = path.match(/\.(png|jpe?g|gif|webp|svg|mp4|webm)$/);
|
|
175
|
+
if (m)
|
|
176
|
+
return `.${m[1] === "jpeg" ? "jpg" : m[1]}`;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
/* ignore */
|
|
180
|
+
}
|
|
181
|
+
return ".bin";
|
|
182
|
+
}
|
|
183
|
+
async function downloadToFile(url, filePath) {
|
|
184
|
+
try {
|
|
185
|
+
const safeUrl = assertSafeHttpUrl(url, { context: "交付物资源 URL" });
|
|
186
|
+
const res = await fetch(safeUrl, {
|
|
187
|
+
headers: { "User-Agent": "gd-cli-deliverables/1.0" },
|
|
188
|
+
signal: AbortSignal.timeout(120_000),
|
|
189
|
+
});
|
|
190
|
+
if (!res.ok)
|
|
191
|
+
return { ok: false, reason: `HTTP ${res.status}` };
|
|
192
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
193
|
+
await writeFile(filePath, buf);
|
|
194
|
+
return { ok: true };
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
reason: redactSensitiveText(error instanceof Error ? error.message : String(error)),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function downloadLabeledImageUrls(urls, imagesDir, fallbackName, startIndex = 0) {
|
|
204
|
+
let imgIdx = startIndex;
|
|
205
|
+
for (const item of urls) {
|
|
206
|
+
const u = item.url;
|
|
207
|
+
const label = item.label || fallbackName;
|
|
208
|
+
const kind = guessUrlKind(u);
|
|
209
|
+
if (kind !== "image")
|
|
210
|
+
continue;
|
|
211
|
+
imgIdx += 1;
|
|
212
|
+
const ext = extFromUrl(u);
|
|
213
|
+
const fn = join(imagesDir, `${pad2(imgIdx)}-${slug(label)}${ext}`);
|
|
214
|
+
const result = await downloadToFile(u, fn);
|
|
215
|
+
if (!result.ok) {
|
|
216
|
+
await writeFile(`${fn}.url.txt`, `下载失败:${result.reason ?? "未知错误"}\n请手动打开:\n${redactSensitiveText(u)}\n`, "utf8");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return imgIdx;
|
|
220
|
+
}
|
|
221
|
+
function invocationToMarkdown(step, inv) {
|
|
222
|
+
const lines = [
|
|
223
|
+
`# ${step.step_name}`,
|
|
224
|
+
"",
|
|
225
|
+
`- **步骤**: ${step.step_order}`,
|
|
226
|
+
`- **节点 ID**: \`${step.step_id}\``,
|
|
227
|
+
`- **工具**: \`${step.tool}\``,
|
|
228
|
+
"",
|
|
229
|
+
];
|
|
230
|
+
const status = inv.status;
|
|
231
|
+
const taskId = inv.task_id;
|
|
232
|
+
if (taskId)
|
|
233
|
+
lines.push(`- **子任务 ID**: \`${taskId}\``, "");
|
|
234
|
+
if (status)
|
|
235
|
+
lines.push(`- **状态**: ${String(status)}`, "");
|
|
236
|
+
if (inv.error != null) {
|
|
237
|
+
lines.push("## 错误", "", "```json", JSON.stringify(inv.error, null, 2), "```", "");
|
|
238
|
+
}
|
|
239
|
+
const outputs = inv.outputs;
|
|
240
|
+
const body = extractReadableText(outputs);
|
|
241
|
+
if (body) {
|
|
242
|
+
lines.push("## 文本结果", "", body, "");
|
|
243
|
+
}
|
|
244
|
+
const urls = new Set();
|
|
245
|
+
collectHttpsUrls(outputs, urls);
|
|
246
|
+
const urlList = [...urls];
|
|
247
|
+
if (urlList.length) {
|
|
248
|
+
lines.push("## 链接与资源", "");
|
|
249
|
+
for (const u of urlList) {
|
|
250
|
+
lines.push(`- ${u}`);
|
|
251
|
+
}
|
|
252
|
+
lines.push("");
|
|
253
|
+
}
|
|
254
|
+
if (!body && outputs != null && typeof outputs === "object") {
|
|
255
|
+
lines.push("## 原始输出(JSON)", "", "```json", JSON.stringify(outputs, null, 2), "```", "");
|
|
256
|
+
}
|
|
257
|
+
return lines.join("\n");
|
|
258
|
+
}
|
|
259
|
+
function parseStepOutputs(outputs) {
|
|
260
|
+
if (!outputs || typeof outputs !== "object")
|
|
261
|
+
return null;
|
|
262
|
+
const o = outputs;
|
|
263
|
+
const raw = o.step_outputs;
|
|
264
|
+
if (!Array.isArray(raw) || raw.length === 0)
|
|
265
|
+
return null;
|
|
266
|
+
const out = [];
|
|
267
|
+
for (const row of raw) {
|
|
268
|
+
if (!row || typeof row !== "object")
|
|
269
|
+
continue;
|
|
270
|
+
const r = row;
|
|
271
|
+
const inv = r.invocation;
|
|
272
|
+
if (!inv || typeof inv !== "object")
|
|
273
|
+
continue;
|
|
274
|
+
out.push({
|
|
275
|
+
step_order: Number(r.step_order) || out.length + 1,
|
|
276
|
+
step_id: String(r.step_id ?? ""),
|
|
277
|
+
step_name: String(r.step_name ?? ""),
|
|
278
|
+
tool: String(r.tool ?? ""),
|
|
279
|
+
invocation: inv,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return out.length ? out : null;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* 将 App 完成后的 outputs 落盘:每步一个 Markdown、图片下载到 images/、打 zip。
|
|
286
|
+
*/
|
|
287
|
+
export async function writeAppDeliverables(opts) {
|
|
288
|
+
const { appId, taskId, outputs, outputDir, activityLabel } = opts;
|
|
289
|
+
const root = resolveSafeOutputDir(outputDir);
|
|
290
|
+
await mkdir(root, { recursive: true });
|
|
291
|
+
const folderName = `${slug(appId)}-${shortId(taskId)}-${nowStamp()}`;
|
|
292
|
+
const created = await createUniqueOutputDir(root, folderName);
|
|
293
|
+
const dir = created.dir;
|
|
294
|
+
const imagesDir = join(dir, "images");
|
|
295
|
+
await mkdir(imagesDir, { recursive: true });
|
|
296
|
+
const label = activityLabel?.trim() || appId;
|
|
297
|
+
const steps = parseStepOutputs(outputs) ?? [];
|
|
298
|
+
if (steps.length > 0) {
|
|
299
|
+
let imgIdx = 0;
|
|
300
|
+
for (const step of steps) {
|
|
301
|
+
const stepTitle = step.step_name || labelForOutputKey(step.step_id || step.tool);
|
|
302
|
+
const baseName = `${pad2(step.step_order)}-${slug(stepTitle)}`;
|
|
303
|
+
const mdPath = join(dir, `${baseName}.md`);
|
|
304
|
+
const md = invocationToMarkdown(step, step.invocation);
|
|
305
|
+
await writeFile(mdPath, md, "utf8");
|
|
306
|
+
const outs = step.invocation.outputs;
|
|
307
|
+
const labeledUrls = collectLabeledUrls(outs).map((item) => ({
|
|
308
|
+
label: item.label === "资源" ? stepTitle : item.label,
|
|
309
|
+
url: item.url,
|
|
310
|
+
}));
|
|
311
|
+
imgIdx = await downloadLabeledImageUrls(labeledUrls, imagesDir, stepTitle, imgIdx);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
/** 无 step_outputs 时退化为整包 JSON + 链接列表 */
|
|
316
|
+
const fallback = join(dir, "交付结果汇总.md");
|
|
317
|
+
const labeledUrls = collectLabeledUrls(outputs);
|
|
318
|
+
const textSections = collectTextSections(outputs);
|
|
319
|
+
const text = typeof outputs === "object" && outputs !== null
|
|
320
|
+
? JSON.stringify(outputs, null, 2)
|
|
321
|
+
: String(outputs);
|
|
322
|
+
await downloadLabeledImageUrls(labeledUrls, imagesDir, "交付资源");
|
|
323
|
+
const textMarkdown = textSections.length > 0
|
|
324
|
+
? `## 文案与提示词\n\n${textSections.map(({ label, text }) => `### ${label}\n\n${text}`).join("\n\n")}\n\n`
|
|
325
|
+
: "";
|
|
326
|
+
await writeFile(fallback, `# 运行结果汇总\n\n${textMarkdown}## 链接\n\n${labeledUrls.map(({ label, url }) => `- **${label}**: ${url}`).join("\n") || "(无)"}\n\n## 完整 outputs\n\n\`\`\`json\n${text}\n\`\`\`\n`, "utf8");
|
|
327
|
+
}
|
|
328
|
+
const readmePath = join(dir, "README.md");
|
|
329
|
+
const zipName = `${created.name}.zip`;
|
|
330
|
+
const zipPath = join(root, zipName);
|
|
331
|
+
const readme = buildReadmeMd({
|
|
332
|
+
label,
|
|
333
|
+
appId,
|
|
334
|
+
taskId,
|
|
335
|
+
zipPath,
|
|
336
|
+
stepCount: steps.length || 1,
|
|
337
|
+
});
|
|
338
|
+
await writeFile(readmePath, readme, "utf8");
|
|
339
|
+
await zipDirectory(dir, zipPath);
|
|
340
|
+
return { dir, zipPath, readmePath };
|
|
341
|
+
}
|
|
342
|
+
function guessUrlKind(url) {
|
|
343
|
+
const u = url.toLowerCase();
|
|
344
|
+
if (/\.(png|jpe?g|gif|webp|svg)(\?|$)/.test(u))
|
|
345
|
+
return "image";
|
|
346
|
+
if (/\/image\//.test(u))
|
|
347
|
+
return "image";
|
|
348
|
+
return "other";
|
|
349
|
+
}
|
|
350
|
+
function buildReadmeMd(p) {
|
|
351
|
+
const lines = [
|
|
352
|
+
`# ${p.label} · 交付说明`,
|
|
353
|
+
"",
|
|
354
|
+
`- **应用 ID**: \`${p.appId}\``,
|
|
355
|
+
`- **任务 ID**: \`${p.taskId}\``,
|
|
356
|
+
`- **生成时间**: ${new Date().toISOString()}`,
|
|
357
|
+
`- **分步文件数**: ${p.stepCount}`,
|
|
358
|
+
"",
|
|
359
|
+
"## 目录结构",
|
|
360
|
+
"",
|
|
361
|
+
"- `README.md` — 本说明",
|
|
362
|
+
"- `*.md` — 各步骤文本结果(Markdown)",
|
|
363
|
+
"- `images/` — 从链接下载的图片(若下载失败会有 `.url.txt`)",
|
|
364
|
+
"",
|
|
365
|
+
"## 压缩包",
|
|
366
|
+
"",
|
|
367
|
+
`同级目录已生成 **${basename(p.zipPath)}**,可直接分发或上传。`,
|
|
368
|
+
"",
|
|
369
|
+
"---",
|
|
370
|
+
"",
|
|
371
|
+
"*由 GD CLI `gd-cli workflows run` 自动生成。*",
|
|
372
|
+
"",
|
|
373
|
+
];
|
|
374
|
+
return lines.join("\n");
|
|
375
|
+
}
|
|
376
|
+
function zipDirectory(sourceDir, zipPath) {
|
|
377
|
+
return new Promise((resolvePromise, reject) => {
|
|
378
|
+
const output = createWriteStream(zipPath);
|
|
379
|
+
const archive = new ZipArchive({ zlib: { level: 9 } });
|
|
380
|
+
output.on("close", () => resolvePromise());
|
|
381
|
+
archive.on("error", (err) => reject(err));
|
|
382
|
+
archive.pipe(output);
|
|
383
|
+
archive.directory(sourceDir, false);
|
|
384
|
+
archive.finalize();
|
|
385
|
+
});
|
|
386
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gaoding-cli",
|
|
3
|
+
"version": "1.0.0-alpha.5",
|
|
4
|
+
"description": "稿定 GD CLI - Tools / Workflows / DAM 命令行工具",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gaoding",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/src/program.js",
|
|
9
|
+
"types": "./dist/src/program.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/src/program.d.ts",
|
|
13
|
+
"import": "./dist/src/program.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"gd-cli": "dist/bin/gd-cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/",
|
|
21
|
+
"!dist/src/commands/app.*",
|
|
22
|
+
"!dist/src/commands/config.*",
|
|
23
|
+
"!dist/src/commands/config-env.*",
|
|
24
|
+
"!dist/src/commands/info.*",
|
|
25
|
+
"!dist/src/commands/search.*",
|
|
26
|
+
"!dist/src/commands/task.*",
|
|
27
|
+
"!dist/src/commands/tool.*",
|
|
28
|
+
"skills/gd-cli/",
|
|
29
|
+
"README.md",
|
|
30
|
+
"SECURITY.md",
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/bin/gd-cli.js",
|
|
36
|
+
"dev": "node scripts/install-dev-bin.mjs --quiet && tsc -p tsconfig.build.json --watch --preserveWatchOutput",
|
|
37
|
+
"dev:setup": "node scripts/install-dev-bin.mjs",
|
|
38
|
+
"start": "tsx bin/gd-cli.ts",
|
|
39
|
+
"sso:probe": "tsx scripts/sso-probe.ts",
|
|
40
|
+
"smoke:cli": "npm run build && tsx scripts/cli-smoke-test.ts",
|
|
41
|
+
"smoke:cli:live": "npm run build && tsx scripts/cli-smoke-test.ts --live",
|
|
42
|
+
"test:package": "npm run build && node scripts/package-integration-test.mjs",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"lint": "eslint src/",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build && npm run smoke:cli && npm run test:package"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@inquirer/prompts": "^7.10.1",
|
|
51
|
+
"ali-oss": "^6.23.0",
|
|
52
|
+
"archiver": "^8.0.0",
|
|
53
|
+
"chalk": "^5.4.1",
|
|
54
|
+
"cli-table3": "^0.6.5",
|
|
55
|
+
"commander": "^13.1.0",
|
|
56
|
+
"log-update": "^6.1.0",
|
|
57
|
+
"open": "^10.1.2",
|
|
58
|
+
"ora": "^8.2.0",
|
|
59
|
+
"qrcode": "^1.5.4",
|
|
60
|
+
"sharp": "^0.34.5",
|
|
61
|
+
"uuid": "^11.1.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/ali-oss": "^6.23.3",
|
|
65
|
+
"@types/archiver": "^8.0.0",
|
|
66
|
+
"@types/node": "^22.14.1",
|
|
67
|
+
"@types/qrcode": "^1.5.6",
|
|
68
|
+
"@types/uuid": "^10.0.0",
|
|
69
|
+
"eslint": "^9.24.0",
|
|
70
|
+
"tsx": "^4.19.4",
|
|
71
|
+
"typescript": "^5.8.3",
|
|
72
|
+
"typescript-eslint": "^8.50.0",
|
|
73
|
+
"vite": "^6.4.3",
|
|
74
|
+
"vitest": "^4.1.8"
|
|
75
|
+
},
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=20.0.0"
|
|
78
|
+
},
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public",
|
|
81
|
+
"registry": "https://registry.npmjs.org/"
|
|
82
|
+
},
|
|
83
|
+
"keywords": [
|
|
84
|
+
"gaoding",
|
|
85
|
+
"gd-cli",
|
|
86
|
+
"cli",
|
|
87
|
+
"visual-creation",
|
|
88
|
+
"ai-tools",
|
|
89
|
+
"dam"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gd-cli
|
|
3
|
+
description: 当用户需要使用稿定生成图片、视频、电商素材或管理 DAM 素材时,优先使用本地 gd-cli 完成能力发现、调用、等待和交付。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GD CLI Agent Skill
|
|
7
|
+
|
|
8
|
+
## 执行原则
|
|
9
|
+
|
|
10
|
+
当用户提出图片、视频、电商物料或 DAM 素材需求时,优先使用本地 `gd-cli` 调用稿定能力。不要因为当前 Agent 的工具列表中没有稿定工具,就改用本地 Canvas、ffmpeg、SVG 或未文档化接口。
|
|
11
|
+
|
|
12
|
+
开始执行前:
|
|
13
|
+
|
|
14
|
+
- 先读 `references/sop.md`。
|
|
15
|
+
- 授权问题读 `references/auth.md`。
|
|
16
|
+
- 组织选择读 `references/org.md`。
|
|
17
|
+
- 权益不足或余额查询读 `references/entitlement.md`。
|
|
18
|
+
- 错误处理和停止规则读 `references/errors.md`。
|
|
19
|
+
- 图片、视频和交付包处理读 `references/deliverables.md`。
|
|
20
|
+
- CLI 与 Skill 升级读 `references/update.md`。
|
|
21
|
+
- 单点能力读 `references/tools.md`,多步骤场景读 `references/workflows.md`。
|
|
22
|
+
|
|
23
|
+
Agent 只根据公开的 `tools`、`workflows` 和 `dam` 命令完成用户需求。普通生成任务中不要切换组织、环境或模型,不要调用内部运行时类、`raw.dify` 或未文档化接口。
|
|
24
|
+
|
|
25
|
+
## 能力选择
|
|
26
|
+
|
|
27
|
+
先读取能力列表,再按用户意图匹配:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
gd-cli tools list --format json
|
|
31
|
+
gd-cli workflows list --format json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| 用户意图 | 命令 |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| 生图、商品主图、海报、场景图 | `gd-cli tools call image.generate` |
|
|
37
|
+
| 抠图、去背景、透明底 | `gd-cli tools call image.cutout` |
|
|
38
|
+
| 高清、放大、变清晰 | `gd-cli tools call image.super-res` |
|
|
39
|
+
| 文生视频、图生视频、动画短片 | `gd-cli tools call video.generate` |
|
|
40
|
+
| Listing、商品图库、上架素材 | `gd-cli workflows run listing-gallery` |
|
|
41
|
+
| 详情页、A+、PDP | `gd-cli workflows run pdp-a-plus` |
|
|
42
|
+
| 小红书种草图文 | `gd-cli workflows run social-seeding-pack` |
|
|
43
|
+
| Campaign KV、多渠道素材 | `gd-cli workflows run campaign-kv-pack` |
|
|
44
|
+
|
|
45
|
+
复杂输入优先通过 `--input <json-file>` 或 stdin 传入。Agent 解析结果时使用 `--format json`,最终回复按 `references/deliverables.md` 展示预览、链接或文件,不要直接转发整段原始 JSON。
|
|
46
|
+
|
|
47
|
+
## 参考资料
|
|
48
|
+
|
|
49
|
+
- `references/sop.md`
|
|
50
|
+
- `references/auth.md`
|
|
51
|
+
- `references/org.md`
|
|
52
|
+
- `references/entitlement.md`
|
|
53
|
+
- `references/errors.md`
|
|
54
|
+
- `references/deliverables.md`
|
|
55
|
+
- `references/update.md`
|
|
56
|
+
- `references/tools.md`
|
|
57
|
+
- `references/workflows.md`
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# GD CLI Auth SOP
|
|
2
|
+
|
|
3
|
+
## 未登录
|
|
4
|
+
|
|
5
|
+
在 Agent 或非 TTY Shell 中执行:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
gd-cli auth login --no-browser --format json
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
命令会输出包含以下字段的授权信息:
|
|
12
|
+
|
|
13
|
+
- `type=device_authorization`
|
|
14
|
+
- `verification_uri_complete`
|
|
15
|
+
- `expires_in`
|
|
16
|
+
- `interval`
|
|
17
|
+
|
|
18
|
+
Agent 必须立即把 `verification_uri_complete` 原样发送给用户,并保持授权进程运行。用户完成授权后,再执行:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gd-cli auth status --format json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 禁止动作
|
|
25
|
+
|
|
26
|
+
- 不向用户索要 Token、Cookie 或 AK/SK。
|
|
27
|
+
- 不用 Agent 沙箱浏览器代替用户完成 OAuth。
|
|
28
|
+
- 不擅自结束仍在等待授权的进程。
|
|
29
|
+
- 授权链接过期后,重新执行登录命令并发送新链接。
|
|
30
|
+
|
|
31
|
+
如果授权完成但缺少组织,按 `org.md` 处理。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# GD CLI Deliverables SOP
|
|
2
|
+
|
|
3
|
+
## 解析字段
|
|
4
|
+
|
|
5
|
+
优先读取:
|
|
6
|
+
|
|
7
|
+
- `assets[]`
|
|
8
|
+
- `outputs.assets[]`
|
|
9
|
+
- `outputs.url`
|
|
10
|
+
- `outputs.*.url`
|
|
11
|
+
- `deliverable_dir`
|
|
12
|
+
- `deliverable_zip`
|
|
13
|
+
- `deliverable_readme`
|
|
14
|
+
|
|
15
|
+
递归查找 `url` 或 `uri`,区分图片、视频和普通文件。
|
|
16
|
+
|
|
17
|
+
## 交付方式
|
|
18
|
+
|
|
19
|
+
- 当前 Agent 支持 Markdown 图片预览时,使用 `` 直接展示。
|
|
20
|
+
- 视频不能内嵌播放时,提供可点击链接;有封面图时先展示封面。
|
|
21
|
+
- 存在 `deliverable_zip` 时,明确说明这是完整交付包。Agent 支持附件时优先交付文件,否则提供本地路径或下载 URL。
|
|
22
|
+
- 不把整段原始 JSON 作为最终回复。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# GD CLI Entitlement SOP
|
|
2
|
+
|
|
3
|
+
## 权益不足
|
|
4
|
+
|
|
5
|
+
当错误码为 `ENTITLEMENT_INSUFFICIENT` 或 `QUOTA_EXCEEDED` 时,停止当前生成任务并说明:
|
|
6
|
+
|
|
7
|
+
- 当前账号或组织权益不足,本次生成无法继续。
|
|
8
|
+
- 优先提供 JSON 中的 `pricing_url`;没有时使用 `https://www.gaoding.com/pricing`。
|
|
9
|
+
- 用户也可以明确选择一个有权益的组织后继续。
|
|
10
|
+
|
|
11
|
+
不要自行切换组织、环境或模型,也不要循环试错。
|
|
12
|
+
|
|
13
|
+
## 查询稿豆余额
|
|
14
|
+
|
|
15
|
+
用户询问剩余稿豆、权益余额、还能生成几次或 usage 时,执行:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
gd-cli usage --format json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
只根据 `organization`、`credits.total`、`credits.used`、`credits.wait` 和 `credits.surplus` 回复。若用户要求查看其他组织,先执行 `gd-cli org list --format json`,等待用户明确选择后再切换。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# GD CLI Error SOP
|
|
2
|
+
|
|
3
|
+
## 停止规则
|
|
4
|
+
|
|
5
|
+
1. 命令非零退出时,先解析 stdout 中的 JSON envelope。
|
|
6
|
+
2. 优先读取 `error.code`、`error.message`、`error.hint`、`error.next_steps`、`pricing_url` 和 `retryable`。
|
|
7
|
+
3. `retryable=false` 或未提供 `retryable` 时,不重复执行同一失败命令。
|
|
8
|
+
4. 只有 `NETWORK_TRANSIENT` 可以短暂重试一次;第二次失败必须停止。
|
|
9
|
+
5. `TOOL_ROUTE_UNAVAILABLE`、`ENTITLEMENT_INSUFFICIENT`、参数错误、授权错误和组织错误都不能盲目重试。
|
|
10
|
+
|
|
11
|
+
## 禁止扩展诊断
|
|
12
|
+
|
|
13
|
+
除非用户明确要求诊断,否则失败后不要切换组织、模型或环境,不查询 `raw.dify`,也不探测未文档化接口。
|
|
14
|
+
|
|
15
|
+
## 回复结构
|
|
16
|
+
|
|
17
|
+
- 发生了什么:使用 `error.message`。
|
|
18
|
+
- 用户下一步:使用 `error.hint`、`error.next_steps`、`pricing_url` 或授权链接。
|
|
19
|
+
- 不向用户复述 Agent 内部执行约束。
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# GD CLI Organization SOP
|
|
2
|
+
|
|
3
|
+
## 组织选择边界
|
|
4
|
+
|
|
5
|
+
Agent 可以读取组织,但不能替用户选择组织:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
gd-cli org list --format json
|
|
9
|
+
gd-cli org current --format json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
只有用户明确选择具体组织后,才执行:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
gd-cli org switch --org <org-id> --format json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
如果 `org list` 返回多个组织,向用户列出组织名称、组织 ID 和当前状态,然后等待选择。不要根据名称、权益、历史记录或猜测自动切换。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# GD CLI Agent SOP
|
|
2
|
+
|
|
3
|
+
## 总规则
|
|
4
|
+
|
|
5
|
+
1. 用户要图片、视频、电商物料或 DAM 素材时,优先使用 `gd-cli`。
|
|
6
|
+
2. 需要解析结果、错误、URL、`task_id` 或 schema 时,使用 `--format json`。
|
|
7
|
+
3. stdout JSON 用于解析结果,stderr 仅用于进度和排错。
|
|
8
|
+
4. 普通生成任务只使用公开的 `tools`、`workflows` 和 `dam` 命令。
|
|
9
|
+
5. 不替用户切换组织、环境或模型;涉及账号、组织、充值或授权时,把选择交给用户。
|
|
10
|
+
|
|
11
|
+
## 推荐流程
|
|
12
|
+
|
|
13
|
+
1. 必要时执行 `gd-cli auth status --format json` 检查授权状态。
|
|
14
|
+
2. 未登录时按 `auth.md` 发起授权,并立即把授权链接交给用户。
|
|
15
|
+
3. 使用 `gd-cli manifest --format json`、`gd-cli tools list --format json` 和 `gd-cli workflows list --format json` 发现能力。
|
|
16
|
+
4. 单项处理选择 Tool,多步骤交付选择 Workflow。
|
|
17
|
+
5. 执行命令后等待终态,解析 `status`、`outputs`、`assets`、`task_id` 和交付路径。
|
|
18
|
+
6. 按 `deliverables.md` 交付预览、链接、本地文件或完整交付包。
|
|
19
|
+
|
|
20
|
+
## 调用边界
|
|
21
|
+
|
|
22
|
+
- 用户未指定模型时,直接调用目标能力,不主动查询或切换模型。
|
|
23
|
+
- 用户未要求诊断时,不探测内部 endpoint、工具路由或组织权限。
|
|
24
|
+
- 一次调用失败后按 `errors.md` 处理,不扩展为无关诊断。
|
|
25
|
+
- Workflow 可能连续调用多个 Tool;不要在 Workflow 运行中并行发起重复任务。
|