@openlibing/openlibing-cli 0.1.12 → 0.1.14

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 (52) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +19 -8
  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 +41 -4
  19. package/dist/commands/auth.js.map +1 -1
  20. package/dist/commands/mcp.d.ts +1 -0
  21. package/dist/commands/mcp.js +16 -1
  22. package/dist/commands/mcp.js.map +1 -1
  23. package/dist/errors.d.ts +21 -0
  24. package/dist/errors.js +13 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/exitCodes.d.ts +9 -0
  27. package/dist/exitCodes.js +10 -0
  28. package/dist/exitCodes.js.map +1 -0
  29. package/dist/index.js +2 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/mcp/registry.js +2 -1
  32. package/dist/mcp/registry.js.map +1 -1
  33. package/dist/mcp/server.d.ts +1 -1
  34. package/dist/mcp/server.js +13 -2
  35. package/dist/mcp/server.js.map +1 -1
  36. package/dist/tools/auth/login.js +5 -4
  37. package/dist/tools/auth/login.js.map +1 -1
  38. package/dist/tools/cli/version.d.ts +4 -0
  39. package/dist/tools/cli/version.js +38 -0
  40. package/dist/tools/cli/version.js.map +1 -0
  41. package/dist/tools/report/listTemplates.js +6 -3
  42. package/dist/tools/report/listTemplates.js.map +1 -1
  43. package/dist/tools/types.d.ts +12 -3
  44. package/dist/tools/types.js +23 -1
  45. package/dist/tools/types.js.map +1 -1
  46. package/dist/updateCheck.d.ts +18 -0
  47. package/dist/updateCheck.js +100 -0
  48. package/dist/updateCheck.js.map +1 -0
  49. package/dist/version.d.ts +2 -0
  50. package/dist/version.js +10 -0
  51. package/dist/version.js.map +1 -0
  52. package/package.json +7 -2
@@ -1,6 +1,10 @@
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 { env } from "../config/env.js";
5
+ import { APP_VERSION } from "../version.js";
6
+ import { checkForUpdate } from "../updateCheck.js";
7
+ import { EXIT_AUTH } from "../exitCodes.js";
4
8
  export function mcpCommand(program) {
5
9
  const cmd = program
6
10
  .command("mcp")
@@ -9,6 +13,8 @@ export function mcpCommand(program) {
9
13
  .command("start")
10
14
  .description("启动 MCP stdio server(自动完成授权:已有凭证自动续期,无凭证弹出浏览器点一次授权)")
11
15
  .action(async () => {
16
+ // 版本横幅:让客户端日志中能直接确认本次运行的实际版本(npx 缓存/配置差异时尤为重要)
17
+ console.error(`[mcp] openlibing-cli v${APP_VERSION} 启动(环境 ${env.env},${tools.length} 个工具)`);
12
18
  try {
13
19
  // 连接即授权:凭证续期/授权失败则退出,提示用户处理,避免无凭证空跑
14
20
  await ensureAuthenticated();
@@ -16,15 +22,24 @@ export function mcpCommand(program) {
16
22
  catch (err) {
17
23
  console.error(`[mcp] 自动授权失败:${err.message}`);
18
24
  console.error("[mcp] 请先运行 `openlibing-cli auth login` 完成登录(或安装 Chrome/Edge 后重连)");
19
- process.exitCode = 1;
25
+ // 认证未建立(含浏览器不可用导致的授权未完成):退出码 4,便于客户端/脚本识别并触发登录
26
+ process.exitCode = EXIT_AUTH;
20
27
  return;
21
28
  }
29
+ // 后台检查更新(fire-and-forget:不阻塞启动;24h 节流;失败静默)
30
+ void checkForUpdate().then((info) => {
31
+ if (info?.hasUpdate) {
32
+ console.error(`[mcp] 提示:openlibing-cli 有新版本 v${info.latest}(当前 v${info.current})。` +
33
+ "建议 MCP 客户端配置中的包名使用 @latest 并重连以升级;也可调用 cli_version 工具查看详情");
34
+ }
35
+ });
22
36
  await startStdioServer();
23
37
  });
24
38
  cmd
25
39
  .command("list")
26
40
  .description("列出已注册的 MCP 工具")
27
41
  .action(() => {
42
+ console.log(`openlibing-cli v${APP_VERSION}(${tools.length} 个工具):`);
28
43
  for (const tool of tools) {
29
44
  console.log(`${tool.name}\t${tool.description}`);
30
45
  }
@@ -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":"AAKA,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,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,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,+CAA+C;QAC/C,OAAO,CAAC,KAAK,CAAC,yBAAyB,WAAW,UAAU,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC;QAC5F,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,4CAA4C;QAC5C,KAAK,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAClC,IAAI,IAAI,EAAE,SAAS,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CACX,iCAAiC,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,OAAO,IAAI;oBAClE,2DAA2D,CAC9D,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,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,OAAO,CAAC,GAAG,CAAC,mBAAmB,WAAW,IAAI,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;QACpE,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"}
@@ -4,5 +4,6 @@
4
4
  */
5
5
  import { reportTools } from "../tools/report/index.js";
6
6
  import { authTools } from "../tools/auth/login.js";
7
- export const tools = [...reportTools, ...authTools];
7
+ import { cliTools } from "../tools/cli/version.js";
8
+ export const tools = [...reportTools, ...authTools, ...cliTools];
8
9
  //# sourceMappingURL=registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD,MAAM,CAAC,MAAM,KAAK,GAAqB,CAAC,GAAG,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,MAAM,CAAC,MAAM,KAAK,GAAqB,CAAC,GAAG,WAAW,EAAE,GAAG,SAAS,EAAE,GAAG,QAAQ,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"}
@@ -0,0 +1,4 @@
1
+ import { type ToolDefinition } from "../types.js";
2
+ export declare const cliVersionTool: ToolDefinition;
3
+ /** cli 功能组工具列表(供 registry 聚合) */
4
+ export declare const cliTools: ToolDefinition[];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * cli 功能组:cli_version —— 查询当前运行的 CLI/MCP 服务版本,并检查是否有新版本。
3
+ * 场景:MCP 使用中用户/AI 无法直接得知 npx 拉起的实际版本(配置缓存差异),
4
+ * 也无法感知版本落后;本工具提供单一查询入口(24h 节流,失败静默)。
5
+ */
6
+ import { env } from "../../config/env.js";
7
+ import { APP_VERSION } from "../../version.js";
8
+ import { checkForUpdate, updateCheckDisabled } from "../../updateCheck.js";
9
+ import { textResult } from "../types.js";
10
+ export const cliVersionTool = {
11
+ name: "cli_version",
12
+ description: "查询当前运行的 openlibing-cli 版本,并检查是否有新版本可用(检查结果缓存 24 小时,网络失败时静默)。" +
13
+ "当用户询问 CLI 版本 / 是否最新 / 如何升级,或怀疑本地版本过旧导致行为不一致时调用。",
14
+ schema: {},
15
+ handler: async () => {
16
+ const update = await checkForUpdate();
17
+ const payload = {
18
+ version: APP_VERSION,
19
+ env: env.env,
20
+ /** ok=已检查;disabled=用户关闭了更新检查;unavailable=网络不可达/超时 */
21
+ updateCheck: updateCheckDisabled() ? "disabled" : update ? "ok" : "unavailable",
22
+ };
23
+ if (update) {
24
+ payload.latestVersion = update.latest;
25
+ payload.hasUpdate = update.hasUpdate;
26
+ }
27
+ if (update?.hasUpdate) {
28
+ payload.updateHint =
29
+ `检测到新版本 v${update.latest}(当前 v${update.current})。升级方式:` +
30
+ "MCP 客户端配置中的包名使用 @openlibing/openlibing-cli@latest 并重连(npx 自动拉取最新版);" +
31
+ "或在终端运行 npx -y @openlibing/openlibing-cli@latest --version 验证。";
32
+ }
33
+ return textResult(payload);
34
+ },
35
+ };
36
+ /** cli 功能组工具列表(供 registry 聚合) */
37
+ export const cliTools = [cliVersionTool];
38
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/tools/cli/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAuB,MAAM,aAAa,CAAC;AAE9D,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,8DAA8D;QAC9D,iDAAiD;IACnD,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,KAAK,IAAI,EAAE;QAClB,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;QACtC,MAAM,OAAO,GAA4B;YACvC,OAAO,EAAE,WAAW;YACpB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,qDAAqD;YACrD,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa;SAChF,CAAC;QACF,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;YACtC,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACvC,CAAC;QACD,IAAI,MAAM,EAAE,SAAS,EAAE,CAAC;YACtB,OAAO,CAAC,UAAU;gBAChB,WAAW,MAAM,CAAC,MAAM,QAAQ,MAAM,CAAC,OAAO,SAAS;oBACvD,qEAAqE;oBACrE,+DAA+D,CAAC;QACpE,CAAC;QACD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;CACF,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,MAAM,QAAQ,GAAqB,CAAC,cAAc,CAAC,CAAC"}
@@ -7,6 +7,7 @@
7
7
  import { z } from "zod";
8
8
  import { listReportTemplates } from "../../client/reportApi.js";
9
9
  import { textResult } from "../types.js";
10
+ import { CliError } from "../../errors.js";
10
11
  export const listTemplatesSchema = {
11
12
  modelCode: z
12
13
  .string()
@@ -31,9 +32,11 @@ export const listTemplatesTool = {
31
32
  }
32
33
  const target = templates.find((t) => t.modelCode === modelCode);
33
34
  if (!target) {
34
- return textResult({
35
- error: `未找到模板:${modelCode}`,
36
- availableModelCodes: templates.map((t) => t.modelCode),
35
+ throw new CliError({
36
+ message: `未找到模板:${modelCode}`,
37
+ type: "not_found",
38
+ hint: "请从 details.availableModelCodes 中选择模板 code 后重试",
39
+ details: { availableModelCodes: templates.map((t) => t.modelCode) },
37
40
  });
38
41
  }
39
42
  return textResult(target);
@@ -1 +1 @@
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;AAE9D,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,OAAO,UAAU,CAAC;gBAChB,KAAK,EAAE,SAAS,SAAS,EAAE;gBAC3B,mBAAmB,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;aACvD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,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,18 @@
1
+ export interface UpdateInfo {
2
+ /** 当前版本 */
3
+ current: string;
4
+ /** registry 上的最新版本 */
5
+ latest: string;
6
+ /** 是否有新版本可用 */
7
+ hasUpdate: boolean;
8
+ }
9
+ /** 更新检查是否被禁用(OPENLIBING_NO_UPDATE_NOTIFIER=1) */
10
+ export declare function updateCheckDisabled(): boolean;
11
+ /** 比较 x.y.z 版本号:a > b 返回正数,相等返回 0(按数字段比较,非字符串比较) */
12
+ export declare function compareVersions(a: string, b: string): number;
13
+ /**
14
+ * 检查是否有新版本可用(24h 节流):
15
+ * - 禁用 / 网络失败 → null(调用方按“无法判断”静默处理)
16
+ * - 其余返回 UpdateInfo(hasUpdate 表示是否落后)
17
+ */
18
+ export declare function checkForUpdate(): Promise<UpdateInfo | null>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * 版本更新检查(借鉴 gh 的 24h 节流 + lark-cli 的缓存优先策略):
3
+ * - 检查源:npm registry 的 latest 版本(包名从 package.json 动态读取)
4
+ * - 节流:结果缓存 24 小时(~/.openlibing-cli/update-check.json),避免频繁网络请求
5
+ * - 静默失败:网络错误 / 超时(3s)返回 null,不影响调用方主流程
6
+ * - 开关:OPENLIBING_NO_UPDATE_NOTIFIER=1 完全禁用检查(MCP 客户端配置 env 中设置)
7
+ * - 测试隔离:OPENLIBING_UPDATE_CHECK_FILE 可覆盖缓存文件路径
8
+ * 注意:环境变量均在调用时读取(而非模块加载时),便于测试覆盖与运行期生效。
9
+ */
10
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { dirname, join } from "node:path";
13
+ import { APP_VERSION, PKG_NAME } from "./version.js";
14
+ const CHECK_INTERVAL_MS = 24 * 60 * 60_000;
15
+ const FETCH_TIMEOUT_MS = 3_000;
16
+ function cacheFilePath() {
17
+ return (process.env.OPENLIBING_UPDATE_CHECK_FILE ??
18
+ join(homedir(), ".openlibing-cli", "update-check.json"));
19
+ }
20
+ /** 更新检查是否被禁用(OPENLIBING_NO_UPDATE_NOTIFIER=1) */
21
+ export function updateCheckDisabled() {
22
+ return !!process.env.OPENLIBING_NO_UPDATE_NOTIFIER;
23
+ }
24
+ function readCache() {
25
+ try {
26
+ return JSON.parse(readFileSync(cacheFilePath(), "utf8"));
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ function writeCache(state) {
33
+ try {
34
+ const file = cacheFilePath();
35
+ mkdirSync(dirname(file), { recursive: true });
36
+ writeFileSync(file, JSON.stringify(state, null, 2));
37
+ }
38
+ catch {
39
+ // 缓存写入失败不影响主流程(下次调用重新检查)
40
+ }
41
+ }
42
+ /** 比较 x.y.z 版本号:a > b 返回正数,相等返回 0(按数字段比较,非字符串比较) */
43
+ export function compareVersions(a, b) {
44
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
45
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
46
+ for (let i = 0; i < 3; i++) {
47
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
48
+ if (diff !== 0)
49
+ return diff;
50
+ }
51
+ return 0;
52
+ }
53
+ function toInfo(latest) {
54
+ return {
55
+ current: APP_VERSION,
56
+ latest,
57
+ hasUpdate: compareVersions(latest, APP_VERSION) > 0,
58
+ };
59
+ }
60
+ /** 从 npm registry 拉取 latest 版本号(超时/失败返回 null) */
61
+ async function fetchLatestVersion() {
62
+ const controller = new AbortController();
63
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
64
+ try {
65
+ const url = `https://registry.npmjs.org/${encodeURIComponent(PKG_NAME)}/latest`;
66
+ const resp = await fetch(url, {
67
+ signal: controller.signal,
68
+ headers: { Accept: "application/json" },
69
+ });
70
+ if (!resp.ok)
71
+ return null;
72
+ const data = (await resp.json());
73
+ return typeof data.version === "string" ? data.version : null;
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ finally {
79
+ clearTimeout(timer);
80
+ }
81
+ }
82
+ /**
83
+ * 检查是否有新版本可用(24h 节流):
84
+ * - 禁用 / 网络失败 → null(调用方按“无法判断”静默处理)
85
+ * - 其余返回 UpdateInfo(hasUpdate 表示是否落后)
86
+ */
87
+ export async function checkForUpdate() {
88
+ if (updateCheckDisabled())
89
+ return null;
90
+ const cached = readCache();
91
+ if (cached && Date.now() - Date.parse(cached.checkedAt) < CHECK_INTERVAL_MS) {
92
+ return toInfo(cached.latestVersion);
93
+ }
94
+ const latest = await fetchLatestVersion();
95
+ if (!latest)
96
+ return null;
97
+ writeCache({ checkedAt: new Date().toISOString(), latestVersion: latest });
98
+ return toInfo(latest);
99
+ }
100
+ //# sourceMappingURL=updateCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateCheck.js","sourceRoot":"","sources":["../src/updateCheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const APP_VERSION: string;
2
+ export declare const PKG_NAME: string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 应用元信息:统一从 package.json 动态读取,
3
+ * 供 CLI --version、MCP ServerInfo.version、更新检查(包名拼 registry URL)共用,
4
+ * 避免硬编码导致版本/包名漂移。
5
+ */
6
+ import { readFileSync } from "node:fs";
7
+ const PKG = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
8
+ export const APP_VERSION = PKG.version;
9
+ export const PKG_NAME = PKG.name;
10
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC7B,CAAC;AAEvC,MAAM,CAAC,MAAM,WAAW,GAAW,GAAG,CAAC,OAAO,CAAC;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAW,GAAG,CAAC,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@openlibing/openlibing-cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
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"