@gaoding/cli 0.0.0 → 1.0.0
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,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "ToolCallOutput",
|
|
4
|
+
"description": "创作工具同步返回的最终内容与所选模型成本。",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"content",
|
|
9
|
+
"usage"
|
|
10
|
+
],
|
|
11
|
+
"properties": {
|
|
12
|
+
"content": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"description": "创作工具最终产出的文本或资源链接。",
|
|
15
|
+
"items": {
|
|
16
|
+
"oneOf": [
|
|
17
|
+
{
|
|
18
|
+
"$ref": "#/$defs/TextContent"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"$ref": "#/$defs/ResourceLink"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"usage": {
|
|
27
|
+
"$ref": "#/$defs/ToolUsage",
|
|
28
|
+
"description": "本次调用所选模型及 Model Catalog 声明的成本。"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"$defs": {
|
|
32
|
+
"CostRange": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": [
|
|
36
|
+
"unit",
|
|
37
|
+
"minimum",
|
|
38
|
+
"maximum"
|
|
39
|
+
],
|
|
40
|
+
"properties": {
|
|
41
|
+
"unit": {
|
|
42
|
+
"const": "gaodou",
|
|
43
|
+
"description": "稿豆计价单位。"
|
|
44
|
+
},
|
|
45
|
+
"minimum": {
|
|
46
|
+
"type": "number",
|
|
47
|
+
"minimum": 0,
|
|
48
|
+
"description": "当前可用配置中的最低稿豆消耗。"
|
|
49
|
+
},
|
|
50
|
+
"maximum": {
|
|
51
|
+
"type": "number",
|
|
52
|
+
"minimum": 0,
|
|
53
|
+
"description": "当前可用配置中的最高稿豆消耗。"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"ToolUsage": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": false,
|
|
60
|
+
"required": [
|
|
61
|
+
"model"
|
|
62
|
+
],
|
|
63
|
+
"properties": {
|
|
64
|
+
"model": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"minLength": 1,
|
|
67
|
+
"pattern": ".*\\S.*",
|
|
68
|
+
"description": "本次调用选择的模型机器标识。"
|
|
69
|
+
},
|
|
70
|
+
"cost": {
|
|
71
|
+
"$ref": "#/$defs/CostRange",
|
|
72
|
+
"description": "Model Catalog 声明的稿豆消耗区间。"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"TextContent": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"additionalProperties": false,
|
|
79
|
+
"required": [
|
|
80
|
+
"type",
|
|
81
|
+
"text"
|
|
82
|
+
],
|
|
83
|
+
"properties": {
|
|
84
|
+
"type": {
|
|
85
|
+
"const": "text",
|
|
86
|
+
"description": "文本内容的固定类型。"
|
|
87
|
+
},
|
|
88
|
+
"text": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"minLength": 1,
|
|
91
|
+
"pattern": ".*\\S.*",
|
|
92
|
+
"description": "创作工具返回的文本。"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"ResourceLink": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": [
|
|
100
|
+
"type",
|
|
101
|
+
"uri",
|
|
102
|
+
"name"
|
|
103
|
+
],
|
|
104
|
+
"properties": {
|
|
105
|
+
"type": {
|
|
106
|
+
"const": "resource_link",
|
|
107
|
+
"description": "资源链接的固定类型。"
|
|
108
|
+
},
|
|
109
|
+
"uri": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"format": "uri",
|
|
112
|
+
"description": "创作工具生成资源的 URI。"
|
|
113
|
+
},
|
|
114
|
+
"name": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"minLength": 1,
|
|
117
|
+
"pattern": ".*\\S.*",
|
|
118
|
+
"description": "资源的文件名。"
|
|
119
|
+
},
|
|
120
|
+
"mimeType": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"minLength": 1,
|
|
123
|
+
"pattern": ".*\\S.*",
|
|
124
|
+
"description": "资源的 MIME type。"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "ToolListResult",
|
|
4
|
+
"description": "当前可用的产品创作工具。",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"tools"
|
|
9
|
+
],
|
|
10
|
+
"properties": {
|
|
11
|
+
"tools": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"description": "当前至少有一个可用模型的产品创作工具。",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"required": [
|
|
18
|
+
"name",
|
|
19
|
+
"title",
|
|
20
|
+
"description"
|
|
21
|
+
],
|
|
22
|
+
"properties": {
|
|
23
|
+
"name": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"pattern": ".*\\S.*",
|
|
27
|
+
"description": "调用创作工具时使用的机器标识。"
|
|
28
|
+
},
|
|
29
|
+
"title": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1,
|
|
32
|
+
"pattern": ".*\\S.*",
|
|
33
|
+
"description": "创作工具的展示名称。"
|
|
34
|
+
},
|
|
35
|
+
"description": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"minLength": 1,
|
|
38
|
+
"pattern": ".*\\S.*",
|
|
39
|
+
"description": "创作工具的用途说明。"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const controller = new AbortController();
|
|
3
|
+
const interrupt = () => controller.abort(new Error("SIGINT"));
|
|
4
|
+
process.once("SIGINT", interrupt);
|
|
5
|
+
let runtime;
|
|
6
|
+
let mapCliError;
|
|
7
|
+
let redact;
|
|
8
|
+
try {
|
|
9
|
+
// Register SIGINT before loading the CLI graph so a cold-start interrupt is
|
|
10
|
+
// converted into the same abort path as an interrupt during stdin reading.
|
|
11
|
+
const [cliModule, runtimeModule, errorsModule, redactModule] = await Promise.all([
|
|
12
|
+
import("../src/bootstrap/create-cli.js"),
|
|
13
|
+
import("../src/bootstrap/create-runtime.js"),
|
|
14
|
+
import("../src/cli/errors.js"),
|
|
15
|
+
import("../src/platform/redact.js")
|
|
16
|
+
]);
|
|
17
|
+
const { createCli, executeCli } = cliModule;
|
|
18
|
+
const { createProductionRuntime } = runtimeModule;
|
|
19
|
+
mapCliError = errorsModule.mapCliError;
|
|
20
|
+
redact = redactModule.redact;
|
|
21
|
+
runtime = createProductionRuntime();
|
|
22
|
+
const program = createCli(runtime, { signal: controller.signal });
|
|
23
|
+
process.exitCode = await executeCli({
|
|
24
|
+
program,
|
|
25
|
+
argv: process.argv.slice(2),
|
|
26
|
+
presenter: runtime.presenter,
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
telemetry: runtime.telemetry,
|
|
29
|
+
telemetrySink: runtime.telemetrySink,
|
|
30
|
+
updateNotification: runtime.updateNotification
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// Dynamic module loading can fail before the error mapper is available.
|
|
35
|
+
// Keep that rare startup failure bounded and avoid an unhandled rejection.
|
|
36
|
+
if (mapCliError === undefined || redact === undefined) {
|
|
37
|
+
process.stderr.write("INTERNAL_ERROR: CLI 启动失败。\n");
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const outcome = redact(mapCliError(error, { aborted: controller.signal.aborted }));
|
|
42
|
+
if (runtime) {
|
|
43
|
+
runtime.presenter.error(outcome, { json: process.argv.includes("--json") });
|
|
44
|
+
}
|
|
45
|
+
else if (outcome.kind === "interrupted") {
|
|
46
|
+
process.stderr.write("已取消。\n");
|
|
47
|
+
}
|
|
48
|
+
else if (process.argv.includes("--json")) {
|
|
49
|
+
process.stderr.write(`${JSON.stringify({ error: outcome.failure })}\n`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
process.stderr.write(`${outcome.failure.code}: ${outcome.failure.message}\n`);
|
|
53
|
+
}
|
|
54
|
+
process.exitCode = outcome.exitCode;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
process.removeListener("SIGINT", interrupt);
|
|
59
|
+
}
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { loadBundledSkills } from "../src/features/skill/bundled-skills.js";
|
|
4
|
+
import { syncBundledSkills } from "../src/features/skill/installer.js";
|
|
5
|
+
export function isSupportedGlobalLifecycle(env) {
|
|
6
|
+
const userAgent = env.npm_config_user_agent ?? "";
|
|
7
|
+
if (env.npm_config_global === "true") {
|
|
8
|
+
return /^(?:npm|pnpm)\//u.test(userAgent);
|
|
9
|
+
}
|
|
10
|
+
const initialDirectory = (env.INIT_CWD ?? "").replace(/\\/gu, "/");
|
|
11
|
+
return userAgent.startsWith("pnpm/")
|
|
12
|
+
&& env.npm_command === "add"
|
|
13
|
+
&& env.npm_lifecycle_event === "postinstall"
|
|
14
|
+
&& env.npm_package_name === "@gaoding/cli"
|
|
15
|
+
&& /\/v\d+\/[0-9a-f]+-[0-9a-f]+-[0-9a-f]{16}$/u.test(initialDirectory);
|
|
16
|
+
}
|
|
17
|
+
export async function runPostinstall(options = {}) {
|
|
18
|
+
const env = options.env ?? process.env;
|
|
19
|
+
if (!isSupportedGlobalLifecycle(env))
|
|
20
|
+
return;
|
|
21
|
+
const writeError = options.writeError ?? ((text) => process.stderr.write(text));
|
|
22
|
+
try {
|
|
23
|
+
const skills = (options.loadSkills ?? loadBundledSkills)(options.startFile ?? fileURLToPath(import.meta.url));
|
|
24
|
+
await (options.syncSkills ?? syncBundledSkills)(skills, {
|
|
25
|
+
env,
|
|
26
|
+
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
writeError(`警告: ${oneLineMessage(error)}\n`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function oneLineMessage(error) {
|
|
34
|
+
const value = error instanceof Error ? error.message : String(error);
|
|
35
|
+
return value.replace(/\s+/gu, " ").trim() || "Agent Skill 自动安装失败";
|
|
36
|
+
}
|
|
37
|
+
const entryPath = process.argv[1];
|
|
38
|
+
const isDirectEntry = entryPath !== undefined
|
|
39
|
+
&& resolve(entryPath) === fileURLToPath(import.meta.url);
|
|
40
|
+
if (isDirectEntry || process.env.npm_lifecycle_event === "postinstall") {
|
|
41
|
+
void runPostinstall();
|
|
42
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Command, CommanderError } from "commander";
|
|
2
|
+
import { assertAllLeafCommandsBound, configureActionEnvironment } from "../cli/action-binding.js";
|
|
3
|
+
import { registerAgentCommands } from "../cli/agent-commands.js";
|
|
4
|
+
import { registerAuthCommands } from "../cli/auth-commands.js";
|
|
5
|
+
import { classifyTelemetryError, isHelpOutcome, mapCliError } from "../cli/errors.js";
|
|
6
|
+
import { registerOrgCommands } from "../cli/org-commands.js";
|
|
7
|
+
import { registerToolCommands } from "../cli/tool-commands.js";
|
|
8
|
+
import { registerModelCommands } from "../cli/model-commands.js";
|
|
9
|
+
import { registerEditorCommands } from "../cli/editor-commands.js";
|
|
10
|
+
import { registerDamCommands } from "../cli/dam-commands.js";
|
|
11
|
+
import { registerUpdateCommand } from "../cli/update-command.js";
|
|
12
|
+
import { redact } from "../platform/redact.js";
|
|
13
|
+
export { assertAllLeafCommandsBound, bindAction } from "../cli/action-binding.js";
|
|
14
|
+
export function createCli(runtime, options) {
|
|
15
|
+
const program = new Command()
|
|
16
|
+
.name("gd-cli")
|
|
17
|
+
.description("稿定命令行工具")
|
|
18
|
+
.version(runtime.version)
|
|
19
|
+
.helpCommand(false)
|
|
20
|
+
.showHelpAfterError(false)
|
|
21
|
+
.showSuggestionAfterError(false)
|
|
22
|
+
.allowExcessArguments(false)
|
|
23
|
+
.exitOverride()
|
|
24
|
+
.configureOutput({
|
|
25
|
+
writeOut: runtime.io.writeOut,
|
|
26
|
+
writeErr: () => undefined
|
|
27
|
+
});
|
|
28
|
+
configureActionEnvironment(program, {
|
|
29
|
+
policies: runtime.accessPolicies,
|
|
30
|
+
signal: options.signal,
|
|
31
|
+
telemetry: runtime.telemetry,
|
|
32
|
+
updateNotification: runtime.updateNotification
|
|
33
|
+
});
|
|
34
|
+
registerAuthCommands(program, runtime);
|
|
35
|
+
registerOrgCommands(program, runtime);
|
|
36
|
+
registerAgentCommands(program, runtime);
|
|
37
|
+
registerToolCommands(program, runtime);
|
|
38
|
+
registerModelCommands(program, runtime);
|
|
39
|
+
registerEditorCommands(program, runtime);
|
|
40
|
+
registerDamCommands(program, runtime);
|
|
41
|
+
registerUpdateCommand(program, runtime);
|
|
42
|
+
assertAllLeafCommandsBound(program);
|
|
43
|
+
return program;
|
|
44
|
+
}
|
|
45
|
+
export async function executeCli(options) {
|
|
46
|
+
try {
|
|
47
|
+
await options.program.parseAsync(options.argv, { from: "user" });
|
|
48
|
+
await sendFinished(options, { outcome: "success" });
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (isHelpOutcome(error)) {
|
|
53
|
+
if (options.argv[0] !== "update") {
|
|
54
|
+
await checkUpdateNotification(options.updateNotification, options.signal);
|
|
55
|
+
}
|
|
56
|
+
if (options.signal.aborted) {
|
|
57
|
+
options.presenter.error({ kind: "interrupted", exitCode: 130 }, { json: options.argv.includes("--json") });
|
|
58
|
+
await sendFinished(options, { outcome: "interrupted" });
|
|
59
|
+
return 130;
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
if (options.telemetry.selected && error instanceof CommanderError) {
|
|
64
|
+
try {
|
|
65
|
+
await options.telemetry.stage("input", () => { throw error; });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// The original Commander error is mapped and presented below.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const outcome = redact(mapCliError(error, { aborted: options.signal.aborted }));
|
|
72
|
+
const telemetryError = classifyTelemetryError(error);
|
|
73
|
+
const traceId = options.telemetry.selected
|
|
74
|
+
? options.telemetry.traceId
|
|
75
|
+
: undefined;
|
|
76
|
+
options.presenter.error(outcome, {
|
|
77
|
+
json: options.argv.includes("--json"),
|
|
78
|
+
...(traceId ? { traceId } : {})
|
|
79
|
+
});
|
|
80
|
+
await sendFinished(options, outcome.kind === "interrupted"
|
|
81
|
+
? { outcome: "interrupted", error }
|
|
82
|
+
: {
|
|
83
|
+
outcome: "failure",
|
|
84
|
+
error,
|
|
85
|
+
errorCode: outcome.failure.code,
|
|
86
|
+
errorMessage: outcome.failure.message,
|
|
87
|
+
...(telemetryError.httpStatus === undefined
|
|
88
|
+
? {}
|
|
89
|
+
: { httpStatus: telemetryError.httpStatus }),
|
|
90
|
+
...(telemetryError.remoteErrorCode === undefined
|
|
91
|
+
? {}
|
|
92
|
+
: { remoteErrorCode: telemetryError.remoteErrorCode }),
|
|
93
|
+
...(telemetryError.remoteErrorBody === undefined
|
|
94
|
+
? {}
|
|
95
|
+
: { remoteErrorBody: telemetryError.remoteErrorBody })
|
|
96
|
+
});
|
|
97
|
+
return outcome.exitCode;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function checkUpdateNotification(updateNotification, signal) {
|
|
101
|
+
try {
|
|
102
|
+
await updateNotification.check(signal);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Version availability must never change the requested command outcome.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function sendFinished(options, completion) {
|
|
109
|
+
const events = options.telemetry.finish(completion);
|
|
110
|
+
if (events.length > 0)
|
|
111
|
+
await options.telemetrySink.send(events);
|
|
112
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createAccessPolicies } from "../features/auth/access-policy.js";
|
|
6
|
+
import { createLocalCredentialStore } from "../features/auth/credential-store.js";
|
|
7
|
+
import { createAuthUseCases } from "../features/auth/use-cases.js";
|
|
8
|
+
import { createSsoService } from "../features/auth/sso-service.js";
|
|
9
|
+
import { createCreativeAgentAdapter } from "../features/agent/creative-agent-adapter.js";
|
|
10
|
+
import { createDamApiAdapter } from "../features/dam/dam-api-adapter.js";
|
|
11
|
+
import { createDamFileDownloader } from "../features/dam/file-downloader.js";
|
|
12
|
+
import { createDamOperationExecutor } from "../features/dam/operation-executor.js";
|
|
13
|
+
import { createDamRepositoryCatalog } from "../features/dam/repository-catalog.js";
|
|
14
|
+
import { createDamRegisteredUploader } from "../features/dam/registered-uploader.js";
|
|
15
|
+
import { createDamTransientUploader } from "../features/dam/transient-uploader.js";
|
|
16
|
+
import { createDamStorageUploader } from "../features/dam/storage-upload.js";
|
|
17
|
+
import { createDamUseCases } from "../features/dam/use-cases.js";
|
|
18
|
+
import { createEditorSession } from "../features/editor/session.js";
|
|
19
|
+
import { createEditorSessionStateStore } from "../features/editor/session-state.js";
|
|
20
|
+
import { createEditorUseCases } from "../features/editor/use-cases.js";
|
|
21
|
+
import { createObjectStorageUploader } from "../features/dam/object-storage.js";
|
|
22
|
+
import { createAgentUseCases } from "../features/agent/use-cases.js";
|
|
23
|
+
import { createMnsCatalogAdapter } from "../features/tool/mns-catalog-adapter.js";
|
|
24
|
+
import { createToolApiAdapter } from "../features/tool/tool-api-adapter.js";
|
|
25
|
+
import { createToolUseCases } from "../features/tool/use-cases.js";
|
|
26
|
+
import { createOrgUseCases } from "../features/org/use-cases.js";
|
|
27
|
+
import { createOrgService } from "../features/org/org-service.js";
|
|
28
|
+
import { createBrowserOpener } from "../platform/open-browser.js";
|
|
29
|
+
import { createSignedHttpTransport } from "../platform/signed-http-transport.js";
|
|
30
|
+
import { createJsonInputReader } from "../platform/json-input.js";
|
|
31
|
+
import { createOrganizationPrompt } from "../cli/prompt.js";
|
|
32
|
+
import { createPresenter } from "../cli/presenter.js";
|
|
33
|
+
import { createContractValidators } from "./validators.js";
|
|
34
|
+
import { loadBundledSkills } from "../features/skill/bundled-skills.js";
|
|
35
|
+
import { createUpdateService } from "../features/update/update-service.js";
|
|
36
|
+
import { createUpdateNotificationService } from "../features/update/update-notification.js";
|
|
37
|
+
import { classifyTelemetryError } from "../cli/errors.js";
|
|
38
|
+
import { createTelemetryInvocation } from "../telemetry/invocation.js";
|
|
39
|
+
import { createSlsTelemetrySink } from "../telemetry/sls-sink.js";
|
|
40
|
+
const productionEndpoints = {
|
|
41
|
+
orgApi: new URL("https://gdcli.gaoding.com/api"),
|
|
42
|
+
agentApi: new URL("https://gdcli.gaoding.com/api"),
|
|
43
|
+
mnsApi: new URL("https://gdcli.gaoding.com/api"),
|
|
44
|
+
toolApi: new URL("https://gdcli.gaoding.com/api"),
|
|
45
|
+
damApi: new URL("https://gdcli.gaoding.com/api"),
|
|
46
|
+
ssoApi: new URL("https://www.gaoding.com/api/sso"),
|
|
47
|
+
authPageOrigin: new URL("https://www.gaoding.art")
|
|
48
|
+
};
|
|
49
|
+
export function createProductionRuntime(options = {}) {
|
|
50
|
+
const bundledSkills = loadBundledSkills(fileURLToPath(import.meta.url));
|
|
51
|
+
const primarySkill = bundledSkills.find((skill) => skill.skill === "gd-cli");
|
|
52
|
+
if (!primarySkill)
|
|
53
|
+
throw new Error("Bundled gd-cli Skill is missing.");
|
|
54
|
+
const endpoints = options.endpoints ?? productionEndpoints;
|
|
55
|
+
const fetch = options.fetch ?? globalThis.fetch;
|
|
56
|
+
const now = options.now ?? (() => new Date());
|
|
57
|
+
const telemetry = createTelemetryInvocation({
|
|
58
|
+
cliVersion: primarySkill.version,
|
|
59
|
+
now: () => now().getTime(),
|
|
60
|
+
traceIdFactory: () => randomBytes(16).toString("hex"),
|
|
61
|
+
spanIdFactory: () => randomBytes(8).toString("hex"),
|
|
62
|
+
runtime: {
|
|
63
|
+
os: process.platform,
|
|
64
|
+
arch: process.arch,
|
|
65
|
+
nodeMajor: Number.parseInt(process.versions.node, 10)
|
|
66
|
+
},
|
|
67
|
+
classifyError: classifyTelemetryError
|
|
68
|
+
});
|
|
69
|
+
const telemetrySink = createSlsTelemetrySink({ fetch });
|
|
70
|
+
const rawIo = options.io ?? {
|
|
71
|
+
input: process.stdin,
|
|
72
|
+
stdout: process.stdout,
|
|
73
|
+
stderr: process.stderr,
|
|
74
|
+
inputTerminal: process.stdin.isTTY === true,
|
|
75
|
+
stderrTerminal: process.stderr.isTTY === true
|
|
76
|
+
};
|
|
77
|
+
const io = {
|
|
78
|
+
writeOut: (text) => { rawIo.stdout.write(text); },
|
|
79
|
+
writeError: (text) => { rawIo.stderr.write(text); },
|
|
80
|
+
inputTerminal: rawIo.inputTerminal ?? hasTerminal(rawIo.input),
|
|
81
|
+
stderrTerminal: rawIo.stderrTerminal ?? hasTerminal(rawIo.stderr)
|
|
82
|
+
};
|
|
83
|
+
const store = createLocalCredentialStore({
|
|
84
|
+
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
|
|
85
|
+
});
|
|
86
|
+
const orgTransport = createSignedHttpTransport({
|
|
87
|
+
baseUrl: endpoints.orgApi,
|
|
88
|
+
fetch,
|
|
89
|
+
now,
|
|
90
|
+
traceparent: () => telemetry.traceparent()
|
|
91
|
+
});
|
|
92
|
+
const agentTransport = createSignedHttpTransport({
|
|
93
|
+
baseUrl: endpoints.agentApi,
|
|
94
|
+
fetch,
|
|
95
|
+
now,
|
|
96
|
+
traceparent: () => telemetry.traceparent()
|
|
97
|
+
});
|
|
98
|
+
const mnsTransport = createSignedHttpTransport({
|
|
99
|
+
baseUrl: endpoints.mnsApi,
|
|
100
|
+
fetch,
|
|
101
|
+
now,
|
|
102
|
+
traceparent: () => telemetry.traceparent()
|
|
103
|
+
});
|
|
104
|
+
const toolTransport = createSignedHttpTransport({
|
|
105
|
+
baseUrl: endpoints.toolApi,
|
|
106
|
+
fetch,
|
|
107
|
+
now,
|
|
108
|
+
traceparent: () => telemetry.traceparent()
|
|
109
|
+
});
|
|
110
|
+
const damTransport = createSignedHttpTransport({
|
|
111
|
+
baseUrl: endpoints.damApi,
|
|
112
|
+
fetch,
|
|
113
|
+
now,
|
|
114
|
+
channelId: "32",
|
|
115
|
+
traceparent: () => telemetry.traceparent()
|
|
116
|
+
});
|
|
117
|
+
const sso = createSsoService({
|
|
118
|
+
ssoApi: endpoints.ssoApi,
|
|
119
|
+
fetch,
|
|
120
|
+
now
|
|
121
|
+
});
|
|
122
|
+
const org = createOrgUseCases({
|
|
123
|
+
store,
|
|
124
|
+
org: createOrgService({ transport: orgTransport }),
|
|
125
|
+
sso,
|
|
126
|
+
telemetry
|
|
127
|
+
});
|
|
128
|
+
const auth = createAuthUseCases({
|
|
129
|
+
store,
|
|
130
|
+
sso,
|
|
131
|
+
organizationBinder: org,
|
|
132
|
+
authPageOrigin: endpoints.authPageOrigin,
|
|
133
|
+
now,
|
|
134
|
+
telemetry,
|
|
135
|
+
sleep: async (milliseconds, signal) => {
|
|
136
|
+
await delay(milliseconds, undefined, { signal });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const storage = options.objectStorage ?? createObjectStorageUploader({ fetch, now });
|
|
140
|
+
const storageUpload = createDamStorageUploader({
|
|
141
|
+
transport: damTransport,
|
|
142
|
+
storage
|
|
143
|
+
});
|
|
144
|
+
const transientUploader = createDamTransientUploader({ storageUpload });
|
|
145
|
+
const presenter = createPresenter({
|
|
146
|
+
writeOut: io.writeOut,
|
|
147
|
+
writeError: io.writeError
|
|
148
|
+
});
|
|
149
|
+
const browser = createBrowserOpener();
|
|
150
|
+
const validators = createContractValidators();
|
|
151
|
+
const modelCatalog = createMnsCatalogAdapter({ transport: mnsTransport });
|
|
152
|
+
const damApi = createDamApiAdapter({ transport: damTransport });
|
|
153
|
+
const damRepositories = createDamRepositoryCatalog({ transport: damTransport });
|
|
154
|
+
const damOperations = createDamOperationExecutor({
|
|
155
|
+
now: () => now().getTime(),
|
|
156
|
+
sleep: async (milliseconds, signal) => {
|
|
157
|
+
await delay(milliseconds, undefined, { signal });
|
|
158
|
+
},
|
|
159
|
+
annotate: (context) => { telemetry.annotate(context); }
|
|
160
|
+
});
|
|
161
|
+
const dam = createDamUseCases({
|
|
162
|
+
api: damApi,
|
|
163
|
+
repositories: damRepositories,
|
|
164
|
+
storage: storageUpload,
|
|
165
|
+
uploader: createDamRegisteredUploader({
|
|
166
|
+
api: damApi,
|
|
167
|
+
storage: storageUpload,
|
|
168
|
+
warn: (message) => { presenter.warning(message); },
|
|
169
|
+
now,
|
|
170
|
+
telemetry
|
|
171
|
+
}),
|
|
172
|
+
downloader: createDamFileDownloader({ fetch }),
|
|
173
|
+
operations: damOperations,
|
|
174
|
+
sleep: async (milliseconds, signal) => {
|
|
175
|
+
await delay(milliseconds, undefined, { signal });
|
|
176
|
+
},
|
|
177
|
+
validate: {
|
|
178
|
+
repositoryList: validators.damRepositoryListOutput,
|
|
179
|
+
list: validators.damListOutput,
|
|
180
|
+
search: validators.damSearchOutput,
|
|
181
|
+
folderList: validators.damFolderListOutput,
|
|
182
|
+
tagList: validators.damTagListOutput,
|
|
183
|
+
download: validators.damDownloadOutput,
|
|
184
|
+
rename: validators.damRenameOutput,
|
|
185
|
+
move: validators.damMoveOutput,
|
|
186
|
+
copy: validators.damCopyOutput,
|
|
187
|
+
get: validators.damGetOutput,
|
|
188
|
+
upload: validators.damUploadOutput,
|
|
189
|
+
delete: validators.damDeleteOutput
|
|
190
|
+
},
|
|
191
|
+
telemetry
|
|
192
|
+
});
|
|
193
|
+
const agent = createAgentUseCases({
|
|
194
|
+
catalog: modelCatalog,
|
|
195
|
+
uploader: transientUploader,
|
|
196
|
+
completion: createCreativeAgentAdapter({
|
|
197
|
+
transport: agentTransport,
|
|
198
|
+
idFactory: randomUUID,
|
|
199
|
+
telemetry
|
|
200
|
+
}),
|
|
201
|
+
warn: (message) => { presenter.warning(message); },
|
|
202
|
+
telemetry
|
|
203
|
+
});
|
|
204
|
+
const tool = createToolUseCases({
|
|
205
|
+
catalog: modelCatalog,
|
|
206
|
+
execution: createToolApiAdapter({ transport: toolTransport, telemetry }),
|
|
207
|
+
uploader: transientUploader,
|
|
208
|
+
warn: (message) => { presenter.warning(message); },
|
|
209
|
+
telemetry
|
|
210
|
+
});
|
|
211
|
+
const editor = createEditorUseCases({
|
|
212
|
+
session: createEditorSession({
|
|
213
|
+
store: createEditorSessionStateStore({
|
|
214
|
+
...(options.homeDirectory === undefined
|
|
215
|
+
? {}
|
|
216
|
+
: { homeDirectory: options.homeDirectory })
|
|
217
|
+
}),
|
|
218
|
+
browser,
|
|
219
|
+
defaultCreateUrl: new URL("https://www.gaoding.art/editor/canvas?mode=create&type=board"),
|
|
220
|
+
workUrl: new URL("https://www.gaoding.art/editor/canvas"),
|
|
221
|
+
...(options.homeDirectory === undefined
|
|
222
|
+
? {}
|
|
223
|
+
: { homeDirectory: options.homeDirectory })
|
|
224
|
+
}),
|
|
225
|
+
validate: {
|
|
226
|
+
connect: validators.editorConnectOutput,
|
|
227
|
+
disconnect: validators.editorDisconnectOutput,
|
|
228
|
+
snapshot: validators.editorSnapshotOutput,
|
|
229
|
+
apply: validators.editorApplyOutput,
|
|
230
|
+
screenshot: validators.editorScreenshotOutput,
|
|
231
|
+
save: validators.editorSaveOutput
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const update = {
|
|
235
|
+
run(signal) {
|
|
236
|
+
const packageRoot = dirname(dirname(primarySkill.sourceDirectory));
|
|
237
|
+
return createUpdateService({
|
|
238
|
+
currentVersion: primarySkill.version,
|
|
239
|
+
packageRoot,
|
|
240
|
+
bundledSkills,
|
|
241
|
+
fetch,
|
|
242
|
+
telemetry,
|
|
243
|
+
...(process.argv[1] ? { binaryPath: process.argv[1] } : {}),
|
|
244
|
+
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
|
|
245
|
+
}).run(signal);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const updateNotification = createUpdateNotificationService({
|
|
249
|
+
currentVersion: primarySkill.version,
|
|
250
|
+
fetch,
|
|
251
|
+
now,
|
|
252
|
+
...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {}),
|
|
253
|
+
...(options.env ? { env: options.env } : {}),
|
|
254
|
+
notify: (message) => { presenter.notice(message); }
|
|
255
|
+
});
|
|
256
|
+
return {
|
|
257
|
+
version: primarySkill.version,
|
|
258
|
+
telemetry,
|
|
259
|
+
telemetrySink,
|
|
260
|
+
accessPolicies: createAccessPolicies({
|
|
261
|
+
store,
|
|
262
|
+
now,
|
|
263
|
+
refreshCurrentOrganization: org.refreshCurrentOrganization
|
|
264
|
+
}),
|
|
265
|
+
auth,
|
|
266
|
+
org,
|
|
267
|
+
agent,
|
|
268
|
+
editor,
|
|
269
|
+
dam,
|
|
270
|
+
tool,
|
|
271
|
+
update,
|
|
272
|
+
updateNotification,
|
|
273
|
+
jsonInput: createJsonInputReader({
|
|
274
|
+
cwd: process.cwd(),
|
|
275
|
+
stdin: rawIo.input
|
|
276
|
+
}),
|
|
277
|
+
validators,
|
|
278
|
+
presenter,
|
|
279
|
+
prompt: createOrganizationPrompt({
|
|
280
|
+
input: rawIo.input,
|
|
281
|
+
output: rawIo.stderr
|
|
282
|
+
}),
|
|
283
|
+
browser,
|
|
284
|
+
now,
|
|
285
|
+
io
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function hasTerminal(value) {
|
|
289
|
+
return "isTTY" in value && value.isTTY === true;
|
|
290
|
+
}
|