item-wms-public-api-tool 2.0.6 → 2.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "item-wms-public-api-tool",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "Public APIs for auth, EDI import, queries, uploads, and item master data.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -32,9 +32,22 @@ function isJsonLike(raw) {
32
32
  return trimmed.startsWith('{') || trimmed.startsWith('[');
33
33
  }
34
34
 
35
- function normalizeToolName(method, pathName) {
36
- const normalizedPath = pathName.replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
37
- return `${method.toLowerCase()}_${normalizedPath.toLowerCase()}`;
35
+ function normalizeToolName(pathName, prefix) {
36
+ let trimmedPath = pathName;
37
+ if (prefix) {
38
+ const normalizedPrefix = prefix.startsWith('/') ? prefix : `/${prefix}`;
39
+ const prefixWithSlash = normalizedPrefix.endsWith('/') ? normalizedPrefix : `${normalizedPrefix}/`;
40
+ if (trimmedPath.startsWith(prefixWithSlash)) {
41
+ trimmedPath = trimmedPath.slice(prefixWithSlash.length);
42
+ } else if (trimmedPath.startsWith(normalizedPrefix)) {
43
+ trimmedPath = trimmedPath.slice(normalizedPrefix.length);
44
+ }
45
+ }
46
+ if (!trimmedPath) {
47
+ trimmedPath = pathName;
48
+ }
49
+ const normalizedPath = trimmedPath.replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
50
+ return normalizedPath.toLowerCase();
38
51
  }
39
52
 
40
53
  function fetchText(url, redirects = 0) {
@@ -70,6 +83,27 @@ function ensureDir(dirPath) {
70
83
  }
71
84
  }
72
85
 
86
+ function stripDefaultParamRequired(node) {
87
+ if (!node || typeof node !== 'object') {
88
+ return;
89
+ }
90
+ if (Array.isArray(node)) {
91
+ node.forEach(stripDefaultParamRequired);
92
+ return;
93
+ }
94
+ if (Array.isArray(node.required)) {
95
+ const next = node.required.filter((key) => !DEFAULT_PARAM_KEYS.includes(key));
96
+ if (next.length > 0) {
97
+ node.required = next;
98
+ } else {
99
+ delete node.required;
100
+ }
101
+ }
102
+ for (const value of Object.values(node)) {
103
+ stripDefaultParamRequired(value);
104
+ }
105
+ }
106
+
73
107
  function parseOpenApi(raw) {
74
108
  if (!raw || !raw.trim()) {
75
109
  throw new Error('OpenAPI content is empty.');
@@ -215,6 +249,7 @@ function buildInputSchema(operation, parameters, components) {
215
249
 
216
250
  function buildTools(openapi) {
217
251
  const tools = [];
252
+ const usedNames = new Set();
218
253
  const operations = openapi.paths || {};
219
254
  for (const [pathName, pathItem] of Object.entries(operations)) {
220
255
  if (PATH_PREFIX && !pathName.startsWith(PATH_PREFIX)) {
@@ -226,13 +261,18 @@ function buildTools(openapi) {
226
261
  if (!operation) {
227
262
  continue;
228
263
  }
229
- const baseName = normalizeToolName(method, pathName);
264
+ const baseName = normalizeToolName(pathName, PATH_PREFIX);
230
265
  let name = baseName;
266
+ const methodSuffix = method.toLowerCase();
267
+ if (usedNames.has(name)) {
268
+ name = `${baseName}_${methodSuffix}`;
269
+ }
231
270
  let counter = 2;
232
- while (tools.find((tool) => tool.name === name)) {
233
- name = `${baseName}_${counter}`;
271
+ while (usedNames.has(name)) {
272
+ name = `${baseName}_${methodSuffix}_${counter}`;
234
273
  counter += 1;
235
274
  }
275
+ usedNames.add(name);
236
276
  const parameters = [
237
277
  ...commonParams,
238
278
  ...(Array.isArray(operation.parameters) ? operation.parameters : [])
@@ -259,6 +299,7 @@ async function main() {
259
299
  fs.writeFileSync(SNAPSHOT_PATH, raw.endsWith('\n') ? raw : `${raw}\n`);
260
300
 
261
301
  const openapi = parseOpenApi(raw);
302
+ stripDefaultParamRequired(openapi);
262
303
  if (!openapi || !openapi.paths) {
263
304
  throw new Error('Invalid OpenAPI content: missing "paths".');
264
305
  }
@@ -107,9 +107,22 @@ function applyDefaultParams(
107
107
  return nextArgs;
108
108
  }
109
109
 
110
- function normalizeToolName(method: string, pathName: string): string {
111
- const normalizedPath = pathName.replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
112
- return `${method.toLowerCase()}_${normalizedPath.toLowerCase()}`;
110
+ function normalizeToolName(pathName: string, prefix?: string): string {
111
+ let trimmedPath = pathName;
112
+ if (prefix) {
113
+ const normalizedPrefix = prefix.startsWith('/') ? prefix : `/${prefix}`;
114
+ const prefixWithSlash = normalizedPrefix.endsWith('/') ? normalizedPrefix : `${normalizedPrefix}/`;
115
+ if (trimmedPath.startsWith(prefixWithSlash)) {
116
+ trimmedPath = trimmedPath.slice(prefixWithSlash.length);
117
+ } else if (trimmedPath.startsWith(normalizedPrefix)) {
118
+ trimmedPath = trimmedPath.slice(normalizedPrefix.length);
119
+ }
120
+ }
121
+ if (!trimmedPath) {
122
+ trimmedPath = pathName;
123
+ }
124
+ const normalizedPath = trimmedPath.replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
125
+ return normalizedPath.toLowerCase();
113
126
  }
114
127
 
115
128
  function mergeSchema(base: Record<string, any>, extra?: Record<string, any>): Record<string, any> {
@@ -264,7 +277,7 @@ export function buildOpenApiIndex(spec: any, options?: { pathPrefix?: string }):
264
277
  if (!operation) {
265
278
  continue;
266
279
  }
267
- const name = normalizeToolName(method, pathName);
280
+ const baseName = normalizeToolName(pathName, prefix);
268
281
  const parameters = [
269
282
  ...commonParams,
270
283
  ...(Array.isArray(operation.parameters) ? operation.parameters : [])
@@ -272,10 +285,14 @@ export function buildOpenApiIndex(spec: any, options?: { pathPrefix?: string }):
272
285
  const description = operation.summary || operation.description || `${method.toUpperCase()} ${pathName}`;
273
286
  const inputSchema = buildInputSchema(operation, parameters, spec.components);
274
287
 
275
- let finalName = name;
288
+ let finalName = baseName;
289
+ const methodSuffix = method.toLowerCase();
290
+ if (operations[finalName]) {
291
+ finalName = `${baseName}_${methodSuffix}`;
292
+ }
276
293
  let counter = 2;
277
294
  while (operations[finalName]) {
278
- finalName = `${name}_${counter}`;
295
+ finalName = `${baseName}_${methodSuffix}_${counter}`;
279
296
  counter += 1;
280
297
  }
281
298
 
@@ -101,11 +101,11 @@ console.log(' // AI工具代码示例');
101
101
  console.log(' const mcpConfig = JSON.parse(fs.readFileSync("mcp.json", "utf8"));');
102
102
  console.log(' ');
103
103
  console.log(' // 发现工具');
104
- console.log(' const loginTool = mcpConfig.tools.find(tool => tool.name === "post_v1_public_user_login");');
104
+ console.log(' const loginTool = mcpConfig.tools.find(tool => tool.name === "user_login");');
105
105
  console.log(' ');
106
106
  console.log(' // 调用工具');
107
107
  console.log(' const result = await executeMCPCommand(');
108
- console.log(' JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "post_v1_public_user_login", arguments: { username: "testuser", password: "testpass" }, options: { baseUrl: "https://wms-staging.item.com/api/public" } } })');
108
+ console.log(' JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "user_login", arguments: { username: "testuser", password: "testpass" }, options: { baseUrl: "https://wms-staging.item.com/api/public" } } })');
109
109
  console.log(' );');
110
110
  console.log(' ');
111
111
  console.log(' // 解析结果');