@gaoding/cli 0.0.0 → 1.0.0-alpha.25
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/LICENSE +21 -0
- package/README.md +40 -3
- package/contracts/operations/agent.send/input.schema.json +353 -0
- package/contracts/operations/agent.send/output.schema.json +271 -0
- package/contracts/operations/auth.status/input.schema.json +7 -0
- package/contracts/operations/auth.status/output.schema.json +132 -0
- package/contracts/operations/dam.copy/input.schema.json +19 -0
- package/contracts/operations/dam.copy/output.schema.json +19 -0
- package/contracts/operations/dam.delete/input.schema.json +23 -0
- package/contracts/operations/dam.delete/output.schema.json +6 -0
- package/contracts/operations/dam.download/input.schema.json +14 -0
- package/contracts/operations/dam.download/output.schema.json +25 -0
- package/contracts/operations/dam.folder.list/input.schema.json +15 -0
- package/contracts/operations/dam.folder.list/output.schema.json +37 -0
- package/contracts/operations/dam.get/input.schema.json +16 -0
- package/contracts/operations/dam.get/output.schema.json +46 -0
- package/contracts/operations/dam.list/input.schema.json +44 -0
- package/contracts/operations/dam.list/output.schema.json +71 -0
- package/contracts/operations/dam.move/input.schema.json +19 -0
- package/contracts/operations/dam.move/output.schema.json +18 -0
- package/contracts/operations/dam.recycle.list/input.schema.json +13 -0
- package/contracts/operations/dam.recycle.list/output.schema.json +34 -0
- package/contracts/operations/dam.recycle.restore/input.schema.json +14 -0
- package/contracts/operations/dam.recycle.restore/output.schema.json +6 -0
- package/contracts/operations/dam.rename/input.schema.json +18 -0
- package/contracts/operations/dam.rename/output.schema.json +18 -0
- package/contracts/operations/dam.repository.list/input.schema.json +8 -0
- package/contracts/operations/dam.repository.list/output.schema.json +52 -0
- package/contracts/operations/dam.search/input.schema.json +46 -0
- package/contracts/operations/dam.search/output.schema.json +71 -0
- package/contracts/operations/dam.tag.list/input.schema.json +12 -0
- package/contracts/operations/dam.tag.list/output.schema.json +26 -0
- package/contracts/operations/dam.upload/input.schema.json +31 -0
- package/contracts/operations/dam.upload/output.schema.json +46 -0
- package/contracts/operations/editor.apply/input.schema.json +134 -0
- package/contracts/operations/editor.apply/output.schema.json +15 -0
- package/contracts/operations/editor.connect/input.schema.json +15 -0
- package/contracts/operations/editor.connect/output.schema.json +17 -0
- package/contracts/operations/editor.disconnect/input.schema.json +8 -0
- package/contracts/operations/editor.disconnect/output.schema.json +14 -0
- package/contracts/operations/editor.save/input.schema.json +8 -0
- package/contracts/operations/editor.save/output.schema.json +23 -0
- package/contracts/operations/editor.screenshot/input.schema.json +8 -0
- package/contracts/operations/editor.screenshot/output.schema.json +16 -0
- package/contracts/operations/editor.snapshot/input.schema.json +8 -0
- package/contracts/operations/editor.snapshot/output.schema.json +113 -0
- package/contracts/operations/model.get/input.schema.json +18 -0
- package/contracts/operations/model.get/output.schema.json +191 -0
- package/contracts/operations/model.list/input.schema.json +15 -0
- package/contracts/operations/model.list/output.schema.json +111 -0
- package/contracts/operations/org.current/input.schema.json +7 -0
- package/contracts/operations/org.current/output.schema.json +49 -0
- package/contracts/operations/org.list/input.schema.json +7 -0
- package/contracts/operations/org.list/output.schema.json +71 -0
- package/contracts/operations/tool.call/input.schema.json +35 -0
- package/contracts/operations/tool.call/output.schema.json +129 -0
- package/contracts/operations/tool.list/input.schema.json +7 -0
- package/contracts/operations/tool.list/output.schema.json +45 -0
- package/dist/bin/gd-cli.js +60 -0
- package/dist/bin/postinstall.js +42 -0
- package/dist/src/bootstrap/create-cli.js +112 -0
- package/dist/src/bootstrap/create-runtime.js +290 -0
- package/dist/src/bootstrap/validators.js +157 -0
- package/dist/src/cli/action-binding.js +109 -0
- package/dist/src/cli/agent-commands.js +49 -0
- package/dist/src/cli/auth-commands.js +55 -0
- package/dist/src/cli/dam-commands.js +469 -0
- package/dist/src/cli/editor-commands.js +73 -0
- package/dist/src/cli/errors.js +157 -0
- package/dist/src/cli/model-commands.js +61 -0
- package/dist/src/cli/org-commands.js +58 -0
- package/dist/src/cli/presenter.js +105 -0
- package/dist/src/cli/prompt.js +30 -0
- package/dist/src/cli/tool-commands.js +77 -0
- package/dist/src/cli/update-command.js +14 -0
- package/dist/src/contracts/schema.js +4 -0
- package/dist/src/features/agent/creative-agent-adapter.js +36 -0
- package/dist/src/features/agent/creative-protocol.js +432 -0
- package/dist/src/features/agent/creative-stream.js +127 -0
- package/dist/src/features/agent/use-cases.js +150 -0
- package/dist/src/features/auth/access-policy.js +101 -0
- package/dist/src/features/auth/credential-store.js +62 -0
- package/dist/src/features/auth/sso-service.js +194 -0
- package/dist/src/features/auth/state.js +129 -0
- package/dist/src/features/auth/use-cases.js +136 -0
- package/dist/src/features/dam/asset-projection.js +278 -0
- package/dist/src/features/dam/dam-api-adapter.js +562 -0
- package/dist/src/features/dam/file-downloader.js +242 -0
- package/dist/src/features/dam/object-storage.js +193 -0
- package/dist/src/features/dam/operation-executor.js +72 -0
- package/dist/src/features/dam/registered-uploader.js +247 -0
- package/dist/src/features/dam/repository-catalog.js +127 -0
- package/dist/src/features/dam/storage-upload.js +141 -0
- package/dist/src/features/dam/transient-uploader.js +17 -0
- package/dist/src/features/dam/use-cases.js +470 -0
- package/dist/src/features/editor/bridge-client.js +109 -0
- package/dist/src/features/editor/bridge-process.js +222 -0
- package/dist/src/features/editor/bridge-server.js +337 -0
- package/dist/src/features/editor/protocol.js +1 -0
- package/dist/src/features/editor/public-url.js +36 -0
- package/dist/src/features/editor/session-state.js +78 -0
- package/dist/src/features/editor/session.js +207 -0
- package/dist/src/features/editor/use-cases.js +88 -0
- package/dist/src/features/org/org-service.js +76 -0
- package/dist/src/features/org/use-cases.js +156 -0
- package/dist/src/features/skill/bundled-skills.js +55 -0
- package/dist/src/features/skill/installer.js +271 -0
- package/dist/src/features/tool/catalog.js +83 -0
- package/dist/src/features/tool/dynamic-schema.js +128 -0
- package/dist/src/features/tool/mns-catalog-adapter.js +265 -0
- package/dist/src/features/tool/tool-api-adapter.js +352 -0
- package/dist/src/features/tool/use-cases.js +177 -0
- package/dist/src/features/update/latest-version.js +37 -0
- package/dist/src/features/update/update-notification.js +262 -0
- package/dist/src/features/update/update-service.js +183 -0
- package/dist/src/platform/json-input.js +67 -0
- package/dist/src/platform/local-json-file.js +59 -0
- package/dist/src/platform/open-browser.js +8 -0
- package/dist/src/platform/redact.js +80 -0
- package/dist/src/platform/remote-error-evidence.js +80 -0
- package/dist/src/platform/remote-protocol.js +10 -0
- package/dist/src/platform/safe-upload-file.js +146 -0
- package/dist/src/platform/signature.js +20 -0
- package/dist/src/platform/signed-http-transport.js +143 -0
- package/dist/src/platform/url-safety.js +100 -0
- package/dist/src/telemetry/invocation.js +156 -0
- package/dist/src/telemetry/sls-sink.js +31 -0
- package/package.json +54 -8
- package/skills/gd-cli/SKILL.md +15 -0
- package/skills/gd-cli/references/auth-org.md +9 -0
- package/skills/gd-cli/references/creation.md +115 -0
- package/skills/gd-cli/references/dam.md +52 -0
- package/skills/gd-cli/references/editor.md +254 -0
- package/skills/gd-cli/references/errors.md +13 -0
- package/skills/gd-cli/references/update.md +13 -0
- package/index.js +0 -3
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { bindAction, bindPreparedAction } from "./action-binding.js";
|
|
2
|
+
import { CliUsageError } from "./errors.js";
|
|
3
|
+
import { repositoryListView } from "./presenter.js";
|
|
4
|
+
export function registerDamCommands(program, runtime) {
|
|
5
|
+
const dam = program.command("dam")
|
|
6
|
+
.description("DAM 素材管理")
|
|
7
|
+
.helpCommand(false);
|
|
8
|
+
const repository = dam.command("repository")
|
|
9
|
+
.description("DAM 资源库")
|
|
10
|
+
.helpCommand(false);
|
|
11
|
+
const repositoryList = leaf(repository.command("list"))
|
|
12
|
+
.description("列出可用资源库")
|
|
13
|
+
.option("--json", "输出 JSON");
|
|
14
|
+
bindAction(repositoryList, "organization", async (context, signal) => {
|
|
15
|
+
const result = await runtime.telemetry.stage("repository", () => (runtime.dam.repositoryList({
|
|
16
|
+
access: organizationAccess(context.state),
|
|
17
|
+
signal
|
|
18
|
+
})));
|
|
19
|
+
await runtime.telemetry.stage("output", async () => {
|
|
20
|
+
runtime.presenter.result(result, {
|
|
21
|
+
json: repositoryList.opts().json === true,
|
|
22
|
+
view: repositoryListView
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}, { operation: "dam.repository.list" });
|
|
26
|
+
const folder = dam.command("folder")
|
|
27
|
+
.description("DAM 文件夹")
|
|
28
|
+
.helpCommand(false);
|
|
29
|
+
const folderList = leaf(folder.command("list"))
|
|
30
|
+
.description("列出文件夹")
|
|
31
|
+
.option("--repository-id <id>", "指定资源库 ID")
|
|
32
|
+
.option("--parent-id <id>", "父文件夹 ID")
|
|
33
|
+
.option("--query <text>", "按名称筛选")
|
|
34
|
+
.option("--page <n>", "页码", positiveInteger)
|
|
35
|
+
.option("--page-size <1-100>", "分页大小", pageSize)
|
|
36
|
+
.option("--json", "输出 JSON");
|
|
37
|
+
bindPreparedAction(folderList, "organization", async (signal) => {
|
|
38
|
+
signal.throwIfAborted();
|
|
39
|
+
const options = folderList.opts();
|
|
40
|
+
const input = {
|
|
41
|
+
...defined("repositoryId", options.repositoryId),
|
|
42
|
+
...defined("parentId", options.parentId),
|
|
43
|
+
...defined("query", options.query),
|
|
44
|
+
...defined("page", options.page),
|
|
45
|
+
...defined("pageSize", options.pageSize)
|
|
46
|
+
};
|
|
47
|
+
runtime.validators.damFolderListInput(input);
|
|
48
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
49
|
+
return { handled: false, input };
|
|
50
|
+
}, async (context, input, signal) => {
|
|
51
|
+
const result = await runtime.dam.folderList({
|
|
52
|
+
input,
|
|
53
|
+
access: organizationAccess(context.state),
|
|
54
|
+
signal
|
|
55
|
+
});
|
|
56
|
+
await runtime.telemetry.stage("output", async () => {
|
|
57
|
+
runtime.presenter.result(result, {
|
|
58
|
+
json: folderList.opts().json === true,
|
|
59
|
+
view: folderListView
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}, { operation: "dam.folder.list" });
|
|
63
|
+
const tag = dam.command("tag")
|
|
64
|
+
.description("DAM 标签")
|
|
65
|
+
.helpCommand(false);
|
|
66
|
+
const tagList = leaf(tag.command("list"))
|
|
67
|
+
.description("列出标签")
|
|
68
|
+
.option("--repository-id <id>", "指定资源库 ID")
|
|
69
|
+
.option("--query <text>", "按名称筛选")
|
|
70
|
+
.option("--json", "输出 JSON");
|
|
71
|
+
bindPreparedAction(tagList, "organization", async (signal) => {
|
|
72
|
+
signal.throwIfAborted();
|
|
73
|
+
const options = tagList.opts();
|
|
74
|
+
const input = {
|
|
75
|
+
...defined("repositoryId", options.repositoryId),
|
|
76
|
+
...defined("query", options.query)
|
|
77
|
+
};
|
|
78
|
+
runtime.validators.damTagListInput(input);
|
|
79
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
80
|
+
return { handled: false, input };
|
|
81
|
+
}, async (context, input, signal) => {
|
|
82
|
+
const result = await runtime.dam.tagList({
|
|
83
|
+
input,
|
|
84
|
+
access: organizationAccess(context.state),
|
|
85
|
+
signal
|
|
86
|
+
});
|
|
87
|
+
await runtime.telemetry.stage("output", async () => {
|
|
88
|
+
runtime.presenter.result(result, {
|
|
89
|
+
json: tagList.opts().json === true,
|
|
90
|
+
view: tagListView
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}, { operation: "dam.tag.list" });
|
|
94
|
+
const download = leaf(dam.command("download"))
|
|
95
|
+
.description("下载一个素材")
|
|
96
|
+
.argument("<asset>", "素材 ID")
|
|
97
|
+
.option("--repository-id <id>", "所属资源库 ID")
|
|
98
|
+
.option("--output-dir <directory>", "输出目录")
|
|
99
|
+
.option("--json", "输出 JSON");
|
|
100
|
+
bindPreparedAction(download, "organization", async (signal) => {
|
|
101
|
+
signal.throwIfAborted();
|
|
102
|
+
const options = download.opts();
|
|
103
|
+
const input = {
|
|
104
|
+
asset_id: position(download, 0),
|
|
105
|
+
...defined("repositoryId", options.repositoryId),
|
|
106
|
+
...defined("outputDir", options.outputDir)
|
|
107
|
+
};
|
|
108
|
+
runtime.validators.damDownloadInput(input);
|
|
109
|
+
runtime.telemetry.annotate({ content_id: input.asset_id, parameters: { ...input } });
|
|
110
|
+
return { handled: false, input };
|
|
111
|
+
}, async (context, input, signal) => {
|
|
112
|
+
const result = await runtime.dam.download({
|
|
113
|
+
input,
|
|
114
|
+
access: organizationAccess(context.state),
|
|
115
|
+
signal
|
|
116
|
+
});
|
|
117
|
+
await runtime.telemetry.stage("output", async () => {
|
|
118
|
+
runtime.presenter.result(result, {
|
|
119
|
+
json: download.opts().json === true,
|
|
120
|
+
view: downloadView
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}, { operation: "dam.download" });
|
|
124
|
+
const rename = leaf(dam.command("rename"))
|
|
125
|
+
.description("重命名一个素材或文件夹")
|
|
126
|
+
.argument("<entry>", "素材或文件夹 ID")
|
|
127
|
+
.requiredOption("--kind <asset|folder>", "条目类型")
|
|
128
|
+
.requiredOption("--title <title>", "新标题")
|
|
129
|
+
.option("--repository-id <id>", "所属资源库 ID")
|
|
130
|
+
.option("--json", "输出 JSON");
|
|
131
|
+
bindPreparedAction(rename, "organization", async (signal) => {
|
|
132
|
+
signal.throwIfAborted();
|
|
133
|
+
const options = rename.opts();
|
|
134
|
+
const input = {
|
|
135
|
+
entry_id: position(rename, 0),
|
|
136
|
+
kind: options.kind,
|
|
137
|
+
title: options.title,
|
|
138
|
+
...defined("repositoryId", options.repositoryId)
|
|
139
|
+
};
|
|
140
|
+
runtime.validators.damRenameInput(input);
|
|
141
|
+
runtime.telemetry.annotate({ content_id: input.entry_id, parameters: { ...input } });
|
|
142
|
+
return { handled: false, input };
|
|
143
|
+
}, async (context, input, signal) => {
|
|
144
|
+
const result = await runtime.dam.rename({
|
|
145
|
+
input,
|
|
146
|
+
access: organizationAccess(context.state),
|
|
147
|
+
signal
|
|
148
|
+
});
|
|
149
|
+
await runtime.telemetry.stage("output", async () => {
|
|
150
|
+
runtime.presenter.result(result, {
|
|
151
|
+
json: rename.opts().json === true,
|
|
152
|
+
view: renameView
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}, { operation: "dam.rename" });
|
|
156
|
+
for (const operation of ["move", "copy"]) {
|
|
157
|
+
const command = leaf(dam.command(operation))
|
|
158
|
+
.description(operation === "move" ? "移动一个素材或文件夹" : "复制一个素材或文件夹")
|
|
159
|
+
.argument("<entry>", "素材或文件夹 ID")
|
|
160
|
+
.requiredOption("--kind <asset|folder>", "条目类型")
|
|
161
|
+
.requiredOption("--target-folder-id <id>", "目标文件夹 ID;根目录使用 0")
|
|
162
|
+
.option("--repository-id <source-id>", "源资源库 ID")
|
|
163
|
+
.option("--target-repository-id <target-id>", "目标资源库 ID")
|
|
164
|
+
.option("--json", "输出 JSON");
|
|
165
|
+
bindPreparedAction(command, "organization", async (signal) => {
|
|
166
|
+
signal.throwIfAborted();
|
|
167
|
+
const options = command.opts();
|
|
168
|
+
const input = {
|
|
169
|
+
entry_id: position(command, 0),
|
|
170
|
+
kind: options.kind,
|
|
171
|
+
targetFolderId: options.targetFolderId,
|
|
172
|
+
...defined("repositoryId", options.repositoryId),
|
|
173
|
+
...defined("targetRepositoryId", options.targetRepositoryId)
|
|
174
|
+
};
|
|
175
|
+
if (operation === "move")
|
|
176
|
+
runtime.validators.damMoveInput(input);
|
|
177
|
+
else
|
|
178
|
+
runtime.validators.damCopyInput(input);
|
|
179
|
+
runtime.telemetry.annotate({ content_id: input.entry_id, parameters: { ...input } });
|
|
180
|
+
return { handled: false, input: input };
|
|
181
|
+
}, async (context, input, signal) => {
|
|
182
|
+
const result = operation === "move"
|
|
183
|
+
? await runtime.dam.move({
|
|
184
|
+
input: input,
|
|
185
|
+
access: organizationAccess(context.state),
|
|
186
|
+
signal
|
|
187
|
+
})
|
|
188
|
+
: await runtime.dam.copy({
|
|
189
|
+
input: input,
|
|
190
|
+
access: organizationAccess(context.state),
|
|
191
|
+
signal
|
|
192
|
+
});
|
|
193
|
+
await runtime.telemetry.stage("output", async () => {
|
|
194
|
+
runtime.presenter.result(result, {
|
|
195
|
+
json: command.opts().json === true,
|
|
196
|
+
view: operation === "move" ? moveView : copyView
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}, { operation: `dam.${operation}` });
|
|
200
|
+
}
|
|
201
|
+
const list = browseCommand(leaf(dam.command("list")))
|
|
202
|
+
.description("查看最近素材");
|
|
203
|
+
bindPreparedAction(list, "organization", async (signal) => {
|
|
204
|
+
signal.throwIfAborted();
|
|
205
|
+
const input = browseInput(list);
|
|
206
|
+
runtime.validators.damListInput(input);
|
|
207
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
208
|
+
return { handled: false, input };
|
|
209
|
+
}, async (context, input, signal) => {
|
|
210
|
+
const result = await runtime.dam.list({
|
|
211
|
+
input,
|
|
212
|
+
access: organizationAccess(context.state),
|
|
213
|
+
signal
|
|
214
|
+
});
|
|
215
|
+
await runtime.telemetry.stage("output", async () => {
|
|
216
|
+
runtime.presenter.result(result, {
|
|
217
|
+
json: list.opts().json === true,
|
|
218
|
+
view: assetListView
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}, { operation: "dam.list" });
|
|
222
|
+
const search = browseCommand(leaf(dam.command("search")))
|
|
223
|
+
.description("按关键词搜索素材")
|
|
224
|
+
.argument("<query>", "搜索关键词");
|
|
225
|
+
bindPreparedAction(search, "organization", async (signal) => {
|
|
226
|
+
signal.throwIfAborted();
|
|
227
|
+
const input = {
|
|
228
|
+
query: position(search, 0),
|
|
229
|
+
...browseInput(search)
|
|
230
|
+
};
|
|
231
|
+
runtime.validators.damSearchInput(input);
|
|
232
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
233
|
+
return { handled: false, input };
|
|
234
|
+
}, async (context, input, signal) => {
|
|
235
|
+
const result = await runtime.dam.search({
|
|
236
|
+
input,
|
|
237
|
+
access: organizationAccess(context.state),
|
|
238
|
+
signal
|
|
239
|
+
});
|
|
240
|
+
await runtime.telemetry.stage("output", async () => {
|
|
241
|
+
runtime.presenter.result(result, {
|
|
242
|
+
json: search.opts().json === true,
|
|
243
|
+
view: assetListView
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}, { operation: "dam.search" });
|
|
247
|
+
const get = leaf(dam.command("get"))
|
|
248
|
+
.description("查看素材完整信息")
|
|
249
|
+
.argument("<asset>", "素材 ID")
|
|
250
|
+
.option("--json", "输出 JSON");
|
|
251
|
+
bindPreparedAction(get, "organization", async (signal) => {
|
|
252
|
+
signal.throwIfAborted();
|
|
253
|
+
const input = { asset_id: position(get, 0) };
|
|
254
|
+
runtime.validators.damGetInput(input);
|
|
255
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
256
|
+
return { handled: false, input };
|
|
257
|
+
}, async (context, input, signal) => {
|
|
258
|
+
const result = await runtime.dam.get({
|
|
259
|
+
input,
|
|
260
|
+
access: organizationAccess(context.state),
|
|
261
|
+
signal
|
|
262
|
+
});
|
|
263
|
+
await runtime.telemetry.stage("output", async () => {
|
|
264
|
+
runtime.presenter.result(result, {
|
|
265
|
+
json: get.opts().json === true,
|
|
266
|
+
view: assetDetailView
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
}, { operation: "dam.get" });
|
|
270
|
+
const upload = leaf(dam.command("upload"))
|
|
271
|
+
.description("上传本地文件并创建素材")
|
|
272
|
+
.argument("<file>", "本地文件路径")
|
|
273
|
+
.option("--repository-id <id>", "目标资源库 ID")
|
|
274
|
+
.option("--title <title>", "素材标题")
|
|
275
|
+
.option("--folder-id <id>", "目标文件夹 ID")
|
|
276
|
+
.option("--tag-ids <csv>", "标签 ID,逗号分隔")
|
|
277
|
+
.option("--allow-sensitive-path", "明确允许受保护路径")
|
|
278
|
+
.option("--wait-analysis", "等待素材分析结束")
|
|
279
|
+
.option("--json", "输出 JSON");
|
|
280
|
+
bindPreparedAction(upload, "organization", async (signal) => {
|
|
281
|
+
signal.throwIfAborted();
|
|
282
|
+
const options = upload.opts();
|
|
283
|
+
const input = {
|
|
284
|
+
file: position(upload, 0),
|
|
285
|
+
...defined("repositoryId", options.repositoryId),
|
|
286
|
+
...defined("title", options.title),
|
|
287
|
+
...defined("folderId", options.folderId),
|
|
288
|
+
...defined("tagIds", csv(options.tagIds)),
|
|
289
|
+
...(options.allowSensitivePath === true ? { allowSensitivePath: true } : {}),
|
|
290
|
+
...(options.waitAnalysis === true ? { waitAnalysis: true } : {})
|
|
291
|
+
};
|
|
292
|
+
runtime.validators.damUploadInput(input);
|
|
293
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
294
|
+
return { handled: false, input };
|
|
295
|
+
}, async (context, input, signal) => {
|
|
296
|
+
const result = await runtime.dam.upload({
|
|
297
|
+
input,
|
|
298
|
+
access: organizationAccess(context.state),
|
|
299
|
+
signal
|
|
300
|
+
});
|
|
301
|
+
await runtime.telemetry.stage("output", async () => {
|
|
302
|
+
runtime.presenter.result(result, {
|
|
303
|
+
json: upload.opts().json === true,
|
|
304
|
+
view: assetDetailView
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}, { operation: "dam.upload" });
|
|
308
|
+
const deleteCommand = leaf(dam.command("delete"))
|
|
309
|
+
.description("删除素材")
|
|
310
|
+
.argument("<asset>", "素材 ID")
|
|
311
|
+
.option("--repository-id <id>", "所属资源库 ID")
|
|
312
|
+
.option("--permanent", "移入回收站后永久删除");
|
|
313
|
+
bindPreparedAction(deleteCommand, "organization", async (signal) => {
|
|
314
|
+
signal.throwIfAborted();
|
|
315
|
+
const options = deleteCommand.opts();
|
|
316
|
+
const input = {
|
|
317
|
+
asset_id: position(deleteCommand, 0),
|
|
318
|
+
...defined("repositoryId", options.repositoryId),
|
|
319
|
+
...(options.permanent === true ? { permanent: true } : {})
|
|
320
|
+
};
|
|
321
|
+
runtime.validators.damDeleteInput(input);
|
|
322
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
323
|
+
return { handled: false, input };
|
|
324
|
+
}, async (context, input, signal) => {
|
|
325
|
+
await runtime.dam.delete({
|
|
326
|
+
input,
|
|
327
|
+
access: organizationAccess(context.state),
|
|
328
|
+
signal
|
|
329
|
+
});
|
|
330
|
+
await runtime.telemetry.stage("output", async () => {
|
|
331
|
+
runtime.presenter.success(input.permanent === true
|
|
332
|
+
? "素材已永久删除。"
|
|
333
|
+
: "素材已移入回收站。");
|
|
334
|
+
});
|
|
335
|
+
}, { operation: "dam.delete" });
|
|
336
|
+
}
|
|
337
|
+
function leaf(command) {
|
|
338
|
+
return command.allowExcessArguments(false);
|
|
339
|
+
}
|
|
340
|
+
function browseCommand(command) {
|
|
341
|
+
return command
|
|
342
|
+
.option("--repository-id <id>", "指定资源库 ID")
|
|
343
|
+
.option("--all-repositories", "查询全部可访问资源库")
|
|
344
|
+
.option("--folder-id <id>", "指定文件夹 ID")
|
|
345
|
+
.option("--no-include-child-folder", "不包含子文件夹")
|
|
346
|
+
.option("--type <type>", "素材类型")
|
|
347
|
+
.option("--asset-format <csv>", "文件格式,逗号分隔")
|
|
348
|
+
.option("--tag-ids <csv>", "标签 ID,逗号分隔")
|
|
349
|
+
.option("--page-size <1-100>", "请求分页大小", pageSize)
|
|
350
|
+
.option("--cursor <id>", "分页游标")
|
|
351
|
+
.option("--json", "输出 JSON");
|
|
352
|
+
}
|
|
353
|
+
function browseInput(command) {
|
|
354
|
+
const options = command.opts();
|
|
355
|
+
return {
|
|
356
|
+
...defined("repositoryId", options.repositoryId),
|
|
357
|
+
...(options.allRepositories === true ? { allRepositories: true } : {}),
|
|
358
|
+
...defined("folderId", options.folderId),
|
|
359
|
+
...(command.getOptionValueSource("includeChildFolder") === "cli"
|
|
360
|
+
? { includeChildFolder: false }
|
|
361
|
+
: {}),
|
|
362
|
+
...defined("type", options.type),
|
|
363
|
+
...defined("assetFormats", csv(options.assetFormat)),
|
|
364
|
+
...defined("tagIds", csv(options.tagIds)),
|
|
365
|
+
...defined("pageSize", options.pageSize),
|
|
366
|
+
...defined("cursor", options.cursor)
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function defined(key, value) {
|
|
370
|
+
return value === undefined ? {} : { [key]: value };
|
|
371
|
+
}
|
|
372
|
+
function csv(value) {
|
|
373
|
+
return value?.split(",").map((item) => item.trim()).filter((item) => item !== "");
|
|
374
|
+
}
|
|
375
|
+
function pageSize(value) {
|
|
376
|
+
if (!/^\d+$/u.test(value))
|
|
377
|
+
throw new CliUsageError();
|
|
378
|
+
const parsed = Number(value);
|
|
379
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100)
|
|
380
|
+
throw new CliUsageError();
|
|
381
|
+
return parsed;
|
|
382
|
+
}
|
|
383
|
+
function positiveInteger(value) {
|
|
384
|
+
if (!/^\d+$/u.test(value))
|
|
385
|
+
throw new CliUsageError();
|
|
386
|
+
const parsed = Number(value);
|
|
387
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1)
|
|
388
|
+
throw new CliUsageError();
|
|
389
|
+
return parsed;
|
|
390
|
+
}
|
|
391
|
+
function position(command, index) {
|
|
392
|
+
const value = command.processedArgs[index];
|
|
393
|
+
if (typeof value !== "string")
|
|
394
|
+
throw new CliUsageError();
|
|
395
|
+
return value;
|
|
396
|
+
}
|
|
397
|
+
function organizationAccess(state) {
|
|
398
|
+
return {
|
|
399
|
+
credential: state.credential,
|
|
400
|
+
organizationId: state.organization.id
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function assetListView(value) {
|
|
404
|
+
const assets = value.assets;
|
|
405
|
+
if (assets.length === 0)
|
|
406
|
+
return "暂无素材。";
|
|
407
|
+
return [
|
|
408
|
+
"ID\t标题\t类型\t格式",
|
|
409
|
+
...assets.map(assetRow)
|
|
410
|
+
].join("\n");
|
|
411
|
+
}
|
|
412
|
+
function assetRow(asset) {
|
|
413
|
+
return [asset.asset_id, asset.title ?? "", asset.type ?? "", asset.format ?? ""].join("\t");
|
|
414
|
+
}
|
|
415
|
+
function assetDetailView(value) {
|
|
416
|
+
const asset = value;
|
|
417
|
+
return [
|
|
418
|
+
`素材:${asset.title ?? asset.asset_id}`,
|
|
419
|
+
`ID:${asset.asset_id}`,
|
|
420
|
+
...(asset.type === undefined ? [] : [`类型:${asset.type}`]),
|
|
421
|
+
...(asset.format === undefined ? [] : [`格式:${asset.format}`]),
|
|
422
|
+
...(asset.url === undefined ? [] : [`URL:${asset.url}`])
|
|
423
|
+
].join("\n");
|
|
424
|
+
}
|
|
425
|
+
function folderListView(value) {
|
|
426
|
+
const folders = value.folders;
|
|
427
|
+
if (folders.length === 0)
|
|
428
|
+
return "暂无文件夹。";
|
|
429
|
+
return [
|
|
430
|
+
"ID\t名称\t子文件夹数\t素材数",
|
|
431
|
+
...folders.map((folder) => [
|
|
432
|
+
folder.folder_id,
|
|
433
|
+
folder.title,
|
|
434
|
+
folder.child_folder_count,
|
|
435
|
+
folder.asset_count
|
|
436
|
+
].join("\t"))
|
|
437
|
+
].join("\n");
|
|
438
|
+
}
|
|
439
|
+
function tagListView(value) {
|
|
440
|
+
const tags = value.tags;
|
|
441
|
+
if (tags.length === 0)
|
|
442
|
+
return "暂无标签。";
|
|
443
|
+
return [
|
|
444
|
+
"ID\t名称\t素材数",
|
|
445
|
+
...tags.map((tag) => [tag.tag_id, tag.name, tag.asset_count].join("\t"))
|
|
446
|
+
].join("\n");
|
|
447
|
+
}
|
|
448
|
+
function downloadView(value) {
|
|
449
|
+
return value.files
|
|
450
|
+
.map((file) => `已下载:${file.path}`)
|
|
451
|
+
.join("\n");
|
|
452
|
+
}
|
|
453
|
+
function renameView(value) {
|
|
454
|
+
const result = value;
|
|
455
|
+
return `已重命名:${result.title} (${result.entry_id})`;
|
|
456
|
+
}
|
|
457
|
+
function moveView(value) {
|
|
458
|
+
const result = value;
|
|
459
|
+
return `已移动至:${result.repository_id} / ${result.folder_id}`;
|
|
460
|
+
}
|
|
461
|
+
function copyView(value) {
|
|
462
|
+
const result = value;
|
|
463
|
+
return [
|
|
464
|
+
`已复制至:${result.repository_id} / ${result.folder_id}`,
|
|
465
|
+
...(result.copied_entry_id === undefined
|
|
466
|
+
? []
|
|
467
|
+
: [`复制条目 ID:${result.copied_entry_id}`])
|
|
468
|
+
].join("\n");
|
|
469
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { bindAction, bindPreparedAction } from "./action-binding.js";
|
|
2
|
+
export function registerEditorCommands(program, runtime) {
|
|
3
|
+
const editor = program.command("editor")
|
|
4
|
+
.description("连接并操作 AI+ Editor")
|
|
5
|
+
.helpCommand(false);
|
|
6
|
+
const connect = leaf(editor.command("connect"))
|
|
7
|
+
.description("打开并连接一个 AI+ Editor 作品")
|
|
8
|
+
.argument("[target]", "作品 ID 或完整 URL");
|
|
9
|
+
bindPreparedAction(connect, "none", async (signal) => {
|
|
10
|
+
signal.throwIfAborted();
|
|
11
|
+
const target = connect.processedArgs[0];
|
|
12
|
+
const input = typeof target === "string" ? { target } : {};
|
|
13
|
+
runtime.validators.editorConnectInput(input);
|
|
14
|
+
return { handled: false, input };
|
|
15
|
+
}, async (_context, input, signal) => {
|
|
16
|
+
const result = await runtime.editor.connect({ input, signal });
|
|
17
|
+
writeJson(runtime, result);
|
|
18
|
+
});
|
|
19
|
+
const disconnect = leaf(editor.command("disconnect"))
|
|
20
|
+
.description("断开当前 Editor 连接");
|
|
21
|
+
bindAction(disconnect, "none", async (_context, signal) => {
|
|
22
|
+
writeJson(runtime, await runtime.editor.disconnect({ signal }));
|
|
23
|
+
});
|
|
24
|
+
const snapshot = leaf(editor.command("snapshot"))
|
|
25
|
+
.description("读取当前作品快照");
|
|
26
|
+
bindAction(snapshot, "none", async (_context, signal) => {
|
|
27
|
+
writeJson(runtime, await runtime.editor.snapshot({ signal }));
|
|
28
|
+
});
|
|
29
|
+
const apply = leaf(editor.command("apply"))
|
|
30
|
+
.description("按顺序应用元素操作")
|
|
31
|
+
.requiredOption("--input <file|->", "从文件或标准输入读取 JSON");
|
|
32
|
+
bindPreparedAction(apply, "none", async (signal) => {
|
|
33
|
+
signal.throwIfAborted();
|
|
34
|
+
const source = apply.opts().input;
|
|
35
|
+
const input = await runtime.jsonInput.read(source, signal);
|
|
36
|
+
runtime.validators.editorApplyInput(input);
|
|
37
|
+
return { handled: false, input };
|
|
38
|
+
}, async (_context, input, signal) => {
|
|
39
|
+
writeJson(runtime, await runtime.editor.apply({ input, signal }));
|
|
40
|
+
});
|
|
41
|
+
const screenshot = leaf(editor.command("screenshot"))
|
|
42
|
+
.description("导出当前作品 PNG 截图")
|
|
43
|
+
.option("--json", "输出 JSON");
|
|
44
|
+
bindAction(screenshot, "none", async (_context, signal) => {
|
|
45
|
+
const result = await runtime.editor.screenshot({ signal });
|
|
46
|
+
runtime.presenter.result(result, {
|
|
47
|
+
json: screenshot.opts().json === true,
|
|
48
|
+
view: screenshotView
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
const save = leaf(editor.command("save"))
|
|
52
|
+
.description("保存当前 AI+ Editor 作品")
|
|
53
|
+
.option("--json", "输出 JSON");
|
|
54
|
+
bindAction(save, "none", async (_context, signal) => {
|
|
55
|
+
const result = await runtime.editor.save({ signal });
|
|
56
|
+
runtime.presenter.result(result, {
|
|
57
|
+
json: save.opts().json === true,
|
|
58
|
+
view: saveView
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function leaf(command) {
|
|
63
|
+
return command.allowExcessArguments(false);
|
|
64
|
+
}
|
|
65
|
+
function writeJson(runtime, value) {
|
|
66
|
+
runtime.io.writeOut(`${JSON.stringify(value)}\n`);
|
|
67
|
+
}
|
|
68
|
+
function screenshotView(value) {
|
|
69
|
+
return `截图已保存至 ${value.path}`;
|
|
70
|
+
}
|
|
71
|
+
function saveView(value) {
|
|
72
|
+
return `作品已保存:${value.url}`;
|
|
73
|
+
}
|