@agile-team/wl-skills-kit 2.4.2 → 2.5.1

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/mcp/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- 'use strict'
2
+ "use strict";
3
3
 
4
4
  /**
5
5
  * wl-skills MCP Server
@@ -8,6 +8,7 @@
8
8
  * 暴露工具:
9
9
  * wls_menu_query 查询菜单树
10
10
  * wls_menu_upsert 批量新增/更新菜单
11
+ * wls_menu_sync_from_report 从 SYS_MENU_INFO*.md 确定性同步菜单
11
12
  * wls_dict_query 查询字典模块
12
13
  * wls_dict_upsert 新增/更新字典模块及字典项
13
14
  * wls_role_query 查询角色列表
@@ -25,10 +26,14 @@
25
26
  * node node_modules/@agile-team/wl-skills-kit/mcp/server.js
26
27
  */
27
28
 
28
- const readline = require('readline')
29
- const { loadConfig } = require('./config')
30
- const { handleMenuQuery, handleMenuUpsert } = require('./tools/menuSync')
31
- const { handleDictQuery, handleDictUpsert } = require('./tools/dictSync')
29
+ const readline = require("readline");
30
+ const { loadConfig } = require("./config");
31
+ const {
32
+ handleMenuQuery,
33
+ handleMenuUpsert,
34
+ handleMenuSyncFromReport,
35
+ } = require("./tools/menuSync");
36
+ const { handleDictQuery, handleDictUpsert } = require("./tools/dictSync");
32
37
  const {
33
38
  handleRoleQuery,
34
39
  handleRoleUpsert,
@@ -36,376 +41,455 @@ const {
36
41
  handleAssignableMenusQuery,
37
42
  handleActionQuery,
38
43
  handleActionUpsert,
39
- } = require('./tools/permissionSync')
44
+ } = require("./tools/permissionSync");
40
45
  const {
41
46
  handleCodeScan,
47
+ handleValidatePage,
48
+ handleDoctorUi,
42
49
  handleRouteCheck,
43
50
  handleGitLogExtract,
44
51
  handleAuditReportPush,
45
- } = require('./tools/projectTools')
52
+ } = require("./tools/projectTools");
46
53
 
47
- const PKG = require('../package.json')
54
+ const PKG = require("../package.json");
48
55
 
49
56
  // ─── Tool 注册表 ────────────────────────────────────────────────────────
50
57
 
51
58
  const TOOLS = [
52
59
  {
53
- name: 'wls_menu_query',
60
+ name: "wls_menu_query",
54
61
  description:
55
- '查询当前应用的完整菜单树。自动从 .github/skills/sync/env.local.json 读取 domainId,' +
56
- '无需传参。在 wls_menu_upsert 前调用,用于判断哪些菜单需要新增、哪些需要更新。',
62
+ "查询当前应用的完整菜单树。自动从 .github/skills/sync/env.local.json 读取 domainId," +
63
+ "无需传参。在 wls_menu_upsert 前调用,用于判断哪些菜单需要新增、哪些需要更新。",
57
64
  inputSchema: {
58
- type: 'object',
65
+ type: "object",
59
66
  properties: {},
60
67
  required: [],
61
68
  },
62
69
  },
63
70
  {
64
- name: 'wls_menu_upsert',
71
+ name: "wls_menu_upsert",
65
72
  description:
66
- '批量新增或更新菜单项。有 id 字段 → 更新;无 id 字段 → 新增。' +
67
- '新增时响应自动包含服务端生成的 id,可链式用于创建子菜单。',
73
+ "批量新增或更新菜单项。有 id 字段 → 更新;无 id 字段 → 新增。" +
74
+ "新增时响应自动包含服务端生成的 id,可链式用于创建子菜单。",
68
75
  inputSchema: {
69
- type: 'object',
76
+ type: "object",
70
77
  properties: {
71
78
  items: {
72
- type: 'array',
79
+ type: "array",
73
80
  description:
74
- 'MenuSaveBody 数组。每项字段:' +
75
- 'id(更新时传), sysAppNo, menuName, menuNameCode, parentId, ' +
81
+ "MenuSaveBody 数组。每项字段:" +
82
+ "id(更新时传), sysAppNo, menuName, menuNameCode, parentId, " +
76
83
  'type("M"=目录/"C"=菜单), path, icon, orderNum, ' +
77
- 'useCache(1), common(2), hidden(false), editMode(false), ' +
78
- 'component(type=C时传), permission(type=C时传)',
79
- items: { type: 'object' },
84
+ "useCache(1), common(2), hidden(false), editMode(false), " +
85
+ "component(type=C时传), permission(type=C时传)",
86
+ items: { type: "object" },
87
+ },
88
+ },
89
+ required: ["items"],
90
+ },
91
+ },
92
+ {
93
+ name: "wls_menu_sync_from_report",
94
+ description:
95
+ "读取 .github/reports/SYS_MENU_INFO*.md,按一级目录(type=M)优先、二级菜单(type=C)随后同步到后端菜单。" +
96
+ "自动查询 domain 菜单树去重,复用或更新已存在菜单,避免把二级页面全部挂到根 parentMenuId。",
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {
100
+ reportPath: {
101
+ type: "string",
102
+ description:
103
+ "可选。SYS_MENU_INFO*.md 路径;不传则使用 .github/reports 下最新报告。",
104
+ },
105
+ dryRun: {
106
+ type: "boolean",
107
+ description: "可选。true 时只解析和预览,不调用保存接口。",
80
108
  },
81
109
  },
82
- required: ['items'],
110
+ required: [],
83
111
  },
84
112
  },
85
113
  {
86
- name: 'wls_dict_query',
114
+ name: "wls_dict_query",
87
115
  description:
88
- '查询当前应用的所有字典模块及字典项。在 wls_dict_upsert 前调用,' +
89
- '用于判断哪些模块/字典项已存在。',
116
+ "查询当前应用的所有字典模块及字典项。在 wls_dict_upsert 前调用," +
117
+ "用于判断哪些模块/字典项已存在。",
90
118
  inputSchema: {
91
- type: 'object',
119
+ type: "object",
92
120
  properties: {},
93
121
  required: [],
94
122
  },
95
123
  },
96
124
  {
97
- name: 'wls_dict_upsert',
125
+ name: "wls_dict_upsert",
98
126
  description:
99
- '新增或更新字典模块及其字典项。内部自动处理:' +
100
- '若模块不存在则创建(data=null 后自动 re-query 获取 id),' +
101
- '若已存在则直接取 id;字典项自动跳过已存在的 strSn。',
127
+ "新增或更新字典模块及其字典项。内部自动处理:" +
128
+ "若模块不存在则创建(data=null 后自动 re-query 获取 id)," +
129
+ "若已存在则直接取 id;字典项自动跳过已存在的 strSn。",
102
130
  inputSchema: {
103
- type: 'object',
131
+ type: "object",
104
132
  properties: {
105
133
  module: {
106
- type: 'object',
107
- description: 'DictModuleSaveBody: strSn(必填), strName(必填), sortPriority("1"), strLevel(2)',
134
+ type: "object",
135
+ description:
136
+ 'DictModuleSaveBody: strSn(必填), strName(必填), sortPriority("1"), strLevel(2)',
108
137
  properties: {
109
- strSn: { type: 'string', description: '模块标识符,如 "gender"' },
110
- strName: { type: 'string', description: '模块显示名,如 "性别"' },
111
- sortPriority: { type: 'string', description: '排序,字符串类型,如 "1"' },
112
- strLevel: { type: 'number', description: '固定传 2' },
138
+ strSn: { type: "string", description: '模块标识符,如 "gender"' },
139
+ strName: { type: "string", description: '模块显示名,如 "性别"' },
140
+ sortPriority: {
141
+ type: "string",
142
+ description: '排序,字符串类型,如 "1"',
143
+ },
144
+ strLevel: { type: "number", description: "固定传 2" },
113
145
  },
114
- required: ['strSn', 'strName'],
146
+ required: ["strSn", "strName"],
115
147
  },
116
148
  items: {
117
- type: 'array',
149
+ type: "array",
118
150
  description:
119
- 'DictItemSaveBody 数组(可选)。每项字段:' +
120
- 'strSn(必填), strName(必填), strLevel(2), ' +
151
+ "DictItemSaveBody 数组(可选)。每项字段:" +
152
+ "strSn(必填), strName(必填), strLevel(2), " +
121
153
  'dtlValue(""), dtlValueRequired(false), dtlValue2Required(false), ' +
122
- 'dtlValue3Required(false), dtlValue4Required(false)',
123
- items: { type: 'object' },
154
+ "dtlValue3Required(false), dtlValue4Required(false)",
155
+ items: { type: "object" },
124
156
  },
125
157
  },
126
- required: ['module'],
158
+ required: ["module"],
127
159
  },
128
160
  },
129
161
  {
130
- name: 'wls_role_query',
162
+ name: "wls_role_query",
131
163
  description:
132
- '查询角色列表。可选参数 current/size 翻页,默认 size=100。返回精简字段:id, roleName, code, sysAppNo, roleDesc。',
164
+ "查询角色列表。可选参数 current/size 翻页,默认 size=100。返回精简字段:id, roleName, code, sysAppNo, roleDesc。",
133
165
  inputSchema: {
134
- type: 'object',
166
+ type: "object",
135
167
  properties: {
136
- current: { type: 'number', description: '页码,默认 1' },
137
- size: { type: 'number', description: '每页数量,默认 100' },
168
+ current: { type: "number", description: "页码,默认 1" },
169
+ size: { type: "number", description: "每页数量,默认 100" },
138
170
  },
139
171
  required: [],
140
172
  },
141
173
  },
142
174
  {
143
- name: 'wls_role_upsert',
175
+ name: "wls_role_upsert",
144
176
  description:
145
- '批量新增角色(按 code 字段自动去重;已存在则跳过)。每项必填 roleName 和 code,可选 configDesc。' +
146
- '注意:角色仅新增不更新,因角色变更通常需要业务确认。',
177
+ "批量新增角色(按 code 字段自动去重;已存在则跳过)。每项必填 roleName 和 code,可选 configDesc。" +
178
+ "注意:角色仅新增不更新,因角色变更通常需要业务确认。",
147
179
  inputSchema: {
148
- type: 'object',
180
+ type: "object",
149
181
  properties: {
150
182
  items: {
151
- type: 'array',
183
+ type: "array",
152
184
  description:
153
- '角色数组。字段:roleName(必填,显示名), code(必填,唯一标识), configDesc(可选,描述)',
154
- items: { type: 'object' },
185
+ "角色数组。字段:roleName(必填,显示名), code(必填,唯一标识), configDesc(可选,描述)",
186
+ items: { type: "object" },
155
187
  },
156
188
  },
157
- required: ['items'],
189
+ required: ["items"],
158
190
  },
159
191
  },
160
192
  {
161
- name: 'wls_assignable_menus_query',
193
+ name: "wls_assignable_menus_query",
162
194
  description:
163
- '查询全量可授权菜单列表(扁平结构,含菜单 id/menuName/permission)。' +
164
- '在 wls_role_assign_menus 前调用,AI 据此选出要分配给角色的 menuIds。',
165
- inputSchema: { type: 'object', properties: {}, required: [] },
195
+ "查询全量可授权菜单列表(扁平结构,含菜单 id/menuName/permission)。" +
196
+ "在 wls_role_assign_menus 前调用,AI 据此选出要分配给角色的 menuIds。",
197
+ inputSchema: { type: "object", properties: {}, required: [] },
166
198
  },
167
199
  {
168
- name: 'wls_role_assign_menus',
200
+ name: "wls_role_assign_menus",
169
201
  description:
170
- '给指定角色批量分配菜单权限。menuIds 传字符串数组,内部自动拼成逗号分隔字符串提交后端。' +
171
- '该接口为全量覆盖式,应包含该角色所有菜单(含已有的,否则会被移除)。',
202
+ "给指定角色批量分配菜单权限。menuIds 传字符串数组,内部自动拼成逗号分隔字符串提交后端。" +
203
+ "该接口为全量覆盖式,应包含该角色所有菜单(含已有的,否则会被移除)。",
172
204
  inputSchema: {
173
- type: 'object',
205
+ type: "object",
174
206
  properties: {
175
- roleId: { type: 'string', description: '角色 id(来自 wls_role_query)' },
207
+ roleId: {
208
+ type: "string",
209
+ description: "角色 id(来自 wls_role_query)",
210
+ },
176
211
  menuIds: {
177
- type: 'array',
178
- description: '该角色应拥有的全部菜单 id 数组',
179
- items: { type: 'string' },
212
+ type: "array",
213
+ description: "该角色应拥有的全部菜单 id 数组",
214
+ items: { type: "string" },
180
215
  },
181
216
  },
182
- required: ['roleId', 'menuIds'],
217
+ required: ["roleId", "menuIds"],
183
218
  },
184
219
  },
185
220
  {
186
- name: 'wls_action_query',
221
+ name: "wls_action_query",
187
222
  description:
188
- '查询指定页面菜单(type=C)下的动作按钮列表(type=A)。返回 id/menuName/permission/orderNum/icon。',
223
+ "查询指定页面菜单(type=C)下的动作按钮列表(type=A)。返回 id/menuName/permission/orderNum/icon。",
189
224
  inputSchema: {
190
- type: 'object',
225
+ type: "object",
191
226
  properties: {
192
- menuId: { type: 'string', description: '父菜单 id(页面菜单)' },
227
+ menuId: { type: "string", description: "父菜单 id(页面菜单)" },
193
228
  },
194
- required: ['menuId'],
229
+ required: ["menuId"],
195
230
  },
196
231
  },
197
232
  {
198
- name: 'wls_action_upsert',
233
+ name: "wls_action_upsert",
199
234
  description:
200
- '在指定页面菜单下批量新增动作按钮(type=A),按 permission 字段自动去重。' +
201
- '权限码命名规范:{资源camelCase}_{动作} 或 {模块}:{资源}:{动作}(与项目既有约定保持一致)。' +
202
- '常见动作:add/edit/remove/export/import/approve。',
235
+ "在指定页面菜单下批量新增动作按钮(type=A),按 permission 字段自动去重。" +
236
+ "权限码命名规范:{资源camelCase}_{动作} 或 {模块}:{资源}:{动作}(与项目既有约定保持一致)。" +
237
+ "常见动作:add/edit/remove/export/import/approve。",
203
238
  inputSchema: {
204
- type: 'object',
239
+ type: "object",
205
240
  properties: {
206
- parentId: { type: 'string', description: '页面菜单 id(动作挂在它下面)' },
241
+ parentId: {
242
+ type: "string",
243
+ description: "页面菜单 id(动作挂在它下面)",
244
+ },
207
245
  items: {
208
- type: 'array',
246
+ type: "array",
209
247
  description:
210
- '动作数组。字段:menuName(必填,显示名), permission(必填,权限码), icon(可选,默认list), orderNum(可选,默认1), useCache(可选,默认1)',
211
- items: { type: 'object' },
248
+ "动作数组。字段:menuName(必填,显示名), permission(必填,权限码), icon(可选,默认list), orderNum(可选,默认1), useCache(可选,默认1)",
249
+ items: { type: "object" },
212
250
  },
213
251
  },
214
- required: ['parentId', 'items'],
252
+ required: ["parentId", "items"],
215
253
  },
216
254
  },
217
255
  {
218
- name: 'wls_code_scan',
256
+ name: "wls_code_scan",
219
257
  description:
220
- '扫描项目页面目录,返回 index.vue/data.ts/index.scss/api.md 完整性与 API_CONFIG 概览。' +
221
- '默认扫描 src/views,可传 path 指定目录。适用于 convention-audit / Agent Pipeline 前置感知项目结构。',
258
+ "扫描项目页面目录,返回 index.vue/data.ts/index.scss/api.md 完整性与 API_CONFIG 概览。" +
259
+ "默认扫描 src/views,可传 path 指定目录。适用于 convention-audit / Agent Pipeline 前置感知项目结构。",
222
260
  inputSchema: {
223
- type: 'object',
261
+ type: "object",
224
262
  properties: {
225
- path: { type: 'string', description: '相对项目根目录的扫描路径,默认 src/views' },
263
+ path: {
264
+ type: "string",
265
+ description: "相对项目根目录的扫描路径,默认 src/views",
266
+ },
226
267
  },
227
268
  required: [],
228
269
  },
229
270
  },
230
271
  {
231
- name: 'wls_route_check',
272
+ name: "wls_route_check",
232
273
  description:
233
- '检查 src/views 页面目录是否能在路由文件中被发现。默认查找 vite/plugins/shared/pages.ts 等常见路由文件,' +
234
- '可传 path 和 routeFile 定制。用于 page-codegen/menu-sync 后闭环验证。',
274
+ "检查 src/views 页面目录是否能在路由文件中被发现。默认查找 vite/plugins/shared/pages.ts 等常见路由文件," +
275
+ "可传 path 和 routeFile 定制。用于 page-codegen/menu-sync 后闭环验证。",
235
276
  inputSchema: {
236
- type: 'object',
277
+ type: "object",
237
278
  properties: {
238
- path: { type: 'string', description: '页面扫描路径,默认 src/views' },
239
- routeFile: { type: 'string', description: '路由文件路径,默认自动探测' },
279
+ path: { type: "string", description: "页面扫描路径,默认 src/views" },
280
+ routeFile: {
281
+ type: "string",
282
+ description: "路由文件路径,默认自动探测",
283
+ },
240
284
  },
241
285
  required: [],
242
286
  },
243
287
  },
244
288
  {
245
- name: 'wls_git_log_extract',
289
+ name: "wls_validate_page",
246
290
  description:
247
- '提取最近 N 次 git commit 摘要,用于 convention-audit 的 Git 规范检查或 changelog-gen 的数据源。',
291
+ "校验页面是否符合 wl-skills-kit 最新页面规范:BaseTable+AGGrid+cid、defineColumns、renderOps、mock-first、api.md 等。",
248
292
  inputSchema: {
249
- type: 'object',
293
+ type: "object",
250
294
  properties: {
251
- n: { type: 'number', description: '提取数量,默认 20,最大 100' },
295
+ path: { type: "string", description: "页面或目录路径,默认 src/views" },
252
296
  },
253
297
  required: [],
254
298
  },
255
299
  },
256
300
  {
257
- name: 'wls_audit_report_push',
301
+ name: "wls_doctor_ui",
302
+ description:
303
+ "检查 @agile-team/wk-skills-ui 是否真正接入:依赖、tokens、styles preset、installCommonPreset、defineColumns、renderOps。",
304
+ inputSchema: { type: "object", properties: {}, required: [] },
305
+ },
306
+ {
307
+ name: "wls_git_log_extract",
258
308
  description:
259
- '将最新审计报告推送到飞书机器人 webhook。未配置 env.local.jsonfeishu_webhook 时静默跳过,不影响其他流程。',
309
+ "提取最近 N git commit 摘要,用于 convention-audit Git 规范检查或 changelog-gen 的数据源。",
260
310
  inputSchema: {
261
- type: 'object',
311
+ type: "object",
262
312
  properties: {
263
- reportPath: { type: 'string', description: '审计报告路径,不传则自动选择 .github/reports 下最新 AUDIT_*.md 或规范审查报告.md' },
313
+ n: { type: "number", description: "提取数量,默认 20,最大 100" },
264
314
  },
265
315
  required: [],
266
316
  },
267
317
  },
268
- ]
318
+ {
319
+ name: "wls_audit_report_push",
320
+ description:
321
+ "将最新审计报告推送到飞书机器人 webhook。未配置 env.local.json 的 feishu_webhook 时静默跳过,不影响其他流程。",
322
+ inputSchema: {
323
+ type: "object",
324
+ properties: {
325
+ reportPath: {
326
+ type: "string",
327
+ description:
328
+ "审计报告路径,不传则自动选择 .github/reports 下最新 AUDIT_*.md 或规范审查报告.md",
329
+ },
330
+ },
331
+ required: [],
332
+ },
333
+ },
334
+ ];
269
335
 
270
336
  // ─── JSON-RPC 协议层 ────────────────────────────────────────────────────
271
337
 
272
338
  function send(obj) {
273
- process.stdout.write(JSON.stringify(obj) + '\n')
339
+ process.stdout.write(JSON.stringify(obj) + "\n");
274
340
  }
275
341
 
276
342
  function sendResult(id, result) {
277
- send({ jsonrpc: '2.0', id, result })
343
+ send({ jsonrpc: "2.0", id, result });
278
344
  }
279
345
 
280
346
  function sendError(id, code, message) {
281
- send({ jsonrpc: '2.0', id, error: { code, message } })
347
+ send({ jsonrpc: "2.0", id, error: { code, message } });
282
348
  }
283
349
 
284
350
  // ─── Tool 调度 ───────────────────────────────────────────────────────────
285
351
 
286
352
  async function dispatchTool(id, toolName, toolArgs) {
287
- let config
353
+ let config;
288
354
  const needsBackendConfig = ![
289
- 'wls_code_scan',
290
- 'wls_route_check',
291
- 'wls_git_log_extract',
292
- 'wls_audit_report_push',
293
- ].includes(toolName)
355
+ "wls_code_scan",
356
+ "wls_route_check",
357
+ "wls_validate_page",
358
+ "wls_doctor_ui",
359
+ "wls_git_log_extract",
360
+ "wls_audit_report_push",
361
+ ].includes(toolName);
294
362
  if (needsBackendConfig) {
295
363
  try {
296
- config = loadConfig()
364
+ config = loadConfig();
297
365
  } catch (e) {
298
366
  // 配置加载失败:以文本形式返回给 AI(不是 JSON-RPC error,AI 能读)
299
- sendResult(id, { content: [{ type: 'text', text: `❌ 配置加载失败: ${e.message}` }], isError: true })
300
- return
367
+ sendResult(id, {
368
+ content: [{ type: "text", text: `❌ 配置加载失败: ${e.message}` }],
369
+ isError: true,
370
+ });
371
+ return;
301
372
  }
302
373
  }
303
374
 
304
375
  try {
305
- let text
376
+ let text;
306
377
  switch (toolName) {
307
- case 'wls_menu_query':
308
- text = await handleMenuQuery(config)
309
- break
310
- case 'wls_menu_upsert':
311
- text = await handleMenuUpsert(toolArgs, config)
312
- break
313
- case 'wls_dict_query':
314
- text = await handleDictQuery(config)
315
- break
316
- case 'wls_dict_upsert':
317
- text = await handleDictUpsert(toolArgs, config)
318
- break
319
- case 'wls_role_query':
320
- text = await handleRoleQuery(toolArgs, config)
321
- break
322
- case 'wls_role_upsert':
323
- text = await handleRoleUpsert(toolArgs, config)
324
- break
325
- case 'wls_assignable_menus_query':
326
- text = await handleAssignableMenusQuery(toolArgs, config)
327
- break
328
- case 'wls_role_assign_menus':
329
- text = await handleRoleAssignMenus(toolArgs, config)
330
- break
331
- case 'wls_action_query':
332
- text = await handleActionQuery(toolArgs, config)
333
- break
334
- case 'wls_action_upsert':
335
- text = await handleActionUpsert(toolArgs, config)
336
- break
337
- case 'wls_code_scan':
338
- text = await handleCodeScan(toolArgs)
339
- break
340
- case 'wls_route_check':
341
- text = await handleRouteCheck(toolArgs)
342
- break
343
- case 'wls_git_log_extract':
344
- text = await handleGitLogExtract(toolArgs)
345
- break
346
- case 'wls_audit_report_push':
347
- text = await handleAuditReportPush(toolArgs)
348
- break
378
+ case "wls_menu_query":
379
+ text = await handleMenuQuery(config);
380
+ break;
381
+ case "wls_menu_upsert":
382
+ text = await handleMenuUpsert(toolArgs, config);
383
+ break;
384
+ case "wls_menu_sync_from_report":
385
+ text = await handleMenuSyncFromReport(toolArgs, config);
386
+ break;
387
+ case "wls_dict_query":
388
+ text = await handleDictQuery(config);
389
+ break;
390
+ case "wls_dict_upsert":
391
+ text = await handleDictUpsert(toolArgs, config);
392
+ break;
393
+ case "wls_role_query":
394
+ text = await handleRoleQuery(toolArgs, config);
395
+ break;
396
+ case "wls_role_upsert":
397
+ text = await handleRoleUpsert(toolArgs, config);
398
+ break;
399
+ case "wls_assignable_menus_query":
400
+ text = await handleAssignableMenusQuery(toolArgs, config);
401
+ break;
402
+ case "wls_role_assign_menus":
403
+ text = await handleRoleAssignMenus(toolArgs, config);
404
+ break;
405
+ case "wls_action_query":
406
+ text = await handleActionQuery(toolArgs, config);
407
+ break;
408
+ case "wls_action_upsert":
409
+ text = await handleActionUpsert(toolArgs, config);
410
+ break;
411
+ case "wls_code_scan":
412
+ text = await handleCodeScan(toolArgs);
413
+ break;
414
+ case "wls_route_check":
415
+ text = await handleRouteCheck(toolArgs);
416
+ break;
417
+ case "wls_validate_page":
418
+ text = await handleValidatePage(toolArgs);
419
+ break;
420
+ case "wls_doctor_ui":
421
+ text = await handleDoctorUi(toolArgs);
422
+ break;
423
+ case "wls_git_log_extract":
424
+ text = await handleGitLogExtract(toolArgs);
425
+ break;
426
+ case "wls_audit_report_push":
427
+ text = await handleAuditReportPush(toolArgs);
428
+ break;
349
429
  default:
350
- sendError(id, -32601, `未知工具: ${toolName}`)
351
- return
430
+ sendError(id, -32601, `未知工具: ${toolName}`);
431
+ return;
352
432
  }
353
- sendResult(id, { content: [{ type: 'text', text }] })
433
+ sendResult(id, { content: [{ type: "text", text }] });
354
434
  } catch (e) {
355
435
  sendResult(id, {
356
- content: [{ type: 'text', text: `❌ 工具执行异常: ${e.message}` }],
436
+ content: [{ type: "text", text: `❌ 工具执行异常: ${e.message}` }],
357
437
  isError: true,
358
- })
438
+ });
359
439
  }
360
440
  }
361
441
 
362
442
  // ─── 消息循环 ────────────────────────────────────────────────────────────
363
443
 
364
- const rl = readline.createInterface({ input: process.stdin, terminal: false })
444
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
365
445
 
366
- rl.on('line', async (line) => {
367
- const raw = line.trim()
368
- if (!raw) return
446
+ rl.on("line", async (line) => {
447
+ const raw = line.trim();
448
+ if (!raw) return;
369
449
 
370
- let msg
450
+ let msg;
371
451
  try {
372
- msg = JSON.parse(raw)
452
+ msg = JSON.parse(raw);
373
453
  } catch (e) {
374
- send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } })
375
- return
454
+ send({
455
+ jsonrpc: "2.0",
456
+ id: null,
457
+ error: { code: -32700, message: "Parse error" },
458
+ });
459
+ return;
376
460
  }
377
461
 
378
- const { id, method, params = {} } = msg
462
+ const { id, method, params = {} } = msg;
379
463
 
380
464
  // Notifications(无 id)不需要响应
381
- if (id === undefined || id === null) return
465
+ if (id === undefined || id === null) return;
382
466
 
383
467
  switch (method) {
384
- case 'initialize':
468
+ case "initialize":
385
469
  sendResult(id, {
386
- protocolVersion: '2024-11-05',
470
+ protocolVersion: "2024-11-05",
387
471
  capabilities: { tools: {} },
388
- serverInfo: { name: 'wl-skills', version: PKG.version },
389
- })
390
- break
472
+ serverInfo: { name: "wl-skills", version: PKG.version },
473
+ });
474
+ break;
391
475
 
392
- case 'tools/list':
393
- sendResult(id, { tools: TOOLS })
394
- break
476
+ case "tools/list":
477
+ sendResult(id, { tools: TOOLS });
478
+ break;
395
479
 
396
- case 'tools/call':
397
- await dispatchTool(id, params.name, params.arguments || {})
398
- break
480
+ case "tools/call":
481
+ await dispatchTool(id, params.name, params.arguments || {});
482
+ break;
399
483
 
400
- case 'ping':
401
- sendResult(id, {})
402
- break
484
+ case "ping":
485
+ sendResult(id, {});
486
+ break;
403
487
 
404
488
  default:
405
- sendError(id, -32601, `Method not found: ${method}`)
489
+ sendError(id, -32601, `Method not found: ${method}`);
406
490
  }
407
- })
491
+ });
408
492
 
409
- rl.on('close', () => {
410
- process.exit(0)
411
- })
493
+ rl.on("close", () => {
494
+ process.exit(0);
495
+ });