@cnbcool/cnb-api-generate 2.4.1 → 2.4.3

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/client/core.ts CHANGED
@@ -4,6 +4,7 @@ import os from 'os';
4
4
  import { fetchResponseHandler } from "./fetch-response-handler";
5
5
  import { generateUniqueId } from './utils/generate-unique-id';
6
6
  import { resolveToken } from './utils/resolve-token';
7
+ import { resolveApiDomain } from './utils/resolve-api-domain';
7
8
 
8
9
  /**
9
10
  * 格式化 API 响应
@@ -118,7 +119,7 @@ async function formatResponse(data: any, response: any) {
118
119
 
119
120
  async function clientFetch(data: any): Promise<any> {
120
121
  const token = await resolveToken();
121
- const domain = process.env.CNB_API_ENDPOINT || 'https://api.cnb.cool'
122
+ const domain = resolveApiDomain()
122
123
  const url = `${domain}${data.url}`
123
124
  const urlParse = new URL(url);
124
125
  if (data.params) {
package/client/index.ts CHANGED
@@ -5,6 +5,8 @@ import { getExtraHelpText } from './lib/extra-help';
5
5
  import { registerModuleCommands } from './lib/register-modules';
6
6
  import { registerFallbackAction } from './lib/register-fallback';
7
7
  import { registerLoginCommand } from './lib/login';
8
+ import { registerLogoutCommand } from './lib/logout';
9
+ import { registerStatusCommand } from './lib/status';
8
10
 
9
11
  // ============================================================
10
12
  // Commander 程序定义
@@ -26,6 +28,8 @@ program
26
28
  // ============================================================
27
29
 
28
30
  registerLoginCommand(program);
31
+ registerLogoutCommand(program);
32
+ registerStatusCommand(program);
29
33
  registerModuleCommands(program);
30
34
  registerFallbackAction(program);
31
35
 
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { resolveToken } from '../utils/resolve-token';
10
+ import { resolveApiDomain } from '../utils/resolve-api-domain';
10
11
 
11
12
  /** CNB 构建号格式:cnb-xxx-xxxxxxxxx(字母/数字组成的两段) */
12
13
  export const SN_PATTERN = /^cnb-[a-z0-9]+-[a-z0-9]+$/i;
@@ -111,7 +112,7 @@ export async function resolveBuildContext(
111
112
  | { ok: true; ctx: ResolvedContext }
112
113
  | { ok: false; message: string }
113
114
  > {
114
- const domain = process.env.CNB_API_ENDPOINT || 'https://api.cnb.cool';
115
+ const domain = resolveApiDomain();
115
116
  const { repo } = options;
116
117
  let sn = options.sn;
117
118
 
@@ -16,12 +16,13 @@ export function registerLoginCommand(program: Command): void {
16
16
  .description('通过 OAuth2 设备授权流登录 CNB,获取并保存 access_token')
17
17
  .option('--client-id <string>', 'OAuth2 client_id', process.env.OAUTH2_CLIENT_ID || 'cnb_cli')
18
18
  .option('--woa', '使用内网环境 (https://cnb.woa.com)', false)
19
+ .option('--host <string>', '指定自定义域名 (优先级高于 --woa)')
19
20
  .option('--debug', '打印调试信息', false)
20
21
  .helpOption('-h, --help', '显示帮助文档')
21
22
  .action(async (opts) => {
22
23
  const cfg: LoginConfig = {
23
24
  clientID: opts.clientId,
24
- platformURL: opts.woa ? 'https://cnb.woa.com' : 'https://cnb.cool',
25
+ platformURL: opts.host ? opts.host : opts.woa ? 'https://cnb.woa.com' : 'https://cnb.cool',
25
26
  debug: opts.debug,
26
27
  };
27
28
 
@@ -77,11 +78,15 @@ export function registerLoginCommand(program: Command): void {
77
78
  }
78
79
  // 持久化 token
79
80
  const nowSec = Math.floor(Date.now() / 1000);
81
+ // 从 platformURL 推导 API 域名,例如 https://cnb.cool -> https://api.cnb.cool
82
+ const platformHost = new URL(cfg.platformURL).hostname;
83
+ const loginHost = `https://api.${platformHost}`;
80
84
  const store: TokenStore = {
81
85
  access_token: tok.access_token,
82
86
  expires_at: nowSec + tok.expires_in,
83
87
  platform_url: cfg.platformURL,
84
88
  client_id: cfg.clientID,
89
+ login_host: loginHost,
85
90
  };
86
91
  if (tok.refresh_token) {
87
92
  store.refresh_token = tok.refresh_token;
@@ -0,0 +1,35 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs';
3
+ import { getTokenPath } from '../utils/token-path';
4
+ import { loadToken } from '../utils/load-token';
5
+
6
+ export function registerLogoutCommand(program: Command): void {
7
+ program
8
+ .command('logout')
9
+ .description('退出登录,删除本地保存的 access_token')
10
+ .option('--debug', '打印调试信息', false)
11
+ .helpOption('-h, --help', '显示帮助文档')
12
+ .action(async (opts) => {
13
+ const tokenPath = getTokenPath();
14
+ const token = loadToken();
15
+
16
+ if (!token) {
17
+ console.log('当前未登录,无需退出。');
18
+ return;
19
+ }
20
+
21
+ if (opts.debug) {
22
+ console.log(`Token 文件路径: ${tokenPath}`);
23
+ console.log(`Platform URL : ${token.platform_url}`);
24
+ console.log(`Client ID : ${token.client_id}`);
25
+ }
26
+
27
+ try {
28
+ fs.unlinkSync(tokenPath);
29
+ console.log('已成功退出登录。');
30
+ } catch (err: any) {
31
+ console.error(`退出登录失败: ${err.message}`);
32
+ process.exit(1);
33
+ }
34
+ });
35
+ }
@@ -0,0 +1,59 @@
1
+ import { Command } from 'commander';
2
+ import { getTokenPath } from '../utils/token-path';
3
+ import { loadToken } from '../utils/load-token';
4
+ import { refreshAccessToken } from '../utils/refresh-token';
5
+
6
+ export function registerStatusCommand(program: Command): void {
7
+ program
8
+ .command('status')
9
+ .description('检查当前登录状态(token 是否存在、是否过期)')
10
+ .option('--debug', '打印调试信息', false)
11
+ .helpOption('-h, --help', '显示帮助文档')
12
+ .action(async (opts) => {
13
+ const tokenPath = getTokenPath();
14
+ const token = loadToken();
15
+
16
+ if (!token) {
17
+ console.log('⚠️ 未登录,请执行 `cnb login` 进行授权。');
18
+ return;
19
+ }
20
+
21
+ if (opts.debug) {
22
+ console.log(`Token 文件路径 : ${tokenPath}`);
23
+ console.log(`Platform URL : ${token.platform_url || '未知'}`);
24
+ console.log(`Client ID : ${token.client_id || '未知'}`);
25
+ console.log(`Expires At : ${new Date(token.expires_at * 1000).toLocaleString()}`);
26
+ }
27
+
28
+ const nowSec = Math.floor(Date.now() / 1000);
29
+ const isExpired = nowSec >= token.expires_at;
30
+
31
+ if (isExpired) {
32
+ // 尝试使用 refresh_token 刷新
33
+ if (token.refresh_token) {
34
+ if (opts.debug) {
35
+ console.log('Token 已过期,尝试使用 refresh_token 刷新...');
36
+ }
37
+ try {
38
+ await refreshAccessToken(token);
39
+ const refreshedToken = loadToken();
40
+ if (refreshedToken) {
41
+ console.log('✅ 已登录。');
42
+ if (opts.debug) {
43
+ console.log(' (Token 已自动刷新)');
44
+ }
45
+ }
46
+ } catch (err: any) {
47
+ if (opts.debug) {
48
+ console.log(`刷新失败: ${err.message}`);
49
+ }
50
+ console.log('⚠️ 未登录,请执行 `cnb login` 重新授权。');
51
+ }
52
+ } else {
53
+ console.log('⚠️ 未登录,请执行 `cnb login` 重新授权。');
54
+ }
55
+ } else {
56
+ console.log('✅ 已登录。');
57
+ }
58
+ });
59
+ }
@@ -0,0 +1,26 @@
1
+ import { loadToken } from './load-token';
2
+
3
+ /**
4
+ * 获取 API 域名。
5
+ *
6
+ * 优先级:
7
+ * 1. 如果设置了环境变量 CNB_TOKEN(即非 OAuth 登录),使用 CNB_API_ENDPOINT 或默认值
8
+ * 2. 如果是 OAuth 登录(token 文件中有 login_host),使用登录时记录的域名
9
+ * 3. 兜底使用 CNB_API_ENDPOINT 或默认值 https://api.cnb.cool
10
+ */
11
+ export function resolveApiDomain(): string {
12
+ const defaultDomain = process.env.CNB_API_ENDPOINT || 'https://api.cnb.cool';
13
+
14
+ // 如果使用环境变量 token,直接走 CNB_API_ENDPOINT
15
+ if (process.env.CNB_TOKEN_FOR_CODEBUDDY || process.env.CNB_TOKEN) {
16
+ return defaultDomain;
17
+ }
18
+
19
+ // OAuth 登录场景:优先使用登录时记录的域名
20
+ const store = loadToken();
21
+ if (store?.login_host) {
22
+ return store.login_host;
23
+ }
24
+
25
+ return defaultDomain;
26
+ }
@@ -42,4 +42,6 @@ export interface TokenStore {
42
42
  platform_url?: string;
43
43
  /** 用于 refresh 时携带 client_id */
44
44
  client_id?: string;
45
+ /** 登录时使用的 API 域名(如 https://api.cnb.cool),用于后续 CLI 调用 */
46
+ login_host?: string;
45
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnbcool/cnb-api-generate",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "main": "./built/index.js",
5
5
  "module": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cnb-api
3
- description: CNB OpenAPI 交互能力,支持仓库、Issue、PR、流水线、制品库等操作。
3
+ description: CNB 平台交互命令,支持仓库、Issue、PR、流水线、制品库等操作。
4
4
  ---
5
5
 
6
6
  # cnb-api
@@ -38,16 +38,14 @@ pulls:
38
38
  - `<$CNB_CLI_CMD$> pulls upload-image --file 图片路径` — 上传图片到当前 PR
39
39
 
40
40
  注意事项:
41
- - **路径参数自动识别**:快捷命令中的 Issue/PR 编号会自动从环境变量识别,无需额外传递。
42
- - **默认只输出摘要**:默认会精简响应输出结果,只返回核心字段。添加 `--verbose` 输出完整数据。
43
- - **多行文本传参使用单引号**:传递多行文本参数时,使用单引号可防止命令注入攻击,并减少不必要的转义。
44
- - **快捷命令范围** 快捷命令只能操作当前仓库的当前 Issue/PR,跨仓库或跨编号操作请使用其他 API 命令。
41
+ - **参数自动识别**:快捷命令中的 Issue/PR 编号会自动从环境变量识别,无需额外传递。
42
+ - **默认仅需摘要**:默认会精简响应输出结果,只返回核心字段。添加 `--verbose` 输出完整数据。
43
+ - **单引号传参**:传递多行文本参数时,使用单引号可防止命令注入攻击,并减少不必要的转义。
44
+ - **快捷命令适用范围**: 快捷命令只能操作当前仓库的当前 Issue/PR,跨仓库或跨编号操作请参考 `更多 API`。
45
+ - **npc提及和召唤的区别**: 评论中直接 @npc 会召唤 npc 干活,如果只提及不召唤,应该去掉 `@` 符号,或使用反引号包裹 `@npc`。
45
46
 
46
47
  ## 更多 API
47
48
 
48
- 优先使用快捷命令,不满足时才使用以下这些命令
49
-
50
49
  1. `<$CNB_CLI_CMD$> --help` 查看所有模块
51
50
  2. `<$CNB_CLI_CMD$> <module> --help` 查看模块下的工具列表
52
51
  3. `<$CNB_CLI_CMD$> <module> <tool> --help` 查看工具参数
53
- 4. 按帮助文档操作,禁止猜测