@julong/mono-rele2-utils 1.18.0 → 1.19.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
@@ -18,13 +18,13 @@ npx @julong/mono-rele2-utils-cli <toolName> [...args]
18
18
  mono-rele2-utils-cli <toolName> [...args]
19
19
  ```
20
20
 
21
- Run without arguments to list all available skills:
21
+ Run without arguments to list all available tools:
22
22
 
23
23
  ```sh
24
24
  mono-rele2-utils-cli
25
25
  ```
26
26
 
27
- ### Skills
27
+ ### Tools
28
28
 
29
29
  #### `cnTool`
30
30
 
@@ -80,6 +80,30 @@ mono-rele2-utils-cli truncateTool "hello world long text" 10 # hello w...
80
80
  mono-rele2-utils-cli truncateTool "hello world" 8 "…" # hello w…
81
81
  ```
82
82
 
83
+ #### `objectFlattenTool`
84
+
85
+ Flattens a nested JSON object of any depth into dot-notation key-value pairs. Accepts a JSON string and recursively flattens all levels. Arrays and primitives at any level are treated as leaf values..
86
+
87
+ ```sh
88
+ mono-rele2-utils-cli objectFlattenTool <json>
89
+ ```
90
+
91
+ | arg | type | description |
92
+ |-----|------|-------------|
93
+ | `json` | string | JSON string of a nested object to flatten (unlimited depth) |
94
+
95
+ ```sh
96
+ mono-rele2-utils-cli objectFlattenTool '{"user":{"name":"Alice","address":{"city":"Seoul","zip":"12345"}},"active":true}' # {
97
+ "user.name": "Alice",
98
+ "user.address.city": "Seoul",
99
+ "user.address.zip": "12345",
100
+ "active": true
101
+ }
102
+ mono-rele2-utils-cli objectFlattenTool '{"a":{"b":{"c":{"d":{"e":"deep"}}}}}' # {
103
+ "a.b.c.d.e": "deep"
104
+ }
105
+ ```
106
+
83
107
  ## MCP Server
84
108
 
85
109
  ```sh
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- function u(e){return{content:[{type:"text",text:e}]}}import{McpServer as w}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as z}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as f}from"zod";function h(e){return`Available skills:
2
+ function a(e){return{content:[{type:"text",text:e}]}}import{McpServer as R}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as N}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as m}from"zod";function x(e){return`Available skills:
3
3
 
4
- `+Object.entries(e).map(([r,o])=>{let a=Object.entries(o.inputSchema),i=Math.max(...a.map(([l])=>l.length)),d=a.map(([l,t])=>{let c=t.description??"";return` ${l.padEnd(i+2)}${c}`}).join(`
5
- `);return` ${r}
6
- ${o.description}
7
- ${d}`}).join(`
4
+ `+Object.entries(e).map(([o,t])=>{let r=Object.entries(t.inputSchema),i=Math.max(...r.map(([l])=>l.length)),p=r.map(([l,s])=>{let u=s.description??"";return` ${l.padEnd(i+2)}${u}`}).join(`
5
+ `);return` ${o}
6
+ ${t.description}
7
+ ${p}`}).join(`
8
8
 
9
- `)}async function m(e){let[,,n,...r]=process.argv;console.log(process.argv),(!n||!(n in e))&&(n&&console.error(`Unknown skill: "${n}"
10
- `),console.log(h(e)),process.exit(n?1:0));let o=e[n],a=Object.keys(o.inputSchema),i={};for(let t=0;t<a.length;t++){let c=r[t];if(c!==void 0)try{i[a[t]]=JSON.parse(c)}catch{i[a[t]]=c}}let d=f.object(o.inputSchema).parse(i),l=await o.handler(d);for(let t of l.content)t.type==="text"&&console.log(t.text)}function g(e){e instanceof f.ZodError?console.error("Validation error:",e.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ")):console.error("Error:",e instanceof Error?e.message:String(e)),process.exit(1)}import{z as v}from"zod";import{z as s}from"zod";function y(...e){return e.filter(Boolean).join(" ")}var p={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:s.array(s.string()).describe("List of class names to merge")},handler:async({classes:e})=>u(y(...e)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:s.string().describe("Text to convert"),to:s.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:e,to:n})=>u(T(e,n)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:s.string().describe("Text to truncate"),maxLength:s.number().int().positive().describe("Maximum character length"),suffix:s.string().default("...").describe("Suffix to append when truncated")},handler:async({input:e,maxLength:n,suffix:r})=>{let o=e.length<=n?e:e.slice(0,n-r.length)+r;return u(o)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},W=p.cnTool,q=p.caseConvertTool,F=p.truncateTool;function T(e,n){switch(n){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.replace(/[-_\s]+(.)/g,(r,o)=>o.toUpperCase()).replace(/^(.)/,r=>r.toLowerCase());case"snake":return e.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return e.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}m(p).catch(g);
9
+ `)}async function g(e){let[,,n,...o]=process.argv;console.log(process.argv),(!n||!(n in e))&&(n&&console.error(`Unknown skill: "${n}"
10
+ `),console.log(x(e)),process.exit(n?1:0));let t=e[n],r=Object.keys(t.inputSchema),i={};for(let s=0;s<r.length;s++){let u=o[s];if(u!==void 0)try{i[r[s]]=JSON.parse(u)}catch{i[r[s]]=u}}let p=m.object(t.inputSchema).parse(i),l=await t.handler(p);for(let s of l.content)s.type==="text"&&console.log(s.text)}function y(e){e instanceof m.ZodError?console.error("Validation error:",e.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ")):console.error("Error:",e instanceof Error?e.message:String(e)),process.exit(1)}import{z as L}from"zod";import{z as c}from"zod";function h(...e){return e.filter(Boolean).join(" ")}var d={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:c.array(c.string()).describe("List of class names to merge")},handler:async({classes:e})=>a(h(...e)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:c.string().describe("Text to convert"),to:c.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:e,to:n})=>a(j(e,n)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:c.string().describe("Text to truncate"),maxLength:c.number().int().positive().describe("Maximum character length"),suffix:c.string().default("...").describe("Suffix to append when truncated")},handler:async({input:e,maxLength:n,suffix:o})=>{let t=e.length<=n?e:e.slice(0,n-o.length)+o;return a(t)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},w=d.cnTool,Z=d.caseConvertTool,A=d.truncateTool;function j(e,n){switch(n){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.replace(/[-_\s]+(.)/g,(o,t)=>t.toUpperCase()).replace(/^(.)/,o=>o.toLowerCase());case"snake":return e.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return e.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}import{z}from"zod";function $(e){let n={};function o(t,r){if(t===null||typeof t!="object"||Array.isArray(t)){n[r]=t;return}for(let[i,p]of Object.entries(t)){let l=r?`${r}.${i}`:i;o(p,l)}}return o(e,""),n}var f={objectFlattenTool:{name:"object_flatten",description:"Flattens a nested JSON object of any depth into dot-notation key-value pairs. Accepts a JSON string and recursively flattens all levels. Arrays and primitives at any level are treated as leaf values.",inputSchema:{json:z.string().describe("JSON string of a nested object to flatten (unlimited depth)")},handler:async({json:e})=>{let n;try{let o=JSON.parse(e);if(typeof o!="object"||o===null||Array.isArray(o))return a(`Error: input must be a JSON object, got ${Array.isArray(o)?"array":typeof o}`);n=o}catch{return a("Error: invalid JSON string \u2014 unable to parse input")}try{let o=$(n);return a(JSON.stringify(o,null,2))}catch(o){return a(`Error: failed to flatten object \u2014 ${o.message}`)}},examples:[{args:[`'{"user":{"name":"Alice","address":{"city":"Seoul","zip":"12345"}},"active":true}'`],result:JSON.stringify({"user.name":"Alice","user.address.city":"Seoul","user.address.zip":"12345",active:!0},null,2)},{args:[`'{"a":{"b":{"c":{"d":{"e":"deep"}}}}}'`],result:JSON.stringify({"a.b.c.d.e":"deep"},null,2)}],guidelines:["Arrays and primitives at any level are always treated as leaf values \u2014 they are never traversed.","The result is always a flat JSON object with dot-notation keys.","There is no depth limit \u2014 objects of any nesting level are fully flattened."]}},k=f.objectFlattenTool;var T={...d,...f};g(T).catch(y);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import * as zod from 'zod';
2
3
  import { z } from 'zod';
3
4
 
4
5
  declare function cn(...classes: (string | undefined | null | false)[]): string;
@@ -29,11 +30,23 @@ declare function generateReadmeSkills(opts: {
29
30
  }): string;
30
31
 
31
32
  declare const tools: {
33
+ objectFlattenTool: {
34
+ name: string;
35
+ description: string;
36
+ inputSchema: {
37
+ readonly json: zod.ZodString;
38
+ };
39
+ handler: (input: {
40
+ json: string;
41
+ }) => Promise<ToolResult>;
42
+ examples?: ToolExample[];
43
+ guidelines?: string[];
44
+ };
32
45
  cnTool: {
33
46
  name: string;
34
47
  description: string;
35
48
  inputSchema: {
36
- readonly classes: z.ZodArray<z.ZodString>;
49
+ readonly classes: zod.ZodArray<zod.ZodString>;
37
50
  };
38
51
  handler: (input: {
39
52
  classes: string[];
@@ -45,8 +58,8 @@ declare const tools: {
45
58
  name: string;
46
59
  description: string;
47
60
  inputSchema: {
48
- readonly input: z.ZodString;
49
- readonly to: z.ZodEnum<{
61
+ readonly input: zod.ZodString;
62
+ readonly to: zod.ZodEnum<{
50
63
  upper: "upper";
51
64
  lower: "lower";
52
65
  capitalize: "capitalize";
@@ -66,9 +79,9 @@ declare const tools: {
66
79
  name: string;
67
80
  description: string;
68
81
  inputSchema: {
69
- readonly input: z.ZodString;
70
- readonly maxLength: z.ZodNumber;
71
- readonly suffix: z.ZodDefault<z.ZodString>;
82
+ readonly input: zod.ZodString;
83
+ readonly maxLength: zod.ZodNumber;
84
+ readonly suffix: zod.ZodDefault<zod.ZodString>;
72
85
  };
73
86
  handler: (input: {
74
87
  input: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- function y(...o){return o.filter(Boolean).join(" ")}function m(o){return{content:[{type:"text",text:o}]}}import{McpServer as V}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as B}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as J}from"zod";import{z as s}from"zod";function S(o){let{binName:n,description:e,tools:r}=o;return`---
1
+ function y(...o){return o.filter(Boolean).join(" ")}function c(o){return{content:[{type:"text",text:o}]}}import{McpServer as G}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as W}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as K}from"zod";import{z as a}from"zod";function w(o){let{binName:n,description:e,tools:t}=o;return`---
2
2
  name: ${n}
3
3
  description: ${e}
4
4
  ---
@@ -11,42 +11,42 @@ ${n} <toolName> [...args]
11
11
 
12
12
  ## Skills
13
13
 
14
- ${w(r)}
14
+ ${Z(t)}
15
15
 
16
16
  ## Examples
17
17
 
18
- ${z(n,r)}
18
+ ${j(n,t)}
19
19
 
20
20
  ## Guidelines
21
21
 
22
- ${$(n,r)}
23
- `}function w(o){return Object.entries(o).map(([n,e])=>{let r=Object.entries(e.inputSchema).map(([a,i])=>`| \`${a}\` | ${b(i)} |`).join(`
22
+ ${k(n,t)}
23
+ `}function Z(o){return Object.entries(o).map(([n,e])=>{let t=Object.entries(e.inputSchema).map(([s,i])=>`| \`${s}\` | ${A(i)} |`).join(`
24
24
  `);return`### ${n}
25
25
 
26
26
  ${e.description}
27
27
 
28
28
  | arg | description |
29
29
  |-----|-------------|
30
- ${r}`}).join(`
30
+ ${t}`}).join(`
31
31
 
32
- `)}function b(o){let n=o.description??"",e=o,r,a=!1;for(;e instanceof s.ZodOptional||e instanceof s.ZodDefault;){if(e instanceof s.ZodDefault){let t=e.def.defaultValue;r=typeof t=="function"?t():t}e instanceof s.ZodOptional&&(a=!0),e=e.unwrap()}let i=[];if(n&&i.push(n),e instanceof s.ZodEnum){let t=e.options.map(l=>`\`${l}\``).join(" \\| ");i.push(t)}return r!==void 0?i.push(`default: \`${String(r)}\``):a&&i.push("optional"),i.join(" \u2014 ")}function z(o,n){let e=[];for(let[r,a]of Object.entries(n))if(a.examples)for(let i of a.examples){let t=[o,r,...i.args].join(" ");e.push(`- \`${t}\` => \`${i.result}\``)}return e.join(`
33
- `)}function $(o,n){let e=[],r=new Set,a=t=>{r.has(t)||(r.add(t),e.push(t))};a("Arguments are positional \u2014 pass them in the order listed in each skill's table");let i=Object.values(n).flatMap(t=>Object.values(t.inputSchema));i.some(t=>h(t,s.ZodNumber))&&a("Numeric args are auto-parsed \u2014 pass as plain numbers (e.g. `10`)"),i.some(t=>h(t,s.ZodArray))&&a('Array args must be valid JSON \u2014 wrap in single quotes on Unix shells (e.g. `\'["a","b"]\'`)'),i.some(t=>t instanceof s.ZodOptional||t instanceof s.ZodDefault)&&a("Optional args with defaults may be omitted");for(let t of Object.values(n))if(t.guidelines)for(let l of t.guidelines)a(l);return a(`Run \`${o}\` with no args to list all available skills`),e.map(t=>`- ${t}`).join(`
34
- `)}function h(o,n){let e=o;for(;e instanceof s.ZodOptional||e instanceof s.ZodDefault;)e=e.unwrap();return e instanceof n}function A(o){console.log(o.binName);let{binName:n,tools:e}=o;return Object.entries(e).map(([r,a])=>k(n,r,a)).join(`
32
+ `)}function A(o){let n=o.description??"",e=o,t,s=!1;for(;e instanceof a.ZodOptional||e instanceof a.ZodDefault;){if(e instanceof a.ZodDefault){let r=e.def.defaultValue;t=typeof r=="function"?r():r}e instanceof a.ZodOptional&&(s=!0),e=e.unwrap()}let i=[];if(n&&i.push(n),e instanceof a.ZodEnum){let r=e.options.map(l=>`\`${l}\``).join(" \\| ");i.push(r)}return t!==void 0?i.push(`default: \`${String(t)}\``):s&&i.push("optional"),i.join(" \u2014 ")}function j(o,n){let e=[];for(let[t,s]of Object.entries(n))if(s.examples)for(let i of s.examples){let r=[o,t,...i.args].join(" ");e.push(`- \`${r}\` => \`${i.result}\``)}return e.join(`
33
+ `)}function k(o,n){let e=[],t=new Set,s=r=>{t.has(r)||(t.add(r),e.push(r))};s("Arguments are positional \u2014 pass them in the order listed in each skill's table");let i=Object.values(n).flatMap(r=>Object.values(r.inputSchema));i.some(r=>x(r,a.ZodNumber))&&s("Numeric args are auto-parsed \u2014 pass as plain numbers (e.g. `10`)"),i.some(r=>x(r,a.ZodArray))&&s('Array args must be valid JSON \u2014 wrap in single quotes on Unix shells (e.g. `\'["a","b"]\'`)'),i.some(r=>r instanceof a.ZodOptional||r instanceof a.ZodDefault)&&s("Optional args with defaults may be omitted");for(let r of Object.values(n))if(r.guidelines)for(let l of r.guidelines)s(l);return s(`Run \`${o}\` with no args to list all available skills`),e.map(r=>`- ${r}`).join(`
34
+ `)}function x(o,n){let e=o;for(;e instanceof a.ZodOptional||e instanceof a.ZodDefault;)e=e.unwrap();return e instanceof n}function z(o){console.log(o.binName);let{binName:n,tools:e}=o;return Object.entries(e).map(([t,s])=>$(n,t,s)).join(`
35
35
 
36
- `)}function k(o,n,e){let r=Object.entries(e.inputSchema),a=r.map(([c,p])=>p instanceof s.ZodOptional||p instanceof s.ZodDefault?`[${c}]`:`<${c}>`).join(" "),i=[o,n,a].filter(Boolean).join(" "),t=r.map(([c,p])=>{let g=j(p),u=v(p);return`| \`${c}\` | ${g} | ${u} |`}).join(`
37
- `),l=e.examples??[],T="";if(l.length>0){let c=l.map(u=>[o,n,...u.args].join(" ")),p=Math.max(...c.map(u=>u.length));T=`
36
+ `)}function $(o,n,e){let t=Object.entries(e.inputSchema),s=t.map(([p,u])=>u instanceof a.ZodOptional||u instanceof a.ZodDefault?`[${p}]`:`<${p}>`).join(" "),i=[o,n,s].filter(Boolean).join(" "),r=t.map(([p,u])=>{let g=v(u),d=O(u);return`| \`${p}\` | ${g} | ${d} |`}).join(`
37
+ `),l=e.examples??[],T="";if(l.length>0){let p=l.map(d=>[o,n,...d.args].join(" ")),u=Math.max(...p.map(d=>d.length));T=`
38
38
 
39
39
  \`\`\`sh
40
- ${l.map((u,Z)=>`${c[Z].padEnd(p)} # ${u.result}`).join(`
40
+ ${l.map((d,b)=>`${p[b].padEnd(u)} # ${d.result}`).join(`
41
41
  `)}
42
- \`\`\``}let x=t?`
42
+ \`\`\``}let S=r?`
43
43
 
44
44
  | arg | type | description |
45
45
  |-----|------|-------------|
46
- ${t}`:"";return`#### \`${n}\`
46
+ ${r}`:"";return`#### \`${n}\`
47
47
 
48
48
  ${e.description}.
49
49
 
50
50
  \`\`\`sh
51
51
  ${i}
52
- \`\`\`${x}${T}`}function j(o){let n=o;for(;n instanceof s.ZodOptional||n instanceof s.ZodDefault;)n=n.unwrap();return n instanceof s.ZodEnum?n.options.map(e=>`\`${e}\``).join(" \\| "):n instanceof s.ZodNumber?"number":n instanceof s.ZodString?"string":n instanceof s.ZodBoolean?"boolean":n instanceof s.ZodArray?"JSON string (array)":"unknown"}function v(o){let n=o.description??"",e=o,r,a=!1;for(;e instanceof s.ZodOptional||e instanceof s.ZodDefault;){if(e instanceof s.ZodDefault){let i=e.def.defaultValue;r=typeof i=="function"?i():i}e instanceof s.ZodOptional&&(a=!0),e=e.unwrap()}return r!==void 0?`${n} (default: \`${String(r)}\`)`:a?`${n} (optional)`:n}import{z as d}from"zod";var f={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:d.array(d.string()).describe("List of class names to merge")},handler:async({classes:o})=>m(y(...o)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:d.string().describe("Text to convert"),to:d.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:o,to:n})=>m(C(o,n)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:d.string().describe("Text to truncate"),maxLength:d.number().int().positive().describe("Maximum character length"),suffix:d.string().default("...").describe("Suffix to append when truncated")},handler:async({input:o,maxLength:n,suffix:e})=>{let r=o.length<=n?o:o.slice(0,n-e.length)+e;return m(r)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},O=f.cnTool,D=f.caseConvertTool,R=f.truncateTool;function C(o,n){switch(n){case"upper":return o.toUpperCase();case"lower":return o.toLowerCase();case"capitalize":return o.charAt(0).toUpperCase()+o.slice(1).toLowerCase();case"camel":return o.replace(/[-_\s]+(.)/g,(e,r)=>r.toUpperCase()).replace(/^(.)/,e=>e.toLowerCase());case"snake":return o.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return o.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}export{y as cn,A as generateReadmeSkills,S as generateSkillMarkdown,f as tools};
52
+ \`\`\`${S}${T}`}function v(o){let n=o;for(;n instanceof a.ZodOptional||n instanceof a.ZodDefault;)n=n.unwrap();return n instanceof a.ZodEnum?n.options.map(e=>`\`${e}\``).join(" \\| "):n instanceof a.ZodNumber?"number":n instanceof a.ZodString?"string":n instanceof a.ZodBoolean?"boolean":n instanceof a.ZodArray?"JSON string (array)":"unknown"}function O(o){let n=o.description??"",e=o,t,s=!1;for(;e instanceof a.ZodOptional||e instanceof a.ZodDefault;){if(e instanceof a.ZodDefault){let i=e.def.defaultValue;t=typeof i=="function"?i():i}e instanceof a.ZodOptional&&(s=!0),e=e.unwrap()}return t!==void 0?`${n} (default: \`${String(t)}\`)`:s?`${n} (optional)`:n}import{z as f}from"zod";var m={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:f.array(f.string()).describe("List of class names to merge")},handler:async({classes:o})=>c(y(...o)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:f.string().describe("Text to convert"),to:f.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:o,to:n})=>c(J(o,n)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:f.string().describe("Text to truncate"),maxLength:f.number().int().positive().describe("Maximum character length"),suffix:f.string().default("...").describe("Suffix to append when truncated")},handler:async({input:o,maxLength:n,suffix:e})=>{let t=o.length<=n?o:o.slice(0,n-e.length)+e;return c(t)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},N=m.cnTool,C=m.caseConvertTool,E=m.truncateTool;function J(o,n){switch(n){case"upper":return o.toUpperCase();case"lower":return o.toLowerCase();case"capitalize":return o.charAt(0).toUpperCase()+o.slice(1).toLowerCase();case"camel":return o.replace(/[-_\s]+(.)/g,(e,t)=>t.toUpperCase()).replace(/^(.)/,e=>e.toLowerCase());case"snake":return o.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return o.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}import{z as M}from"zod";function _(o){let n={};function e(t,s){if(t===null||typeof t!="object"||Array.isArray(t)){n[s]=t;return}for(let[i,r]of Object.entries(t)){let l=s?`${s}.${i}`:i;e(r,l)}}return e(o,""),n}var h={objectFlattenTool:{name:"object_flatten",description:"Flattens a nested JSON object of any depth into dot-notation key-value pairs. Accepts a JSON string and recursively flattens all levels. Arrays and primitives at any level are treated as leaf values.",inputSchema:{json:M.string().describe("JSON string of a nested object to flatten (unlimited depth)")},handler:async({json:o})=>{let n;try{let e=JSON.parse(o);if(typeof e!="object"||e===null||Array.isArray(e))return c(`Error: input must be a JSON object, got ${Array.isArray(e)?"array":typeof e}`);n=e}catch{return c("Error: invalid JSON string \u2014 unable to parse input")}try{let e=_(n);return c(JSON.stringify(e,null,2))}catch(e){return c(`Error: failed to flatten object \u2014 ${e.message}`)}},examples:[{args:[`'{"user":{"name":"Alice","address":{"city":"Seoul","zip":"12345"}},"active":true}'`],result:JSON.stringify({"user.name":"Alice","user.address.city":"Seoul","user.address.zip":"12345",active:!0},null,2)},{args:[`'{"a":{"b":{"c":{"d":{"e":"deep"}}}}}'`],result:JSON.stringify({"a.b.c.d.e":"deep"},null,2)}],guidelines:["Arrays and primitives at any level are always treated as leaf values \u2014 they are never traversed.","The result is always a flat JSON object with dot-notation keys.","There is no depth limit \u2014 objects of any nesting level are fully flattened."]}},L=h.objectFlattenTool;var V={...m,...h};export{y as cn,z as generateReadmeSkills,w as generateSkillMarkdown,V as tools};
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- function s(e){return{content:[{type:"text",text:e}]}}import{McpServer as f}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as m}from"@modelcontextprotocol/sdk/server/stdio.js";function p(e,n){let o=new f(e);for(let t of n)o.registerTool(t.name,{description:t.description,inputSchema:t.inputSchema},t.handler);return o}async function u(e){let n=new m;await e.connect(n)}import{z as b}from"zod";import{z as A}from"zod";import{z as r}from"zod";function d(...e){return e.filter(Boolean).join(" ")}var a={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:r.array(r.string()).describe("List of class names to merge")},handler:async({classes:e})=>s(d(...e)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:r.string().describe("Text to convert"),to:r.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:e,to:n})=>s(g(e,n)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:r.string().describe("Text to truncate"),maxLength:r.number().int().positive().describe("Maximum character length"),suffix:r.string().default("...").describe("Suffix to append when truncated")},handler:async({input:e,maxLength:n,suffix:o})=>{let t=e.length<=n?e:e.slice(0,n-o.length)+o;return s(t)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},i=a.cnTool,l=a.caseConvertTool,c=a.truncateTool;function g(e,n){switch(n){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.replace(/[-_\s]+(.)/g,(o,t)=>t.toUpperCase()).replace(/^(.)/,o=>o.toLowerCase());case"snake":return e.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return e.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}var y=p({name:"mono-rele2-utils",version:"1.0.0"},[i,l,c]);u(y).catch(e=>{console.error("[utils] server error:",e),process.exit(1)});
2
+ function r(e){return{content:[{type:"text",text:e}]}}import{McpServer as S}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as x}from"@modelcontextprotocol/sdk/server/stdio.js";function m(e,o){let n=new S(e);for(let t of o)n.registerTool(t.name,{description:t.description,inputSchema:t.inputSchema},t.handler);return n}async function g(e){let o=new x;await e.connect(o)}import{z as N}from"zod";import{z as J}from"zod";import{z as s}from"zod";function y(...e){return e.filter(Boolean).join(" ")}var a={cnTool:{name:"cn",description:"Merges class names, filtering out falsy values",inputSchema:{classes:s.array(s.string()).describe("List of class names to merge")},handler:async({classes:e})=>r(y(...e)),examples:[{args:[`'["btn","active","large"]'`],result:"btn active large"}]},caseConvertTool:{name:"case_convert",description:"Converts text to the specified case format",inputSchema:{input:s.string().describe("Text to convert"),to:s.enum(["upper","lower","capitalize","camel","snake","kebab"]).describe("Target case format")},handler:async({input:e,to:o})=>r(Z(e,o)),examples:[{args:['"hello world"',"camel"],result:"helloWorld"},{args:['"helloWorld"',"snake"],result:"hello_world"},{args:['"hello world"',"kebab"],result:"hello-world"}]},truncateTool:{name:"truncate",description:"Truncates text to a maximum length and appends a suffix",inputSchema:{input:s.string().describe("Text to truncate"),maxLength:s.number().int().positive().describe("Maximum character length"),suffix:s.string().default("...").describe("Suffix to append when truncated")},handler:async({input:e,maxLength:o,suffix:n})=>{let t=e.length<=o?e:e.slice(0,o-n.length)+n;return r(t)},examples:[{args:['"hello world long text"',"10"],result:"hello w..."},{args:['"hello world"',"8",'"\u2026"'],result:"hello w\u2026"}]}},l=a.cnTool,c=a.caseConvertTool,p=a.truncateTool;function Z(e,o){switch(o){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.replace(/[-_\s]+(.)/g,(n,t)=>t.toUpperCase()).replace(/^(.)/,n=>n.toLowerCase());case"snake":return e.replace(/([A-Z])/g,"_$1").replace(/[-\s]+/g,"_").toLowerCase().replace(/^_/,"");case"kebab":return e.replace(/([A-Z])/g,"-$1").replace(/[_\s]+/g,"-").toLowerCase().replace(/^-/,"")}}import{z as A}from"zod";function j(e){let o={};function n(t,i){if(t===null||typeof t!="object"||Array.isArray(t)){o[i]=t;return}for(let[f,T]of Object.entries(t)){let h=i?`${i}.${f}`:f;n(T,h)}}return n(e,""),o}var u={objectFlattenTool:{name:"object_flatten",description:"Flattens a nested JSON object of any depth into dot-notation key-value pairs. Accepts a JSON string and recursively flattens all levels. Arrays and primitives at any level are treated as leaf values.",inputSchema:{json:A.string().describe("JSON string of a nested object to flatten (unlimited depth)")},handler:async({json:e})=>{let o;try{let n=JSON.parse(e);if(typeof n!="object"||n===null||Array.isArray(n))return r(`Error: input must be a JSON object, got ${Array.isArray(n)?"array":typeof n}`);o=n}catch{return r("Error: invalid JSON string \u2014 unable to parse input")}try{let n=j(o);return r(JSON.stringify(n,null,2))}catch(n){return r(`Error: failed to flatten object \u2014 ${n.message}`)}},examples:[{args:[`'{"user":{"name":"Alice","address":{"city":"Seoul","zip":"12345"}},"active":true}'`],result:JSON.stringify({"user.name":"Alice","user.address.city":"Seoul","user.address.zip":"12345",active:!0},null,2)},{args:[`'{"a":{"b":{"c":{"d":{"e":"deep"}}}}}'`],result:JSON.stringify({"a.b.c.d.e":"deep"},null,2)}],guidelines:["Arrays and primitives at any level are always treated as leaf values \u2014 they are never traversed.","The result is always a flat JSON object with dot-notation keys.","There is no depth limit \u2014 objects of any nesting level are fully flattened."]}},d=u.objectFlattenTool;var te={...a,...u};var v=m({name:"mono-rele2-utils",version:"1.0.0"},[l,c,p,d]);g(v).catch(e=>{console.error("[utils] server error:",e),process.exit(1)});
@@ -38,6 +38,14 @@ Truncates text to a maximum length and appends a suffix
38
38
  | `maxLength` | Maximum character length |
39
39
  | `suffix` | Suffix to append when truncated — default: `...` |
40
40
 
41
+ ### objectFlattenTool
42
+
43
+ Flattens a nested JSON object of any depth into dot-notation key-value pairs. Accepts a JSON string and recursively flattens all levels. Arrays and primitives at any level are treated as leaf values.
44
+
45
+ | arg | description |
46
+ |-----|-------------|
47
+ | `json` | JSON string of a nested object to flatten (unlimited depth) |
48
+
41
49
  ## Examples
42
50
 
43
51
  - `mono-rele2-utils-cli cnTool '["btn","active","large"]'` => `btn active large`
@@ -46,6 +54,15 @@ Truncates text to a maximum length and appends a suffix
46
54
  - `mono-rele2-utils-cli caseConvertTool "hello world" kebab` => `hello-world`
47
55
  - `mono-rele2-utils-cli truncateTool "hello world long text" 10` => `hello w...`
48
56
  - `mono-rele2-utils-cli truncateTool "hello world" 8 "…"` => `hello w…`
57
+ - `mono-rele2-utils-cli objectFlattenTool '{"user":{"name":"Alice","address":{"city":"Seoul","zip":"12345"}},"active":true}'` => `{
58
+ "user.name": "Alice",
59
+ "user.address.city": "Seoul",
60
+ "user.address.zip": "12345",
61
+ "active": true
62
+ }`
63
+ - `mono-rele2-utils-cli objectFlattenTool '{"a":{"b":{"c":{"d":{"e":"deep"}}}}}'` => `{
64
+ "a.b.c.d.e": "deep"
65
+ }`
49
66
 
50
67
  ## Guidelines
51
68
 
@@ -53,4 +70,7 @@ Truncates text to a maximum length and appends a suffix
53
70
  - Numeric args are auto-parsed — pass as plain numbers (e.g. `10`)
54
71
  - Array args must be valid JSON — wrap in single quotes on Unix shells (e.g. `'["a","b"]'`)
55
72
  - Optional args with defaults may be omitted
73
+ - Arrays and primitives at any level are always treated as leaf values — they are never traversed.
74
+ - The result is always a flat JSON object with dot-notation keys.
75
+ - There is no depth limit — objects of any nesting level are fully flattened.
56
76
  - Run `mono-rele2-utils-cli` with no args to list all available skills
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@julong/mono-rele2-utils",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
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.",
5
5
  "license": "ISC",
6
6
  "type": "module",