@openlibing/openlibing-cli 0.1.11 → 0.1.13

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 (44) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +27 -9
  3. package/dist/auth/authedRequest.d.ts +13 -0
  4. package/dist/auth/authedRequest.js +80 -0
  5. package/dist/auth/authedRequest.js.map +1 -0
  6. package/dist/auth/jwt.d.ts +2 -0
  7. package/dist/auth/jwt.js +21 -0
  8. package/dist/auth/jwt.js.map +1 -0
  9. package/dist/auth/login.js +2 -0
  10. package/dist/auth/login.js.map +1 -1
  11. package/dist/auth/refresh.js +2 -0
  12. package/dist/auth/refresh.js.map +1 -1
  13. package/dist/auth/store.d.ts +2 -0
  14. package/dist/auth/store.js.map +1 -1
  15. package/dist/client/reportApi.js +19 -42
  16. package/dist/client/reportApi.js.map +1 -1
  17. package/dist/commands/auth.d.ts +2 -0
  18. package/dist/commands/auth.js +38 -4
  19. package/dist/commands/auth.js.map +1 -1
  20. package/dist/commands/mcp.js +3 -1
  21. package/dist/commands/mcp.js.map +1 -1
  22. package/dist/errors.d.ts +21 -0
  23. package/dist/errors.js +13 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/exitCodes.d.ts +9 -0
  26. package/dist/exitCodes.js +10 -0
  27. package/dist/exitCodes.js.map +1 -0
  28. package/dist/index.js +2 -3
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/server.d.ts +1 -1
  31. package/dist/mcp/server.js +13 -2
  32. package/dist/mcp/server.js.map +1 -1
  33. package/dist/tools/auth/login.js +5 -4
  34. package/dist/tools/auth/login.js.map +1 -1
  35. package/dist/tools/report/listTemplates.d.ts +10 -0
  36. package/dist/tools/report/listTemplates.js +34 -5
  37. package/dist/tools/report/listTemplates.js.map +1 -1
  38. package/dist/tools/types.d.ts +12 -3
  39. package/dist/tools/types.js +23 -1
  40. package/dist/tools/types.js.map +1 -1
  41. package/dist/version.d.ts +1 -0
  42. package/dist/version.js +7 -0
  43. package/dist/version.js.map +1 -0
  44. package/package.json +7 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,73 @@
1
+ # 变更记录
2
+
3
+ 本文件记录 `@openlibing/openlibing-cli` 的版本变更(自 0.1.8 起)。
4
+ 0.1.8 之前为旧包 `@openlibing/mcp-cli`(已 deprecated),迁移说明见 README。
5
+
6
+ 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
7
+
8
+ ## [0.1.13] - 2026-10-29
9
+
10
+ ### Added
11
+
12
+ - `auth status --json`:机器可读输出(环境 / 登录状态 / 账号 / token 过期时间 / 凭证路径),未登录时退出码 4
13
+ - CLI 退出码约定:`0` 成功 / `1` 一般错误 / `4` 认证未建立或凭证失效(脚本可据此触发重新登录)
14
+ - 凭证新增 `expiresAt`(从 JWT exp 解析):调用前临近过期自动预续期(CSRF 滑窗 25 分钟 / token 临期 5 分钟)
15
+
16
+ ### Changed
17
+
18
+ - MCP 工具失败返回统一为 `isError` + `{error,type,hint,details}` 结构化结果,AI 客户端可据 `type` 编程分支
19
+ - 401 续期逻辑收敛至 `authedRequest` 统一入口(预刷新 + 401 自动续期重试 + 结构化认证错误),
20
+ `reportApi` 去除重复逻辑,新增业务 API 自动具备续期能力
21
+
22
+ ### Fixed
23
+
24
+ - `SERVER_INFO.version` / `--version` 改为动态读取 package.json,修复硬编码 `0.1.0` 与实际包版本脱节
25
+
26
+ ## [0.1.12] - 2026-10-29
27
+
28
+ ### Changed
29
+
30
+ - `report_listTemplates` 改为渐进式返回:不传 `modelCode` 返回模板概览列表(modelCode / modelName / description);
31
+ 传入 `modelCode` 返回该模板完整详情(字段元数据 + 仓库列表);不存在时返回错误引导与可用 code 列表
32
+
33
+ ### Docs
34
+
35
+ - README 修正:401 描述对齐实际行为、版本信息更新、新增 MCP 工具说明表与超时配置说明
36
+ (`START_MCP_TIMEOUT_MS` / `RUN_MCP_TIMEOUT_MS` 归属 Trae 客户端)
37
+
38
+ ## [0.1.11] - 2026-10-28
39
+
40
+ ### Changed
41
+
42
+ - CLI 默认环境由 `beta` 改为 `prod`(未设置 `OPENLIBING_ENV` 时生效),
43
+ 修复 CLI auth 写入 beta 凭证、与 MCP 客户端 prod 配置错配的问题
44
+
45
+ ### Added
46
+
47
+ - `auth login` / `auth status` / `auth logout` 输出当前环境标识
48
+
49
+ ### Docs
50
+
51
+ - README 客户端配置示例与 `OPENLIBING_ENV` 默认值同步改为 prod,移除 gamma 描述
52
+
53
+ ## [0.1.10] - 2026-10-13
54
+
55
+ ### Changed
56
+
57
+ - 401 引导改造(面向 AI):服务级 `instructions` 随 initialize 下发(401 时先重新授权、不要排查源码);
58
+ 401 错误文案第一行动项改为"直接调用 auth_login 工具";`auth_login` 工具描述补充"其他工具返回 401 时应首选调用本工具"
59
+
60
+ ## [0.1.9] - 2026-09-23
61
+
62
+ ### Added
63
+
64
+ - 凭证按环境分文件存储(`~/.openlibing-cli/auth.{env}.json`),beta / prod 独立登录、互不覆盖,
65
+ 避免"beta 凭证调 prod 网关"导致 401 / 续期失败
66
+
67
+ ## [0.1.8] - 2026-09-20
68
+
69
+ ### Changed
70
+
71
+ - 更名:npm 包 `@openlibing/mcp-cli` → `@openlibing/openlibing-cli`;bin 命令 `mcp-cli` → `openlibing-cli`;
72
+ 插件 ID 与凭证目录同步调整(迁移说明见 README)
73
+ - 返回字段命名同步 workflow 与 job 级时间
package/README.md CHANGED
@@ -4,7 +4,16 @@ OpenLibing MCP 本地 CLI:把 ops 报告等只读能力包装为 MCP 工具(
4
4
 
5
5
  - **源码仓库**:<https://gitcode.com/w30060144/openlibing-cli>
6
6
  - **npm**:<https://www.npmjs.com/package/@openlibing/openlibing-cli>
7
- - 发布维护:`@openlibing/openlibing-cli`(npmjs latest)
7
+
8
+ ## MCP 工具
9
+
10
+ | 工具 | 说明 |
11
+ | --- | --- |
12
+ | `report_listTemplates` | 查询报告模板:不传参数返回模板概览列表(modelCode / modelName / description);传 `modelCode` 返回该模板完整详情(字段元数据 + 已上报仓库列表) |
13
+ | `report_queryData` | 按模板与条件查询报告数据:支持仓库多选、时间范围、字段过滤与分页(默认 20 条/页,上限 500) |
14
+ | `auth_login` | 触发登录授权(自动弹浏览器,点一次授权即完成);其他工具返回 401 / 提示凭证失效时调用 |
15
+
16
+ > 推荐流程:先 `report_listTemplates` 确认模板与字段,再 `report_queryData` 查询数据(AI 客户端会按此流程自动调用)。
8
17
 
9
18
  ## 特性
10
19
 
@@ -12,10 +21,12 @@ OpenLibing MCP 本地 CLI:把 ops 报告等只读能力包装为 MCP 工具(
12
21
  - **连接即授权**:`mcp start` 启动时自动续期凭证;凭证失效自动弹出浏览器授权,**点一次即完成**
13
22
  - **平台选择**:登录时弹出平台选择页(GitCode / Gitee / GitHub / UniPortal / OpenUBMC),点选后跳转对应平台授权
14
23
  - **凭证安全**:token/refresh/csrf 本地 AES-256-GCM 加密存储(`~/.openlibing-cli/auth.{env}.json`,**按环境分文件**,beta/prod 互不覆盖),不落服务端
15
- - **401 自愈**:工具调用遇 401 自动 refresh 续期重试;续期失败返回明确引导(不依赖外部 cookie)
24
+ - **401 自愈**:工具调用遇 401 自动 refresh 续期重试;续期失败返回明确引导(提示 AI 调用 `auth_login` 工具重新授权,不依赖外部 cookie)
16
25
 
17
26
  ## 安装
18
27
 
28
+ 要求 Node.js ≥ 20.19(或 ≥ 22.12),npx 随 Node 自带。
29
+
19
30
  ```powershell
20
31
  # 直接通过 npx 使用(推荐,AI 客户端配置方式)
21
32
  npx -y @openlibing/openlibing-cli --version
@@ -24,6 +35,8 @@ npx -y @openlibing/openlibing-cli --version
24
35
  npm install -g @openlibing/openlibing-cli
25
36
  ```
26
37
 
38
+ > 提示:若 npx 缓存导致版本滞后,可在包名后加 `@latest` 强制拉取最新版。
39
+
27
40
  ## 客户端配置
28
41
 
29
42
  ### Trae(手动添加 MCP)
@@ -43,7 +56,7 @@ npm install -g @openlibing/openlibing-cli
43
56
  }
44
57
  ```
45
58
 
46
- > `START_MCP_TIMEOUT_MS` 建议 ≥ 300000(5 分钟),给首次授权留足时间,避免 60 秒默认超时误判失败。
59
+ > `START_MCP_TIMEOUT_MS` / `RUN_MCP_TIMEOUT_MS` 为 **Trae 客户端读取的配置**(不是 CLI 环境变量):前者是 MCP 服务启动超时(默认 60000ms),首次授权建议 ≥ 300000(5 分钟),避免超时误判失败;后者是工具调用超时(默认 60000ms),大查询可适当调大。
47
60
 
48
61
  ### OpenCode(opencode.jsonc)
49
62
 
@@ -79,17 +92,19 @@ npx -y @openlibing/openlibing-cli auth login --manual
79
92
 
80
93
  # 查看登录状态 / 续期 / 退出
81
94
  npx -y @openlibing/openlibing-cli auth status
95
+ npx -y @openlibing/openlibing-cli auth status --json # 机器可读输出(脚本/Agent 消费,含 token 过期时间)
82
96
  npx -y @openlibing/openlibing-cli auth refresh
83
97
  npx -y @openlibing/openlibing-cli auth logout
84
98
  ```
85
99
 
86
100
  > 自动登录依赖本机 Chrome 或 Edge(优先 Chrome,失败回退 Edge)。两者都没有时回退手动粘贴方式。
101
+ > CLI 退出码约定:`0` 成功;`1` 一般错误;`4` 认证未建立或凭证失效(脚本可据此触发 `auth login` 重新登录)。
87
102
 
88
103
  ## 环境变量
89
104
 
90
105
  | 变量 | 默认 | 说明 |
91
106
  | --- | --- | --- |
92
- | `OPENLIBING_ENV` | `prod` | 环境:`prod`(建议使用)/ `beta`(开发调试)/ `local`,决定网关与 ops 地址 |
107
+ | `OPENLIBING_ENV` | `prod` | 环境:`prod`(建议使用)/ `beta`(开发调试,数据不实时、与正式不一致)/ `local`,决定网关与 ops 地址 |
93
108
  | `OPENLIBING_PLATFORM` | `gitcode` | 默认登录平台(手动模式兜底用;自动模式弹选择页) |
94
109
  | `OPENLIBING_GATEWAY_URL` | 按 env | 覆盖网关地址 |
95
110
  | `OPENLIBING_OPS_URL` | 按 env | 覆盖 ops 报告接口地址 |
@@ -101,14 +116,14 @@ npx -y @openlibing/openlibing-cli auth logout
101
116
 
102
117
  - 凭证文件:`~/.openlibing-cli/auth.{env}.json`(如 `auth.prod.json` / `auth.beta.json`;AES-256-GCM,密钥由本机标识派生,换机器/用户不可解密)
103
118
  - **环境隔离**:各环境独立登录、独立凭证文件;切换 `OPENLIBING_ENV` 自动读写对应环境凭证,不再互相覆盖
104
- - token / csrf 有效期约 30 分钟:`mcp start` 启动和 401 时自动用 refresh token 续期,无需手动干预
119
+ - token 有效期 8 小时(JWT exp);csrf 为 30 分钟滑动有效期:凭证临近过期时调用会自动**预续期**,401 时自动续期并重试,无需手动干预
105
120
  - refresh token 失效后需重新授权(自动弹浏览器,点一次即可)
106
- - 401 错误信息明确指引运行 `auth login` / `auth refresh`,不会引导获取网关 cookie
121
+ - 401 错误信息明确指引 AI 调用 `auth_login` 工具重新授权(命令行 `auth login` 为备选),不会引导获取网关 cookie
107
122
 
108
123
  ## 发布与维护
109
124
 
110
- - 版本发布走项目级 `npm-manage` skill(`publish.py` 解密 npm token 发布,token 不落明文)
111
- - 版本:`0.1.8`(登录平台选择 / 连接即授权 / 401 自愈 / Playwright 自动登录 / 登录态持久化 / 字段命名同步 workflow 与 job 级时间)
125
+ - 变更记录:[CHANGELOG.md](https://gitcode.com/w30060144/openlibing-cli/blob/main/CHANGELOG.md)
126
+ - 发版流程:更新 CHANGELOG → `npm version --no-git-tag-version` bump 版本 → 提交并打 tag(`vX.Y.Z`)→ 运行 `npm-manage` 的 `publish.py` 发布(npm token 不落明文)
112
127
  - 包名:`@openlibing/openlibing-cli`(原 `@openlibing/mcp-cli` 已 deprecated,迁移说明见下)
113
128
 
114
129
  ### 迁移说明(mcp-cli → openlibing-cli)
@@ -134,5 +149,8 @@ npm test # vitest(握手/凭证/工具注册)
134
149
  | `src/auth/browser.ts` | 系统浏览器启动(chrome→edge 回退)、平台选择页、回调捕获 |
135
150
  | `src/auth/login.ts` | 插件登录 / 自动授权 / 凭证续期 / MCP 启动鉴权 |
136
151
  | `src/auth/store.ts` | 凭证 AES-256-GCM 本地加密存储 |
137
- | `src/client/reportApi.ts` | 报告接口客户端(401 自动续期 + 引导错误) |
152
+ | `src/auth/authedRequest.ts` | 认证请求入口:预刷新 + 401 续期重试 + 结构化错误(业务 API 统一经此) |
153
+ | `src/client/reportApi.ts` | 报告接口客户端 |
154
+ | `src/tools/` | MCP 工具定义(name / description / schema / handler) |
155
+ | `src/config/env.ts` | 环境解析(网关 / ops 地址、默认 prod) |
138
156
  | `src/mcp/server.ts` | MCP stdio server 组装 |
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 认证请求入口:所有需要登录态的业务 API 统一经此发起(续期逻辑单点维护,新增 API 自动具备)。
3
+ *
4
+ * 策略(依据 gateway 行为,见 LoginServiceImpl/AuthFilter):
5
+ * 1. 预刷新:CSRF 为 Redis 滑动 30 分钟(每次请求续期),access token exp 8 小时。
6
+ * 若本地凭证 updatedAt(续期时会同步重取 CSRF)距今超过 25 分钟(留 5 分钟余量),
7
+ * 或 token 剩余有效期不足 5 分钟,则先续期再发起请求——避免“必然失败一次再重试”的往返;
8
+ * 2. 401 兜底:任何 401(含 CSRF 过期、token 失效)自动续期一次并重试;
9
+ * 3. 续期仍失败 → 抛 CliError(type=auth),引导 AI 调用 auth_login(与既有行为指引一致)。
10
+ */
11
+ import { type RequestOptions } from "../client/http.js";
12
+ /** 发起需要登录态的请求:预刷新 → 请求 → 401 自动续期重试一次 → 结构化认证错误 */
13
+ export declare function authedRequest<T>(url: string, opts?: RequestOptions): Promise<T>;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * 认证请求入口:所有需要登录态的业务 API 统一经此发起(续期逻辑单点维护,新增 API 自动具备)。
3
+ *
4
+ * 策略(依据 gateway 行为,见 LoginServiceImpl/AuthFilter):
5
+ * 1. 预刷新:CSRF 为 Redis 滑动 30 分钟(每次请求续期),access token exp 8 小时。
6
+ * 若本地凭证 updatedAt(续期时会同步重取 CSRF)距今超过 25 分钟(留 5 分钟余量),
7
+ * 或 token 剩余有效期不足 5 分钟,则先续期再发起请求——避免“必然失败一次再重试”的往返;
8
+ * 2. 401 兜底:任何 401(含 CSRF 过期、token 失效)自动续期一次并重试;
9
+ * 3. 续期仍失败 → 抛 CliError(type=auth),引导 AI 调用 auth_login(与既有行为指引一致)。
10
+ */
11
+ import { ApiError, request } from "../client/http.js";
12
+ import { refreshToken } from "./refresh.js";
13
+ import { loadAuth } from "./store.js";
14
+ import { CliError } from "../errors.js";
15
+ /** CSRF 滑窗 30 分钟,提前 5 分钟预刷新 */
16
+ const CSRF_REFRESH_WINDOW_MS = 25 * 60_000;
17
+ /** access token 临期 5 分钟内预刷新 */
18
+ const TOKEN_REFRESH_WINDOW_MS = 5 * 60_000;
19
+ /** 凭证失效错误:第一行动项为调用 auth_login(AI 可直接执行),命令行登录为备选;不点名具体 skill */
20
+ function authRequiredError() {
21
+ return new CliError({
22
+ message: "访问被拒绝(HTTP 401):本地 MCP 凭证已失效,自动续期失败。",
23
+ type: "auth",
24
+ hint: "请直接调用 auth_login 工具完成重新授权(会自动弹出浏览器,用户点一次授权即可)。" +
25
+ "若工具不可用,再由用户手动运行 `openlibing-cli auth login` 重新登录" +
26
+ "(凭证按环境独立存储于 ~/.openlibing-cli/auth.{env}.json,与浏览器 cookie 无关)。",
27
+ });
28
+ }
29
+ /** 预刷新判断:凭证临近 CSRF 滑窗或 token 临期时先续期(失败不阻塞,走 401 兜底) */
30
+ async function ensureFreshAuth() {
31
+ const auth = loadAuth();
32
+ if (!auth) {
33
+ throw new CliError({
34
+ message: "未检测到本地登录凭证。",
35
+ type: "auth",
36
+ hint: "请先调用 auth_login 工具完成授权,或由用户运行 `openlibing-cli auth login` 登录。",
37
+ });
38
+ }
39
+ const now = Date.now();
40
+ const csrfStale = now - Date.parse(auth.updatedAt) > CSRF_REFRESH_WINDOW_MS;
41
+ const tokenExpiring = auth.expiresAt
42
+ ? Date.parse(auth.expiresAt) - now < TOKEN_REFRESH_WINDOW_MS
43
+ : false;
44
+ if (csrfStale || tokenExpiring) {
45
+ try {
46
+ await refreshToken();
47
+ }
48
+ catch {
49
+ // 预刷新失败不阻塞:请求若 401 会再触发一次续期(并产出行动导向错误)
50
+ }
51
+ }
52
+ }
53
+ /** 发起需要登录态的请求:预刷新 → 请求 → 401 自动续期重试一次 → 结构化认证错误 */
54
+ export async function authedRequest(url, opts = {}) {
55
+ await ensureFreshAuth();
56
+ try {
57
+ return await request(url, { ...opts, auth: true });
58
+ }
59
+ catch (err) {
60
+ if (!(err instanceof ApiError) || err.status !== 401)
61
+ throw err;
62
+ // 401:续期一次后重试
63
+ try {
64
+ await refreshToken();
65
+ }
66
+ catch {
67
+ throw authRequiredError();
68
+ }
69
+ try {
70
+ return await request(url, { ...opts, auth: true });
71
+ }
72
+ catch (retryErr) {
73
+ if (retryErr instanceof ApiError && retryErr.status === 401) {
74
+ throw authRequiredError();
75
+ }
76
+ throw retryErr;
77
+ }
78
+ }
79
+ }
80
+ //# sourceMappingURL=authedRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authedRequest.js","sourceRoot":"","sources":["../../src/auth/authedRequest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAuB,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,+BAA+B;AAC/B,MAAM,sBAAsB,GAAG,EAAE,GAAG,MAAM,CAAC;AAC3C,+BAA+B;AAC/B,MAAM,uBAAuB,GAAG,CAAC,GAAG,MAAM,CAAC;AAE3C,gEAAgE;AAChE,SAAS,iBAAiB;IACxB,OAAO,IAAI,QAAQ,CAAC;QAClB,OAAO,EAAE,sCAAsC;QAC/C,IAAI,EAAE,MAAM;QACZ,IAAI,EACF,gDAAgD;YAChD,kDAAkD;YAClD,gEAAgE;KACnE,CAAC,CAAC;AACL,CAAC;AAED,uDAAuD;AACvD,KAAK,UAAU,eAAe;IAC5B,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,QAAQ,CAAC;YACjB,OAAO,EAAE,aAAa;YACtB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,+DAA+D;SACtE,CAAC,CAAC;IACL,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,sBAAsB,CAAC;IAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS;QAClC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,GAAG,uBAAuB;QAC5D,CAAC,CAAC,KAAK,CAAC;IACV,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,YAAY,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAI,GAAmB,EAAE;IAEzB,MAAM,eAAe,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,QAAQ,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,GAAG,CAAC;QAChE,cAAc;QACd,IAAI,CAAC;YACH,MAAM,YAAY,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,iBAAiB,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAI,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,IAAI,QAAQ,YAAY,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5D,MAAM,iBAAiB,EAAE,CAAC;YAC5B,CAAC;YACD,MAAM,QAAQ,CAAC;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** 解析 JWT payload 的 exp(秒)并转为 ISO 时间;解析失败返回 undefined(旧凭证/非 JWT 均按无过期信息处理) */
2
+ export declare function parseJwtExpiresAt(token: string): string | undefined;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * JWT 本地解析(不验签):仅用于读取 exp 做本地过期判断与展示,不用于任何安全决策。
3
+ * 插件 access token 为网关签发的标准 JWT(exp = 8 小时),见 LoginServiceImpl#generatePluginAuth。
4
+ */
5
+ import { Buffer } from "node:buffer";
6
+ /** 解析 JWT payload 的 exp(秒)并转为 ISO 时间;解析失败返回 undefined(旧凭证/非 JWT 均按无过期信息处理) */
7
+ export function parseJwtExpiresAt(token) {
8
+ try {
9
+ const payload = token.split(".")[1];
10
+ if (!payload)
11
+ return undefined;
12
+ const json = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
13
+ return typeof json.exp === "number"
14
+ ? new Date(json.exp * 1000).toISOString()
15
+ : undefined;
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC/B,CAAC;QACtB,OAAO,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ;YACjC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;YACzC,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -13,6 +13,7 @@ import { createInterface } from "node:readline";
13
13
  import { env } from "../config/env.js";
14
14
  import { request } from "../client/http.js";
15
15
  import { refreshToken } from "./refresh.js";
16
+ import { parseJwtExpiresAt } from "./jwt.js";
16
17
  import { clearAuth, fingerprint, loadAuth, saveAuth } from "./store.js";
17
18
  import { waitForCallbackUrlWithPicker } from "./browser.js";
18
19
  /** 打开系统浏览器 */
@@ -61,6 +62,7 @@ export async function exchangeCode(code) {
61
62
  accountId: data.accountId,
62
63
  email: data.email,
63
64
  updatedAt: new Date().toISOString(),
65
+ expiresAt: parseJwtExpiresAt(data.token),
64
66
  };
65
67
  }
66
68
  const BROWSER_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36";
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/auth/login.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@
5
5
  import { env } from "../config/env.js";
6
6
  import { request } from "../client/http.js";
7
7
  import { fetchCsrf } from "./login.js";
8
+ import { parseJwtExpiresAt } from "./jwt.js";
8
9
  import { loadAuth, saveAuth } from "./store.js";
9
10
  /** 用 refresh token 换新 access token;成功后更新本地凭证 */
10
11
  export async function refreshToken() {
@@ -22,6 +23,7 @@ export async function refreshToken() {
22
23
  token: data.token,
23
24
  refreshedToken: data.refreshedToken ?? current.refreshedToken,
24
25
  updatedAt: new Date().toISOString(),
26
+ expiresAt: parseJwtExpiresAt(data.token),
25
27
  };
26
28
  // csrf 与 token 同为 30 分钟有效期,续期后同步刷新(失败不阻塞,业务调用时会再次触发续期)
27
29
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAwB,MAAM,YAAY,CAAC;AAetE,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,GAAG,GAAG,CAAC,cAAc,2CAA2C,EAChE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE,CACrE,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,CAAC,OAAO,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,OAAO,GAAoB;QAC/B,GAAG,OAAO;QACV,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,OAAO,CAAC,cAAc;QAC7D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,uDAAuD;IACvD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;IACD,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/auth/refresh.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAwB,MAAM,YAAY,CAAC;AAetE,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,GAAG,GAAG,CAAC,cAAc,2CAA2C,EAChE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE,CACrE,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,CAAC,OAAO,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,OAAO,GAAoB;QAC/B,GAAG,OAAO;QACV,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,OAAO,CAAC,cAAc;QAC7D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;KACzC,CAAC;IACF,uDAAuD;IACvD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;IACD,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -10,6 +10,8 @@ export interface AuthCredentials {
10
10
  email?: string;
11
11
  /** 本地保存时间 ISO */
12
12
  updatedAt: string;
13
+ /** access token 过期时间 ISO(从 JWT exp 解析,可选:旧凭证无此字段时按 401 兜底处理) */
14
+ expiresAt?: string;
13
15
  }
14
16
  export declare function authFilePath(): string;
15
17
  export declare function loadAuth(): AuthCredentials | null;
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/auth/store.ts"],"names":[],"mappings":"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"}
@@ -2,54 +2,31 @@
2
2
  * 报告功能组 REST 客户端:真实调用 ops 报告接口(走网关转发)。
3
3
  * 对应 ops ReportController:POST /test-report/template/list、POST /test-report/data/query。
4
4
  * 响应为 ops 统一 Result<T>({code, messageCn, messageEn, data})。
5
+ * 认证与 401 续期由 authedRequest 统一处理(预刷新 + 401 重试 + 结构化认证错误)。
5
6
  */
6
7
  import { env } from "../config/env.js";
7
- import { ApiError, request } from "./http.js";
8
- import { refreshToken } from "../auth/refresh.js";
9
- /**
10
- * 401 处理(面向 AI 的行动引导):
11
- * 1. 自动用 refresh token 续期一次并重试;
12
- * 2. 续期失败则抛出行动指向明确的错误——第一行动项是“调用 auth_login 工具”(AI 可直接执行),
13
- * 命令行登录作为备选(AI 不一定有 shell 权限);不点名具体 skill,避免反向引导 AI 去排查源码。
14
- */
15
- async function withAuthRetry(fn) {
16
- try {
17
- return await fn();
18
- }
19
- catch (err) {
20
- if (err instanceof ApiError && err.status === 401) {
21
- try {
22
- await refreshToken();
23
- return await fn();
24
- }
25
- catch {
26
- throw new Error("访问被拒绝(HTTP 401):本地 MCP 凭证已失效,自动续期失败。\n" +
27
- "下一步:请直接调用 auth_login 工具完成重新授权(会自动弹出浏览器,用户点一次授权即可)。\n" +
28
- "若工具不可用,再由用户手动运行 `openlibing-cli auth login` 重新登录" +
29
- "(凭证按环境独立存储于 ~/.openlibing-cli/auth.{env}.json,与浏览器 cookie 无关)。");
30
- }
31
- }
32
- throw err;
33
- }
34
- }
8
+ import { authedRequest } from "../auth/authedRequest.js";
9
+ import { CliError } from "../errors.js";
35
10
  /** 查询测试报告模板列表 */
36
11
  export async function listReportTemplates() {
37
- return withAuthRetry(async () => {
38
- const result = await request(`${env.opsBaseUrl}/test-report/template/list`, { method: "POST", body: {}, auth: true });
39
- if (result.code !== 200) {
40
- throw new Error(`listTemplates 失败: ${result.messageCn ?? result.messageEn ?? result.code}`);
41
- }
42
- return result.data;
43
- });
12
+ const result = await authedRequest(`${env.opsBaseUrl}/test-report/template/list`, { method: "POST", body: {} });
13
+ if (result.code !== 200) {
14
+ throw new CliError({
15
+ message: `listTemplates 失败: ${result.messageCn ?? result.messageEn ?? result.code}`,
16
+ type: "api_error",
17
+ });
18
+ }
19
+ return result.data;
44
20
  }
45
21
  /** 按条件查询测试报告数据,分页返回 */
46
22
  export async function queryReportData(params) {
47
- return withAuthRetry(async () => {
48
- const result = await request(`${env.opsBaseUrl}/test-report/data/query`, { method: "POST", body: params, auth: true });
49
- if (result.code !== 200) {
50
- throw new Error(`queryData 失败: ${result.messageCn ?? result.messageEn ?? result.code}`);
51
- }
52
- return result.data;
53
- });
23
+ const result = await authedRequest(`${env.opsBaseUrl}/test-report/data/query`, { method: "POST", body: params });
24
+ if (result.code !== 200) {
25
+ throw new CliError({
26
+ message: `queryData 失败: ${result.messageCn ?? result.messageEn ?? result.code}`,
27
+ type: "api_error",
28
+ });
29
+ }
30
+ return result.data;
54
31
  }
55
32
  //# sourceMappingURL=reportApi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reportApi.js","sourceRoot":"","sources":["../../src/client/reportApi.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA+DlD;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAAI,EAAoB;IAClD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,MAAM,YAAY,EAAE,CAAC;gBACrB,OAAO,MAAM,EAAE,EAAE,CAAC;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACb,wCAAwC;oBACxC,sDAAsD;oBACtD,kDAAkD;oBAClD,gEAAgE,CACjE,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,iBAAiB;AACjB,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,OAAO,aAAa,CAAC,KAAK,IAAI,EAAE;QAC9B,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,GAAG,GAAG,CAAC,UAAU,4BAA4B,EAC7C,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CACzC,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uBAAuB;AACvB,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAA6B;IAE7B,OAAO,aAAa,CAAC,KAAK,IAAI,EAAE;QAC9B,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,GAAG,GAAG,CAAC,UAAU,yBAAyB,EAC1C,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAC7C,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"reportApi.js","sourceRoot":"","sources":["../../src/client/reportApi.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA+DxC,iBAAiB;AACjB,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,GAAG,GAAG,CAAC,UAAU,4BAA4B,EAC7C,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAC7B,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC;YACjB,OAAO,EAAE,qBAAqB,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE;YACnF,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,uBAAuB;AACvB,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAA6B;IAE7B,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,GAAG,GAAG,CAAC,UAAU,yBAAyB,EAC1C,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CACjC,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC;YACjB,OAAO,EAAE,iBAAiB,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE;YAC/E,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * auth 子命令:auth login / auth status / auth logout / auth refresh。
3
+ * 退出码约定:成功 0;认证未建立或凭证失效 4(EXIT_AUTH,脚本可据此触发登录);其他失败 1。
4
+ * auth status 支持 --json 机器可读输出(脚本/Agent 消费;未登录时为 {loggedIn:false} + 退出码 4)。
3
5
  */
4
6
  import { Command } from "commander";
5
7
  export declare function authCommand(program: Command): void;
@@ -2,6 +2,17 @@ import { login, logout, fingerprint } from "../auth/login.js";
2
2
  import { refreshToken } from "../auth/refresh.js";
3
3
  import { loadAuth, authFilePath } from "../auth/store.js";
4
4
  import { env } from "../config/env.js";
5
+ import { EXIT_AUTH } from "../exitCodes.js";
6
+ /** 剩余有效时间的人类可读描述(基于本地时钟差值,仅作展示) */
7
+ function remainingText(iso) {
8
+ const ms = Date.parse(iso) - Date.now();
9
+ if (Number.isNaN(ms))
10
+ return "未知";
11
+ if (ms <= 0)
12
+ return "已过期";
13
+ const minutes = Math.floor(ms / 60_000);
14
+ return minutes >= 60 ? `${Math.floor(minutes / 60)} 小时 ${minutes % 60} 分钟` : `${minutes} 分钟`;
15
+ }
5
16
  export function authCommand(program) {
6
17
  const cmd = program
7
18
  .command("auth")
@@ -17,22 +28,45 @@ export function authCommand(program) {
17
28
  }
18
29
  catch (err) {
19
30
  console.error(`登录失败:${err.message}`);
20
- process.exitCode = 1;
31
+ process.exitCode = EXIT_AUTH;
21
32
  }
22
33
  });
23
34
  cmd
24
35
  .command("status")
25
36
  .description("查看登录状态与凭证位置")
26
- .action(() => {
27
- console.log(`当前环境:${env.env}`);
37
+ .option("--json", "以 JSON 输出(脚本/Agent 消费;未登录时退出码 4)")
38
+ .action((opts) => {
28
39
  const auth = loadAuth();
40
+ if (opts.json) {
41
+ const payload = {
42
+ env: env.env,
43
+ loggedIn: auth !== null,
44
+ accountName: auth?.accountName,
45
+ accountId: auth?.accountId,
46
+ email: auth?.email,
47
+ updatedAt: auth?.updatedAt,
48
+ /** access token 过期时间(JWT exp 解析;旧凭证可能缺失) */
49
+ expiresAt: auth?.expiresAt,
50
+ authFile: authFilePath(),
51
+ };
52
+ console.log(JSON.stringify(payload, null, 2));
53
+ if (!auth) {
54
+ process.exitCode = EXIT_AUTH;
55
+ }
56
+ return;
57
+ }
58
+ console.log(`当前环境:${env.env}`);
29
59
  if (!auth) {
30
60
  console.log("未登录。执行 openlibing-cli auth login 完成授权。");
61
+ process.exitCode = EXIT_AUTH;
31
62
  return;
32
63
  }
33
64
  console.log(`已登录:${auth.accountName ?? "unknown"}(fingerprint=${fingerprint(auth.accountId)})`);
34
65
  console.log(`凭证文件:${authFilePath()}`);
35
66
  console.log(`保存时间:${auth.updatedAt}`);
67
+ if (auth.expiresAt) {
68
+ console.log(`token 有效期至:${auth.expiresAt}(剩余约 ${remainingText(auth.expiresAt)},到期前调用会自动续期)`);
69
+ }
36
70
  });
37
71
  cmd
38
72
  .command("logout")
@@ -51,7 +85,7 @@ export function authCommand(program) {
51
85
  }
52
86
  catch (err) {
53
87
  console.error(`续期失败:${err.message}`);
54
- process.exitCode = 1;
88
+ process.exitCode = EXIT_AUTH;
55
89
  }
56
90
  });
57
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,WAAW,CAAC,CAAC;IAE5B,GAAG;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,UAAU,EAAE,uCAAuC,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,IAA0B,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,WAAW,IAAI,SAAS,OAAO,GAAG,CAAC,GAAG,gBAAgB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACjH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,QAAS,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAChD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,aAAa,CAAC;SAC1B,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,WAAW,IAAI,SAAS,gBAAgB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAChG,OAAO,CAAC,GAAG,CAAC,QAAQ,YAAY,EAAE,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,QAAQ,CAAC;SACrB,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,iCAAiC,CAAC;SAC9C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,WAAW,IAAI,SAAS,gBAAgB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,QAAS,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAChD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { startStdioServer } from "../mcp/server.js";
2
2
  import { tools } from "../mcp/registry.js";
3
3
  import { ensureAuthenticated } from "../auth/login.js";
4
+ import { EXIT_AUTH } from "../exitCodes.js";
4
5
  export function mcpCommand(program) {
5
6
  const cmd = program
6
7
  .command("mcp")
@@ -16,7 +17,8 @@ export function mcpCommand(program) {
16
17
  catch (err) {
17
18
  console.error(`[mcp] 自动授权失败:${err.message}`);
18
19
  console.error("[mcp] 请先运行 `openlibing-cli auth login` 完成登录(或安装 Chrome/Edge 后重连)");
19
- process.exitCode = 1;
20
+ // 认证未建立(含浏览器不可用导致的授权未完成):退出码 4,便于客户端/脚本识别并触发登录
21
+ process.exitCode = EXIT_AUTH;
20
22
  return;
21
23
  }
22
24
  await startStdioServer();
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,UAAU,CAAC,CAAC;IAE3B,GAAG;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oDAAoD,CAAC;SACjE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,oCAAoC;YACpC,MAAM,mBAAmB,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,gBAAiB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACxD,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;YAClF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,gBAAgB,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,eAAe,CAAC;SAC5B,MAAM,CAAC,GAAG,EAAE;QACX,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,MAAM,GAAG,GAAG,OAAO;SAChB,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,UAAU,CAAC,CAAC;IAE3B,GAAG;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oDAAoD,CAAC;SACjE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,oCAAoC;YACpC,MAAM,mBAAmB,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,gBAAiB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACxD,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;YAClF,+CAA+C;YAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,MAAM,gBAAgB,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEL,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,eAAe,CAAC;SAC5B,MAAM,CAAC,GAAG,EAAE;QACX,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 结构化错误:CLI / MCP 工具共用的错误载体。
3
+ * type 供程序分支(AI 客户端可编程恢复),hint 给出下一步行动,details 附机器可读的补充数据。
4
+ */
5
+ export type CliErrorType = "auth" | "not_found" | "api_error" | "unexpected";
6
+ export interface CliErrorOptions {
7
+ /** 面向用户/模型的错误说明 */
8
+ message: string;
9
+ /** 错误分类,默认 unexpected */
10
+ type?: CliErrorType;
11
+ /** 下一步行动指引(如“调用 auth_login 重新授权”) */
12
+ hint?: string;
13
+ /** 附加数据(如可用选项列表) */
14
+ details?: Record<string, unknown>;
15
+ }
16
+ export declare class CliError extends Error {
17
+ readonly type: CliErrorType;
18
+ readonly hint?: string;
19
+ readonly details?: Record<string, unknown>;
20
+ constructor(opts: CliErrorOptions);
21
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,13 @@
1
+ export class CliError extends Error {
2
+ type;
3
+ hint;
4
+ details;
5
+ constructor(opts) {
6
+ super(opts.message);
7
+ this.name = "CliError";
8
+ this.type = opts.type ?? "unexpected";
9
+ this.hint = opts.hint;
10
+ this.details = opts.details;
11
+ }
12
+ }
13
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAe;IACnB,IAAI,CAAU;IACd,OAAO,CAA2B;IAE3C,YAAY,IAAqB;QAC/B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CLI 退出码约定(脚本可据此分支):
3
+ * - 0 成功
4
+ * - 1 一般错误(含 commander 用法错误)
5
+ * - 4 认证未建立或凭证失效(脚本可据此触发 openlibing-cli auth login)
6
+ */
7
+ export declare const EXIT_OK = 0;
8
+ export declare const EXIT_ERROR = 1;
9
+ export declare const EXIT_AUTH = 4;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CLI 退出码约定(脚本可据此分支):
3
+ * - 0 成功
4
+ * - 1 一般错误(含 commander 用法错误)
5
+ * - 4 认证未建立或凭证失效(脚本可据此触发 openlibing-cli auth login)
6
+ */
7
+ export const EXIT_OK = 0;
8
+ export const EXIT_ERROR = 1;
9
+ export const EXIT_AUTH = 4;
10
+ //# sourceMappingURL=exitCodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exitCodes.js","sourceRoot":"","sources":["../src/exitCodes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -4,15 +4,14 @@
4
4
  * 用法:openlibing-cli mcp start(AI 客户端配置 command 方式启动);openlibing-cli auth login(插件授权登录)
5
5
  */
6
6
  import { Command } from "commander";
7
- import { readFileSync } from "node:fs";
8
7
  import { mcpCommand } from "./commands/mcp.js";
9
8
  import { authCommand } from "./commands/auth.js";
10
- const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
9
+ import { APP_VERSION } from "./version.js";
11
10
  const program = new Command();
12
11
  program
13
12
  .name("openlibing-cli")
14
13
  .description("OpenLibing MCP CLI:本地 stdio MCP server")
15
- .version(pkg.version);
14
+ .version(APP_VERSION);
16
15
  mcpCommand(program);
17
16
  authCommand(program);
18
17
  program.parse(process.argv);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC3C,CAAC;AAEzB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAExB,UAAU,CAAC,OAAO,CAAC,CAAC;AACpB,WAAW,CAAC,OAAO,CAAC,CAAC;AAErB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,WAAW,CAAC,CAAC;AAExB,UAAU,CAAC,OAAO,CAAC,CAAC;AACpB,WAAW,CAAC,OAAO,CAAC,CAAC;AAErB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -5,7 +5,7 @@
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  export declare const SERVER_INFO: {
7
7
  readonly name: "openlibing-mcp";
8
- readonly version: "0.1.0";
8
+ readonly version: string;
9
9
  };
10
10
  export declare function createMcpServer(): McpServer;
11
11
  /** 启动 stdio 传输的 MCP Server(阻塞运行,直到 stdin 关闭) */
@@ -5,9 +5,11 @@
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { tools } from "./registry.js";
8
+ import { toErrorResult } from "../tools/types.js";
9
+ import { APP_VERSION } from "../version.js";
8
10
  export const SERVER_INFO = {
9
11
  name: "openlibing-mcp",
10
- version: "0.1.0",
12
+ version: APP_VERSION,
11
13
  };
12
14
  export function createMcpServer() {
13
15
  const server = new McpServer(SERVER_INFO, {
@@ -21,7 +23,16 @@ export function createMcpServer() {
21
23
  "(3) 所有工具均为只读,不会修改平台数据。",
22
24
  });
23
25
  for (const tool of tools) {
24
- server.tool(tool.name, tool.description, tool.schema, async (args) => tool.handler(args));
26
+ server.tool(tool.name, tool.description, tool.schema, async (args) => {
27
+ // 统一失败契约:handler 抛出的 CliError/普通异常均转为 isError 结构化结果,
28
+ // 不再落到 SDK 裸文本兜底(丢失 type/hint 等机器可读信息)
29
+ try {
30
+ return await tool.handler(args);
31
+ }
32
+ catch (err) {
33
+ return toErrorResult(err);
34
+ }
35
+ });
25
36
  }
26
37
  return server;
27
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,OAAO;CACR,CAAC;AAEX,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,WAAW,EACX;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B;8CACsC;QACtC,YAAY,EACV,6BAA6B;YAC7B,uDAAuD;YACvD,gDAAgD;YAChD,2DAA2D;YAC3D,wBAAwB;KAC3B,CACF,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,MAAM,EACX,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAA+B,CAAC,CAC9D,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,gBAAgB;IACtB,OAAO,EAAE,WAAW;CACZ,CAAC;AAEX,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,WAAW,EACX;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B;8CACsC;QACtC,YAAY,EACV,6BAA6B;YAC7B,uDAAuD;YACvD,gDAAgD;YAChD,2DAA2D;YAC3D,wBAAwB;KAC3B,CACF,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,MAAM,EACX,KAAK,EAAE,IAAI,EAAE,EAAE;YACb,qDAAqD;YACrD,uCAAuC;YACvC,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAA+B,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { loginAuto } from "../../auth/login.js";
2
2
  import { textResult } from "../types.js";
3
+ import { CliError } from "../../errors.js";
3
4
  export const authLoginTool = {
4
5
  name: "auth_login",
5
6
  description: "触发浏览器授权登录(自动弹出浏览器,用户点一次授权即完成,无需手动复制 URL)。" +
@@ -11,15 +12,15 @@ export const authLoginTool = {
11
12
  try {
12
13
  const auth = await loginAuto();
13
14
  return textResult({
14
- success: true,
15
15
  message: "登录成功",
16
16
  accountName: auth.accountName ?? "unknown",
17
17
  });
18
18
  }
19
19
  catch (err) {
20
- return textResult({
21
- success: false,
22
- message: `登录失败:${err.message}(可让用户手动运行 openlibing-cli auth login 完成登录)`,
20
+ throw new CliError({
21
+ message: `登录失败:${err.message}`,
22
+ type: "auth",
23
+ hint: "可让用户手动运行 openlibing-cli auth login 完成登录;或确认已安装 Chrome/Edge 后重试",
23
24
  });
24
25
  }
25
26
  },
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/tools/auth/login.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AAE9D,MAAM,CAAC,MAAM,aAAa,GAAmB;IAC3C,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,2CAA2C;QAC3C,qCAAqC;QACrC,wBAAwB;QACxB,wBAAwB;IAC1B,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC;YAC/B,OAAO,UAAU,CAAC;gBAChB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,MAAM;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,UAAU,CAAC;gBAChB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,QAAS,GAAa,CAAC,OAAO,2CAA2C;aACnF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAC;AAEF,kCAAkC;AAClC,MAAM,CAAC,MAAM,SAAS,GAAqB,CAAC,aAAa,CAAC,CAAC"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/tools/auth/login.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,MAAM,aAAa,GAAmB;IAC3C,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,2CAA2C;QAC3C,qCAAqC;QACrC,wBAAwB;QACxB,wBAAwB;IAC1B,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,EAAE,CAAC;YAC/B,OAAO,UAAU,CAAC;gBAChB,OAAO,EAAE,MAAM;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,SAAS;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,QAAQ,CAAC;gBACjB,OAAO,EAAE,QAAS,GAAa,CAAC,OAAO,EAAE;gBACzC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,gEAAgE;aACvE,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAC;AAEF,kCAAkC;AAClC,MAAM,CAAC,MAAM,SAAS,GAAqB,CAAC,aAAa,CAAC,CAAC"}
@@ -1,2 +1,12 @@
1
+ /**
2
+ * report 功能组:查询测试报告模板。
3
+ * 渐进式披露:默认返回模板概览列表(code/名称/描述);传 modelCode 返回单模板完整详情
4
+ * (字段元数据 + 仓库列表),避免模板较多时全量字段一次性返回、不便查看。
5
+ * 对齐 ops ReportMcpTools#listReportTemplates(REST 消费面 / MCP 工具同源)。
6
+ */
7
+ import { z } from "zod";
1
8
  import { type ToolDefinition } from "../types.js";
9
+ export declare const listTemplatesSchema: {
10
+ modelCode: z.ZodOptional<z.ZodString>;
11
+ };
2
12
  export declare const listTemplatesTool: ToolDefinition;
@@ -1,16 +1,45 @@
1
1
  /**
2
- * report 功能组:查询测试报告模板列表。
2
+ * report 功能组:查询测试报告模板。
3
+ * 渐进式披露:默认返回模板概览列表(code/名称/描述);传 modelCode 返回单模板完整详情
4
+ * (字段元数据 + 仓库列表),避免模板较多时全量字段一次性返回、不便查看。
3
5
  * 对齐 ops ReportMcpTools#listReportTemplates(REST 消费面 / MCP 工具同源)。
4
6
  */
7
+ import { z } from "zod";
5
8
  import { listReportTemplates } from "../../client/reportApi.js";
6
9
  import { textResult } from "../types.js";
10
+ import { CliError } from "../../errors.js";
11
+ export const listTemplatesSchema = {
12
+ modelCode: z
13
+ .string()
14
+ .optional()
15
+ .describe("模板 code(可选):传入时返回该模板完整详情(字段元数据 columns 与仓库列表 repoUrls);不传则返回全部模板的概览列表"),
16
+ };
7
17
  export const listTemplatesTool = {
8
18
  name: "report_listTemplates",
9
- description: "查询测试报告模板列表,返回模板 code、模板名、字段元数据(列名/注释/类型/必填)与已上报数据的仓库地址列表",
10
- schema: {},
11
- handler: async () => {
19
+ description: "查询测试报告模板。不传 modelCode:返回模板概览列表(每项含 modelCode/modelName/description)," +
20
+ "模板较多时先看概览确认模板 code;传入 modelCode:返回该模板完整详情(字段元数据 columns、已上报仓库列表 repoUrls)," +
21
+ "用于确认可用字段与查询范围后再调用 report_queryData 查数据。",
22
+ schema: listTemplatesSchema,
23
+ handler: async (args) => {
12
24
  const templates = await listReportTemplates();
13
- return textResult(templates);
25
+ const modelCode = args.modelCode?.trim();
26
+ if (!modelCode) {
27
+ return textResult(templates.map((t) => ({
28
+ modelCode: t.modelCode,
29
+ modelName: t.modelName,
30
+ description: t.description ?? "",
31
+ })));
32
+ }
33
+ const target = templates.find((t) => t.modelCode === modelCode);
34
+ if (!target) {
35
+ throw new CliError({
36
+ message: `未找到模板:${modelCode}`,
37
+ type: "not_found",
38
+ hint: "请从 details.availableModelCodes 中选择模板 code 后重试",
39
+ details: { availableModelCodes: templates.map((t) => t.modelCode) },
40
+ });
41
+ }
42
+ return textResult(target);
14
43
  },
15
44
  };
16
45
  //# sourceMappingURL=listTemplates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"listTemplates.js","sourceRoot":"","sources":["../../../src/tools/report/listTemplates.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AAE9D,MAAM,CAAC,MAAM,iBAAiB,GAAmB;IAC/C,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,0DAA0D;IAC5D,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,SAAS,GAAG,MAAM,mBAAmB,EAAE,CAAC;QAC9C,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"listTemplates.js","sourceRoot":"","sources":["../../../src/tools/report/listTemplates.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAuB,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,uEAAuE,CACxE;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAmB;IAC/C,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,sEAAsE;QACtE,4EAA4E;QAC5E,yCAAyC;IAC3C,MAAM,EAAE,mBAAmB;IAC3B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtB,MAAM,SAAS,GAAG,MAAM,mBAAmB,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAI,IAAI,CAAC,SAAgC,EAAE,IAAI,EAAE,CAAC;QACjE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,UAAU,CACf,SAAS,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC;gBACpC,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;aACjC,CAAC,CAAC,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAAC;gBACjB,OAAO,EAAE,SAAS,SAAS,EAAE;gBAC7B,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,+CAA+C;gBACrD,OAAO,EAAE,EAAE,mBAAmB,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE;aACpE,CAAC,CAAC;QACL,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;CACF,CAAC"}
@@ -1,9 +1,14 @@
1
1
  /**
2
- * MCP 工具定义类型。
2
+ * MCP 工具定义类型与结果构造。
3
+ * 返回契约(与 lark-cli 信封思路一致):
4
+ * - 成功:textResult(data),纯业务 JSON;
5
+ * - 失败:errorResult/toErrorResult → isError: true + { error, type, hint?, details? },
6
+ * AI 客户端可据 isError/type 编程分支(如 auth 类错误引导调用 auth_login)。
3
7
  * 协议层由 @modelcontextprotocol/sdk 内置,工具只需声明 name/schema/执行函数。
4
8
  */
5
9
  import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
6
10
  import type { ZodRawShape } from "zod";
11
+ import { CliError } from "../errors.js";
7
12
  export interface ToolDefinition {
8
13
  /** 工具名:<功能组>_<动作>,如 report_listTemplates */
9
14
  name: string;
@@ -11,8 +16,12 @@ export interface ToolDefinition {
11
16
  description: string;
12
17
  /** 参数 schema(zod),自动生成 JSON Schema */
13
18
  schema: ZodRawShape;
14
- /** 执行函数:参数为按 schema 校验后的对象,返回 MCP CallToolResult */
19
+ /** 执行函数:参数为按 schema 校验后的对象,返回 MCP CallToolResult;业务错误建议抛 CliError,由 server 层统一转失败结果 */
15
20
  handler: (args: Record<string, unknown>) => Promise<CallToolResult>;
16
21
  }
17
- /** 把任意 JSON 序列化为文本内容块 */
22
+ /** 把任意 JSON 序列化为文本内容块(成功结果) */
18
23
  export declare function textResult(data: unknown): CallToolResult;
24
+ /** 构造失败结果:结构化 JSON + isError 标记 */
25
+ export declare function errorResult(err: CliError): CallToolResult;
26
+ /** 把任意异常统一转为失败结果(server 注册层 catch 使用;非 CliError 归为 unexpected) */
27
+ export declare function toErrorResult(err: unknown): CallToolResult;
@@ -1,7 +1,29 @@
1
- /** 把任意 JSON 序列化为文本内容块 */
1
+ import { CliError } from "../errors.js";
2
+ /** 把任意 JSON 序列化为文本内容块(成功结果) */
2
3
  export function textResult(data) {
3
4
  return {
4
5
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
5
6
  };
6
7
  }
8
+ /** 构造失败结果:结构化 JSON + isError 标记 */
9
+ export function errorResult(err) {
10
+ const payload = { error: err.message, type: err.type };
11
+ if (err.hint)
12
+ payload.hint = err.hint;
13
+ if (err.details)
14
+ payload.details = err.details;
15
+ return {
16
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
17
+ isError: true,
18
+ };
19
+ }
20
+ /** 把任意异常统一转为失败结果(server 注册层 catch 使用;非 CliError 归为 unexpected) */
21
+ export function toErrorResult(err) {
22
+ if (err instanceof CliError)
23
+ return errorResult(err);
24
+ return errorResult(new CliError({
25
+ message: err instanceof Error ? err.message : String(err),
26
+ type: "unexpected",
27
+ }));
28
+ }
7
29
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAkBA,yBAAyB;AACzB,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAaxC,+BAA+B;AAC/B,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,WAAW,CAAC,GAAa;IACvC,MAAM,OAAO,GAA4B,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;IAChF,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtC,IAAI,GAAG,CAAC,OAAO;QAAE,OAAO,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC/C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACnE,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,IAAI,GAAG,YAAY,QAAQ;QAAE,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IACrD,OAAO,WAAW,CAChB,IAAI,QAAQ,CAAC;QACX,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACzD,IAAI,EAAE,YAAY;KACnB,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const APP_VERSION: string;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 应用版本:统一从 package.json 动态读取,
3
+ * 供 CLI --version 与 MCP ServerInfo.version 共用,避免硬编码导致版本漂移。
4
+ */
5
+ import { readFileSync } from "node:fs";
6
+ export const APP_VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
7
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GACtB,IAAI,CAAC,KAAK,CACR,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAEpE,CAAC,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@openlibing/openlibing-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "OpenLibing MCP 本地 CLI:把 ops 报告等只读能力包装为 MCP 工具(stdio 传输)",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://gitcode.com/w30060144/openlibing-cli.git"
8
+ },
5
9
  "type": "module",
6
10
  "bin": {
7
11
  "openlibing-cli": "dist/index.js"
@@ -10,7 +14,8 @@
10
14
  "access": "public"
11
15
  },
12
16
  "files": [
13
- "dist"
17
+ "dist",
18
+ "CHANGELOG.md"
14
19
  ],
15
20
  "engines": {
16
21
  "node": "^20.19.0 || >=22.12.0"