@gaoding/cli 1.1.0 → 1.2.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.
Files changed (38) hide show
  1. package/dist/bin/gd-cli.js +2 -1
  2. package/dist/bin/insmind-cli.js +60 -0
  3. package/dist/bin/postinstall.js +1 -1
  4. package/dist/src/bootstrap/create-cli.js +14 -4
  5. package/dist/src/bootstrap/create-runtime.js +88 -30
  6. package/dist/src/bootstrap/validators.js +9 -5
  7. package/dist/src/cli/agent-commands.js +5 -4
  8. package/dist/src/cli/auth-commands.js +13 -10
  9. package/dist/src/cli/credits-command.js +23 -0
  10. package/dist/src/cli/dam-commands.js +70 -69
  11. package/dist/src/cli/editor-commands.js +12 -11
  12. package/dist/src/cli/errors.js +49 -9
  13. package/dist/src/cli/model-commands.js +6 -5
  14. package/dist/src/cli/presenter.js +24 -6
  15. package/dist/src/cli/tool-commands.js +7 -6
  16. package/dist/src/cli/update-command.js +4 -3
  17. package/dist/src/features/auth/credential-store.js +1 -1
  18. package/dist/src/features/auth/sso-service.js +3 -1
  19. package/dist/src/features/auth/use-cases.js +38 -12
  20. package/dist/src/features/credits/use-cases.js +52 -0
  21. package/dist/src/features/dam/storage-upload.js +1 -1
  22. package/dist/src/features/editor/bridge-process.js +11 -4
  23. package/dist/src/features/editor/session-state.js +1 -1
  24. package/dist/src/features/editor/session.js +14 -8
  25. package/dist/src/features/org/use-cases.js +7 -0
  26. package/dist/src/features/skill/bundled-skills.js +13 -5
  27. package/dist/src/features/tool/catalog.js +13 -13
  28. package/dist/src/features/tool/use-cases.js +3 -3
  29. package/dist/src/features/update/latest-version.js +2 -2
  30. package/dist/src/features/update/update-notification.js +10 -3
  31. package/dist/src/features/update/update-service.js +57 -23
  32. package/dist/src/platform/signed-http-transport.js +1 -0
  33. package/dist/src/product/billing.js +45 -0
  34. package/dist/src/product/config.js +83 -0
  35. package/dist/src/product/locale.js +38 -0
  36. package/dist/src/product/text.js +3 -0
  37. package/dist/src/telemetry/sls-sink.js +1 -2
  38. package/package.json +5 -5
@@ -27,7 +27,8 @@ try {
27
27
  signal: controller.signal,
28
28
  telemetry: runtime.telemetry,
29
29
  telemetrySink: runtime.telemetrySink,
30
- updateNotification: runtime.updateNotification
30
+ updateNotification: runtime.updateNotification,
31
+ product: runtime.product
31
32
  });
32
33
  }
33
34
  catch (error) {
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ import { insmindProduct } from "../src/product/config.js";
3
+ import { localeOption } from "../src/product/locale.js";
4
+ const controller = new AbortController();
5
+ const interrupt = () => controller.abort(new Error("SIGINT"));
6
+ process.once("SIGINT", interrupt);
7
+ let runtime;
8
+ let mapCliError;
9
+ let redact;
10
+ try {
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
+ mapCliError = errorsModule.mapCliError;
18
+ redact = redactModule.redact;
19
+ const selectedLocale = localeOption(process.argv.slice(2));
20
+ runtime = runtimeModule.createProductionRuntime({
21
+ product: insmindProduct,
22
+ ...(selectedLocale === undefined ? {} : { locale: selectedLocale })
23
+ });
24
+ const program = cliModule.createCli(runtime, { signal: controller.signal });
25
+ process.exitCode = await cliModule.executeCli({
26
+ program,
27
+ argv: process.argv.slice(2),
28
+ presenter: runtime.presenter,
29
+ signal: controller.signal,
30
+ telemetry: runtime.telemetry,
31
+ telemetrySink: runtime.telemetrySink,
32
+ updateNotification: runtime.updateNotification,
33
+ product: runtime.product
34
+ });
35
+ }
36
+ catch (error) {
37
+ if (mapCliError === undefined || redact === undefined) {
38
+ process.stderr.write("INTERNAL_ERROR: CLI failed to start.\n");
39
+ process.exitCode = 1;
40
+ }
41
+ else {
42
+ const outcome = redact(mapCliError(error, { aborted: controller.signal.aborted, product: insmindProduct }));
43
+ if (runtime) {
44
+ runtime.presenter.error(outcome, { json: process.argv.includes("--json") });
45
+ }
46
+ else if (outcome.kind === "interrupted") {
47
+ process.stderr.write("Cancelled.\n");
48
+ }
49
+ else if (process.argv.includes("--json")) {
50
+ process.stderr.write(`${JSON.stringify({ error: outcome.failure })}\n`);
51
+ }
52
+ else {
53
+ process.stderr.write(`${outcome.failure.code}: ${outcome.failure.message}\n`);
54
+ }
55
+ process.exitCode = outcome.exitCode;
56
+ }
57
+ }
58
+ finally {
59
+ process.removeListener("SIGINT", interrupt);
60
+ }
@@ -12,7 +12,7 @@ export function isSupportedGlobalLifecycle(env) {
12
12
  return userAgent.startsWith("pnpm/")
13
13
  && env.npm_command === "add"
14
14
  && env.npm_lifecycle_event === "postinstall"
15
- && env.npm_package_name === "@gaoding/cli"
15
+ && (env.npm_package_name === "@gaoding/cli" || env.npm_package_name === "@insmind/cli")
16
16
  && /\/v\d+\/[0-9a-f]+-[0-9a-f]+-[0-9a-f]{16}$/u.test(initialDirectory);
17
17
  }
18
18
  export async function runPostinstall(options = {}) {
@@ -9,12 +9,13 @@ import { registerModelCommands } from "../cli/model-commands.js";
9
9
  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
+ import { registerCreditsCommand } from "../cli/credits-command.js";
12
13
  import { redact } from "../platform/redact.js";
13
14
  export { assertAllLeafCommandsBound, bindAction } from "../cli/action-binding.js";
14
15
  export function createCli(runtime, options) {
15
16
  const program = new Command()
16
- .name("gd-cli")
17
- .description("稿定命令行工具")
17
+ .name(runtime.product.commandName)
18
+ .description(runtime.product.description)
18
19
  .version(runtime.version)
19
20
  .helpCommand(false)
20
21
  .showHelpAfterError(false)
@@ -25,6 +26,9 @@ export function createCli(runtime, options) {
25
26
  writeOut: runtime.io.writeOut,
26
27
  writeErr: () => undefined
27
28
  });
29
+ if (runtime.product.id === "insmind") {
30
+ program.option("--locale <locale>", "locale for service-owned business descriptions");
31
+ }
28
32
  configureActionEnvironment(program, {
29
33
  policies: runtime.accessPolicies,
30
34
  signal: options.signal,
@@ -32,7 +36,10 @@ export function createCli(runtime, options) {
32
36
  updateNotification: runtime.updateNotification
33
37
  });
34
38
  registerAuthCommands(program, runtime);
35
- registerOrgCommands(program, runtime);
39
+ if (runtime.product.exposesOrganizations)
40
+ registerOrgCommands(program, runtime);
41
+ else
42
+ registerCreditsCommand(program, runtime);
36
43
  registerAgentCommands(program, runtime);
37
44
  registerToolCommands(program, runtime);
38
45
  registerModelCommands(program, runtime);
@@ -68,7 +75,10 @@ export async function executeCli(options) {
68
75
  // The original Commander error is mapped and presented below.
69
76
  }
70
77
  }
71
- const outcome = redact(mapCliError(error, { aborted: options.signal.aborted }));
78
+ const outcome = redact(mapCliError(error, {
79
+ aborted: options.signal.aborted,
80
+ ...(options.product ? { product: options.product } : {})
81
+ }));
72
82
  const telemetryError = classifyTelemetryError(error);
73
83
  const traceId = options.telemetry.selected
74
84
  ? options.telemetry.traceId
@@ -25,6 +25,7 @@ import { createToolApiAdapter } from "../features/tool/tool-api-adapter.js";
25
25
  import { createToolUseCases } from "../features/tool/use-cases.js";
26
26
  import { createOrgUseCases } from "../features/org/use-cases.js";
27
27
  import { createOrgService } from "../features/org/org-service.js";
28
+ import { createCreditsUseCases } from "../features/credits/use-cases.js";
28
29
  import { createBrowserOpener } from "../platform/open-browser.js";
29
30
  import { createSignedHttpTransport } from "../platform/signed-http-transport.js";
30
31
  import { createJsonInputReader } from "../platform/json-input.js";
@@ -37,25 +38,36 @@ import { createUpdateNotificationService } from "../features/update/update-notif
37
38
  import { classifyTelemetryError } from "../cli/errors.js";
38
39
  import { createTelemetryInvocation } from "../telemetry/invocation.js";
39
40
  import { createSlsTelemetrySink } from "../telemetry/sls-sink.js";
41
+ import { gaodingProduct } from "../product/config.js";
42
+ import { resolveProductLocale, systemLocale } from "../product/locale.js";
43
+ import { withAgentBillingUnit, withToolBillingUnit } from "../product/billing.js";
40
44
  import { readInstallationOwner } from "../platform/installation-owner.js";
41
- const productionEndpoints = {
42
- orgApi: new URL("https://gdcli.gaoding.com/api"),
43
- agentApi: new URL("https://gdcli.gaoding.com/api"),
44
- mnsApi: new URL("https://gdcli.gaoding.com/api"),
45
- toolApi: new URL("https://gdcli.gaoding.com/api"),
46
- damApi: new URL("https://gdcli.gaoding.com/api"),
47
- ssoApi: new URL("https://www.gaoding.com/api/sso"),
48
- authPageOrigin: new URL("https://www.gaoding.art")
49
- };
50
45
  export function createProductionRuntime(options = {}) {
46
+ const product = options.product ?? gaodingProduct;
51
47
  const bundledSkills = loadBundledSkills(fileURLToPath(import.meta.url));
52
- const primarySkill = bundledSkills.find((skill) => skill.skill === "gd-cli");
48
+ const primarySkill = bundledSkills.find((skill) => skill.skill === product.skillName);
53
49
  if (!primarySkill)
54
- throw new Error("Bundled gd-cli Skill is missing.");
50
+ throw new Error(`Bundled ${product.skillName} Skill is missing.`);
55
51
  const packageRoot = dirname(dirname(primarySkill.sourceDirectory));
56
52
  const installationOwner = readInstallationOwner(packageRoot);
57
- const endpoints = options.endpoints ?? productionEndpoints;
53
+ const endpoints = options.endpoints ?? product.endpoints;
58
54
  const fetch = options.fetch ?? globalThis.fetch;
55
+ const env = options.env ?? process.env;
56
+ const environmentLocale = product.localeEnvironmentVariable
57
+ ? env[product.localeEnvironmentVariable]
58
+ : undefined;
59
+ const localSystemLocale = systemLocale();
60
+ const locale = resolveProductLocale({
61
+ ...(options.locale === undefined ? {} : { explicit: options.locale }),
62
+ ...(environmentLocale === undefined ? {} : { environment: environmentLocale }),
63
+ ...(localSystemLocale === undefined ? {} : { system: localSystemLocale })
64
+ });
65
+ const businessHeaders = product.id === "insmind" ? {
66
+ "X-Locale": locale.locale,
67
+ "X-Language": locale.language,
68
+ "X-Market": locale.market,
69
+ "X-Legal-Region": locale.legalRegion
70
+ } : undefined;
59
71
  const now = options.now ?? (() => new Date());
60
72
  const telemetry = createTelemetryInvocation({
61
73
  cliVersion: primarySkill.version,
@@ -69,7 +81,10 @@ export function createProductionRuntime(options = {}) {
69
81
  },
70
82
  classifyError: classifyTelemetryError
71
83
  });
72
- const telemetrySink = createSlsTelemetrySink({ fetch });
84
+ const telemetrySink = createSlsTelemetrySink({
85
+ fetch,
86
+ trackingUrl: product.telemetryUrl
87
+ });
73
88
  const rawIo = options.io ?? {
74
89
  input: process.stdin,
75
90
  stdout: process.stdout,
@@ -84,41 +99,55 @@ export function createProductionRuntime(options = {}) {
84
99
  stderrTerminal: rawIo.stderrTerminal ?? hasTerminal(rawIo.stderr)
85
100
  };
86
101
  const store = createLocalCredentialStore({
87
- ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
102
+ ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {}),
103
+ stateDirectory: product.stateDirectory
88
104
  });
89
105
  const orgTransport = createSignedHttpTransport({
90
106
  baseUrl: endpoints.orgApi,
91
107
  fetch,
92
108
  now,
93
- traceparent: () => telemetry.traceparent()
109
+ traceparent: () => telemetry.traceparent(),
110
+ ...(businessHeaders ? { businessHeaders } : {})
111
+ });
112
+ const creditsTransport = createSignedHttpTransport({
113
+ baseUrl: endpoints.creditsApi,
114
+ fetch,
115
+ now,
116
+ traceparent: () => telemetry.traceparent(),
117
+ ...(businessHeaders ? { businessHeaders } : {})
94
118
  });
95
119
  const agentTransport = createSignedHttpTransport({
96
120
  baseUrl: endpoints.agentApi,
97
121
  fetch,
98
122
  now,
99
- traceparent: () => telemetry.traceparent()
123
+ traceparent: () => telemetry.traceparent(),
124
+ ...(businessHeaders ? { businessHeaders } : {})
100
125
  });
101
126
  const mnsTransport = createSignedHttpTransport({
102
127
  baseUrl: endpoints.mnsApi,
103
128
  fetch,
104
129
  now,
105
- traceparent: () => telemetry.traceparent()
130
+ traceparent: () => telemetry.traceparent(),
131
+ ...(businessHeaders ? { businessHeaders } : {})
106
132
  });
107
133
  const toolTransport = createSignedHttpTransport({
108
134
  baseUrl: endpoints.toolApi,
109
135
  fetch,
110
136
  now,
111
- traceparent: () => telemetry.traceparent()
137
+ traceparent: () => telemetry.traceparent(),
138
+ ...(businessHeaders ? { businessHeaders } : {})
112
139
  });
113
140
  const damTransport = createSignedHttpTransport({
114
141
  baseUrl: endpoints.damApi,
115
142
  fetch,
116
143
  now,
117
144
  channelId: "32",
118
- traceparent: () => telemetry.traceparent()
145
+ traceparent: () => telemetry.traceparent(),
146
+ ...(businessHeaders ? { businessHeaders } : {})
119
147
  });
120
148
  const sso = createSsoService({
121
149
  ssoApi: endpoints.ssoApi,
150
+ clientId: product.deviceClientId,
122
151
  fetch,
123
152
  now
124
153
  });
@@ -126,13 +155,18 @@ export function createProductionRuntime(options = {}) {
126
155
  store,
127
156
  org: createOrgService({ transport: orgTransport }),
128
157
  sso,
129
- telemetry
158
+ telemetry,
159
+ ...(product.exposesOrganizations
160
+ ? {}
161
+ : { singleOrganizationName: product.displayName })
130
162
  });
131
163
  const auth = createAuthUseCases({
132
164
  store,
133
165
  sso,
134
166
  organizationBinder: org,
135
167
  authPageOrigin: endpoints.authPageOrigin,
168
+ commandName: product.commandName,
169
+ requireOrganization: !product.exposesOrganizations,
136
170
  now,
137
171
  telemetry,
138
172
  sleep: async (milliseconds, signal) => {
@@ -140,6 +174,10 @@ export function createProductionRuntime(options = {}) {
140
174
  }
141
175
  });
142
176
  const storage = options.objectStorage ?? createObjectStorageUploader({ fetch, now });
177
+ const credits = createCreditsUseCases({
178
+ transport: creditsTransport,
179
+ billingUnit: product.billingUnit
180
+ });
143
181
  const storageUpload = createDamStorageUploader({
144
182
  transport: damTransport,
145
183
  storage
@@ -147,10 +185,13 @@ export function createProductionRuntime(options = {}) {
147
185
  const transientUploader = createDamTransientUploader({ storageUpload });
148
186
  const presenter = createPresenter({
149
187
  writeOut: io.writeOut,
150
- writeError: io.writeError
188
+ writeError: io.writeError,
189
+ product
151
190
  });
152
191
  const browser = createBrowserOpener();
153
- const validators = createContractValidators();
192
+ const validators = createContractValidators({
193
+ organizations: product.exposesOrganizations
194
+ });
154
195
  const modelCatalog = createMnsCatalogAdapter({ transport: mnsTransport });
155
196
  const damApi = createDamApiAdapter({ transport: damTransport });
156
197
  const damRepositories = createDamRepositoryCatalog({ transport: damTransport });
@@ -193,7 +234,7 @@ export function createProductionRuntime(options = {}) {
193
234
  },
194
235
  telemetry
195
236
  });
196
- const agent = createAgentUseCases({
237
+ const agent = withAgentBillingUnit(createAgentUseCases({
197
238
  catalog: modelCatalog,
198
239
  uploader: transientUploader,
199
240
  completion: createCreativeAgentAdapter({
@@ -203,24 +244,29 @@ export function createProductionRuntime(options = {}) {
203
244
  }),
204
245
  warn: (message) => { presenter.warning(message); },
205
246
  telemetry
206
- });
207
- const tool = createToolUseCases({
247
+ }), product.billingUnit);
248
+ const tool = withToolBillingUnit(createToolUseCases({
208
249
  catalog: modelCatalog,
250
+ tools: product.tools,
209
251
  execution: createToolApiAdapter({ transport: toolTransport, telemetry }),
210
252
  uploader: transientUploader,
211
253
  warn: (message) => { presenter.warning(message); },
212
254
  telemetry
213
- });
255
+ }), product.billingUnit);
214
256
  const editor = createEditorUseCases({
215
257
  session: createEditorSession({
216
258
  store: createEditorSessionStateStore({
217
259
  ...(options.homeDirectory === undefined
218
260
  ? {}
219
- : { homeDirectory: options.homeDirectory })
261
+ : { homeDirectory: options.homeDirectory }),
262
+ stateDirectory: product.stateDirectory
220
263
  }),
221
264
  browser,
222
- defaultCreateUrl: new URL("https://www.gaoding.art/editor/canvas?mode=create&type=board"),
223
- workUrl: new URL("https://www.gaoding.art/editor/canvas"),
265
+ defaultCreateUrl: product.defaultEditorCreateUrl,
266
+ workUrl: product.editorWorkUrl,
267
+ commandName: product.commandName,
268
+ restrictTargets: product.restrictEditorTargets,
269
+ stateDirectory: product.stateDirectory,
224
270
  ...(options.homeDirectory === undefined
225
271
  ? {}
226
272
  : { homeDirectory: options.homeDirectory })
@@ -242,6 +288,11 @@ export function createProductionRuntime(options = {}) {
242
288
  bundledSkills,
243
289
  fetch,
244
290
  telemetry,
291
+ ...(product.id === "insmind" ? {
292
+ packageName: product.npmPackage,
293
+ commandName: product.commandName,
294
+ registryUrl: `https://registry.npmjs.org/${encodeURIComponent(product.npmPackage)}`
295
+ } : {}),
245
296
  installationOwner,
246
297
  ...(process.argv[1] ? { binaryPath: process.argv[1] } : {}),
247
298
  ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {})
@@ -255,9 +306,15 @@ export function createProductionRuntime(options = {}) {
255
306
  installationOwner,
256
307
  ...(options.homeDirectory ? { homeDirectory: options.homeDirectory } : {}),
257
308
  ...(options.env ? { env: options.env } : {}),
258
- notify: (message) => { presenter.notice(message); }
309
+ notify: (message) => { presenter.notice(message); },
310
+ ...(product.id === "insmind" ? {
311
+ stateDirectoryName: product.stateDirectory,
312
+ registryUrl: `https://registry.npmjs.org/${encodeURIComponent(product.npmPackage)}`,
313
+ commandName: product.commandName
314
+ } : {})
259
315
  });
260
316
  return {
317
+ product,
261
318
  version: primarySkill.version,
262
319
  telemetry,
263
320
  telemetrySink,
@@ -272,6 +329,7 @@ export function createProductionRuntime(options = {}) {
272
329
  editor,
273
330
  dam,
274
331
  tool,
332
+ credits,
275
333
  update,
276
334
  updateNotification,
277
335
  jsonInput: createJsonInputReader({
@@ -35,8 +35,6 @@ const editorDisconnectOutputSchema = contractSchema("editor.disconnect", "output
35
35
  const editorSaveOutputSchema = contractSchema("editor.save", "output");
36
36
  const editorScreenshotOutputSchema = contractSchema("editor.screenshot", "output");
37
37
  const editorSnapshotOutputSchema = contractSchema("editor.snapshot", "output");
38
- const orgCurrentSchema = contractSchema("org.current", "output");
39
- const orgListSchema = contractSchema("org.list", "output");
40
38
  const modelGetInputSchema = contractSchema("model.get", "input");
41
39
  const modelGetOutputSchema = contractSchema("model.get", "output");
42
40
  const modelListInputSchema = contractSchema("model.list", "input");
@@ -56,7 +54,7 @@ export class OutputContractError extends Error {
56
54
  this.name = "OutputContractError";
57
55
  }
58
56
  }
59
- export function createContractValidators() {
57
+ export function createContractValidators(options = {}) {
60
58
  const ajv = new Ajv2020({ allErrors: true, strict: true });
61
59
  const addFormats = addFormatsImport;
62
60
  addFormats(ajv);
@@ -94,8 +92,13 @@ export function createContractValidators() {
94
92
  const editorApplyOutput = ajv.compile(editorApplyOutputSchema);
95
93
  const editorScreenshotOutput = ajv.compile(editorScreenshotOutputSchema);
96
94
  const editorSaveOutput = ajv.compile(editorSaveOutputSchema);
97
- const orgList = ajv.compile(orgListSchema);
98
- const orgCurrent = ajv.compile(orgCurrentSchema);
95
+ const organizations = options.organizations !== false;
96
+ const orgList = organizations
97
+ ? ajv.compile(contractSchema("org.list", "output"))
98
+ : unavailableValidator;
99
+ const orgCurrent = organizations
100
+ ? ajv.compile(contractSchema("org.current", "output"))
101
+ : unavailableValidator;
99
102
  const toolListOutput = ajv.compile(toolListOutputSchema);
100
103
  const modelListInput = ajv.compile(modelListInputSchema);
101
104
  const modelListOutput = ajv.compile(modelListOutputSchema);
@@ -149,6 +152,7 @@ export function createContractValidators() {
149
152
  toolCallOutput: assertion(toolCallOutput, OutputContractError)
150
153
  };
151
154
  }
155
+ const unavailableValidator = Object.assign(() => false, { errors: null, schema: false, schemaEnv: undefined });
152
156
  function assertion(validate, ErrorType) {
153
157
  return (value) => {
154
158
  if (!validate(value))
@@ -1,15 +1,16 @@
1
1
  import { contractSchema } from "../contracts/schema.js";
2
2
  import { bindPreparedAction } from "./action-binding.js";
3
3
  import { CliUsageError } from "./errors.js";
4
+ import { productText as text } from "../product/text.js";
4
5
  const agentSendInputSchema = contractSchema("agent.send", "input");
5
6
  export function registerAgentCommands(program, runtime) {
6
7
  const agent = program.command("agent")
7
- .description("稿定 Agent")
8
+ .description(text(runtime.product, "稿定 Agent", "insMind Agent"))
8
9
  .helpCommand(false);
9
10
  const send = agent.command("send")
10
- .description("发送结构化创作消息")
11
- .option("--schema", "输出输入 Schema")
12
- .option("--input <file|->", "从文件或标准输入读取 JSON")
11
+ .description(text(runtime.product, "发送结构化创作消息", "Send a structured creation message"))
12
+ .option("--schema", text(runtime.product, "输出输入 Schema", "output the input Schema"))
13
+ .option("--input <file|->", text(runtime.product, "从文件或标准输入读取 JSON", "read JSON from a file or stdin"))
13
14
  .allowExcessArguments(false);
14
15
  bindPreparedAction(send, "organization", async (signal) => {
15
16
  signal.throwIfAborted();
@@ -1,12 +1,13 @@
1
1
  import { bindAction } from "./action-binding.js";
2
- import { authStatusView } from "./presenter.js";
2
+ import { authStatusViewFor } from "./presenter.js";
3
+ import { productText as text } from "../product/text.js";
3
4
  export function registerAuthCommands(program, runtime) {
4
5
  const auth = program.command("auth")
5
- .description("登录与本机凭证")
6
+ .description(text(runtime.product, "登录与本机凭证", "Authentication and local credentials"))
6
7
  .helpCommand(false);
7
8
  const login = leaf(auth.command("login"))
8
- .description("登录稿定")
9
- .option("--no-browser", "不自动打开浏览器");
9
+ .description(text(runtime.product, "登录稿定", "Sign in to insMind"))
10
+ .option("--no-browser", text(runtime.product, "不自动打开浏览器", "do not open a browser automatically"));
10
11
  bindAction(login, "none", async (_context, signal) => {
11
12
  const noBrowser = login.opts().browser === false;
12
13
  runtime.telemetry.annotate({ parameters: { noBrowser } });
@@ -23,30 +24,32 @@ export function registerAuthCommands(program, runtime) {
23
24
  }
24
25
  });
25
26
  await runtime.telemetry.stage("output", async () => {
26
- runtime.presenter.success(result.status === "already_logged_in" ? "已登录。" : "登录成功。");
27
+ runtime.presenter.success(result.status === "already_logged_in"
28
+ ? text(runtime.product, "已登录。", "Already signed in.")
29
+ : text(runtime.product, "登录成功。", "Signed in successfully."));
27
30
  if (result.status === "already_logged_in" && !result.organizationSelected) {
28
31
  runtime.presenter.warning("尚未选择组织,请执行 gd-cli org switch。");
29
32
  }
30
33
  });
31
34
  }, { operation: "auth.login" });
32
35
  const status = leaf(auth.command("status"))
33
- .description("查看登录状态")
34
- .option("--json", "输出 JSON");
36
+ .description(text(runtime.product, "查看登录状态", "Show authentication status"))
37
+ .option("--json", text(runtime.product, "输出 JSON", "output JSON"));
35
38
  bindAction(status, "none", async () => {
36
39
  const result = await runtime.auth.status({ now: runtime.now() });
37
40
  await runtime.telemetry.stage("output", async () => {
38
41
  runtime.validators.authStatus(result);
39
42
  runtime.presenter.result(result, {
40
43
  json: status.opts().json === true,
41
- view: authStatusView
44
+ view: authStatusViewFor(runtime.product)
42
45
  });
43
46
  });
44
47
  }, { operation: "auth.status" });
45
- const logout = leaf(auth.command("logout")).description("退出登录");
48
+ const logout = leaf(auth.command("logout")).description(text(runtime.product, "退出登录", "Sign out"));
46
49
  bindAction(logout, "none", async () => {
47
50
  await runtime.auth.logout();
48
51
  await runtime.telemetry.stage("output", async () => {
49
- runtime.presenter.success("已退出登录。");
52
+ runtime.presenter.success(text(runtime.product, "已退出登录。", "Signed out."));
50
53
  });
51
54
  }, { operation: "auth.logout" });
52
55
  }
@@ -0,0 +1,23 @@
1
+ import { bindAction } from "./action-binding.js";
2
+ export function registerCreditsCommand(program, runtime) {
3
+ const credits = program.command("credits")
4
+ .description("Show the current insMind credits balance")
5
+ .option("--json", "output JSON")
6
+ .allowExcessArguments(false);
7
+ bindAction(credits, "organization", async (context, signal) => {
8
+ const result = await runtime.credits.get({
9
+ credential: context.state.credential,
10
+ organizationId: context.state.organization.id,
11
+ signal
12
+ });
13
+ await runtime.telemetry.stage("output", async () => {
14
+ runtime.presenter.result(result, {
15
+ json: credits.opts().json === true,
16
+ view: (value) => {
17
+ const balance = value;
18
+ return `${balance.credits.available} insMind credits available`;
19
+ }
20
+ });
21
+ });
22
+ }, { operation: "credits.get" });
23
+ }