bfi-cli 0.1.86 → 0.1.89

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/dist/cli.mjs CHANGED
@@ -8307,12 +8307,12 @@ async function runYmc(args, globalOpts) {
8307
8307
  const token = globalOpts.token;
8308
8308
  const api = new YmcApi(token ?? null, void 0, dryRun);
8309
8309
  if (!sub || sub === "--help" || sub === "-h") {
8310
- printHelp$2();
8310
+ printHelp$3();
8311
8311
  return;
8312
8312
  }
8313
8313
  if (sub === "help") {
8314
8314
  if (!rest[0]) {
8315
- printHelp$2();
8315
+ printHelp$3();
8316
8316
  return;
8317
8317
  }
8318
8318
  printCommandHelp(rest[0]);
@@ -8888,7 +8888,7 @@ async function runYmc(args, globalOpts) {
8888
8888
  }
8889
8889
  default:
8890
8890
  console.error(`未知子命令:${sub}`);
8891
- printHelp$2();
8891
+ printHelp$3();
8892
8892
  process.exit(1);
8893
8893
  }
8894
8894
  }
@@ -9023,11 +9023,11 @@ function printCommandHelp(cmd) {
9023
9023
  if (h) console.log(h);
9024
9024
  else {
9025
9025
  console.error(`未知子命令:${cmd}`);
9026
- printHelp$2();
9026
+ printHelp$3();
9027
9027
  process.exit(1);
9028
9028
  }
9029
9029
  }
9030
- function printHelp$2() {
9030
+ function printHelp$3() {
9031
9031
  console.log(`
9032
9032
  bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
9033
9033
 
@@ -9082,7 +9082,7 @@ const RESOURCES = [
9082
9082
  "type-info",
9083
9083
  "listener-doc"
9084
9084
  ];
9085
- function printHelp$1() {
9085
+ function printHelp$2() {
9086
9086
  console.log(`bfi event — YonBIP 事件中心取数(诊断编排见 bfi-diagnose-event 技能)
9087
9087
 
9088
9088
  用法:
@@ -9119,7 +9119,7 @@ async function runEvent(args, globalOpts) {
9119
9119
  const sub = args[0];
9120
9120
  const rest = args.slice(1);
9121
9121
  if (!sub || sub === "--help" || sub === "-h" || flag(rest, "--help") || flag(rest, "-h")) {
9122
- printHelp$1();
9122
+ printHelp$2();
9123
9123
  return;
9124
9124
  }
9125
9125
  const jsonMode = flag(rest, "--json");
@@ -9290,6 +9290,65 @@ async function runEvent(args, globalOpts) {
9290
9290
  console.error(`未知子命令: ${sub}。运行 bfi event --help`);
9291
9291
  process.exit(1);
9292
9292
  }
9293
+ function printHelp$1() {
9294
+ console.log(`bfi ms — 微服务→仓库映射(诊断中把微服务编码可靠地转换为仓库列表)
9295
+
9296
+ 用法:
9297
+ bfi ms <微服务编码> # 精确/模糊查询(精确匹配行排前)
9298
+ bfi ms --keyword <名称关键词> # 按微服务中文名模糊查询
9299
+ 全局: --json / --dry-run / --token <tok>
9300
+
9301
+ 输出: 每个微服务的 code/名称/类型/部门/负责人/Jira 项目 + repos 列表
9302
+ (repo 为 BCS 图谱仓库名(git 地址末段),可直接作 bfi-code-search context 的 repo 参数)
9303
+
9304
+ 示例:
9305
+ bfi ms yonbip-scm-stock
9306
+ bfi ms --keyword 库存
9307
+
9308
+ 提示: 事件监听的 microServiceCode 字段 / 异常栈的包名线索都可用本命令反查仓库。`);
9309
+ }
9310
+ async function runMs(args, globalOpts) {
9311
+ const rest = args;
9312
+ if (!args[0] || flag(rest, "--help") || flag(rest, "-h")) {
9313
+ printHelp$1();
9314
+ return;
9315
+ }
9316
+ const jsonMode = flag(rest, "--json");
9317
+ const dryRun = flag(rest, "--dry-run");
9318
+ const api = new YmcApi(globalOpts.token ?? null, void 0, dryRun);
9319
+ if (!dryRun && !api.token) {
9320
+ console.error("未认证。先运行:bfi auth login --token <sk-token>(或传 --token)");
9321
+ process.exit(1);
9322
+ }
9323
+ const keyword = opt(rest, "--keyword");
9324
+ const code = keyword ? "" : positionals(rest)[0] ?? "";
9325
+ if (!code && !keyword) {
9326
+ console.error("缺少微服务编码或 --keyword。运行 bfi ms --help 查看用法。");
9327
+ process.exit(1);
9328
+ }
9329
+ const body = {
9330
+ code,
9331
+ name: keyword ?? "",
9332
+ use_status: opt(rest, "--use-status") ?? "1",
9333
+ page: Number(opt(rest, "--page") ?? 1),
9334
+ size: Number(opt(rest, "--size") ?? 20)
9335
+ };
9336
+ emit(await api.call("code/microservice", body), jsonMode, (data) => {
9337
+ const d = data;
9338
+ const rows = d.rows ?? [];
9339
+ if (!rows.length) return `无匹配微服务(total=${d.total ?? 0})`;
9340
+ return rows.map((r) => {
9341
+ const repos = r.repos ?? [];
9342
+ const repoLines = repos.map((x) => ` - ${x.repo} (${x.git_url}${x.branch ? ` @${x.branch}` : ""})`).join("\n");
9343
+ return [
9344
+ `${r.code} ${r.name} [${r.type || "-"}]`,
9345
+ ` 部门: ${r.department || "-"} | 开发: ${r.developer_name || "-"} | 架构: ${r.architect_name || "-"} | Jira: ${r.jira_project_name || "-"}`,
9346
+ ` 仓库(${repos.length}):`,
9347
+ repoLines || " (无 git 地址)"
9348
+ ].join("\n");
9349
+ }).join("\n\n");
9350
+ });
9351
+ }
9293
9352
  async function runDb(args, globalOpts) {
9294
9353
  const sub = args[0];
9295
9354
  const rest = args.slice(1);
@@ -10019,6 +10078,9 @@ async function main() {
10019
10078
  case "event":
10020
10079
  await runEvent(restArgs, globalOpts);
10021
10080
  break;
10081
+ case "ms":
10082
+ await runMs(restArgs, globalOpts);
10083
+ break;
10022
10084
  case "db":
10023
10085
  await runDb(restArgs, globalOpts);
10024
10086
  break;
@@ -90,10 +90,86 @@ function loadGlobalConfig() {
90
90
  }
91
91
  return null;
92
92
  }
93
+ function resolveApiBase() {
94
+ return process.env.BFI_API_BASE || "http://172.20.35.178:8901";
95
+ }
93
96
  function resolveToken() {
94
97
  if (process.env.BFI_TOKEN) return process.env.BFI_TOKEN;
95
98
  return loadGlobalConfig()?.token ?? null;
96
99
  }
100
+ const LOCAL_TOOL_NAMES = ["microservice_repo"];
101
+ const LOCAL_TOOLS = [{
102
+ name: "microservice_repo",
103
+ description: "微服务编码→仓库映射(代码定位前置:微服务编码≠仓库名,勿猜 repo)。返回该微服务的 BCS 图谱仓库名(裸名,可直接作 context/query 的 repo 参数)及 git 地址/分支/部门/负责人/Jira 项目。编码来源:事件监听的 microServiceCode 字段、异常栈包名线索、服务名。注意:zoekt_search 的 repo 是 org__repo 形态(如 SEM__EPM_BP),喂给图谱系前须去掉 org__ 前缀。",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ code: {
108
+ type: "string",
109
+ description: "微服务编码(如 yonbip-scm-stock;bfi 侧模糊匹配,精确行排前)"
110
+ },
111
+ name: {
112
+ type: "string",
113
+ description: "微服务中文名模糊查询(可选,如 库存)"
114
+ },
115
+ size: {
116
+ type: "number",
117
+ description: "返回行数上限(默认 20)"
118
+ }
119
+ }
120
+ }
121
+ }];
122
+ async function microserviceRepo(args) {
123
+ const code = String(args?.code ?? "").trim();
124
+ const name = String(args?.name ?? "").trim();
125
+ if (!code && !name) return errResult("microservice_repo 需要 code 或 name —— 例 { \"code\": \"yonbip-scm-stock\" }", "invalid_params");
126
+ const token = resolveToken();
127
+ if (!token) return errResult("未找到 bfi token:请先执行 `bfi auth login --token <sk-token>`(token 获取地址 https://bfi.yyuap.com/user/profile),或设置 BFI_TOKEN 环境变量", "unauthorized");
128
+ let resp;
129
+ try {
130
+ resp = await fetch(`${resolveApiBase()}/bficli/api/v2/code/microservice`, {
131
+ method: "POST",
132
+ headers: {
133
+ "Content-Type": "application/json",
134
+ Authorization: `Bearer ${token}`
135
+ },
136
+ body: JSON.stringify({
137
+ code,
138
+ name,
139
+ use_status: "1",
140
+ page: 1,
141
+ size: Number(args?.size ?? 20)
142
+ })
143
+ });
144
+ } catch (e) {
145
+ return errResult(`bfi-api 不可达:${e instanceof Error ? e.message : String(e)}`, "unreachable");
146
+ }
147
+ if (resp.status === 401 || resp.status === 403) return errResult("v2 token 无效或过期:请重新 `bfi auth login --token <token>`", "unauthorized");
148
+ const body = await resp.json().catch(() => null);
149
+ if (!body || body.code !== 0) return errResult(`bfi-api 返回异常:${body?.msg ?? resp.status}`, "upstream_error");
150
+ return { content: [{
151
+ type: "text",
152
+ text: JSON.stringify(body.data, null, 2)
153
+ }] };
154
+ }
155
+ function errResult(message, errorKind) {
156
+ return {
157
+ content: [{
158
+ type: "text",
159
+ text: JSON.stringify({
160
+ ok: false,
161
+ error_kind: errorKind,
162
+ message
163
+ }, null, 2)
164
+ }],
165
+ isError: true
166
+ };
167
+ }
168
+ async function callLocalTool(name, args) {
169
+ if (!LOCAL_TOOL_NAMES.includes(name)) return null;
170
+ if (name === "microservice_repo") return microserviceRepo(args);
171
+ return null;
172
+ }
97
173
  function textResult(payload, isError = false) {
98
174
  return {
99
175
  content: [{
@@ -117,15 +193,20 @@ function buildServer(remote) {
117
193
  "· 规则链:rule_chain(单据动作有效规则链)/ rule_impact(规则被哪些链使用)/ rule_search(模糊搜规则/单据)",
118
194
  "· 内容检索:zoekt_search(跨 309 仓文本/正则/行级,毫秒级——搜字面量/URL/配置值/报错文案);read_file / grep(单仓工作区文件读取与文本检索——定位到仓后取原文片段用)",
119
195
  "· 多仓契约组:group_list(组清单)/ group_sync(契约同步);组内可跨仓 trace(repo 传 \"@组名\")",
196
+ "· 微服务→仓库:microservice_repo(本地工具)——微服务编码映射 BCS 图谱仓库名(裸名,直接作 context 的 repo 参数);编码来源:事件监听 microServiceCode/异常栈包名",
197
+ "· ⚠️ 仓名两套形态:zoekt_search 用 org__repo(SEM__EPM_BP),图谱系用裸名(EPM_BP)——zoekt 结果喂 context 前去掉 org__ 前缀",
120
198
  "· 佐证纪律:多候选必须让用户确认;trace 结果校验仓库归属;检索结果不是完整源码,结合行号取源码片段引用;跨仓 trace 仅覆盖契约可提取的调用形态,\"无路径\"不等于\"无调用\""
121
199
  ].join("\n")
122
200
  });
123
201
  server.setRequestHandler(ListToolsRequestSchema, async () => {
124
- return { tools: await bcs.listTools() };
202
+ const tools = await bcs.listTools();
203
+ return { tools: [...LOCAL_TOOLS, ...tools] };
125
204
  });
126
205
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
127
206
  const { name, arguments: args } = request.params;
128
207
  try {
208
+ const local = await callLocalTool(name, args);
209
+ if (local) return local;
129
210
  return await bcs.callTool(name, args);
130
211
  } catch (e) {
131
212
  return textResult({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfi-cli",
3
- "version": "0.1.86",
3
+ "version": "0.1.89",
4
4
  "description": "用友大业财BFI统一命令行工具,支持技能,技能包,元数据,UI元数据等",
5
5
  "type": "module",
6
6
  "bin": {