gaoding-cli 1.0.0-alpha.13 → 1.0.0-alpha.14
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/README.md +3 -2
- package/contracts/operations/agent.send/input.schema.json +4 -0
- package/contracts/operations/model.get/output.schema.json +1 -0
- package/dist/bin/gd-cli.js +3 -1
- package/dist/src/bootstrap/create-cli.js +36 -3
- package/dist/src/bootstrap/create-runtime.js +32 -7
- package/dist/src/cli/action-binding.js +43 -9
- package/dist/src/cli/agent-commands.js +13 -3
- package/dist/src/cli/auth-commands.js +21 -13
- package/dist/src/cli/dam-commands.js +35 -20
- package/dist/src/cli/errors.js +19 -1
- package/dist/src/cli/model-commands.js +41 -11
- package/dist/src/cli/org-commands.js +18 -12
- package/dist/src/cli/presenter.js +11 -1
- package/dist/src/cli/tool-commands.js +19 -7
- package/dist/src/cli/update-command.js +6 -4
- package/dist/src/features/agent/creative-agent-adapter.js +19 -14
- package/dist/src/features/agent/creative-protocol.js +7 -3
- package/dist/src/features/agent/use-cases.js +63 -54
- package/dist/src/features/auth/use-cases.js +82 -65
- package/dist/src/features/dam/asset-projection.js +22 -14
- package/dist/src/features/dam/dam-api-adapter.js +19 -4
- package/dist/src/features/dam/object-storage.js +2 -0
- package/dist/src/features/dam/registered-uploader.js +58 -35
- package/dist/src/features/dam/use-cases.js +39 -32
- package/dist/src/features/org/use-cases.js +27 -11
- package/dist/src/features/tool/catalog.js +7 -3
- package/dist/src/features/tool/dynamic-schema.js +19 -9
- package/dist/src/features/tool/mns-catalog-adapter.js +7 -4
- package/dist/src/features/tool/tool-api-adapter.js +35 -33
- package/dist/src/features/tool/use-cases.js +68 -36
- package/dist/src/features/update/update-service.js +28 -22
- package/dist/src/platform/json-input.js +3 -0
- package/dist/src/platform/remote-protocol.js +6 -0
- package/dist/src/telemetry/invocation.js +128 -0
- package/dist/src/telemetry/sls-sink.js +31 -0
- package/package.json +1 -1
- package/skills/gd-cli/references/creation.md +4 -2
- package/skills/gd-cli/references/errors.md +3 -1
package/README.md
CHANGED
|
@@ -28,10 +28,11 @@ gd-cli org switch --org <org-id>
|
|
|
28
28
|
gd-cli agent send --schema
|
|
29
29
|
gd-cli tool list
|
|
30
30
|
gd-cli model list --tool <tool>
|
|
31
|
-
gd-cli
|
|
31
|
+
gd-cli model get <model>
|
|
32
|
+
gd-cli model get <model> --schema
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
选定 Model 后,`model get --schema` 给出该 Model 的实际运行时输入;`tool call --schema` 给出整个 Tool 的参数并集。运行 `gd-cli --help` 查看当前命令;运行任一命令的 `--help` 查看参数。`gd-cli update` 固定检查 npm `latest`,支持更新 npm、pnpm 全局安装并同步 Agent Skill。
|
|
35
36
|
|
|
36
37
|
## License
|
|
37
38
|
|
package/dist/bin/gd-cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Command } from "commander";
|
|
1
|
+
import { Command, CommanderError } from "commander";
|
|
2
2
|
import { assertAllLeafCommandsBound, configureActionEnvironment } from "../cli/action-binding.js";
|
|
3
3
|
import { registerAgentCommands } from "../cli/agent-commands.js";
|
|
4
4
|
import { registerAuthCommands } from "../cli/auth-commands.js";
|
|
@@ -10,6 +10,7 @@ import { registerEditorCommands } from "../cli/editor-commands.js";
|
|
|
10
10
|
import { registerDamCommands } from "../cli/dam-commands.js";
|
|
11
11
|
import { registerUpdateCommand } from "../cli/update-command.js";
|
|
12
12
|
import { redact } from "../platform/redact.js";
|
|
13
|
+
import { RemoteRequestError } from "../platform/signed-http-transport.js";
|
|
13
14
|
export { assertAllLeafCommandsBound, bindAction } from "../cli/action-binding.js";
|
|
14
15
|
export function createCli(runtime, options) {
|
|
15
16
|
const program = new Command()
|
|
@@ -27,7 +28,8 @@ export function createCli(runtime, options) {
|
|
|
27
28
|
});
|
|
28
29
|
configureActionEnvironment(program, {
|
|
29
30
|
policies: runtime.accessPolicies,
|
|
30
|
-
signal: options.signal
|
|
31
|
+
signal: options.signal,
|
|
32
|
+
telemetry: runtime.telemetry
|
|
31
33
|
});
|
|
32
34
|
registerAuthCommands(program, runtime);
|
|
33
35
|
registerOrgCommands(program, runtime);
|
|
@@ -43,13 +45,44 @@ export function createCli(runtime, options) {
|
|
|
43
45
|
export async function executeCli(options) {
|
|
44
46
|
try {
|
|
45
47
|
await options.program.parseAsync(options.argv, { from: "user" });
|
|
48
|
+
await sendFinished(options, { outcome: "success" });
|
|
46
49
|
return 0;
|
|
47
50
|
}
|
|
48
51
|
catch (error) {
|
|
49
52
|
if (isHelpOutcome(error))
|
|
50
53
|
return 0;
|
|
54
|
+
if (options.telemetry.selected && error instanceof CommanderError) {
|
|
55
|
+
try {
|
|
56
|
+
await options.telemetry.stage("input", () => { throw error; });
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// The original Commander error is mapped and presented below.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
51
62
|
const outcome = redact(mapCliError(error, { aborted: options.signal.aborted }));
|
|
52
|
-
|
|
63
|
+
const invocationId = options.telemetry.selected
|
|
64
|
+
? options.telemetry.invocationId
|
|
65
|
+
: undefined;
|
|
66
|
+
options.presenter.error(outcome, {
|
|
67
|
+
json: options.argv.includes("--json"),
|
|
68
|
+
...(invocationId ? { invocationId } : {})
|
|
69
|
+
});
|
|
70
|
+
await sendFinished(options, outcome.kind === "interrupted"
|
|
71
|
+
? { outcome: "interrupted", error }
|
|
72
|
+
: {
|
|
73
|
+
outcome: "failure",
|
|
74
|
+
error,
|
|
75
|
+
errorCode: outcome.failure.code,
|
|
76
|
+
errorMessage: outcome.failure.message,
|
|
77
|
+
...(error instanceof RemoteRequestError && error.status !== undefined
|
|
78
|
+
? { httpStatus: error.status }
|
|
79
|
+
: {})
|
|
80
|
+
});
|
|
53
81
|
return outcome.exitCode;
|
|
54
82
|
}
|
|
55
83
|
}
|
|
84
|
+
async function sendFinished(options, completion) {
|
|
85
|
+
const events = options.telemetry.finish(completion);
|
|
86
|
+
if (events.length > 0)
|
|
87
|
+
await options.telemetrySink.send(events);
|
|
88
|
+
}
|
|
@@ -30,6 +30,9 @@ import { createPresenter } from "../cli/presenter.js";
|
|
|
30
30
|
import { createContractValidators } from "./validators.js";
|
|
31
31
|
import { loadBundledSkills } from "../features/skill/bundled-skills.js";
|
|
32
32
|
import { createUpdateService } from "../features/update/update-service.js";
|
|
33
|
+
import { classifyTelemetryError } from "../cli/errors.js";
|
|
34
|
+
import { createTelemetryInvocation } from "../telemetry/invocation.js";
|
|
35
|
+
import { createSlsTelemetrySink } from "../telemetry/sls-sink.js";
|
|
33
36
|
const productionEndpoints = {
|
|
34
37
|
orgApi: new URL("https://gdcli.gaoding.com/api"),
|
|
35
38
|
agentApi: new URL("https://gdcli.gaoding.com/api"),
|
|
@@ -47,6 +50,18 @@ export function createProductionRuntime(options = {}) {
|
|
|
47
50
|
const endpoints = options.endpoints ?? productionEndpoints;
|
|
48
51
|
const fetch = options.fetch ?? globalThis.fetch;
|
|
49
52
|
const now = options.now ?? (() => new Date());
|
|
53
|
+
const telemetry = createTelemetryInvocation({
|
|
54
|
+
cliVersion: primarySkill.version,
|
|
55
|
+
now: () => now().getTime(),
|
|
56
|
+
idFactory: randomUUID,
|
|
57
|
+
runtime: {
|
|
58
|
+
os: process.platform,
|
|
59
|
+
arch: process.arch,
|
|
60
|
+
nodeMajor: Number.parseInt(process.versions.node, 10)
|
|
61
|
+
},
|
|
62
|
+
classifyError: classifyTelemetryError
|
|
63
|
+
});
|
|
64
|
+
const telemetrySink = createSlsTelemetrySink({ fetch });
|
|
50
65
|
const rawIo = options.io ?? {
|
|
51
66
|
input: process.stdin,
|
|
52
67
|
stdout: process.stdout,
|
|
@@ -97,7 +112,8 @@ export function createProductionRuntime(options = {}) {
|
|
|
97
112
|
const org = createOrgUseCases({
|
|
98
113
|
store,
|
|
99
114
|
org: createOrgService({ transport: orgTransport }),
|
|
100
|
-
sso
|
|
115
|
+
sso,
|
|
116
|
+
telemetry
|
|
101
117
|
});
|
|
102
118
|
const auth = createAuthUseCases({
|
|
103
119
|
store,
|
|
@@ -105,6 +121,7 @@ export function createProductionRuntime(options = {}) {
|
|
|
105
121
|
organizationBinder: org,
|
|
106
122
|
authPageOrigin: endpoints.authPageOrigin,
|
|
107
123
|
now,
|
|
124
|
+
telemetry,
|
|
108
125
|
sleep: async (milliseconds, signal) => {
|
|
109
126
|
await delay(milliseconds, undefined, { signal });
|
|
110
127
|
}
|
|
@@ -129,7 +146,8 @@ export function createProductionRuntime(options = {}) {
|
|
|
129
146
|
api: damApi,
|
|
130
147
|
storage: storageUpload,
|
|
131
148
|
warn: (message) => { presenter.warning(message); },
|
|
132
|
-
now
|
|
149
|
+
now,
|
|
150
|
+
telemetry
|
|
133
151
|
}),
|
|
134
152
|
validate: {
|
|
135
153
|
list: validators.damListOutput,
|
|
@@ -137,20 +155,24 @@ export function createProductionRuntime(options = {}) {
|
|
|
137
155
|
get: validators.damGetOutput,
|
|
138
156
|
upload: validators.damUploadOutput,
|
|
139
157
|
delete: validators.damDeleteOutput
|
|
140
|
-
}
|
|
158
|
+
},
|
|
159
|
+
telemetry
|
|
141
160
|
});
|
|
142
161
|
const agent = createAgentUseCases({
|
|
143
162
|
uploader: transientUploader,
|
|
144
163
|
completion: createCreativeAgentAdapter({
|
|
145
164
|
transport: agentTransport,
|
|
146
|
-
idFactory: randomUUID
|
|
147
|
-
|
|
165
|
+
idFactory: randomUUID,
|
|
166
|
+
telemetry
|
|
167
|
+
}),
|
|
168
|
+
telemetry
|
|
148
169
|
});
|
|
149
170
|
const tool = createToolUseCases({
|
|
150
171
|
catalog: createMnsCatalogAdapter({ transport: mnsTransport }),
|
|
151
|
-
execution: createToolApiAdapter({ transport: toolTransport }),
|
|
172
|
+
execution: createToolApiAdapter({ transport: toolTransport, telemetry }),
|
|
152
173
|
uploader: transientUploader,
|
|
153
|
-
warn: (message) => { presenter.warning(message); }
|
|
174
|
+
warn: (message) => { presenter.warning(message); },
|
|
175
|
+
telemetry
|
|
154
176
|
});
|
|
155
177
|
const editor = createEditorUseCases({
|
|
156
178
|
session: createEditorSession({
|
|
@@ -183,6 +205,7 @@ export function createProductionRuntime(options = {}) {
|
|
|
183
205
|
packageRoot,
|
|
184
206
|
bundledSkills,
|
|
185
207
|
fetch,
|
|
208
|
+
telemetry,
|
|
186
209
|
...(process.argv[1] ? { binaryPath: process.argv[1] } : {}),
|
|
187
210
|
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
|
|
188
211
|
}).run(signal);
|
|
@@ -190,6 +213,8 @@ export function createProductionRuntime(options = {}) {
|
|
|
190
213
|
};
|
|
191
214
|
return {
|
|
192
215
|
version: primarySkill.version,
|
|
216
|
+
telemetry,
|
|
217
|
+
telemetrySink,
|
|
193
218
|
accessPolicies: createAccessPolicies({
|
|
194
219
|
store,
|
|
195
220
|
now,
|
|
@@ -3,34 +3,46 @@ const boundPolicies = new WeakMap();
|
|
|
3
3
|
export function configureActionEnvironment(program, environment) {
|
|
4
4
|
environments.set(program, environment);
|
|
5
5
|
}
|
|
6
|
-
export function bindAction(command, policy, handler) {
|
|
6
|
+
export function bindAction(command, policy, handler, telemetry) {
|
|
7
7
|
if (boundPolicies.has(command))
|
|
8
8
|
throw new Error(`Action already bound: ${commandPath(command)}`);
|
|
9
9
|
boundPolicies.set(command, policy);
|
|
10
|
+
bindTelemetrySelection(command, telemetry);
|
|
10
11
|
command.action(async () => {
|
|
11
12
|
const environment = environments.get(rootCommand(command));
|
|
12
13
|
if (!environment)
|
|
13
14
|
throw new Error("CLI action environment is missing.");
|
|
14
|
-
const context = await environment.
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const context = await environment.telemetry.stage("access", async () => {
|
|
16
|
+
const authorized = await environment.policies[policy].authorize(environment.signal);
|
|
17
|
+
if (authorized.policy !== policy) {
|
|
18
|
+
throw new Error("Access policy returned the wrong context.");
|
|
19
|
+
}
|
|
20
|
+
return authorized;
|
|
21
|
+
});
|
|
22
|
+
annotateAccessContext(environment.telemetry, context);
|
|
17
23
|
await handler(context, environment.signal);
|
|
18
24
|
});
|
|
19
25
|
}
|
|
20
|
-
export function bindPreparedAction(command, policy, prepare, run) {
|
|
26
|
+
export function bindPreparedAction(command, policy, prepare, run, telemetry) {
|
|
21
27
|
if (boundPolicies.has(command))
|
|
22
28
|
throw new Error(`Action already bound: ${commandPath(command)}`);
|
|
23
29
|
boundPolicies.set(command, policy);
|
|
30
|
+
bindTelemetrySelection(command, telemetry);
|
|
24
31
|
command.action(async () => {
|
|
25
32
|
const environment = environments.get(rootCommand(command));
|
|
26
33
|
if (!environment)
|
|
27
34
|
throw new Error("CLI action environment is missing.");
|
|
28
|
-
const prepared = await prepare(environment.signal);
|
|
35
|
+
const prepared = await environment.telemetry.stage("input", () => prepare(environment.signal));
|
|
29
36
|
if (prepared.handled)
|
|
30
37
|
return;
|
|
31
|
-
const context = await environment.
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
const context = await environment.telemetry.stage("access", async () => {
|
|
39
|
+
const authorized = await environment.policies[policy].authorize(environment.signal);
|
|
40
|
+
if (authorized.policy !== policy) {
|
|
41
|
+
throw new Error("Access policy returned the wrong context.");
|
|
42
|
+
}
|
|
43
|
+
return authorized;
|
|
44
|
+
});
|
|
45
|
+
annotateAccessContext(environment.telemetry, context);
|
|
34
46
|
await run(context, prepared.input, environment.signal);
|
|
35
47
|
});
|
|
36
48
|
}
|
|
@@ -52,6 +64,28 @@ function rootCommand(command) {
|
|
|
52
64
|
current = current.parent;
|
|
53
65
|
return current;
|
|
54
66
|
}
|
|
67
|
+
function bindTelemetrySelection(command, definition) {
|
|
68
|
+
if (!definition)
|
|
69
|
+
return;
|
|
70
|
+
if (!command.parent)
|
|
71
|
+
throw new Error(`Telemetry command has no parent: ${command.name()}`);
|
|
72
|
+
command.parent.hook("preSubcommand", (parent, selected) => {
|
|
73
|
+
if (selected !== command)
|
|
74
|
+
return;
|
|
75
|
+
const environment = environments.get(rootCommand(parent));
|
|
76
|
+
if (!environment)
|
|
77
|
+
throw new Error("CLI action environment is missing.");
|
|
78
|
+
environment.telemetry.select(definition);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function annotateAccessContext(telemetry, context) {
|
|
82
|
+
if (context.policy === "none")
|
|
83
|
+
return;
|
|
84
|
+
telemetry.annotate({
|
|
85
|
+
account_id: context.state.account?.id,
|
|
86
|
+
organization_id: context.state.organization?.id
|
|
87
|
+
});
|
|
88
|
+
}
|
|
55
89
|
function commandPath(command) {
|
|
56
90
|
const names = [];
|
|
57
91
|
let current = command;
|
|
@@ -18,11 +18,14 @@ export function registerAgentCommands(program, runtime) {
|
|
|
18
18
|
if (modes !== 1)
|
|
19
19
|
throw new CliUsageError();
|
|
20
20
|
if (options.schema === true) {
|
|
21
|
-
runtime.
|
|
21
|
+
await runtime.telemetry.stage("output", async () => {
|
|
22
|
+
runtime.io.writeOut(`${JSON.stringify(agentSendInputSchema)}\n`);
|
|
23
|
+
});
|
|
22
24
|
return { handled: true };
|
|
23
25
|
}
|
|
24
26
|
const input = await runtime.jsonInput.read(options.input, signal);
|
|
25
27
|
runtime.validators.agentSendInput(input);
|
|
28
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
26
29
|
return { handled: false, input };
|
|
27
30
|
}, async (context, input, signal) => {
|
|
28
31
|
const result = await runtime.agent.send({
|
|
@@ -33,7 +36,14 @@ export function registerAgentCommands(program, runtime) {
|
|
|
33
36
|
},
|
|
34
37
|
signal
|
|
35
38
|
});
|
|
36
|
-
runtime.
|
|
37
|
-
|
|
39
|
+
await runtime.telemetry.stage("output", async () => {
|
|
40
|
+
runtime.validators.agentSendOutput(result);
|
|
41
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
42
|
+
});
|
|
43
|
+
}, {
|
|
44
|
+
operation: "agent.send",
|
|
45
|
+
mode: () => send.opts().schema === true
|
|
46
|
+
? "schema"
|
|
47
|
+
: "execute"
|
|
38
48
|
});
|
|
39
49
|
}
|
|
@@ -8,8 +8,10 @@ export function registerAuthCommands(program, runtime) {
|
|
|
8
8
|
.description("登录稿定")
|
|
9
9
|
.option("--no-browser", "不自动打开浏览器");
|
|
10
10
|
bindAction(login, "none", async (_context, signal) => {
|
|
11
|
+
const noBrowser = login.opts().browser === false;
|
|
12
|
+
runtime.telemetry.annotate({ parameters: { noBrowser } });
|
|
11
13
|
const result = await runtime.auth.login({
|
|
12
|
-
noBrowser
|
|
14
|
+
noBrowser,
|
|
13
15
|
signal,
|
|
14
16
|
interaction: {
|
|
15
17
|
showAuthorization: (url) => runtime.presenter.authorization({
|
|
@@ -20,27 +22,33 @@ export function registerAuthCommands(program, runtime) {
|
|
|
20
22
|
warn: (message) => runtime.presenter.warning(message)
|
|
21
23
|
}
|
|
22
24
|
});
|
|
23
|
-
runtime.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
await runtime.telemetry.stage("output", async () => {
|
|
26
|
+
runtime.presenter.success(result.status === "already_logged_in" ? "已登录。" : "登录成功。");
|
|
27
|
+
if (result.status === "already_logged_in" && !result.organizationSelected) {
|
|
28
|
+
runtime.presenter.warning("尚未选择组织,请执行 gd-cli org switch。");
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}, { operation: "auth.login" });
|
|
28
32
|
const status = leaf(auth.command("status"))
|
|
29
33
|
.description("查看登录状态")
|
|
30
34
|
.option("--json", "输出 JSON");
|
|
31
35
|
bindAction(status, "none", async () => {
|
|
32
36
|
const result = await runtime.auth.status({ now: runtime.now() });
|
|
33
|
-
runtime.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
await runtime.telemetry.stage("output", async () => {
|
|
38
|
+
runtime.validators.authStatus(result);
|
|
39
|
+
runtime.presenter.result(result, {
|
|
40
|
+
json: status.opts().json === true,
|
|
41
|
+
view: authStatusView
|
|
42
|
+
});
|
|
37
43
|
});
|
|
38
|
-
});
|
|
44
|
+
}, { operation: "auth.status" });
|
|
39
45
|
const logout = leaf(auth.command("logout")).description("退出登录");
|
|
40
46
|
bindAction(logout, "none", async () => {
|
|
41
47
|
await runtime.auth.logout();
|
|
42
|
-
runtime.
|
|
43
|
-
|
|
48
|
+
await runtime.telemetry.stage("output", async () => {
|
|
49
|
+
runtime.presenter.success("已退出登录。");
|
|
50
|
+
});
|
|
51
|
+
}, { operation: "auth.logout" });
|
|
44
52
|
}
|
|
45
53
|
function leaf(command) {
|
|
46
54
|
return command.allowExcessArguments(false);
|
|
@@ -10,6 +10,7 @@ export function registerDamCommands(program, runtime) {
|
|
|
10
10
|
signal.throwIfAborted();
|
|
11
11
|
const input = browseInput(list);
|
|
12
12
|
runtime.validators.damListInput(input);
|
|
13
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
13
14
|
return { handled: false, input };
|
|
14
15
|
}, async (context, input, signal) => {
|
|
15
16
|
const result = await runtime.dam.list({
|
|
@@ -17,11 +18,13 @@ export function registerDamCommands(program, runtime) {
|
|
|
17
18
|
access: organizationAccess(context.state),
|
|
18
19
|
signal
|
|
19
20
|
});
|
|
20
|
-
runtime.
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
await runtime.telemetry.stage("output", async () => {
|
|
22
|
+
runtime.presenter.result(result, {
|
|
23
|
+
json: list.opts().json === true,
|
|
24
|
+
view: assetListView
|
|
25
|
+
});
|
|
23
26
|
});
|
|
24
|
-
});
|
|
27
|
+
}, { operation: "dam.list" });
|
|
25
28
|
const search = browseCommand(leaf(dam.command("search")))
|
|
26
29
|
.description("按关键词搜索素材")
|
|
27
30
|
.argument("<query>", "搜索关键词");
|
|
@@ -32,6 +35,7 @@ export function registerDamCommands(program, runtime) {
|
|
|
32
35
|
...browseInput(search)
|
|
33
36
|
};
|
|
34
37
|
runtime.validators.damSearchInput(input);
|
|
38
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
35
39
|
return { handled: false, input };
|
|
36
40
|
}, async (context, input, signal) => {
|
|
37
41
|
const result = await runtime.dam.search({
|
|
@@ -39,11 +43,13 @@ export function registerDamCommands(program, runtime) {
|
|
|
39
43
|
access: organizationAccess(context.state),
|
|
40
44
|
signal
|
|
41
45
|
});
|
|
42
|
-
runtime.
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
await runtime.telemetry.stage("output", async () => {
|
|
47
|
+
runtime.presenter.result(result, {
|
|
48
|
+
json: search.opts().json === true,
|
|
49
|
+
view: assetListView
|
|
50
|
+
});
|
|
45
51
|
});
|
|
46
|
-
});
|
|
52
|
+
}, { operation: "dam.search" });
|
|
47
53
|
const get = leaf(dam.command("get"))
|
|
48
54
|
.description("查看素材完整信息")
|
|
49
55
|
.argument("<asset>", "素材 ID")
|
|
@@ -52,6 +58,7 @@ export function registerDamCommands(program, runtime) {
|
|
|
52
58
|
signal.throwIfAborted();
|
|
53
59
|
const input = { asset_id: position(get, 0) };
|
|
54
60
|
runtime.validators.damGetInput(input);
|
|
61
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
55
62
|
return { handled: false, input };
|
|
56
63
|
}, async (context, input, signal) => {
|
|
57
64
|
const result = await runtime.dam.get({
|
|
@@ -59,11 +66,13 @@ export function registerDamCommands(program, runtime) {
|
|
|
59
66
|
access: organizationAccess(context.state),
|
|
60
67
|
signal
|
|
61
68
|
});
|
|
62
|
-
runtime.
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
await runtime.telemetry.stage("output", async () => {
|
|
70
|
+
runtime.presenter.result(result, {
|
|
71
|
+
json: get.opts().json === true,
|
|
72
|
+
view: assetDetailView
|
|
73
|
+
});
|
|
65
74
|
});
|
|
66
|
-
});
|
|
75
|
+
}, { operation: "dam.get" });
|
|
67
76
|
const upload = leaf(dam.command("upload"))
|
|
68
77
|
.description("上传本地文件并创建素材")
|
|
69
78
|
.argument("<file>", "本地文件路径")
|
|
@@ -87,6 +96,7 @@ export function registerDamCommands(program, runtime) {
|
|
|
87
96
|
...(options.waitAnalysis === true ? { waitAnalysis: true } : {})
|
|
88
97
|
};
|
|
89
98
|
runtime.validators.damUploadInput(input);
|
|
99
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
90
100
|
return { handled: false, input };
|
|
91
101
|
}, async (context, input, signal) => {
|
|
92
102
|
const result = await runtime.dam.upload({
|
|
@@ -94,11 +104,13 @@ export function registerDamCommands(program, runtime) {
|
|
|
94
104
|
access: organizationAccess(context.state),
|
|
95
105
|
signal
|
|
96
106
|
});
|
|
97
|
-
runtime.
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
await runtime.telemetry.stage("output", async () => {
|
|
108
|
+
runtime.presenter.result(result, {
|
|
109
|
+
json: upload.opts().json === true,
|
|
110
|
+
view: assetDetailView
|
|
111
|
+
});
|
|
100
112
|
});
|
|
101
|
-
});
|
|
113
|
+
}, { operation: "dam.upload" });
|
|
102
114
|
const deleteCommand = leaf(dam.command("delete"))
|
|
103
115
|
.description("删除素材")
|
|
104
116
|
.argument("<asset>", "素材 ID")
|
|
@@ -113,6 +125,7 @@ export function registerDamCommands(program, runtime) {
|
|
|
113
125
|
...(options.permanent === true ? { permanent: true } : {})
|
|
114
126
|
};
|
|
115
127
|
runtime.validators.damDeleteInput(input);
|
|
128
|
+
runtime.telemetry.annotate({ parameters: { ...input } });
|
|
116
129
|
return { handled: false, input };
|
|
117
130
|
}, async (context, input, signal) => {
|
|
118
131
|
await runtime.dam.delete({
|
|
@@ -120,10 +133,12 @@ export function registerDamCommands(program, runtime) {
|
|
|
120
133
|
access: organizationAccess(context.state),
|
|
121
134
|
signal
|
|
122
135
|
});
|
|
123
|
-
runtime.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
await runtime.telemetry.stage("output", async () => {
|
|
137
|
+
runtime.presenter.success(input.permanent === true
|
|
138
|
+
? "素材已永久删除。"
|
|
139
|
+
: "素材已移入回收站。");
|
|
140
|
+
});
|
|
141
|
+
}, { operation: "dam.delete" });
|
|
127
142
|
}
|
|
128
143
|
function leaf(command) {
|
|
129
144
|
return command.allowExcessArguments(false);
|
package/dist/src/cli/errors.js
CHANGED
|
@@ -6,10 +6,12 @@ import { DeviceAuthorizationExpiredError } from "../features/auth/use-cases.js";
|
|
|
6
6
|
import { AgentInputError } from "../features/agent/use-cases.js";
|
|
7
7
|
import { ToolInputError } from "../features/tool/catalog.js";
|
|
8
8
|
import { ObjectStorageUploadError } from "../features/dam/object-storage.js";
|
|
9
|
+
import { DamAssetNotFoundError } from "../features/dam/dam-api-adapter.js";
|
|
9
10
|
import { DamInputError } from "../features/dam/use-cases.js";
|
|
10
11
|
import { OrganizationResponseError } from "../features/org/org-service.js";
|
|
11
12
|
import { OrganizationBindFailedError, OrganizationInvalidError, OrgUsageError } from "../features/org/use-cases.js";
|
|
12
13
|
import { RemoteRequestError } from "../platform/signed-http-transport.js";
|
|
14
|
+
import { RemoteProtocolError } from "../platform/remote-protocol.js";
|
|
13
15
|
import { InputContractError, OutputContractError } from "../bootstrap/validators.js";
|
|
14
16
|
import { JsonInputError } from "../platform/json-input.js";
|
|
15
17
|
import { LocalFileInputError } from "../platform/safe-upload-file.js";
|
|
@@ -59,13 +61,19 @@ export function mapCliError(error, options) {
|
|
|
59
61
|
|| error instanceof CommanderError) {
|
|
60
62
|
return failure("USAGE_ERROR", "命令或参数无效,请查看 --help。", 2);
|
|
61
63
|
}
|
|
64
|
+
if (error instanceof RemoteProtocolError) {
|
|
65
|
+
return failure("REMOTE_PROTOCOL_INCOMPATIBLE", "稿定服务返回了当前 CLI 无法安全处理的结果;为避免重复创作,已停止处理。", 1);
|
|
66
|
+
}
|
|
67
|
+
if (error instanceof DamAssetNotFoundError) {
|
|
68
|
+
return failure("DAM_ASSET_NOT_FOUND", "未找到指定的 DAM 素材。", 1);
|
|
69
|
+
}
|
|
62
70
|
if (error instanceof RemoteRequestError
|
|
63
71
|
|| error instanceof SsoRequestError
|
|
64
72
|
|| error instanceof DeviceAuthorizationExpiredError
|
|
65
73
|
|| error instanceof OrganizationResponseError
|
|
66
74
|
|| error instanceof OrganizationBindFailedError
|
|
67
75
|
|| error instanceof ObjectStorageUploadError) {
|
|
68
|
-
return failure("REMOTE_REQUEST_FAILED", "
|
|
76
|
+
return failure("REMOTE_REQUEST_FAILED", "稿定服务请求失败。", 1);
|
|
69
77
|
}
|
|
70
78
|
if (error instanceof OutputContractError) {
|
|
71
79
|
return failure("INTERNAL_ERROR", "CLI 内部结果校验失败。", 1);
|
|
@@ -77,6 +85,16 @@ export function mapCliError(error, options) {
|
|
|
77
85
|
}
|
|
78
86
|
return failure("INTERNAL_ERROR", "CLI 发生内部错误。", 1);
|
|
79
87
|
}
|
|
88
|
+
export function classifyTelemetryError(error) {
|
|
89
|
+
const outcome = mapCliError(error, { aborted: false });
|
|
90
|
+
return {
|
|
91
|
+
outcome: outcome.kind === "interrupted" ? "interrupted" : "failure",
|
|
92
|
+
...(outcome.kind === "failure" ? { errorCode: outcome.failure.code } : {}),
|
|
93
|
+
...(error instanceof RemoteRequestError && error.status !== undefined
|
|
94
|
+
? { httpStatus: error.status }
|
|
95
|
+
: {})
|
|
96
|
+
};
|
|
97
|
+
}
|
|
80
98
|
function failure(code, message, exitCode, nextSteps) {
|
|
81
99
|
return {
|
|
82
100
|
kind: "failure",
|
|
@@ -11,7 +11,9 @@ export function registerModelCommands(program, runtime) {
|
|
|
11
11
|
bindAction(list, "organization", async (context, signal) => {
|
|
12
12
|
const selectedTool = list.opts().tool;
|
|
13
13
|
const input = selectedTool === undefined ? {} : { tool: selectedTool };
|
|
14
|
-
runtime.
|
|
14
|
+
await runtime.telemetry.stage("input", async () => {
|
|
15
|
+
runtime.validators.modelListInput(input);
|
|
16
|
+
});
|
|
15
17
|
const result = await runtime.tool.listModels({
|
|
16
18
|
input,
|
|
17
19
|
access: {
|
|
@@ -20,28 +22,56 @@ export function registerModelCommands(program, runtime) {
|
|
|
20
22
|
},
|
|
21
23
|
signal
|
|
22
24
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
if (selectedTool !== undefined)
|
|
26
|
+
runtime.telemetry.annotate({ tool_name: selectedTool });
|
|
27
|
+
await runtime.telemetry.stage("output", async () => {
|
|
28
|
+
runtime.validators.modelListOutput(result);
|
|
29
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
30
|
+
});
|
|
31
|
+
}, { operation: "model.list" });
|
|
26
32
|
const get = model.command("get")
|
|
27
33
|
.description("查看模型完整信息")
|
|
28
34
|
.argument("<model>", "模型机器标识")
|
|
35
|
+
.option("--schema", "输出所选模型的实际运行时输入 Schema")
|
|
29
36
|
.allowExcessArguments(false);
|
|
30
37
|
bindAction(get, "organization", async (context, signal) => {
|
|
31
38
|
const modelName = get.processedArgs[0];
|
|
32
39
|
if (typeof modelName !== "string" || modelName.trim() === "")
|
|
33
40
|
throw new CliUsageError();
|
|
34
41
|
const input = { model: modelName };
|
|
35
|
-
runtime.
|
|
42
|
+
await runtime.telemetry.stage("input", async () => {
|
|
43
|
+
runtime.validators.modelGetInput(input);
|
|
44
|
+
});
|
|
45
|
+
const access = {
|
|
46
|
+
credential: context.state.credential,
|
|
47
|
+
organizationId: context.state.organization.id
|
|
48
|
+
};
|
|
49
|
+
if (get.opts().schema === true) {
|
|
50
|
+
const schema = await runtime.tool.getModelArgumentsSchema({
|
|
51
|
+
model: modelName,
|
|
52
|
+
access,
|
|
53
|
+
signal
|
|
54
|
+
});
|
|
55
|
+
runtime.telemetry.annotate({ model_id: modelName });
|
|
56
|
+
await runtime.telemetry.stage("output", async () => {
|
|
57
|
+
runtime.io.writeOut(`${JSON.stringify(schema)}\n`);
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
36
61
|
const result = await runtime.tool.getModel({
|
|
37
62
|
input,
|
|
38
|
-
access
|
|
39
|
-
credential: context.state.credential,
|
|
40
|
-
organizationId: context.state.organization.id
|
|
41
|
-
},
|
|
63
|
+
access,
|
|
42
64
|
signal
|
|
43
65
|
});
|
|
44
|
-
runtime.
|
|
45
|
-
runtime.
|
|
66
|
+
runtime.telemetry.annotate({ model_id: modelName });
|
|
67
|
+
await runtime.telemetry.stage("output", async () => {
|
|
68
|
+
runtime.validators.modelGetOutput(result);
|
|
69
|
+
runtime.io.writeOut(`${JSON.stringify(result)}\n`);
|
|
70
|
+
});
|
|
71
|
+
}, {
|
|
72
|
+
operation: "model.get",
|
|
73
|
+
mode: () => get.opts().schema === true
|
|
74
|
+
? "schema"
|
|
75
|
+
: "detail"
|
|
46
76
|
});
|
|
47
77
|
}
|