@julong/mono-rele2-utils 1.3.1 → 1.5.0

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/README.md CHANGED
@@ -36,40 +36,41 @@ Available skills:
36
36
 
37
37
  ### Skills
38
38
 
39
- #### `caseConvertTool`
39
+ <!-- SKILLS:START -->
40
40
 
41
- Converts text to the specified case format.
41
+ #### `cnTool`
42
+
43
+ Merges class names, filtering out falsy values.
42
44
 
43
45
  ```sh
44
- mono-rele2-utils caseConvertTool <input> <to>
46
+ mono-rele2-utils cnTool <classes>
45
47
  ```
46
48
 
47
49
  | arg | type | description |
48
50
  |-----|------|-------------|
49
- | `input` | string | Text to convert |
50
- | `to` | `upper` \| `lower` \| `capitalize` \| `camel` \| `snake` \| `kebab` | Target case format |
51
+ | `classes` | JSON string (array) | List of class names to merge |
51
52
 
52
53
  ```sh
53
- mono-rele2-utils caseConvertTool "hello world" camel # helloWorld
54
- mono-rele2-utils caseConvertTool "helloWorld" snake # hello_world
55
- mono-rele2-utils caseConvertTool "hello world" kebab # hello-world
56
- mono-rele2-utils caseConvertTool "hello world" upper # HELLO WORLD
54
+ mono-rele2-utils cnTool '["btn","active","large"]' # btn active large
57
55
  ```
58
56
 
59
- #### `cnTool`
57
+ #### `caseConvertTool`
60
58
 
61
- Merges class names, filtering out falsy values.
59
+ Converts text to the specified case format.
62
60
 
63
61
  ```sh
64
- mono-rele2-utils cnTool <classes>
62
+ mono-rele2-utils caseConvertTool <input> <to>
65
63
  ```
66
64
 
67
65
  | arg | type | description |
68
66
  |-----|------|-------------|
69
- | `classes` | JSON string (array) | Class names to merge |
67
+ | `input` | string | Text to convert |
68
+ | `to` | `upper` \| `lower` \| `capitalize` \| `camel` \| `snake` \| `kebab` | Target case format |
70
69
 
71
70
  ```sh
72
- mono-rele2-utils cnTool '["btn", "active", "large"]' # btn active large
71
+ mono-rele2-utils caseConvertTool "hello world" camel # helloWorld
72
+ mono-rele2-utils caseConvertTool "helloWorld" snake # hello_world
73
+ mono-rele2-utils caseConvertTool "hello world" kebab # hello-world
73
74
  ```
74
75
 
75
76
  #### `truncateTool`
@@ -84,13 +85,15 @@ mono-rele2-utils truncateTool <input> <maxLength> [suffix]
84
85
  |-----|------|-------------|
85
86
  | `input` | string | Text to truncate |
86
87
  | `maxLength` | number | Maximum character length |
87
- | `suffix` | string | Suffix to append (default: `...`) |
88
+ | `suffix` | string | Suffix to append when truncated (default: `...`) |
88
89
 
89
90
  ```sh
90
91
  mono-rele2-utils truncateTool "hello world long text" 10 # hello w...
91
92
  mono-rele2-utils truncateTool "hello world" 8 "…" # hello w…
92
93
  ```
93
94
 
95
+ <!-- SKILLS:END -->
96
+
94
97
  ## MCP Server
95
98
 
96
99
  ```sh
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../common/mcp/tool.ts
3
+ // ../common/kit/tool.ts
4
4
  function toolDef(def) {
5
5
  return def;
6
6
  }
@@ -11,11 +11,11 @@ function text(content) {
11
11
  return { content: [{ type: "text", text: content }] };
12
12
  }
13
13
 
14
- // ../common/mcp/server.ts
14
+ // ../common/kit/server.ts
15
15
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
16
16
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17
17
 
18
- // ../common/mcp/cli.ts
18
+ // ../common/kit/cli.ts
19
19
  import { z } from "zod";
20
20
  function formatSkills(tools2) {
21
21
  const sections = Object.entries(tools2).map(([key, tool]) => {
@@ -66,9 +66,12 @@ function handleCliError(err) {
66
66
  process.exit(1);
67
67
  }
68
68
 
69
- // src/tools/text.ts
69
+ // ../common/kit/skill.ts
70
70
  import { z as z2 } from "zod";
71
71
 
72
+ // src/tools/text.ts
73
+ import { z as z3 } from "zod";
74
+
72
75
  // src/cn.ts
73
76
  function cn(...classes) {
74
77
  return classes.filter(Boolean).join(" ");
@@ -80,31 +83,43 @@ var tools = {
80
83
  name: "cn",
81
84
  description: "Merges class names, filtering out falsy values",
82
85
  inputSchema: {
83
- classes: z2.array(z2.string()).describe("List of class names to merge")
86
+ classes: z3.array(z3.string()).describe("List of class names to merge")
84
87
  },
85
- handler: async ({ classes }) => text(cn(...classes))
88
+ handler: async ({ classes }) => text(cn(...classes)),
89
+ examples: [
90
+ { args: [`'["btn","active","large"]'`], result: "btn active large" }
91
+ ]
86
92
  }),
87
93
  caseConvertTool: toolDef({
88
94
  name: "case_convert",
89
95
  description: "Converts text to the specified case format",
90
96
  inputSchema: {
91
- input: z2.string().describe("Text to convert"),
92
- to: z2.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
97
+ input: z3.string().describe("Text to convert"),
98
+ to: z3.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
93
99
  },
94
- handler: async ({ input, to }) => text(convert(input, to))
100
+ handler: async ({ input, to }) => text(convert(input, to)),
101
+ examples: [
102
+ { args: [`"hello world"`, "camel"], result: "helloWorld" },
103
+ { args: [`"helloWorld"`, "snake"], result: "hello_world" },
104
+ { args: [`"hello world"`, "kebab"], result: "hello-world" }
105
+ ]
95
106
  }),
96
107
  truncateTool: toolDef({
97
108
  name: "truncate",
98
109
  description: "Truncates text to a maximum length and appends a suffix",
99
110
  inputSchema: {
100
- input: z2.string().describe("Text to truncate"),
101
- maxLength: z2.number().int().positive().describe("Maximum character length"),
102
- suffix: z2.string().default("...").describe("Suffix to append when truncated")
111
+ input: z3.string().describe("Text to truncate"),
112
+ maxLength: z3.number().int().positive().describe("Maximum character length"),
113
+ suffix: z3.string().default("...").describe("Suffix to append when truncated")
103
114
  },
104
115
  handler: async ({ input, maxLength, suffix }) => {
105
116
  const result = input.length <= maxLength ? input : input.slice(0, maxLength - suffix.length) + suffix;
106
117
  return text(result);
107
- }
118
+ },
119
+ examples: [
120
+ { args: [`"hello world long text"`, "10"], result: "hello w..." },
121
+ { args: [`"hello world"`, "8", `"\u2026"`], result: "hello w\u2026" }
122
+ ]
108
123
  })
109
124
  };
110
125
  var cnTool = defineTool(tools.cnTool);
package/dist/index.d.ts CHANGED
@@ -1,7 +1,86 @@
1
1
  import * as _modelcontextprotocol_sdk_server_mcp_js from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
+ import { z } from 'zod';
2
4
 
3
5
  declare function cn(...classes: (string | undefined | null | false)[]): string;
4
6
 
7
+ type ToolResult = CallToolResult;
8
+ type ToolExample = {
9
+ args: string[];
10
+ result: string;
11
+ };
12
+ type AnyToolDef = {
13
+ name: string;
14
+ description: string;
15
+ inputSchema: z.ZodRawShape;
16
+ handler: (args: any) => Promise<ToolResult>;
17
+ examples?: ToolExample[];
18
+ guidelines?: string[];
19
+ };
20
+
21
+ type SkillTools = Record<string, AnyToolDef>;
22
+ declare function generateSkillMarkdown(opts: {
23
+ binName: string;
24
+ description: string;
25
+ tools: SkillTools;
26
+ }): string;
27
+ declare function generateReadmeSkills(opts: {
28
+ binName: string;
29
+ tools: SkillTools;
30
+ }): string;
31
+
32
+ declare const tools: {
33
+ cnTool: {
34
+ name: string;
35
+ description: string;
36
+ inputSchema: {
37
+ readonly classes: z.ZodArray<z.ZodString>;
38
+ };
39
+ handler: (input: {
40
+ classes: string[];
41
+ }) => Promise<ToolResult>;
42
+ examples?: ToolExample[];
43
+ guidelines?: string[];
44
+ };
45
+ caseConvertTool: {
46
+ name: string;
47
+ description: string;
48
+ inputSchema: {
49
+ readonly input: z.ZodString;
50
+ readonly to: z.ZodEnum<{
51
+ upper: "upper";
52
+ lower: "lower";
53
+ capitalize: "capitalize";
54
+ camel: "camel";
55
+ snake: "snake";
56
+ kebab: "kebab";
57
+ }>;
58
+ };
59
+ handler: (input: {
60
+ input: string;
61
+ to: "upper" | "lower" | "capitalize" | "camel" | "snake" | "kebab";
62
+ }) => Promise<ToolResult>;
63
+ examples?: ToolExample[];
64
+ guidelines?: string[];
65
+ };
66
+ truncateTool: {
67
+ name: string;
68
+ description: string;
69
+ inputSchema: {
70
+ readonly input: z.ZodString;
71
+ readonly maxLength: z.ZodNumber;
72
+ readonly suffix: z.ZodDefault<z.ZodString>;
73
+ };
74
+ handler: (input: {
75
+ input: string;
76
+ maxLength: number;
77
+ suffix: string;
78
+ }) => Promise<ToolResult>;
79
+ examples?: ToolExample[];
80
+ guidelines?: string[];
81
+ };
82
+ };
83
+
5
84
  declare function createUtilsServer(): _modelcontextprotocol_sdk_server_mcp_js.McpServer;
6
85
 
7
- export { cn, createUtilsServer };
86
+ export { cn, createUtilsServer, generateReadmeSkills, generateSkillMarkdown, tools };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // ../common/mcp/tool.ts
1
+ // ../common/kit/tool.ts
2
2
  function toolDef(def) {
3
3
  return def;
4
4
  }
@@ -9,27 +9,211 @@ function text(content) {
9
9
  return { content: [{ type: "text", text: content }] };
10
10
  }
11
11
 
12
- // ../common/mcp/server.ts
12
+ // ../common/kit/server.ts
13
13
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
14
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
15
15
  function createMcpServer(config, tools2) {
16
- const server = new McpServer(config);
16
+ const server2 = new McpServer(config);
17
17
  for (const tool of tools2) {
18
- server.registerTool(
18
+ server2.registerTool(
19
19
  tool.name,
20
20
  { description: tool.description, inputSchema: tool.inputSchema },
21
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
22
  tool.handler
23
23
  );
24
24
  }
25
- return server;
25
+ return server2;
26
+ }
27
+ async function startServer(server2) {
28
+ const transport = new StdioServerTransport();
29
+ await server2.connect(transport);
26
30
  }
27
31
 
28
- // ../common/mcp/cli.ts
32
+ // ../common/kit/cli.ts
29
33
  import { z } from "zod";
30
34
 
31
- // src/tools/text.ts
35
+ // ../common/kit/skill.ts
32
36
  import { z as z2 } from "zod";
37
+ function generateSkillMarkdown(opts) {
38
+ const { binName, description, tools: tools2 } = opts;
39
+ return `---
40
+ name: ${binName}
41
+ description: ${description}
42
+ ---
43
+
44
+ # ${binName}
45
+
46
+ \`\`\`sh
47
+ ${binName} <skillName> [...args]
48
+ \`\`\`
49
+
50
+ ## Skills
51
+
52
+ ${renderSkills(tools2)}
53
+
54
+ ## Examples
55
+
56
+ ${renderExamples(binName, tools2)}
57
+
58
+ ## Guidelines
59
+
60
+ ${renderGuidelines(binName, tools2)}
61
+ `;
62
+ }
63
+ function renderSkills(tools2) {
64
+ return Object.entries(tools2).map(([key, tool]) => {
65
+ const rows = Object.entries(tool.inputSchema).map(([field, schema]) => `| \`${field}\` | ${describeField(schema)} |`).join("\n");
66
+ return `### ${key}
67
+
68
+ ${tool.description}
69
+
70
+ | arg | description |
71
+ |-----|-------------|
72
+ ${rows}`;
73
+ }).join("\n\n");
74
+ }
75
+ function describeField(schema) {
76
+ const baseDesc = schema.description ?? "";
77
+ let inner = schema;
78
+ let defaultValue;
79
+ let isOptional = false;
80
+ while (inner instanceof z2.ZodOptional || inner instanceof z2.ZodDefault) {
81
+ if (inner instanceof z2.ZodDefault) {
82
+ const raw = inner.def.defaultValue;
83
+ defaultValue = typeof raw === "function" ? raw() : raw;
84
+ }
85
+ if (inner instanceof z2.ZodOptional) isOptional = true;
86
+ inner = inner.unwrap();
87
+ }
88
+ const parts = [];
89
+ if (baseDesc) parts.push(baseDesc);
90
+ if (inner instanceof z2.ZodEnum) {
91
+ const values = inner.options.map((v) => `\`${v}\``).join(" \\| ");
92
+ parts.push(values);
93
+ }
94
+ if (defaultValue !== void 0) parts.push(`default: \`${String(defaultValue)}\``);
95
+ else if (isOptional) parts.push("optional");
96
+ return parts.join(" \u2014 ");
97
+ }
98
+ function renderExamples(binName, tools2) {
99
+ const lines = [];
100
+ for (const [key, tool] of Object.entries(tools2)) {
101
+ if (!tool.examples) continue;
102
+ for (const ex of tool.examples) {
103
+ const cmd = [binName, key, ...ex.args].join(" ");
104
+ lines.push(`- \`${cmd}\` => \`${ex.result}\``);
105
+ }
106
+ }
107
+ return lines.join("\n");
108
+ }
109
+ function renderGuidelines(binName, tools2) {
110
+ const items = [];
111
+ const seen = /* @__PURE__ */ new Set();
112
+ const push = (g) => {
113
+ if (seen.has(g)) return;
114
+ seen.add(g);
115
+ items.push(g);
116
+ };
117
+ push("Arguments are positional \u2014 pass them in the order listed in each skill's table");
118
+ const allSchemas = Object.values(tools2).flatMap((t) => Object.values(t.inputSchema));
119
+ if (allSchemas.some((s) => containsType(s, z2.ZodNumber))) {
120
+ push("Numeric args are auto-parsed \u2014 pass as plain numbers (e.g. `10`)");
121
+ }
122
+ if (allSchemas.some((s) => containsType(s, z2.ZodArray))) {
123
+ push('Array args must be valid JSON \u2014 wrap in single quotes on Unix shells (e.g. `\'["a","b"]\'`)');
124
+ }
125
+ if (allSchemas.some((s) => s instanceof z2.ZodOptional || s instanceof z2.ZodDefault)) {
126
+ push("Optional args with defaults may be omitted");
127
+ }
128
+ for (const tool of Object.values(tools2)) {
129
+ if (!tool.guidelines) continue;
130
+ for (const g of tool.guidelines) push(g);
131
+ }
132
+ push(`Run \`${binName}\` with no args to list all available skills`);
133
+ return items.map((g) => `- ${g}`).join("\n");
134
+ }
135
+ function containsType(schema, ctor) {
136
+ let inner = schema;
137
+ while (inner instanceof z2.ZodOptional || inner instanceof z2.ZodDefault) {
138
+ inner = inner.unwrap();
139
+ }
140
+ return inner instanceof ctor;
141
+ }
142
+ function generateReadmeSkills(opts) {
143
+ const { binName, tools: tools2 } = opts;
144
+ return Object.entries(tools2).map(([key, tool]) => renderReadmeSkill(binName, key, tool)).join("\n\n");
145
+ }
146
+ function renderReadmeSkill(binName, key, tool) {
147
+ const fields = Object.entries(tool.inputSchema);
148
+ const usageArgs = fields.map(([field, schema]) => {
149
+ const isOpt = schema instanceof z2.ZodOptional || schema instanceof z2.ZodDefault;
150
+ return isOpt ? `[${field}]` : `<${field}>`;
151
+ }).join(" ");
152
+ const usage = [binName, key, usageArgs].filter(Boolean).join(" ");
153
+ const rows = fields.map(([field, schema]) => {
154
+ const t = describeReadmeType(schema);
155
+ const d = describeReadmeDesc(schema);
156
+ return `| \`${field}\` | ${t} | ${d} |`;
157
+ }).join("\n");
158
+ const examples = tool.examples ?? [];
159
+ let exampleBlock = "";
160
+ if (examples.length > 0) {
161
+ const cmds = examples.map((ex) => [binName, key, ...ex.args].join(" "));
162
+ const width = Math.max(...cmds.map((c) => c.length));
163
+ const lines = examples.map((ex, i) => `${cmds[i].padEnd(width)} # ${ex.result}`);
164
+ exampleBlock = `
165
+
166
+ \`\`\`sh
167
+ ${lines.join("\n")}
168
+ \`\`\``;
169
+ }
170
+ const tableBlock = rows ? `
171
+
172
+ | arg | type | description |
173
+ |-----|------|-------------|
174
+ ${rows}` : "";
175
+ return `#### \`${key}\`
176
+
177
+ ${tool.description}.
178
+
179
+ \`\`\`sh
180
+ ${usage}
181
+ \`\`\`${tableBlock}${exampleBlock}`;
182
+ }
183
+ function describeReadmeType(schema) {
184
+ let inner = schema;
185
+ while (inner instanceof z2.ZodOptional || inner instanceof z2.ZodDefault) {
186
+ inner = inner.unwrap();
187
+ }
188
+ if (inner instanceof z2.ZodEnum) {
189
+ return inner.options.map((v) => `\`${v}\``).join(" \\| ");
190
+ }
191
+ if (inner instanceof z2.ZodNumber) return "number";
192
+ if (inner instanceof z2.ZodString) return "string";
193
+ if (inner instanceof z2.ZodBoolean) return "boolean";
194
+ if (inner instanceof z2.ZodArray) return "JSON string (array)";
195
+ return "unknown";
196
+ }
197
+ function describeReadmeDesc(schema) {
198
+ const baseDesc = schema.description ?? "";
199
+ let inner = schema;
200
+ let defaultValue;
201
+ let isOptional = false;
202
+ while (inner instanceof z2.ZodOptional || inner instanceof z2.ZodDefault) {
203
+ if (inner instanceof z2.ZodDefault) {
204
+ const raw = inner.def.defaultValue;
205
+ defaultValue = typeof raw === "function" ? raw() : raw;
206
+ }
207
+ if (inner instanceof z2.ZodOptional) isOptional = true;
208
+ inner = inner.unwrap();
209
+ }
210
+ if (defaultValue !== void 0) return `${baseDesc} (default: \`${String(defaultValue)}\`)`;
211
+ if (isOptional) return `${baseDesc} (optional)`;
212
+ return baseDesc;
213
+ }
214
+
215
+ // src/tools/text.ts
216
+ import { z as z3 } from "zod";
33
217
 
34
218
  // src/cn.ts
35
219
  function cn(...classes) {
@@ -42,31 +226,43 @@ var tools = {
42
226
  name: "cn",
43
227
  description: "Merges class names, filtering out falsy values",
44
228
  inputSchema: {
45
- classes: z2.array(z2.string()).describe("List of class names to merge")
229
+ classes: z3.array(z3.string()).describe("List of class names to merge")
46
230
  },
47
- handler: async ({ classes }) => text(cn(...classes))
231
+ handler: async ({ classes }) => text(cn(...classes)),
232
+ examples: [
233
+ { args: [`'["btn","active","large"]'`], result: "btn active large" }
234
+ ]
48
235
  }),
49
236
  caseConvertTool: toolDef({
50
237
  name: "case_convert",
51
238
  description: "Converts text to the specified case format",
52
239
  inputSchema: {
53
- input: z2.string().describe("Text to convert"),
54
- to: z2.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
240
+ input: z3.string().describe("Text to convert"),
241
+ to: z3.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
55
242
  },
56
- handler: async ({ input, to }) => text(convert(input, to))
243
+ handler: async ({ input, to }) => text(convert(input, to)),
244
+ examples: [
245
+ { args: [`"hello world"`, "camel"], result: "helloWorld" },
246
+ { args: [`"helloWorld"`, "snake"], result: "hello_world" },
247
+ { args: [`"hello world"`, "kebab"], result: "hello-world" }
248
+ ]
57
249
  }),
58
250
  truncateTool: toolDef({
59
251
  name: "truncate",
60
252
  description: "Truncates text to a maximum length and appends a suffix",
61
253
  inputSchema: {
62
- input: z2.string().describe("Text to truncate"),
63
- maxLength: z2.number().int().positive().describe("Maximum character length"),
64
- suffix: z2.string().default("...").describe("Suffix to append when truncated")
254
+ input: z3.string().describe("Text to truncate"),
255
+ maxLength: z3.number().int().positive().describe("Maximum character length"),
256
+ suffix: z3.string().default("...").describe("Suffix to append when truncated")
65
257
  },
66
258
  handler: async ({ input, maxLength, suffix }) => {
67
259
  const result = input.length <= maxLength ? input : input.slice(0, maxLength - suffix.length) + suffix;
68
260
  return text(result);
69
- }
261
+ },
262
+ examples: [
263
+ { args: [`"hello world long text"`, "10"], result: "hello w..." },
264
+ { args: [`"hello world"`, "8", `"\u2026"`], result: "hello w\u2026" }
265
+ ]
70
266
  })
71
267
  };
72
268
  var cnTool = defineTool(tools.cnTool);
@@ -96,7 +292,15 @@ function createUtilsServer() {
96
292
  [cnTool, caseConvertTool, truncateTool]
97
293
  );
98
294
  }
295
+ var server = createUtilsServer();
296
+ startServer(server).catch((err) => {
297
+ console.error("[utils] server error:", err);
298
+ process.exit(1);
299
+ });
99
300
  export {
100
301
  cn,
101
- createUtilsServer
302
+ createUtilsServer,
303
+ generateReadmeSkills,
304
+ generateSkillMarkdown,
305
+ tools
102
306
  };
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../common/mcp/tool.ts
3
+ // ../common/kit/tool.ts
4
4
  function toolDef(def) {
5
5
  return def;
6
6
  }
@@ -11,32 +11,35 @@ function text(content) {
11
11
  return { content: [{ type: "text", text: content }] };
12
12
  }
13
13
 
14
- // ../common/mcp/server.ts
14
+ // ../common/kit/server.ts
15
15
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
16
16
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17
17
  function createMcpServer(config, tools2) {
18
- const server2 = new McpServer(config);
18
+ const server3 = new McpServer(config);
19
19
  for (const tool of tools2) {
20
- server2.registerTool(
20
+ server3.registerTool(
21
21
  tool.name,
22
22
  { description: tool.description, inputSchema: tool.inputSchema },
23
23
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
24
  tool.handler
25
25
  );
26
26
  }
27
- return server2;
27
+ return server3;
28
28
  }
29
- async function startServer(server2) {
29
+ async function startServer(server3) {
30
30
  const transport = new StdioServerTransport();
31
- await server2.connect(transport);
31
+ await server3.connect(transport);
32
32
  }
33
33
 
34
- // ../common/mcp/cli.ts
34
+ // ../common/kit/cli.ts
35
35
  import { z } from "zod";
36
36
 
37
- // src/tools/text.ts
37
+ // ../common/kit/skill.ts
38
38
  import { z as z2 } from "zod";
39
39
 
40
+ // src/tools/text.ts
41
+ import { z as z3 } from "zod";
42
+
40
43
  // src/cn.ts
41
44
  function cn(...classes) {
42
45
  return classes.filter(Boolean).join(" ");
@@ -48,31 +51,43 @@ var tools = {
48
51
  name: "cn",
49
52
  description: "Merges class names, filtering out falsy values",
50
53
  inputSchema: {
51
- classes: z2.array(z2.string()).describe("List of class names to merge")
54
+ classes: z3.array(z3.string()).describe("List of class names to merge")
52
55
  },
53
- handler: async ({ classes }) => text(cn(...classes))
56
+ handler: async ({ classes }) => text(cn(...classes)),
57
+ examples: [
58
+ { args: [`'["btn","active","large"]'`], result: "btn active large" }
59
+ ]
54
60
  }),
55
61
  caseConvertTool: toolDef({
56
62
  name: "case_convert",
57
63
  description: "Converts text to the specified case format",
58
64
  inputSchema: {
59
- input: z2.string().describe("Text to convert"),
60
- to: z2.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
65
+ input: z3.string().describe("Text to convert"),
66
+ to: z3.enum(["upper", "lower", "capitalize", "camel", "snake", "kebab"]).describe("Target case format")
61
67
  },
62
- handler: async ({ input, to }) => text(convert(input, to))
68
+ handler: async ({ input, to }) => text(convert(input, to)),
69
+ examples: [
70
+ { args: [`"hello world"`, "camel"], result: "helloWorld" },
71
+ { args: [`"helloWorld"`, "snake"], result: "hello_world" },
72
+ { args: [`"hello world"`, "kebab"], result: "hello-world" }
73
+ ]
63
74
  }),
64
75
  truncateTool: toolDef({
65
76
  name: "truncate",
66
77
  description: "Truncates text to a maximum length and appends a suffix",
67
78
  inputSchema: {
68
- input: z2.string().describe("Text to truncate"),
69
- maxLength: z2.number().int().positive().describe("Maximum character length"),
70
- suffix: z2.string().default("...").describe("Suffix to append when truncated")
79
+ input: z3.string().describe("Text to truncate"),
80
+ maxLength: z3.number().int().positive().describe("Maximum character length"),
81
+ suffix: z3.string().default("...").describe("Suffix to append when truncated")
71
82
  },
72
83
  handler: async ({ input, maxLength, suffix }) => {
73
84
  const result = input.length <= maxLength ? input : input.slice(0, maxLength - suffix.length) + suffix;
74
85
  return text(result);
75
- }
86
+ },
87
+ examples: [
88
+ { args: [`"hello world long text"`, "10"], result: "hello w..." },
89
+ { args: [`"hello world"`, "8", `"\u2026"`], result: "hello w\u2026" }
90
+ ]
76
91
  })
77
92
  };
78
93
  var cnTool = defineTool(tools.cnTool);
@@ -102,10 +117,15 @@ function createUtilsServer() {
102
117
  [cnTool, caseConvertTool, truncateTool]
103
118
  );
104
119
  }
105
-
106
- // src/server.ts
107
120
  var server = createUtilsServer();
108
121
  startServer(server).catch((err) => {
109
122
  console.error("[utils] server error:", err);
110
123
  process.exit(1);
111
124
  });
125
+
126
+ // src/server.ts
127
+ var server2 = createUtilsServer();
128
+ startServer(server2).catch((err) => {
129
+ console.error("[utils] server error:", err);
130
+ process.exit(1);
131
+ });
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: mono-rele2-utils
3
+ description: Use this skill to invoke text utility functions via the mono-rele2-utils CLI. Handles class name merging, case conversion, and text truncation.
4
+ ---
5
+
6
+ # mono-rele2-utils
7
+
8
+ ```sh
9
+ mono-rele2-utils <skillName> [...args]
10
+ ```
11
+
12
+ ## Skills
13
+
14
+ ### cnTool
15
+
16
+ Merges class names, filtering out falsy values
17
+
18
+ | arg | description |
19
+ |-----|-------------|
20
+ | `classes` | List of class names to merge |
21
+
22
+ ### caseConvertTool
23
+
24
+ Converts text to the specified case format
25
+
26
+ | arg | description |
27
+ |-----|-------------|
28
+ | `input` | Text to convert |
29
+ | `to` | Target case format — `upper` \| `lower` \| `capitalize` \| `camel` \| `snake` \| `kebab` |
30
+
31
+ ### truncateTool
32
+
33
+ Truncates text to a maximum length and appends a suffix
34
+
35
+ | arg | description |
36
+ |-----|-------------|
37
+ | `input` | Text to truncate |
38
+ | `maxLength` | Maximum character length |
39
+ | `suffix` | Suffix to append when truncated — default: `...` |
40
+
41
+ ## Examples
42
+
43
+ - `mono-rele2-utils cnTool '["btn","active","large"]'` => `btn active large`
44
+ - `mono-rele2-utils caseConvertTool "hello world" camel` => `helloWorld`
45
+ - `mono-rele2-utils caseConvertTool "helloWorld" snake` => `hello_world`
46
+ - `mono-rele2-utils caseConvertTool "hello world" kebab` => `hello-world`
47
+ - `mono-rele2-utils truncateTool "hello world long text" 10` => `hello w...`
48
+ - `mono-rele2-utils truncateTool "hello world" 8 "…"` => `hello w…`
49
+
50
+ ## Guidelines
51
+
52
+ - Arguments are positional — pass them in the order listed in each skill's table
53
+ - Numeric args are auto-parsed — pass as plain numbers (e.g. `10`)
54
+ - Array args must be valid JSON — wrap in single quotes on Unix shells (e.g. `'["a","b"]'`)
55
+ - Optional args with defaults may be omitted
56
+ - Run `mono-rele2-utils` with no args to list all available skills
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@julong/mono-rele2-utils",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
+ "description": "Use this skill to invoke text utility functions via the mono-rele2-utils CLI. Handles class name merging, case conversion, and text truncation.",
4
5
  "license": "ISC",
5
6
  "type": "module",
6
7
  "exports": {
@@ -1,58 +0,0 @@
1
- ---
2
- name: mono-rele2-utils
3
- description: Use this skill to invoke text utility functions via the mono-rele2-utils CLI. Handles class name merging, case conversion, and text truncation.
4
- ---
5
-
6
- # mono-rele2-utils
7
-
8
- CLI for running text utility functions from the mono-rele2 package.
9
-
10
- ```sh
11
- mono-rele2-utils <skillName> [...args]
12
- ```
13
-
14
- ## Skills
15
-
16
- ### caseConvertTool
17
-
18
- Converts text to the specified case format.
19
-
20
- | arg | description |
21
- |-----|-------------|
22
- | `input` | Text to convert |
23
- | `to` | Target format: `upper` \| `lower` \| `capitalize` \| `camel` \| `snake` \| `kebab` |
24
-
25
- ### cnTool
26
-
27
- Merges class names, filtering out falsy values.
28
-
29
- | arg | description |
30
- |-----|-------------|
31
- | `classes` | JSON array of class name strings, e.g. `'["btn","active"]'` |
32
-
33
- ### truncateTool
34
-
35
- Truncates text to a maximum length and appends a suffix.
36
-
37
- | arg | description |
38
- |-----|-------------|
39
- | `input` | Text to truncate |
40
- | `maxLength` | Maximum character length |
41
- | `suffix` | Suffix to append when truncated (default: `...`) |
42
-
43
- ## Examples
44
-
45
- - `mono-rele2-utils caseConvertTool "hello world" camel` → `helloWorld`
46
- - `mono-rele2-utils caseConvertTool "helloWorld" snake` → `hello_world`
47
- - `mono-rele2-utils caseConvertTool "hello world" kebab` → `hello-world`
48
- - `mono-rele2-utils truncateTool "hello world long text" 10` → `hello w...`
49
- - `mono-rele2-utils truncateTool "hello world" 8 "…"` → `hello w…`
50
- - `mono-rele2-utils cnTool '["btn","active","large"]'` → `btn active large`
51
-
52
- ## Guidelines
53
-
54
- - Arguments are positional — pass them in the order listed in each skill's table
55
- - Numeric args (e.g. `maxLength`) are auto-parsed — pass as plain numbers: `10`
56
- - Array args (e.g. `classes`) must be valid JSON — wrap in single quotes on Unix shells
57
- - Optional args with defaults (e.g. `suffix`) may be omitted
58
- - Run `mono-rele2-utils` with no args to list all available skills