gaoding-cli 1.0.0-alpha.10

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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/contracts/operations/agent.send/input.schema.json +354 -0
  4. package/contracts/operations/agent.send/output.schema.json +271 -0
  5. package/contracts/operations/auth.status/input.schema.json +7 -0
  6. package/contracts/operations/auth.status/output.schema.json +132 -0
  7. package/contracts/operations/dam.delete/input.schema.json +23 -0
  8. package/contracts/operations/dam.delete/output.schema.json +6 -0
  9. package/contracts/operations/dam.get/input.schema.json +16 -0
  10. package/contracts/operations/dam.get/output.schema.json +46 -0
  11. package/contracts/operations/dam.list/input.schema.json +44 -0
  12. package/contracts/operations/dam.list/output.schema.json +71 -0
  13. package/contracts/operations/dam.search/input.schema.json +46 -0
  14. package/contracts/operations/dam.search/output.schema.json +71 -0
  15. package/contracts/operations/dam.upload/input.schema.json +31 -0
  16. package/contracts/operations/dam.upload/output.schema.json +46 -0
  17. package/contracts/operations/editor.apply/input.schema.json +134 -0
  18. package/contracts/operations/editor.apply/output.schema.json +15 -0
  19. package/contracts/operations/editor.connect/input.schema.json +15 -0
  20. package/contracts/operations/editor.connect/output.schema.json +17 -0
  21. package/contracts/operations/editor.disconnect/input.schema.json +8 -0
  22. package/contracts/operations/editor.disconnect/output.schema.json +14 -0
  23. package/contracts/operations/editor.save/input.schema.json +8 -0
  24. package/contracts/operations/editor.save/output.schema.json +23 -0
  25. package/contracts/operations/editor.screenshot/input.schema.json +8 -0
  26. package/contracts/operations/editor.screenshot/output.schema.json +16 -0
  27. package/contracts/operations/editor.snapshot/input.schema.json +8 -0
  28. package/contracts/operations/editor.snapshot/output.schema.json +113 -0
  29. package/contracts/operations/model.get/input.schema.json +18 -0
  30. package/contracts/operations/model.get/output.schema.json +190 -0
  31. package/contracts/operations/model.list/input.schema.json +15 -0
  32. package/contracts/operations/model.list/output.schema.json +111 -0
  33. package/contracts/operations/org.current/input.schema.json +7 -0
  34. package/contracts/operations/org.current/output.schema.json +49 -0
  35. package/contracts/operations/org.list/input.schema.json +7 -0
  36. package/contracts/operations/org.list/output.schema.json +71 -0
  37. package/contracts/operations/tool.call/input.schema.json +35 -0
  38. package/contracts/operations/tool.call/output.schema.json +129 -0
  39. package/contracts/operations/tool.list/input.schema.json +7 -0
  40. package/contracts/operations/tool.list/output.schema.json +45 -0
  41. package/dist/bin/gd-cli.js +38 -0
  42. package/dist/bin/postinstall.js +42 -0
  43. package/dist/src/bootstrap/create-cli.js +55 -0
  44. package/dist/src/bootstrap/create-runtime.js +222 -0
  45. package/dist/src/bootstrap/validators.js +118 -0
  46. package/dist/src/cli/action-binding.js +63 -0
  47. package/dist/src/cli/agent-commands.js +39 -0
  48. package/dist/src/cli/auth-commands.js +47 -0
  49. package/dist/src/cli/dam-commands.js +207 -0
  50. package/dist/src/cli/editor-commands.js +73 -0
  51. package/dist/src/cli/errors.js +90 -0
  52. package/dist/src/cli/model-commands.js +47 -0
  53. package/dist/src/cli/org-commands.js +52 -0
  54. package/dist/src/cli/presenter.js +80 -0
  55. package/dist/src/cli/prompt.js +30 -0
  56. package/dist/src/cli/tool-commands.js +65 -0
  57. package/dist/src/cli/update-command.js +12 -0
  58. package/dist/src/contracts/schema.js +4 -0
  59. package/dist/src/features/agent/creative-agent-adapter.js +31 -0
  60. package/dist/src/features/agent/creative-protocol.js +324 -0
  61. package/dist/src/features/agent/creative-stream.js +127 -0
  62. package/dist/src/features/agent/use-cases.js +113 -0
  63. package/dist/src/features/auth/access-policy.js +101 -0
  64. package/dist/src/features/auth/credential-store.js +62 -0
  65. package/dist/src/features/auth/sso-service.js +179 -0
  66. package/dist/src/features/auth/state.js +129 -0
  67. package/dist/src/features/auth/use-cases.js +106 -0
  68. package/dist/src/features/dam/asset-projection.js +270 -0
  69. package/dist/src/features/dam/dam-api-adapter.js +206 -0
  70. package/dist/src/features/dam/object-storage.js +191 -0
  71. package/dist/src/features/dam/registered-uploader.js +224 -0
  72. package/dist/src/features/dam/storage-upload.js +141 -0
  73. package/dist/src/features/dam/transient-uploader.js +17 -0
  74. package/dist/src/features/dam/use-cases.js +151 -0
  75. package/dist/src/features/editor/bridge-client.js +96 -0
  76. package/dist/src/features/editor/bridge-process.js +222 -0
  77. package/dist/src/features/editor/bridge-server.js +311 -0
  78. package/dist/src/features/editor/protocol.js +1 -0
  79. package/dist/src/features/editor/session-state.js +78 -0
  80. package/dist/src/features/editor/session.js +193 -0
  81. package/dist/src/features/editor/use-cases.js +61 -0
  82. package/dist/src/features/org/org-service.js +76 -0
  83. package/dist/src/features/org/use-cases.js +140 -0
  84. package/dist/src/features/skill/bundled-skills.js +55 -0
  85. package/dist/src/features/skill/installer.js +265 -0
  86. package/dist/src/features/tool/catalog.js +79 -0
  87. package/dist/src/features/tool/dynamic-schema.js +96 -0
  88. package/dist/src/features/tool/mns-catalog-adapter.js +262 -0
  89. package/dist/src/features/tool/tool-api-adapter.js +200 -0
  90. package/dist/src/features/tool/use-cases.js +126 -0
  91. package/dist/src/features/update/update-service.js +194 -0
  92. package/dist/src/platform/json-input.js +64 -0
  93. package/dist/src/platform/local-json-file.js +59 -0
  94. package/dist/src/platform/open-browser.js +8 -0
  95. package/dist/src/platform/redact.js +80 -0
  96. package/dist/src/platform/safe-upload-file.js +146 -0
  97. package/dist/src/platform/signature.js +19 -0
  98. package/dist/src/platform/signed-http-transport.js +109 -0
  99. package/dist/src/platform/url-safety.js +100 -0
  100. package/package.json +56 -0
  101. package/skills/gd-cli/SKILL.md +15 -0
  102. package/skills/gd-cli/references/auth-org.md +9 -0
  103. package/skills/gd-cli/references/creation.md +38 -0
  104. package/skills/gd-cli/references/dam.md +20 -0
  105. package/skills/gd-cli/references/editor.md +12 -0
  106. package/skills/gd-cli/references/errors.md +10 -0
  107. package/skills/gd-cli/references/update.md +11 -0
@@ -0,0 +1,222 @@
1
+ import { 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 { createDamRegisteredUploader } from "../features/dam/registered-uploader.js";
12
+ import { createDamTransientUploader } from "../features/dam/transient-uploader.js";
13
+ import { createDamStorageUploader } from "../features/dam/storage-upload.js";
14
+ import { createDamUseCases } from "../features/dam/use-cases.js";
15
+ import { createEditorSession } from "../features/editor/session.js";
16
+ import { createEditorSessionStateStore } from "../features/editor/session-state.js";
17
+ import { createEditorUseCases } from "../features/editor/use-cases.js";
18
+ import { createObjectStorageUploader } from "../features/dam/object-storage.js";
19
+ import { createAgentUseCases } from "../features/agent/use-cases.js";
20
+ import { createMnsCatalogAdapter } from "../features/tool/mns-catalog-adapter.js";
21
+ import { createToolApiAdapter } from "../features/tool/tool-api-adapter.js";
22
+ import { createToolUseCases } from "../features/tool/use-cases.js";
23
+ import { createOrgUseCases } from "../features/org/use-cases.js";
24
+ import { createOrgService } from "../features/org/org-service.js";
25
+ import { createBrowserOpener } from "../platform/open-browser.js";
26
+ import { createSignedHttpTransport } from "../platform/signed-http-transport.js";
27
+ import { createJsonInputReader } from "../platform/json-input.js";
28
+ import { createOrganizationPrompt } from "../cli/prompt.js";
29
+ import { createPresenter } from "../cli/presenter.js";
30
+ import { createContractValidators } from "./validators.js";
31
+ import { loadBundledSkills } from "../features/skill/bundled-skills.js";
32
+ import { createUpdateService } from "../features/update/update-service.js";
33
+ const productionEndpoints = {
34
+ orgApi: new URL("https://gdcli.gaoding.com/api"),
35
+ agentApi: new URL("https://gdcli.gaoding.com/api"),
36
+ mnsApi: new URL("https://gdcli.gaoding.com/api"),
37
+ toolApi: new URL("https://gdcli.gaoding.com/api"),
38
+ damApi: new URL("https://gdcli.gaoding.com/api"),
39
+ ssoApi: new URL("https://www.gaoding.com/api/sso"),
40
+ authPageOrigin: new URL("https://www.gaoding.com")
41
+ };
42
+ export function createProductionRuntime(options = {}) {
43
+ const bundledSkills = loadBundledSkills(fileURLToPath(import.meta.url));
44
+ const primarySkill = bundledSkills.find((skill) => skill.skill === "gd-cli");
45
+ if (!primarySkill)
46
+ throw new Error("Bundled gd-cli Skill is missing.");
47
+ const endpoints = options.endpoints ?? productionEndpoints;
48
+ const fetch = options.fetch ?? globalThis.fetch;
49
+ const now = options.now ?? (() => new Date());
50
+ const rawIo = options.io ?? {
51
+ input: process.stdin,
52
+ stdout: process.stdout,
53
+ stderr: process.stderr,
54
+ inputTerminal: process.stdin.isTTY === true,
55
+ stderrTerminal: process.stderr.isTTY === true
56
+ };
57
+ const io = {
58
+ writeOut: (text) => { rawIo.stdout.write(text); },
59
+ writeError: (text) => { rawIo.stderr.write(text); },
60
+ inputTerminal: rawIo.inputTerminal ?? hasTerminal(rawIo.input),
61
+ stderrTerminal: rawIo.stderrTerminal ?? hasTerminal(rawIo.stderr)
62
+ };
63
+ const store = createLocalCredentialStore({
64
+ ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
65
+ });
66
+ const orgTransport = createSignedHttpTransport({
67
+ baseUrl: endpoints.orgApi,
68
+ fetch,
69
+ now
70
+ });
71
+ const agentTransport = createSignedHttpTransport({
72
+ baseUrl: endpoints.agentApi,
73
+ fetch,
74
+ now
75
+ });
76
+ const mnsTransport = createSignedHttpTransport({
77
+ baseUrl: endpoints.mnsApi,
78
+ fetch,
79
+ now
80
+ });
81
+ const toolTransport = createSignedHttpTransport({
82
+ baseUrl: endpoints.toolApi,
83
+ fetch,
84
+ now
85
+ });
86
+ const damTransport = createSignedHttpTransport({
87
+ baseUrl: endpoints.damApi,
88
+ fetch,
89
+ now,
90
+ channelId: "32"
91
+ });
92
+ const sso = createSsoService({
93
+ ssoApi: endpoints.ssoApi,
94
+ fetch,
95
+ now
96
+ });
97
+ const org = createOrgUseCases({
98
+ store,
99
+ org: createOrgService({ transport: orgTransport }),
100
+ sso
101
+ });
102
+ const auth = createAuthUseCases({
103
+ store,
104
+ sso,
105
+ organizationBinder: org,
106
+ authPageOrigin: endpoints.authPageOrigin,
107
+ now,
108
+ sleep: async (milliseconds, signal) => {
109
+ await delay(milliseconds, undefined, { signal });
110
+ }
111
+ });
112
+ const storage = options.objectStorage ?? createObjectStorageUploader({ fetch, now });
113
+ const storageUpload = createDamStorageUploader({
114
+ transport: damTransport,
115
+ storage
116
+ });
117
+ const transientUploader = createDamTransientUploader({ storageUpload });
118
+ const presenter = createPresenter({
119
+ writeOut: io.writeOut,
120
+ writeError: io.writeError
121
+ });
122
+ const browser = createBrowserOpener();
123
+ const validators = createContractValidators();
124
+ const damApi = createDamApiAdapter({ transport: damTransport });
125
+ const dam = createDamUseCases({
126
+ api: damApi,
127
+ storage: storageUpload,
128
+ uploader: createDamRegisteredUploader({
129
+ api: damApi,
130
+ storage: storageUpload,
131
+ warn: (message) => { presenter.warning(message); },
132
+ now
133
+ }),
134
+ validate: {
135
+ list: validators.damListOutput,
136
+ search: validators.damSearchOutput,
137
+ get: validators.damGetOutput,
138
+ upload: validators.damUploadOutput,
139
+ delete: validators.damDeleteOutput
140
+ }
141
+ });
142
+ const agent = createAgentUseCases({
143
+ uploader: transientUploader,
144
+ completion: createCreativeAgentAdapter({
145
+ transport: agentTransport,
146
+ idFactory: randomUUID
147
+ })
148
+ });
149
+ const tool = createToolUseCases({
150
+ catalog: createMnsCatalogAdapter({ transport: mnsTransport }),
151
+ execution: createToolApiAdapter({ transport: toolTransport }),
152
+ uploader: transientUploader,
153
+ warn: (message) => { presenter.warning(message); }
154
+ });
155
+ const editor = createEditorUseCases({
156
+ session: createEditorSession({
157
+ store: createEditorSessionStateStore({
158
+ ...(options.homeDirectory === undefined
159
+ ? {}
160
+ : { homeDirectory: options.homeDirectory })
161
+ }),
162
+ browser,
163
+ defaultCreateUrl: new URL("https://www.gaoding.art/editor/canvas?mode=create&type=board"),
164
+ workUrl: new URL("https://www.gaoding.art/editor/canvas"),
165
+ ...(options.homeDirectory === undefined
166
+ ? {}
167
+ : { homeDirectory: options.homeDirectory })
168
+ }),
169
+ validate: {
170
+ connect: validators.editorConnectOutput,
171
+ disconnect: validators.editorDisconnectOutput,
172
+ snapshot: validators.editorSnapshotOutput,
173
+ apply: validators.editorApplyOutput,
174
+ screenshot: validators.editorScreenshotOutput,
175
+ save: validators.editorSaveOutput
176
+ }
177
+ });
178
+ const update = {
179
+ run(signal) {
180
+ const packageRoot = dirname(dirname(primarySkill.sourceDirectory));
181
+ return createUpdateService({
182
+ currentVersion: primarySkill.version,
183
+ packageRoot,
184
+ bundledSkills,
185
+ fetch,
186
+ ...(process.argv[1] ? { binaryPath: process.argv[1] } : {}),
187
+ ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
188
+ }).run(signal);
189
+ }
190
+ };
191
+ return {
192
+ version: primarySkill.version,
193
+ accessPolicies: createAccessPolicies({
194
+ store,
195
+ now,
196
+ refreshCurrentOrganization: org.refreshCurrentOrganization
197
+ }),
198
+ auth,
199
+ org,
200
+ agent,
201
+ editor,
202
+ dam,
203
+ tool,
204
+ update,
205
+ jsonInput: createJsonInputReader({
206
+ cwd: process.cwd(),
207
+ stdin: rawIo.input
208
+ }),
209
+ validators,
210
+ presenter,
211
+ prompt: createOrganizationPrompt({
212
+ input: rawIo.input,
213
+ output: rawIo.stderr
214
+ }),
215
+ browser,
216
+ now,
217
+ io
218
+ };
219
+ }
220
+ function hasTerminal(value) {
221
+ return "isTTY" in value && value.isTTY === true;
222
+ }
@@ -0,0 +1,118 @@
1
+ import { Ajv2020 } from "ajv/dist/2020.js";
2
+ import addFormatsImport, {} from "ajv-formats";
3
+ import { contractSchema } from "../contracts/schema.js";
4
+ const agentSendInputSchema = contractSchema("agent.send", "input");
5
+ const agentSendOutputSchema = contractSchema("agent.send", "output");
6
+ const authStatusSchema = contractSchema("auth.status", "output");
7
+ const damDeleteInputSchema = contractSchema("dam.delete", "input");
8
+ const damDeleteOutputSchema = contractSchema("dam.delete", "output");
9
+ const damGetInputSchema = contractSchema("dam.get", "input");
10
+ const damGetOutputSchema = contractSchema("dam.get", "output");
11
+ const damListInputSchema = contractSchema("dam.list", "input");
12
+ const damListOutputSchema = contractSchema("dam.list", "output");
13
+ const damSearchInputSchema = contractSchema("dam.search", "input");
14
+ const damSearchOutputSchema = contractSchema("dam.search", "output");
15
+ const damUploadInputSchema = contractSchema("dam.upload", "input");
16
+ const damUploadOutputSchema = contractSchema("dam.upload", "output");
17
+ const editorApplyInputSchema = contractSchema("editor.apply", "input");
18
+ const editorApplyOutputSchema = contractSchema("editor.apply", "output");
19
+ const editorConnectInputSchema = contractSchema("editor.connect", "input");
20
+ const editorConnectOutputSchema = contractSchema("editor.connect", "output");
21
+ const editorDisconnectOutputSchema = contractSchema("editor.disconnect", "output");
22
+ const editorSaveOutputSchema = contractSchema("editor.save", "output");
23
+ const editorScreenshotOutputSchema = contractSchema("editor.screenshot", "output");
24
+ const editorSnapshotOutputSchema = contractSchema("editor.snapshot", "output");
25
+ const orgCurrentSchema = contractSchema("org.current", "output");
26
+ const orgListSchema = contractSchema("org.list", "output");
27
+ const modelGetInputSchema = contractSchema("model.get", "input");
28
+ const modelGetOutputSchema = contractSchema("model.get", "output");
29
+ const modelListInputSchema = contractSchema("model.list", "input");
30
+ const modelListOutputSchema = contractSchema("model.list", "output");
31
+ const toolCallInputSchema = contractSchema("tool.call", "input");
32
+ const toolCallOutputSchema = contractSchema("tool.call", "output");
33
+ const toolListOutputSchema = contractSchema("tool.list", "output");
34
+ export class InputContractError extends Error {
35
+ constructor() {
36
+ super("输入不符合命令契约。");
37
+ this.name = "InputContractError";
38
+ }
39
+ }
40
+ export class OutputContractError extends Error {
41
+ constructor() {
42
+ super("命令结果不符合公开契约。");
43
+ this.name = "OutputContractError";
44
+ }
45
+ }
46
+ export function createContractValidators() {
47
+ const ajv = new Ajv2020({ allErrors: true, strict: true });
48
+ const addFormats = addFormatsImport;
49
+ addFormats(ajv);
50
+ const agentSendInput = ajv.compile(agentSendInputSchema);
51
+ const agentSendOutput = ajv.compile(agentSendOutputSchema);
52
+ const authStatus = ajv.compile(authStatusSchema);
53
+ const damListInput = ajv.compile(damListInputSchema);
54
+ const damListOutput = ajv.compile(damListOutputSchema);
55
+ const damSearchInput = ajv.compile(damSearchInputSchema);
56
+ const damSearchOutput = ajv.compile(damSearchOutputSchema);
57
+ const damGetInput = ajv.compile(damGetInputSchema);
58
+ const damGetOutput = ajv.compile(damGetOutputSchema);
59
+ const damUploadInput = ajv.compile(damUploadInputSchema);
60
+ const damUploadOutput = ajv.compile(damUploadOutputSchema);
61
+ const damDeleteInput = ajv.compile(damDeleteInputSchema);
62
+ const damDeleteOutput = ajv.compile(damDeleteOutputSchema);
63
+ const editorConnectInput = ajv.compile(editorConnectInputSchema);
64
+ const editorConnectOutput = ajv.compile(editorConnectOutputSchema);
65
+ const editorDisconnectOutput = ajv.compile(editorDisconnectOutputSchema);
66
+ const editorSnapshotOutput = ajv.compile(editorSnapshotOutputSchema);
67
+ const editorApplyInput = ajv.compile(editorApplyInputSchema);
68
+ const editorApplyOutput = ajv.compile(editorApplyOutputSchema);
69
+ const editorScreenshotOutput = ajv.compile(editorScreenshotOutputSchema);
70
+ const editorSaveOutput = ajv.compile(editorSaveOutputSchema);
71
+ const orgList = ajv.compile(orgListSchema);
72
+ const orgCurrent = ajv.compile(orgCurrentSchema);
73
+ const toolListOutput = ajv.compile(toolListOutputSchema);
74
+ const modelListInput = ajv.compile(modelListInputSchema);
75
+ const modelListOutput = ajv.compile(modelListOutputSchema);
76
+ const modelGetInput = ajv.compile(modelGetInputSchema);
77
+ const modelGetOutput = ajv.compile(modelGetOutputSchema);
78
+ const toolCallInput = ajv.compile(toolCallInputSchema);
79
+ const toolCallOutput = ajv.compile(toolCallOutputSchema);
80
+ return {
81
+ agentSendInput: assertion(agentSendInput, InputContractError),
82
+ agentSendOutput: assertion(agentSendOutput, OutputContractError),
83
+ authStatus: assertion(authStatus, OutputContractError),
84
+ damListInput: assertion(damListInput, InputContractError),
85
+ damListOutput: assertion(damListOutput, OutputContractError),
86
+ damSearchInput: assertion(damSearchInput, InputContractError),
87
+ damSearchOutput: assertion(damSearchOutput, OutputContractError),
88
+ damGetInput: assertion(damGetInput, InputContractError),
89
+ damGetOutput: assertion(damGetOutput, OutputContractError),
90
+ damUploadInput: assertion(damUploadInput, InputContractError),
91
+ damUploadOutput: assertion(damUploadOutput, OutputContractError),
92
+ damDeleteInput: assertion(damDeleteInput, InputContractError),
93
+ damDeleteOutput: assertion(damDeleteOutput, OutputContractError),
94
+ editorConnectInput: assertion(editorConnectInput, InputContractError),
95
+ editorConnectOutput: assertion(editorConnectOutput, OutputContractError),
96
+ editorDisconnectOutput: assertion(editorDisconnectOutput, OutputContractError),
97
+ editorSnapshotOutput: assertion(editorSnapshotOutput, OutputContractError),
98
+ editorApplyInput: assertion(editorApplyInput, InputContractError),
99
+ editorApplyOutput: assertion(editorApplyOutput, OutputContractError),
100
+ editorScreenshotOutput: assertion(editorScreenshotOutput, OutputContractError),
101
+ editorSaveOutput: assertion(editorSaveOutput, OutputContractError),
102
+ orgList: assertion(orgList, OutputContractError),
103
+ orgCurrent: assertion(orgCurrent, OutputContractError),
104
+ toolListOutput: assertion(toolListOutput, OutputContractError),
105
+ modelListInput: assertion(modelListInput, InputContractError),
106
+ modelListOutput: assertion(modelListOutput, OutputContractError),
107
+ modelGetInput: assertion(modelGetInput, InputContractError),
108
+ modelGetOutput: assertion(modelGetOutput, OutputContractError),
109
+ toolCallInput: assertion(toolCallInput, InputContractError),
110
+ toolCallOutput: assertion(toolCallOutput, OutputContractError)
111
+ };
112
+ }
113
+ function assertion(validate, ErrorType) {
114
+ return (value) => {
115
+ if (!validate(value))
116
+ throw new ErrorType();
117
+ };
118
+ }
@@ -0,0 +1,63 @@
1
+ const environments = new WeakMap();
2
+ const boundPolicies = new WeakMap();
3
+ export function configureActionEnvironment(program, environment) {
4
+ environments.set(program, environment);
5
+ }
6
+ export function bindAction(command, policy, handler) {
7
+ if (boundPolicies.has(command))
8
+ throw new Error(`Action already bound: ${commandPath(command)}`);
9
+ boundPolicies.set(command, policy);
10
+ command.action(async () => {
11
+ const environment = environments.get(rootCommand(command));
12
+ if (!environment)
13
+ throw new Error("CLI action environment is missing.");
14
+ const context = await environment.policies[policy].authorize(environment.signal);
15
+ if (context.policy !== policy)
16
+ throw new Error("Access policy returned the wrong context.");
17
+ await handler(context, environment.signal);
18
+ });
19
+ }
20
+ export function bindPreparedAction(command, policy, prepare, run) {
21
+ if (boundPolicies.has(command))
22
+ throw new Error(`Action already bound: ${commandPath(command)}`);
23
+ boundPolicies.set(command, policy);
24
+ command.action(async () => {
25
+ const environment = environments.get(rootCommand(command));
26
+ if (!environment)
27
+ throw new Error("CLI action environment is missing.");
28
+ const prepared = await prepare(environment.signal);
29
+ if (prepared.handled)
30
+ return;
31
+ const context = await environment.policies[policy].authorize(environment.signal);
32
+ if (context.policy !== policy)
33
+ throw new Error("Access policy returned the wrong context.");
34
+ await run(context, prepared.input, environment.signal);
35
+ });
36
+ }
37
+ export function assertAllLeafCommandsBound(program) {
38
+ for (const command of leafCommands(program)) {
39
+ if (!boundPolicies.has(command)) {
40
+ throw new Error(`Leaf command is missing an access policy: ${commandPath(command)}`);
41
+ }
42
+ }
43
+ }
44
+ function leafCommands(command) {
45
+ if (command.commands.length === 0)
46
+ return [command];
47
+ return command.commands.flatMap(leafCommands);
48
+ }
49
+ function rootCommand(command) {
50
+ let current = command;
51
+ while (current.parent)
52
+ current = current.parent;
53
+ return current;
54
+ }
55
+ function commandPath(command) {
56
+ const names = [];
57
+ let current = command;
58
+ while (current) {
59
+ names.unshift(current.name());
60
+ current = current.parent;
61
+ }
62
+ return names.join(" ");
63
+ }
@@ -0,0 +1,39 @@
1
+ import { contractSchema } from "../contracts/schema.js";
2
+ import { bindPreparedAction } from "./action-binding.js";
3
+ import { CliUsageError } from "./errors.js";
4
+ const agentSendInputSchema = contractSchema("agent.send", "input");
5
+ export function registerAgentCommands(program, runtime) {
6
+ const agent = program.command("agent")
7
+ .description("稿定 Agent")
8
+ .helpCommand(false);
9
+ const send = agent.command("send")
10
+ .description("发送结构化创作消息")
11
+ .option("--schema", "输出输入 Schema")
12
+ .option("--input <file|->", "从文件或标准输入读取 JSON")
13
+ .allowExcessArguments(false);
14
+ bindPreparedAction(send, "organization", async (signal) => {
15
+ signal.throwIfAborted();
16
+ const options = send.opts();
17
+ const modes = Number(options.schema === true) + Number(options.input !== undefined);
18
+ if (modes !== 1)
19
+ throw new CliUsageError();
20
+ if (options.schema === true) {
21
+ runtime.io.writeOut(`${JSON.stringify(agentSendInputSchema)}\n`);
22
+ return { handled: true };
23
+ }
24
+ const input = await runtime.jsonInput.read(options.input, signal);
25
+ runtime.validators.agentSendInput(input);
26
+ return { handled: false, input };
27
+ }, async (context, input, signal) => {
28
+ const result = await runtime.agent.send({
29
+ input,
30
+ access: {
31
+ credential: context.state.credential,
32
+ organizationId: context.state.organization.id
33
+ },
34
+ signal
35
+ });
36
+ runtime.validators.agentSendOutput(result);
37
+ runtime.io.writeOut(`${JSON.stringify(result)}\n`);
38
+ });
39
+ }
@@ -0,0 +1,47 @@
1
+ import { bindAction } from "./action-binding.js";
2
+ import { authStatusView } from "./presenter.js";
3
+ export function registerAuthCommands(program, runtime) {
4
+ const auth = program.command("auth")
5
+ .description("登录与本机凭证")
6
+ .helpCommand(false);
7
+ const login = leaf(auth.command("login"))
8
+ .description("登录稿定")
9
+ .option("--no-browser", "不自动打开浏览器");
10
+ bindAction(login, "none", async (_context, signal) => {
11
+ const result = await runtime.auth.login({
12
+ noBrowser: login.opts().browser === false,
13
+ signal,
14
+ interaction: {
15
+ showAuthorization: (url) => runtime.presenter.authorization({
16
+ url,
17
+ terminal: runtime.io.stderrTerminal
18
+ }),
19
+ openBrowser: (url) => runtime.browser.open(url),
20
+ warn: (message) => runtime.presenter.warning(message)
21
+ }
22
+ });
23
+ runtime.presenter.success(result.status === "already_logged_in" ? "已登录。" : "登录成功。");
24
+ if (result.status === "already_logged_in" && !result.organizationSelected) {
25
+ runtime.presenter.warning("尚未选择组织,请执行 gd-cli org switch。");
26
+ }
27
+ });
28
+ const status = leaf(auth.command("status"))
29
+ .description("查看登录状态")
30
+ .option("--json", "输出 JSON");
31
+ bindAction(status, "none", async () => {
32
+ const result = await runtime.auth.status({ now: runtime.now() });
33
+ runtime.validators.authStatus(result);
34
+ runtime.presenter.result(result, {
35
+ json: status.opts().json === true,
36
+ view: authStatusView
37
+ });
38
+ });
39
+ const logout = leaf(auth.command("logout")).description("退出登录");
40
+ bindAction(logout, "none", async () => {
41
+ await runtime.auth.logout();
42
+ runtime.presenter.success("已退出登录。");
43
+ });
44
+ }
45
+ function leaf(command) {
46
+ return command.allowExcessArguments(false);
47
+ }