tezign-ai-appstore-sdk 0.2.0 → 0.2.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/open-api/cli.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAanF,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAA;AAEzE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,OAAO,GAAG,8BAA8B,CAAA;CACzD;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAq2BD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBrF;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa,CAKhF;AAshCD,wBAAsB,aAAa,CACjC,IAAI,GAAE,MAAM,EAAgE,EAC5E,EAAE,GAAE,YAAiB,GACpB,OAAO,CAAC,IAAI,CAAC,CAmEf"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/open-api/cli.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAsCnF,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAA;AAEzE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,OAAO,GAAG,8BAA8B,CAAA;CACzD;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA+3BD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBrF;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa,CAKhF;AAoqCD,wBAAsB,aAAa,CACjC,IAAI,GAAE,MAAM,EAAgE,EAC5E,EAAE,GAAE,YAAiB,GACpB,OAAO,CAAC,IAAI,CAAC,CAmEf"}
@@ -6,6 +6,8 @@ import { clearOpenApiCliStoredKey, readOpenApiCliCurrentEnvironment, readOpenApi
6
6
  import { createOpenApiClient, OpenApiError } from './client.js';
7
7
  import { findOpenApiProjectLocalConfig, writeOpenApiProjectLocalConfig, } from './project-local-config.js';
8
8
  import { createOpenApiSourceArchive, inspectOpenApiSourceArchive } from './source-archive.js';
9
+ import { OPEN_API_CLI_STDOUT_TYPESCRIPT_HELP, } from './cli-output-types.js';
10
+ import { OPEN_API_CLI_INPUT_TYPESCRIPT_HELP } from './cli-input-help.js';
9
11
  class CliUsageError extends Error {
10
12
  helpText;
11
13
  constructor(message, helpText) {
@@ -24,7 +26,7 @@ const ENV_TARGET_CLI_OPTION_HELP = {
24
26
  };
25
27
  const BASE_URL_TARGET_CLI_OPTION_HELP = {
26
28
  flag: '--baseUrl <url>',
27
- description: '可选。直接指定平台地址,例如 https://ops.static.tezign.com。未传 --env 时使用;会去掉末尾斜杠。',
29
+ description: '可选。直接指定平台地址。未传 --env 时使用;会去掉末尾斜杠。',
28
30
  };
29
31
  const TARGET_CLI_OPTION_HELP = [
30
32
  ENV_TARGET_CLI_OPTION_HELP,
@@ -59,7 +61,7 @@ const DAILY_WORKFLOW_HELP = [
59
61
  description: '在项目目录中新建或绑定平台项目:tezign-ai-appstore project init --env test --mode create --input \'{"name":"Demo"}\'',
60
62
  },
61
63
  {
62
- flag: '4. upload-source',
64
+ flag: '4. project upload-source',
63
65
  description: '先 dry-run 预览,再上传源码:tezign-ai-appstore project upload-source --dry-run',
64
66
  },
65
67
  {
@@ -70,7 +72,7 @@ const DAILY_WORKFLOW_HELP = [
70
72
  const COMMAND_GROUP_HELP = {
71
73
  auth: '登录、退出和查看本地 Open API CLI 认证状态',
72
74
  env: '管理 baseUrl 对应的环境别名',
73
- project: '创建、绑定、更新、上传源码和部署项目',
75
+ project: '创建、绑定、更新、上传源码、部署项目及管理自定义访问域名',
74
76
  deployment: '查询部署状态',
75
77
  };
76
78
  const FINAL_DEPLOYMENT_STATUS = new Set(['READY', 'FAILED', 'SUCCEEDED']);
@@ -97,12 +99,22 @@ function renderGlobalHelp() {
97
99
  ' tezign-ai-appstore <group> --help',
98
100
  ' tezign-ai-appstore <group> <action> --help',
99
101
  '',
102
+ 'Help command:',
103
+ ' tezign-ai-appstore help 查看全局帮助与推荐工作流',
104
+ ' tezign-ai-appstore help <group> 查看某个命令组下有哪些 action',
105
+ ' tezign-ai-appstore help <group> <action> 查看具体命令的参数、说明和示例',
106
+ '',
107
+ 'Equivalent forms:',
108
+ ' tezign-ai-appstore help project == tezign-ai-appstore project --help',
109
+ ' tezign-ai-appstore help project init == tezign-ai-appstore project init --help',
110
+ '',
100
111
  'Command groups:',
101
112
  ];
102
113
  for (const [group, description] of Object.entries(COMMAND_GROUP_HELP)) {
103
114
  lines.push(` ${group.padEnd(11)}${description}`);
104
115
  }
105
- lines.push('', 'Recommended workflow:', ...DAILY_WORKFLOW_HELP.map((item) => ` ${item.flag.padEnd(16)}${item.description}`), '', 'More help:', ' tezign-ai-appstore help project', ' tezign-ai-appstore project --help', ' tezign-ai-appstore help project upload-source', ' tezign-ai-appstore project create --help');
116
+ lines.push('', '通用规则:', ...TARGET_RESOLUTION_HELP.map((line) => ` - ${line}`));
117
+ lines.push('', 'Recommended workflow:', ...DAILY_WORKFLOW_HELP.map((item) => ` ${item.flag.padEnd(16)}${item.description}`), '', 'More help:', ' tezign-ai-appstore help project', ' tezign-ai-appstore project --help', ' tezign-ai-appstore help project upload-source', ' tezign-ai-appstore project init --help');
106
118
  return lines.join('\n');
107
119
  }
108
120
  function renderGroupHelp(group) {
@@ -114,13 +126,25 @@ function renderGroupHelp(group) {
114
126
  '',
115
127
  'Commands:',
116
128
  ];
129
+ const omitUsageLines = group === 'project' || group === 'env';
117
130
  for (const command of commands) {
118
131
  lines.push(` ${command.action.padEnd(15)}${command.summary}`);
119
- for (const usage of command.usage) {
120
- lines.push(` ${usage}`);
132
+ if (!omitUsageLines) {
133
+ for (const usage of command.usage) {
134
+ lines.push(` ${usage}`);
135
+ }
121
136
  }
122
137
  }
123
- lines.push('', `Run \`tezign-ai-appstore ${group} <action> --help\` to see command options, parameter rules, and examples.`);
138
+ if (group === 'env') {
139
+ lines.push('', '说明:', ' • 其它命令(auth / project / deployment 等)可传 `--env <name>` 显式指定使用的环境别名。', ' • 不显式传 `--env` / `--baseUrl` 时,按全局「通用规则」解析目标平台;通常会使用配置文件中的默认当前环境(`currentEnvironment`),或由目录绑定等规则推断。', ' • 查看当前默认环境别名:执行 `tezign-ai-appstore env list`,输出 JSON 的 `currentEnvironment`(未设置时为 null);也可参考 `auth status` 中的 `currentEnvironment`。');
140
+ }
141
+ const simplifiedFooter = group === 'project'
142
+ ? '子命令详情请执行:tezign-ai-appstore project <action> --help(含选项、--input/stdout 形状与示例)。'
143
+ : group === 'env'
144
+ ? '子命令详情请执行:tezign-ai-appstore env <action> --help(含选项与示例)。'
145
+ : null;
146
+ lines.push('', simplifiedFooter ??
147
+ `Run \`tezign-ai-appstore ${group} <action> --help\` to see command options, parameter rules, and examples.`);
124
148
  return lines.join('\n');
125
149
  }
126
150
  function renderCommandHelp(commandKey) {
@@ -140,6 +164,16 @@ function renderCommandHelp(commandKey) {
140
164
  lines.push('', 'Options:');
141
165
  lines.push(...command.options.map((option) => ` ${option.flag.padEnd(24)}${option.description}`));
142
166
  }
167
+ const inputTypescriptHelp = OPEN_API_CLI_INPUT_TYPESCRIPT_HELP[command.key];
168
+ if (inputTypescriptHelp) {
169
+ lines.push('', '--input JSON(TypeScript 形状):');
170
+ lines.push(...inputTypescriptHelp.split('\n').map((line) => ` ${line}`));
171
+ }
172
+ const stdoutTypescriptHelp = OPEN_API_CLI_STDOUT_TYPESCRIPT_HELP[command.key];
173
+ if (stdoutTypescriptHelp) {
174
+ lines.push('', 'Stdout (JSON 对应的 TypeScript 形状):');
175
+ lines.push(...stdoutTypescriptHelp.split('\n').map((line) => ` ${line}`));
176
+ }
143
177
  if (command.notes && command.notes.length > 0) {
144
178
  lines.push('', 'Notes:');
145
179
  lines.push(...command.notes.map((note) => ` - ${note}`));
@@ -433,7 +467,6 @@ async function resolveProjectIdForCommand(options, commandKey, io) {
433
467
  }
434
468
  throw createCliUsageError(`${commandKey} requires --projectId,或先在当前目录执行 \`tezign-ai-appstore project init\` 绑定项目`, commandKey);
435
469
  }
436
- const PROJECT_CREATE_ALLOWED_OPTION_KEYS = new Set(['env', 'baseUrl', 'config', 'input']);
437
470
  const PROJECT_LIST_ALLOWED_OPTION_KEYS = new Set(['env', 'baseUrl', 'config']);
438
471
  const PROJECT_UPDATE_ALLOWED_OPTION_KEYS = new Set(['env', 'baseUrl', 'config', 'input', 'projectId', 'id']);
439
472
  const PROJECT_DEPLOY_ALLOWED_OPTION_KEYS = new Set(['env', 'baseUrl', 'config', 'projectId', 'id']);
@@ -458,33 +491,25 @@ const PROJECT_UPLOAD_SOURCE_ALLOWED_OPTION_KEYS = new Set([
458
491
  'remark',
459
492
  'dry-run',
460
493
  ]);
461
- function buildCreateProjectInput(options) {
462
- const commandKey = 'project create';
463
- for (const key of Object.keys(options)) {
464
- if (!PROJECT_CREATE_ALLOWED_OPTION_KEYS.has(key)) {
465
- throw createCliUsageError(`project create 不再支持 --${key},请使用 --input 传入完整 JSON 请求体(与 Open API 创建项目接口一致)`, commandKey);
466
- }
467
- }
468
- const raw = readStringOption(options, 'input');
469
- if (!raw) {
470
- throw createCliUsageError('project create 需要 --input <json>,内容为创建项目的请求体', commandKey);
471
- }
472
- let parsed;
473
- try {
474
- parsed = JSON.parse(raw);
475
- }
476
- catch {
477
- throw createCliUsageError('Invalid JSON value for --input', commandKey);
478
- }
479
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
480
- throw createCliUsageError('--input must be a JSON object', commandKey);
481
- }
482
- const input = parsed;
483
- if (typeof input.name !== 'string' || !input.name.trim()) {
484
- throw createCliUsageError('project create 需要 --input 中含有非空字符串字段 name', commandKey);
485
- }
486
- return input;
487
- }
494
+ const PROJECT_LIST_DOMAINS_ALLOWED_OPTION_KEYS = new Set(['env', 'baseUrl', 'config', 'projectId', 'id']);
495
+ const PROJECT_ADD_DOMAIN_ALLOWED_OPTION_KEYS = new Set([
496
+ 'env',
497
+ 'baseUrl',
498
+ 'config',
499
+ 'projectId',
500
+ 'id',
501
+ 'subdomain',
502
+ 'full-domain',
503
+ 'use-full-domain',
504
+ ]);
505
+ const PROJECT_REMOVE_DOMAIN_ALLOWED_OPTION_KEYS = new Set([
506
+ 'env',
507
+ 'baseUrl',
508
+ 'config',
509
+ 'projectId',
510
+ 'id',
511
+ 'domain-id',
512
+ ]);
488
513
  function buildUpdateProjectInput(options) {
489
514
  const commandKey = 'project update';
490
515
  for (const key of Object.keys(options)) {
@@ -652,7 +677,7 @@ async function handleAuthLogin(options, io) {
652
677
  message: cliOptions.environmentName
653
678
  ? `Open API CLI 已登录到环境 ${cliOptions.environmentName},后续命令会自动复用本地保存的 key。`
654
679
  : 'Open API CLI 登录完成,后续命令会自动复用本地保存的 key。',
655
- environment: cliOptions.environmentName,
680
+ environment: cliOptions.environmentName ?? null,
656
681
  baseUrl: cliOptions.baseUrl,
657
682
  currentEnvironment,
658
683
  configPath: resolveOpenApiCliConfigPath(cliOptions.configPath),
@@ -674,7 +699,7 @@ async function handleAuthLogout(options, io) {
674
699
  message: removed
675
700
  ? '本地保存的 Open API Key 已移除。'
676
701
  : '当前 baseUrl 没有本地保存的 Open API Key。',
677
- environment: cliOptions.environmentName,
702
+ environment: cliOptions.environmentName ?? null,
678
703
  baseUrl: cliOptions.baseUrl,
679
704
  currentEnvironment,
680
705
  removed,
@@ -697,7 +722,7 @@ async function handleAuthStatus(options, io) {
697
722
  ? '当前 Open API CLI 已认证。'
698
723
  : '当前 Open API CLI 尚未认证,请先执行 auth login。',
699
724
  source: storedKey ? 'config' : 'none',
700
- environment: cliOptions.environmentName,
725
+ environment: cliOptions.environmentName ?? null,
701
726
  baseUrl: cliOptions.baseUrl,
702
727
  currentEnvironment,
703
728
  configPath: resolveOpenApiCliConfigPath(cliOptions.configPath),
@@ -778,13 +803,6 @@ async function handleEnvironmentRemove(options, io) {
778
803
  configPath: resolveOpenApiCliConfigPath(configPath),
779
804
  }, io);
780
805
  }
781
- async function handleProjectCreate(options, io) {
782
- const commandKey = 'project create';
783
- const cliOptions = await resolveCliOptions(options, commandKey, io);
784
- const client = createOpenApiCliClient(cliOptions);
785
- const project = await client.createProject(buildCreateProjectInput(options));
786
- printJson(project, io);
787
- }
788
806
  async function handleProjectList(options, io) {
789
807
  const commandKey = 'project list';
790
808
  for (const key of Object.keys(options)) {
@@ -808,15 +826,19 @@ function readProjectInitMode(options) {
808
826
  }
809
827
  throw createCliUsageError('project init 不再支持交互式向导,请传入 --mode create 或 --mode link', commandKey);
810
828
  }
811
- function buildProjectInitCreateInput(options) {
829
+ function requireProjectInitCreateFlowOptions(options) {
812
830
  const commandKey = 'project init';
813
- const raw = readStringOption(options, 'input');
814
- if (!raw) {
831
+ const input = readStringOption(options, 'input');
832
+ if (!input) {
815
833
  throw createCliUsageError('project init --mode create 需要 --input <json>,内容为创建项目的请求体', commandKey);
816
834
  }
835
+ return { input };
836
+ }
837
+ function buildProjectInitCreateInput(options) {
838
+ const commandKey = 'project init';
817
839
  let parsed;
818
840
  try {
819
- parsed = JSON.parse(raw);
841
+ parsed = JSON.parse(options.input);
820
842
  }
821
843
  catch {
822
844
  throw createCliUsageError('Invalid JSON value for --input', commandKey);
@@ -828,6 +850,9 @@ function buildProjectInitCreateInput(options) {
828
850
  if (typeof input.name !== 'string' || !input.name.trim()) {
829
851
  throw createCliUsageError('project init --mode create 需要 --input 中含有非空字符串字段 name', commandKey);
830
852
  }
853
+ if (!Object.prototype.hasOwnProperty.call(input, 'requireAuth')) {
854
+ input.requireAuth = false;
855
+ }
831
856
  return input;
832
857
  }
833
858
  async function runProjectInitCreateFlow(client, options) {
@@ -902,7 +927,7 @@ async function handleProjectInit(options, io) {
902
927
  const mode = readProjectInitMode(options);
903
928
  const client = createOpenApiCliClient(cliOptions);
904
929
  const project = mode === 'create'
905
- ? await runProjectInitCreateFlow(client, options)
930
+ ? await runProjectInitCreateFlow(client, requireProjectInitCreateFlowOptions(options))
906
931
  : await runProjectInitLinkFlow(client, options);
907
932
  const binding = await writeOpenApiProjectLocalConfig({
908
933
  version: 1,
@@ -980,6 +1005,16 @@ async function handleProjectDeploy(options, io) {
980
1005
  if (isFailedDeploymentStatus(finalDeployment.status)) {
981
1006
  throw new Error(`部署失败(deploymentId: ${finalDeployment.deploymentId || finalDeployment.id})`);
982
1007
  }
1008
+ const urls = Array.isArray(finalDeployment.accessUrls) && finalDeployment.accessUrls.length > 0
1009
+ ? finalDeployment.accessUrls
1010
+ : typeof finalDeployment.accessUrl === 'string' && finalDeployment.accessUrl.length > 0
1011
+ ? [finalDeployment.accessUrl]
1012
+ : [];
1013
+ if (urls.length > 0) {
1014
+ io.stderr(urls.length === 1
1015
+ ? `部署成功。应用访问链接:${urls[0]}`
1016
+ : `部署成功。应用访问链接:\n${urls.map((u) => ` • ${u}`).join('\n')}`);
1017
+ }
983
1018
  }
984
1019
  async function handleProjectUploadSource(options, io) {
985
1020
  const commandKey = 'project upload-source';
@@ -1077,11 +1112,68 @@ async function handleProjectUploadSource(options, io) {
1077
1112
  }
1078
1113
  }
1079
1114
  }
1115
+ async function handleProjectListDomains(options, io) {
1116
+ const commandKey = 'project list-domains';
1117
+ for (const key of Object.keys(options)) {
1118
+ if (!PROJECT_LIST_DOMAINS_ALLOWED_OPTION_KEYS.has(key)) {
1119
+ throw createCliUsageError(`Unknown option for project list-domains: --${key}`, commandKey);
1120
+ }
1121
+ }
1122
+ const projectId = await resolveProjectIdForCommand(options, commandKey, io);
1123
+ const cliOptions = await resolveCliOptions(options, commandKey, io);
1124
+ const client = createOpenApiCliClient(cliOptions);
1125
+ const list = await client.listProjectDomains(projectId);
1126
+ printJson(list, io);
1127
+ }
1128
+ async function handleProjectAddDomain(options, io) {
1129
+ const commandKey = 'project add-domain';
1130
+ for (const key of Object.keys(options)) {
1131
+ if (!PROJECT_ADD_DOMAIN_ALLOWED_OPTION_KEYS.has(key)) {
1132
+ throw createCliUsageError(`Unknown option for project add-domain: --${key}`, commandKey);
1133
+ }
1134
+ }
1135
+ const subdomain = readStringOption(options, 'subdomain');
1136
+ const fullDomain = readStringOption(options, 'full-domain');
1137
+ const useFullDomain = readBooleanOption(options, 'use-full-domain', commandKey) ?? false;
1138
+ if (!subdomain && !fullDomain) {
1139
+ throw createCliUsageError('project add-domain 需要 --subdomain <label>(绑定为平台 SERVICE_DOMAIN 下的二级域名)或 --full-domain <hostname>(仅密钥所属用户为超级管理员时可用)', commandKey);
1140
+ }
1141
+ if (subdomain && fullDomain) {
1142
+ throw createCliUsageError('project add-domain 不能同时传入 --subdomain 与 --full-domain', commandKey);
1143
+ }
1144
+ const body = subdomain
1145
+ ? { subdomain }
1146
+ : useFullDomain
1147
+ ? { fullDomain, useFullDomain: true }
1148
+ : { fullDomain };
1149
+ const projectId = await resolveProjectIdForCommand(options, commandKey, io);
1150
+ const cliOptions = await resolveCliOptions(options, commandKey, io);
1151
+ const client = createOpenApiCliClient(cliOptions);
1152
+ const created = await client.addProjectDomain(projectId, body);
1153
+ printJson(created, io);
1154
+ }
1155
+ async function handleProjectRemoveDomain(options, io) {
1156
+ const commandKey = 'project remove-domain';
1157
+ for (const key of Object.keys(options)) {
1158
+ if (!PROJECT_REMOVE_DOMAIN_ALLOWED_OPTION_KEYS.has(key)) {
1159
+ throw createCliUsageError(`Unknown option for project remove-domain: --${key}`, commandKey);
1160
+ }
1161
+ }
1162
+ const domainId = readStringOption(options, 'domain-id');
1163
+ if (!domainId) {
1164
+ throw createCliUsageError('project remove-domain 需要 --domain-id <id>', commandKey);
1165
+ }
1166
+ const projectId = await resolveProjectIdForCommand(options, commandKey, io);
1167
+ const cliOptions = await resolveCliOptions(options, commandKey, io);
1168
+ const client = createOpenApiCliClient(cliOptions);
1169
+ const removed = await client.removeProjectDomain(projectId, domainId);
1170
+ printJson(removed, io);
1171
+ }
1080
1172
  async function handleDeploymentGet(options, io) {
1081
1173
  const commandKey = 'deployment get';
1082
1174
  const deploymentId = readStringOption(options, 'deploymentId') || readStringOption(options, 'id');
1083
1175
  if (!deploymentId) {
1084
- throw createCliUsageError('deployment get requires --deploymentId', commandKey);
1176
+ throw createCliUsageError('deployment get requires --deploymentId or --id', commandKey);
1085
1177
  }
1086
1178
  const cliOptions = await resolveCliOptions(options, commandKey, io);
1087
1179
  const client = createOpenApiCliClient(cliOptions);
@@ -1134,7 +1226,6 @@ function commandDefinitions() {
1134
1226
  usage: ['tezign-ai-appstore auth status [--env test | --baseUrl https://platform.example.com]'],
1135
1227
  options: [...TARGET_CLI_OPTION_HELP],
1136
1228
  notes: [
1137
- '输出 JSON,包含 authenticated、environment、baseUrl、currentEnvironment、configPath 和 keyPrefix。',
1138
1229
  '未传 --env / --baseUrl 时,按目标平台解析顺序检查当前可用环境。',
1139
1230
  ],
1140
1231
  examples: [
@@ -1154,7 +1245,7 @@ function commandDefinitions() {
1154
1245
  ENV_NAME_CLI_OPTION_HELP,
1155
1246
  {
1156
1247
  flag: '--baseUrl <url>',
1157
- description: '必填。平台地址,例如 https://ops.static.tezign.com;保存时会规范化并去掉末尾斜杠。',
1248
+ description: '必填。平台地址。保存时会规范化并去掉末尾斜杠。',
1158
1249
  },
1159
1250
  CONFIG_CLI_OPTION_HELP,
1160
1251
  {
@@ -1179,10 +1270,6 @@ function commandDefinitions() {
1179
1270
  summary: '列出当前所有环境别名',
1180
1271
  usage: ['tezign-ai-appstore env list'],
1181
1272
  options: [CONFIG_CLI_OPTION_HELP],
1182
- notes: [
1183
- '输出 JSON,包含 environments、currentEnvironment 和 configPath。',
1184
- '每个环境会标记是否为当前环境,以及该环境是否已有本地 key。',
1185
- ],
1186
1273
  examples: ['tezign-ai-appstore env list'],
1187
1274
  handler: handleEnvironmentList,
1188
1275
  },
@@ -1207,14 +1294,14 @@ function commandDefinitions() {
1207
1294
  key: 'env remove',
1208
1295
  group: 'env',
1209
1296
  action: 'remove',
1210
- summary: '删除环境别名,不影响已保存的 key 记录',
1297
+ summary: '删除本机该环境的整条配置(别名、baseUrl、本地保存的 Open API Key)',
1211
1298
  usage: ['tezign-ai-appstore env remove --env test'],
1212
1299
  options: [
1213
1300
  ENV_NAME_CLI_OPTION_HELP,
1214
1301
  CONFIG_CLI_OPTION_HELP,
1215
1302
  ],
1216
1303
  notes: [
1217
- '只删除环境别名 profile,不主动撤销平台 key。',
1304
+ '会从 CLI 配置文件中移除该环境的 profile(含本地缓存的 key);不会在平台上吊销或删除 Open API Key。',
1218
1305
  '如果删除的是当前环境,后续命令需要重新 env use 或显式传 --env / --baseUrl。',
1219
1306
  ],
1220
1307
  examples: ['tezign-ai-appstore env remove --env test'],
@@ -1237,7 +1324,7 @@ function commandDefinitions() {
1237
1324
  },
1238
1325
  {
1239
1326
  flag: '--input <json>',
1240
- description: 'mode=create 时必填。创建项目请求体 JSON 对象,字段与 Open API 创建项目接口一致;至少包含非空 name。',
1327
+ description: 'mode=create 时必填。创建项目请求体 JSON;字段形状见下方「--input JSON(TypeScript 形状)」;至少包含非空 name。',
1241
1328
  },
1242
1329
  PROJECT_ID_CLI_OPTION_HELP,
1243
1330
  {
@@ -1248,11 +1335,15 @@ function commandDefinitions() {
1248
1335
  notes: [
1249
1336
  '在当前工作目录写入 .tezign/open-api-project.json,用于记录绑定的项目 ID、项目名和平台环境。',
1250
1337
  '该命令不再进入交互式向导,所有初始化信息都必须通过参数传入。',
1251
- 'mode=create 会调用创建项目接口;mode=link 会通过项目列表校验 --projectId 并绑定匹配项目。',
1338
+ 'mode=create 会调用创建项目接口;创建字段均放入 --input JSON,不再支持 --name、--appType 等拆散参数。',
1339
+ 'mode=create 时若 --input 未包含 requireAuth,CLI 会先写入 requireAuth: false 再请求接口(默认匿名访问);需要登录校验时请显式传 requireAuth: true 并提供 tenantId。',
1340
+ 'mode=link 会通过项目列表校验 --projectId 并绑定匹配项目。',
1341
+ 'mode=create 时 --input 字段形状见前文「--input JSON(TypeScript 形状)」。',
1342
+ 'JSON 参数建议用单引号包裹,例如 --input \'{"name":"Demo"}\';在 PowerShell 中也可用双引号并转义内部引号。',
1252
1343
  '如果当前目录已有绑定,必须传入 --force 才会覆盖。',
1253
1344
  ],
1254
1345
  examples: [
1255
- `tezign-ai-appstore project init --env test --mode create --input '{"name":"Marketing Portal","appType":"STATIC_SITE","requireAuth":false}'`,
1346
+ `tezign-ai-appstore project init --env test --mode create --input '{"name":"Marketing Portal","appType":"STATIC_SITE"}'`,
1256
1347
  'tezign-ai-appstore project init --env test --mode link --projectId proj_123',
1257
1348
  `tezign-ai-appstore project init --baseUrl https://platform.example.com --mode create --input '{"name":"Ops Console"}' --force`,
1258
1349
  ],
@@ -1268,7 +1359,6 @@ function commandDefinitions() {
1268
1359
  ],
1269
1360
  options: [...TARGET_CLI_OPTION_HELP],
1270
1361
  notes: [
1271
- '输出 JSON 项目数组,包含 id、name、appType、requireAuth 等字段。',
1272
1362
  '绑定已有项目前,先执行 project list,把项目列表展示给用户选择,再用选中的 projectId 执行 project init --mode link。',
1273
1363
  ],
1274
1364
  examples: [
@@ -1291,7 +1381,6 @@ function commandDefinitions() {
1291
1381
  ],
1292
1382
  notes: [
1293
1383
  '只读取当前目录项目绑定和全局 CLI 配置,不发起 Open API 请求。',
1294
- '输出 JSON,bound=false 表示当前目录还没有执行 project init。',
1295
1384
  ],
1296
1385
  examples: [
1297
1386
  'tezign-ai-appstore project status',
@@ -1299,33 +1388,6 @@ function commandDefinitions() {
1299
1388
  ],
1300
1389
  handler: handleProjectStatus,
1301
1390
  },
1302
- {
1303
- key: 'project create',
1304
- group: 'project',
1305
- action: 'create',
1306
- summary: '创建一个新的 Open API 项目',
1307
- usage: [
1308
- 'tezign-ai-appstore project create [--env test | --baseUrl https://platform.example.com] --input \'{"name":"Demo"}\'',
1309
- ],
1310
- options: [
1311
- ...TARGET_CLI_OPTION_HELP,
1312
- {
1313
- flag: '--input <json>',
1314
- description: '必填。创建项目请求体 JSON 对象,字段与 Open API 创建项目接口一致;至少包含非空 name。',
1315
- },
1316
- ],
1317
- notes: [
1318
- '不再支持 --name、--appType、--buildCommand 等拆散参数;所有创建字段都放入 --input JSON。',
1319
- '常用字段包括 name、appType、requireAuth、buildCommand、outputDir、tenantId;实际以 Open API 创建项目接口为准。',
1320
- '创建成功后只返回项目 JSON,不会自动写入当前目录绑定;如需绑定目录,使用 project init。',
1321
- ],
1322
- examples: [
1323
- `tezign-ai-appstore project create --env test --input '{"name":"Marketing Portal","requireAuth":false}'`,
1324
- `tezign-ai-appstore project create --input '{"name":"Ops Console","appType":"STATIC_SITE","requireAuth":false}'`,
1325
- `tezign-ai-appstore project create --input '{"name":"SaaS Portal","tenantId":"ten_1"}'`,
1326
- ],
1327
- handler: handleProjectCreate,
1328
- },
1329
1391
  {
1330
1392
  key: 'project update',
1331
1393
  group: 'project',
@@ -1339,12 +1401,13 @@ function commandDefinitions() {
1339
1401
  PROJECT_ID_CLI_OPTION_HELP,
1340
1402
  {
1341
1403
  flag: '--input <json>',
1342
- description: '必填。更新项目请求体 JSON 对象,字段与 Open API 更新项目接口一致;至少包含一个要更新的字段。',
1404
+ description: '必填。更新项目请求体 JSON;字段形状见下方「--input JSON(TypeScript 形状)」;至少包含一个要更新的字段。',
1343
1405
  },
1344
1406
  ],
1345
1407
  notes: [
1346
1408
  '未传 --projectId / --id 时,必须先在当前目录执行 project init 生成项目绑定。',
1347
1409
  '不再支持 --name、--buildCommand、--outputDir 等拆散参数;所有更新字段都放入 --input JSON。',
1410
+ '字段形状见前文「--input JSON(TypeScript 形状)」。',
1348
1411
  ],
1349
1412
  examples: [
1350
1413
  `tezign-ai-appstore project update --env test --projectId proj_123 --input '{"buildCommand":"npm run build","outputDir":"dist"}'`,
@@ -1368,6 +1431,7 @@ function commandDefinitions() {
1368
1431
  '未传 --projectId / --id 时,必须先在当前目录执行 project init 生成项目绑定。',
1369
1432
  '部署是异步的;CLI 会通过返回的 webSocketUrl 自动追踪构建日志和最终状态。',
1370
1433
  '如果最终状态为 FAILED,命令会以失败退出;可用 deployment get 查询部署详情。',
1434
+ '成功时 stdout JSON 含 accessUrls(及 accessUrl 首项);stderr 会列出全部访问链接。',
1371
1435
  ],
1372
1436
  examples: [
1373
1437
  'tezign-ai-appstore project deploy --env test --projectId proj_123',
@@ -1410,6 +1474,80 @@ function commandDefinitions() {
1410
1474
  ],
1411
1475
  handler: handleProjectUploadSource,
1412
1476
  },
1477
+ {
1478
+ key: 'project list-domains',
1479
+ group: 'project',
1480
+ action: 'list-domains',
1481
+ summary: '列出项目已绑定的自定义访问域名',
1482
+ usage: [
1483
+ 'tezign-ai-appstore project list-domains [--env test | --baseUrl https://platform.example.com] [--projectId proj_123]',
1484
+ ],
1485
+ options: [...TARGET_CLI_OPTION_HELP, PROJECT_ID_CLI_OPTION_HELP],
1486
+ notes: [
1487
+ '需要 Open API scope `project:read`。',
1488
+ '未传 --projectId / --id 时,读取当前目录 .tezign/open-api-project.json 绑定。',
1489
+ ],
1490
+ examples: [
1491
+ 'tezign-ai-appstore project list-domains',
1492
+ 'tezign-ai-appstore project list-domains --projectId proj_123',
1493
+ ],
1494
+ handler: handleProjectListDomains,
1495
+ },
1496
+ {
1497
+ key: 'project add-domain',
1498
+ group: 'project',
1499
+ action: 'add-domain',
1500
+ summary: '为项目绑定新的自定义域名(子域名或完整域名)',
1501
+ usage: [
1502
+ 'tezign-ai-appstore project add-domain [--env test | --baseUrl ...] [--projectId proj_123] --subdomain my-app',
1503
+ 'tezign-ai-appstore project add-domain [--projectId proj_123] --full-domain app.example.com [--use-full-domain]',
1504
+ ],
1505
+ options: [
1506
+ ...TARGET_CLI_OPTION_HELP,
1507
+ PROJECT_ID_CLI_OPTION_HELP,
1508
+ {
1509
+ flag: '--subdomain <label>',
1510
+ description: '与 SERVICE_DOMAIN 拼接为完整域名(例如 my-app.example.com);不能与 --full-domain 同时使用。',
1511
+ },
1512
+ {
1513
+ flag: '--full-domain <hostname>',
1514
+ description: '完整域名(需在白名单内);通常仅超级管理员可用;不能与 --subdomain 同时使用。',
1515
+ },
1516
+ {
1517
+ flag: '--use-full-domain <bool>',
1518
+ description: '可选。与 --full-domain 联用时显式声明完整域名模式;也可仅写 --use-full-domain 等价 true。',
1519
+ },
1520
+ ],
1521
+ notes: [
1522
+ '需要 Open API scope `project:update`。',
1523
+ '校验规则与控制台「绑定域名」一致(保留字、白名单、管理前缀冲突等)。',
1524
+ ],
1525
+ examples: [
1526
+ 'tezign-ai-appstore project add-domain --subdomain my-demo-app',
1527
+ 'tezign-ai-appstore project add-domain --projectId proj_123 --full-domain portal.internal.example --use-full-domain',
1528
+ ],
1529
+ handler: handleProjectAddDomain,
1530
+ },
1531
+ {
1532
+ key: 'project remove-domain',
1533
+ group: 'project',
1534
+ action: 'remove-domain',
1535
+ summary: '移除项目下的一条域名绑定',
1536
+ usage: [
1537
+ 'tezign-ai-appstore project remove-domain [--env test | --baseUrl ...] [--projectId proj_123] --domain-id dom_uuid',
1538
+ ],
1539
+ options: [
1540
+ ...TARGET_CLI_OPTION_HELP,
1541
+ PROJECT_ID_CLI_OPTION_HELP,
1542
+ {
1543
+ flag: '--domain-id <id>',
1544
+ description: '必填。域名记录 ID(来自 project list-domains 的 JSON)。',
1545
+ },
1546
+ ],
1547
+ notes: ['需要 Open API scope `project:update`。'],
1548
+ examples: ['tezign-ai-appstore project remove-domain --domain-id abc-def-123'],
1549
+ handler: handleProjectRemoveDomain,
1550
+ },
1413
1551
  {
1414
1552
  key: 'deployment get',
1415
1553
  group: 'deployment',