@getkrafter/resume-toolkit 1.0.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/dist/bin/cli.d.ts +3 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +4 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/krafter/client.d.ts +54 -0
  8. package/dist/krafter/client.d.ts.map +1 -0
  9. package/dist/krafter/client.js +130 -0
  10. package/dist/krafter/client.js.map +1 -0
  11. package/dist/krafter/errors.d.ts +26 -0
  12. package/dist/krafter/errors.d.ts.map +1 -0
  13. package/dist/krafter/errors.js +45 -0
  14. package/dist/krafter/errors.js.map +1 -0
  15. package/dist/lib/ats-scorer.d.ts +12 -0
  16. package/dist/lib/ats-scorer.d.ts.map +1 -0
  17. package/dist/lib/ats-scorer.js +83 -0
  18. package/dist/lib/ats-scorer.js.map +1 -0
  19. package/dist/lib/index.d.ts +6 -0
  20. package/dist/lib/index.d.ts.map +1 -0
  21. package/dist/lib/index.js +8 -0
  22. package/dist/lib/index.js.map +1 -0
  23. package/dist/lib/resume-scorer.d.ts +62 -0
  24. package/dist/lib/resume-scorer.d.ts.map +1 -0
  25. package/dist/lib/resume-scorer.js +236 -0
  26. package/dist/lib/resume-scorer.js.map +1 -0
  27. package/dist/lib/resume-transformer.d.ts +13 -0
  28. package/dist/lib/resume-transformer.d.ts.map +1 -0
  29. package/dist/lib/resume-transformer.js +113 -0
  30. package/dist/lib/resume-transformer.js.map +1 -0
  31. package/dist/lib/text-utils.d.ts +57 -0
  32. package/dist/lib/text-utils.d.ts.map +1 -0
  33. package/dist/lib/text-utils.js +282 -0
  34. package/dist/lib/text-utils.js.map +1 -0
  35. package/dist/lib/types.d.ts +31 -0
  36. package/dist/lib/types.d.ts.map +1 -0
  37. package/dist/lib/types.js +2 -0
  38. package/dist/lib/types.js.map +1 -0
  39. package/dist/mcp/server.d.ts +31 -0
  40. package/dist/mcp/server.d.ts.map +1 -0
  41. package/dist/mcp/server.js +70 -0
  42. package/dist/mcp/server.js.map +1 -0
  43. package/dist/mcp/tools/krafter.d.ts +14 -0
  44. package/dist/mcp/tools/krafter.d.ts.map +1 -0
  45. package/dist/mcp/tools/krafter.js +228 -0
  46. package/dist/mcp/tools/krafter.js.map +1 -0
  47. package/dist/mcp/tools/scoring.d.ts +46 -0
  48. package/dist/mcp/tools/scoring.d.ts.map +1 -0
  49. package/dist/mcp/tools/scoring.js +135 -0
  50. package/dist/mcp/tools/scoring.js.map +1 -0
  51. package/package.json +67 -0
  52. package/skills/score/SKILL.md +185 -0
  53. package/skills/tailor/SKILL.md +211 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * MCP tool handlers for Krafter resume CRUD and scoring.
3
+ *
4
+ * Defines 11 tools that wrap {@link KrafterClient} methods with MCP-formatted
5
+ * error handling. The `score_krafter_resume` tool chains three operations:
6
+ * fetch resume -> transform to ResumeData -> score.
7
+ *
8
+ * All tools return standard MCP {@link CallToolResult} objects. On error,
9
+ * the result includes `isError: true` with the error message as text content.
10
+ */
11
+ import { z } from 'zod';
12
+ import { KrafterError } from '../../krafter/errors.js';
13
+ import { toResumeData } from '../../lib/resume-transformer.js';
14
+ import { scoreResume } from '../../lib/resume-scorer.js';
15
+ // ---------------------------------------------------------------------------
16
+ // Error handling
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Wrap a handler function with MCP-compatible error handling.
20
+ *
21
+ * If the handler throws a {@link KrafterError} (or subclass), the error
22
+ * message is returned as an MCP error result (`isError: true`). Unexpected
23
+ * errors are caught the same way so the MCP transport never sees a raw
24
+ * exception.
25
+ */
26
+ function withErrorHandling(fn) {
27
+ return async (args) => {
28
+ try {
29
+ return await fn(args);
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof KrafterError
33
+ ? error.message
34
+ : error instanceof Error
35
+ ? error.message
36
+ : 'An unexpected error occurred.';
37
+ return {
38
+ content: [{ type: 'text', text: message }],
39
+ isError: true,
40
+ };
41
+ }
42
+ };
43
+ }
44
+ /**
45
+ * Build a standard success result wrapping the given data as JSON text.
46
+ */
47
+ function ok(data) {
48
+ return {
49
+ content: [{ type: 'text', text: JSON.stringify(data) }],
50
+ };
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Tool descriptions
54
+ // ---------------------------------------------------------------------------
55
+ const DESCRIPTIONS = {
56
+ get_resume: 'Fetch a single Krafter resume by ID. Returns the full resume object as JSON.',
57
+ list_resumes: 'List all resumes for the authenticated Krafter user.',
58
+ create_resume: 'Create a new resume in Krafter. Accepts a data object with resume fields.',
59
+ update_resume: 'Update an existing Krafter resume. Accepts the resume ID and a data object with fields to update.',
60
+ delete_resume: 'Delete a Krafter resume by ID.',
61
+ duplicate_resume: 'Duplicate an existing Krafter resume. Returns the new resume.',
62
+ update_settings: 'Update resume settings (template, colors, font, etc.). Accepts resume ID and a settings object.',
63
+ update_section: 'Update a specific resume section (experience, education, skills, etc.). Accepts resume ID, section type, and items array.',
64
+ list_templates: 'List all available Krafter resume templates.',
65
+ get_resume_schema: 'Fetch the Krafter resume JSON schema. Useful for understanding the resume data structure.',
66
+ score_krafter_resume: 'Score a Krafter resume for quality across 5 dimensions (0-100). Fetches the resume by ID, ' +
67
+ 'converts it to scoring format, and runs the deterministic scorer. Optionally accepts a job ' +
68
+ 'description for ATS keyword matching. Returns total score, mode, breakdown per dimension, and diagnostic flags.',
69
+ };
70
+ // ---------------------------------------------------------------------------
71
+ // Public API
72
+ // ---------------------------------------------------------------------------
73
+ /**
74
+ * Build and return the array of Krafter tool descriptors.
75
+ *
76
+ * Each tool wraps a {@link KrafterClient} method with MCP-formatted
77
+ * error handling. The tools use the same {@link ScoringTool} interface
78
+ * as the scoring tools so they can be registered uniformly.
79
+ *
80
+ * @param client - A configured {@link KrafterClient} instance.
81
+ * @returns An array of tool descriptors ready for MCP server registration.
82
+ */
83
+ export function getKrafterTools(client) {
84
+ return [
85
+ // -----------------------------------------------------------------
86
+ // get_resume
87
+ // -----------------------------------------------------------------
88
+ {
89
+ name: 'get_resume',
90
+ description: DESCRIPTIONS.get_resume,
91
+ inputSchema: z.object({ id: z.string() }),
92
+ handler: withErrorHandling(async (args) => {
93
+ const resume = await client.getResume(args.id);
94
+ return ok(resume);
95
+ }),
96
+ },
97
+ // -----------------------------------------------------------------
98
+ // list_resumes
99
+ // -----------------------------------------------------------------
100
+ {
101
+ name: 'list_resumes',
102
+ description: DESCRIPTIONS.list_resumes,
103
+ inputSchema: z.object({}),
104
+ handler: withErrorHandling(async () => {
105
+ const resumes = await client.listResumes();
106
+ return ok(resumes);
107
+ }),
108
+ },
109
+ // -----------------------------------------------------------------
110
+ // create_resume
111
+ // -----------------------------------------------------------------
112
+ {
113
+ name: 'create_resume',
114
+ description: DESCRIPTIONS.create_resume,
115
+ inputSchema: z.object({ data: z.record(z.unknown()) }),
116
+ handler: withErrorHandling(async (args) => {
117
+ const result = await client.createResume(args.data);
118
+ return ok(result);
119
+ }),
120
+ },
121
+ // -----------------------------------------------------------------
122
+ // update_resume
123
+ // -----------------------------------------------------------------
124
+ {
125
+ name: 'update_resume',
126
+ description: DESCRIPTIONS.update_resume,
127
+ inputSchema: z.object({ id: z.string(), data: z.record(z.unknown()) }),
128
+ handler: withErrorHandling(async (args) => {
129
+ const result = await client.updateResume(args.id, args.data);
130
+ return ok(result);
131
+ }),
132
+ },
133
+ // -----------------------------------------------------------------
134
+ // delete_resume
135
+ // -----------------------------------------------------------------
136
+ {
137
+ name: 'delete_resume',
138
+ description: DESCRIPTIONS.delete_resume,
139
+ inputSchema: z.object({ id: z.string() }),
140
+ handler: withErrorHandling(async (args) => {
141
+ const result = await client.deleteResume(args.id);
142
+ return ok(result);
143
+ }),
144
+ },
145
+ // -----------------------------------------------------------------
146
+ // duplicate_resume
147
+ // -----------------------------------------------------------------
148
+ {
149
+ name: 'duplicate_resume',
150
+ description: DESCRIPTIONS.duplicate_resume,
151
+ inputSchema: z.object({ id: z.string() }),
152
+ handler: withErrorHandling(async (args) => {
153
+ const result = await client.duplicateResume(args.id);
154
+ return ok(result);
155
+ }),
156
+ },
157
+ // -----------------------------------------------------------------
158
+ // update_settings
159
+ // -----------------------------------------------------------------
160
+ {
161
+ name: 'update_settings',
162
+ description: DESCRIPTIONS.update_settings,
163
+ inputSchema: z.object({ id: z.string(), settings: z.record(z.unknown()) }),
164
+ handler: withErrorHandling(async (args) => {
165
+ const result = await client.updateSettings(args.id, args.settings);
166
+ return ok(result);
167
+ }),
168
+ },
169
+ // -----------------------------------------------------------------
170
+ // update_section
171
+ // -----------------------------------------------------------------
172
+ {
173
+ name: 'update_section',
174
+ description: DESCRIPTIONS.update_section,
175
+ inputSchema: z.object({
176
+ id: z.string(),
177
+ type: z.string(),
178
+ items: z.array(z.unknown()),
179
+ }),
180
+ handler: withErrorHandling(async (args) => {
181
+ const result = await client.updateSection(args.id, args.type, args.items);
182
+ return ok(result);
183
+ }),
184
+ },
185
+ // -----------------------------------------------------------------
186
+ // list_templates
187
+ // -----------------------------------------------------------------
188
+ {
189
+ name: 'list_templates',
190
+ description: DESCRIPTIONS.list_templates,
191
+ inputSchema: z.object({}),
192
+ handler: withErrorHandling(async () => {
193
+ const templates = await client.listTemplates();
194
+ return ok(templates);
195
+ }),
196
+ },
197
+ // -----------------------------------------------------------------
198
+ // get_resume_schema
199
+ // -----------------------------------------------------------------
200
+ {
201
+ name: 'get_resume_schema',
202
+ description: DESCRIPTIONS.get_resume_schema,
203
+ inputSchema: z.object({}),
204
+ handler: withErrorHandling(async () => {
205
+ const schema = await client.getResumeSchema();
206
+ return ok(schema);
207
+ }),
208
+ },
209
+ // -----------------------------------------------------------------
210
+ // score_krafter_resume
211
+ // -----------------------------------------------------------------
212
+ {
213
+ name: 'score_krafter_resume',
214
+ description: DESCRIPTIONS.score_krafter_resume,
215
+ inputSchema: z.object({
216
+ id: z.string(),
217
+ jdText: z.string().optional(),
218
+ }),
219
+ handler: withErrorHandling(async (args) => {
220
+ const resume = await client.getResume(args.id);
221
+ const resumeData = toResumeData(resume);
222
+ const score = scoreResume(resumeData, args.jdText);
223
+ return ok(score);
224
+ }),
225
+ },
226
+ ];
227
+ }
228
+ //# sourceMappingURL=krafter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"krafter.js","sourceRoot":"","sources":["../../../src/mcp/tools/krafter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * MCP tool handlers for resume scoring.
3
+ *
4
+ * Defines two tools:
5
+ * - score_resume: Full multi-dimensional resume quality score (0-100)
6
+ * - score_ats: Focused ATS keyword-match score against a job description
7
+ *
8
+ * Each tool accepts raw text input, parses it into the internal ResumeData
9
+ * format, and delegates to the deterministic scoring engine.
10
+ */
11
+ import { z } from 'zod';
12
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
13
+ import type { ResumeData } from '../../lib/types.js';
14
+ /**
15
+ * Descriptor for a scoring tool: its name, description, Zod input schema,
16
+ * and async handler function that returns a standard MCP CallToolResult.
17
+ */
18
+ export interface ScoringTool {
19
+ name: string;
20
+ description: string;
21
+ inputSchema: z.ZodObject<any>;
22
+ handler: (args: any) => Promise<CallToolResult>;
23
+ }
24
+ /**
25
+ * Parse raw pasted resume text into the internal {@link ResumeData} format.
26
+ *
27
+ * Detection strategy:
28
+ * 1. Split into lines.
29
+ * 2. Lines matching {@link BULLET_RE} are extracted as bullets (marker stripped).
30
+ * 3. Short, non-bullet lines that are ALL CAPS or Title Case are treated as
31
+ * section headings.
32
+ * 4. Lines that are neither bullets nor headings are ignored (they may be
33
+ * paragraph text, contact info, etc.).
34
+ *
35
+ * @param text - Raw resume text, typically pasted by the user.
36
+ * @returns A {@link ResumeData} object with rawText, bullets, and sections.
37
+ */
38
+ export declare function parseRawText(text: string): ResumeData;
39
+ /**
40
+ * Build and return the array of scoring tool descriptors.
41
+ *
42
+ * Each tool's handler accepts parsed arguments and returns a standard
43
+ * MCP result with a single text content block containing JSON.
44
+ */
45
+ export declare function getScoringTools(): ScoringTool[];
46
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQrD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CACjD;AA6BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAwBrD;AAiBD;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,WAAW,EAAE,CAuD/C"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * MCP tool handlers for resume scoring.
3
+ *
4
+ * Defines two tools:
5
+ * - score_resume: Full multi-dimensional resume quality score (0-100)
6
+ * - score_ats: Focused ATS keyword-match score against a job description
7
+ *
8
+ * Each tool accepts raw text input, parses it into the internal ResumeData
9
+ * format, and delegates to the deterministic scoring engine.
10
+ */
11
+ import { z } from 'zod';
12
+ import { scoreResume } from '../../lib/resume-scorer.js';
13
+ import { scoreATS } from '../../lib/ats-scorer.js';
14
+ // ---------------------------------------------------------------------------
15
+ // Bullet / section detection patterns
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Matches lines that start with common bullet markers:
19
+ * - dash (-)
20
+ * - bullet character (bullet)
21
+ * - asterisk (*)
22
+ * - numbered list (1., 2., etc.)
23
+ *
24
+ * Allows optional leading whitespace.
25
+ */
26
+ const BULLET_RE = /^\s*(?:[-\u2022*]|\d+[.)]\s)/;
27
+ /**
28
+ * Matches lines that look like section headings:
29
+ * - ALL CAPS words (2+ chars, possibly with spaces)
30
+ * - Title Case lines that are short (under 50 chars) and not bullet-like
31
+ */
32
+ const HEADING_ALLCAPS_RE = /^[A-Z][A-Z &/]+$/;
33
+ const HEADING_TITLECASE_RE = /^[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*$/;
34
+ // ---------------------------------------------------------------------------
35
+ // parseRawText
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Parse raw pasted resume text into the internal {@link ResumeData} format.
39
+ *
40
+ * Detection strategy:
41
+ * 1. Split into lines.
42
+ * 2. Lines matching {@link BULLET_RE} are extracted as bullets (marker stripped).
43
+ * 3. Short, non-bullet lines that are ALL CAPS or Title Case are treated as
44
+ * section headings.
45
+ * 4. Lines that are neither bullets nor headings are ignored (they may be
46
+ * paragraph text, contact info, etc.).
47
+ *
48
+ * @param text - Raw resume text, typically pasted by the user.
49
+ * @returns A {@link ResumeData} object with rawText, bullets, and sections.
50
+ */
51
+ export function parseRawText(text) {
52
+ const lines = text.split('\n');
53
+ const bullets = [];
54
+ const sections = [];
55
+ for (const line of lines) {
56
+ const trimmed = line.trim();
57
+ if (!trimmed)
58
+ continue;
59
+ if (BULLET_RE.test(trimmed)) {
60
+ // Strip the bullet marker to get the pure bullet text
61
+ const bulletText = trimmed.replace(/^\s*(?:[-\u2022*]|\d+[.)]\s?)\s*/, '').trim();
62
+ if (bulletText) {
63
+ bullets.push(bulletText);
64
+ }
65
+ }
66
+ else if (trimmed.length < 50 &&
67
+ (HEADING_ALLCAPS_RE.test(trimmed) || HEADING_TITLECASE_RE.test(trimmed))) {
68
+ sections.push(trimmed);
69
+ }
70
+ }
71
+ return { rawText: text, bullets, sections };
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // Tool definitions
75
+ // ---------------------------------------------------------------------------
76
+ const SCORE_RESUME_DESCRIPTION = 'Score a resume for quality across 5 dimensions (0-100). Deterministic — same input always produces the same score. ' +
77
+ 'The result includes: total score, mode (with-jd or without-jd), breakdown per dimension ' +
78
+ '(quantification, verb strength, ATS match, bullet structure, section completeness), and diagnostic flags. ' +
79
+ 'Your role: explain what each dimension means for THIS resume, give specific actionable suggestions for low-scoring dimensions, ' +
80
+ 'highlight top 5 missing keywords if ATS match is low, and frame the score constructively.';
81
+ const SCORE_ATS_DESCRIPTION = 'Score resume-to-job-description keyword match (0-100). Returns matched keywords, missing keywords, ' +
82
+ 'and bigram/unigram breakdown. Use this for focused ATS analysis without the full resume quality score.';
83
+ /**
84
+ * Build and return the array of scoring tool descriptors.
85
+ *
86
+ * Each tool's handler accepts parsed arguments and returns a standard
87
+ * MCP result with a single text content block containing JSON.
88
+ */
89
+ export function getScoringTools() {
90
+ // -----------------------------------------------------------------------
91
+ // Tool 1: score_resume
92
+ // -----------------------------------------------------------------------
93
+ const scoreResumeSchema = z.object({
94
+ resumeText: z.string(),
95
+ jdText: z.string().optional(),
96
+ });
97
+ const scoreResumeHandler = async (args) => {
98
+ const resumeData = parseRawText(args.resumeText);
99
+ const result = scoreResume(resumeData, args.jdText);
100
+ return {
101
+ content: [{ type: 'text', text: JSON.stringify(result) }],
102
+ };
103
+ };
104
+ // -----------------------------------------------------------------------
105
+ // Tool 2: score_ats
106
+ // -----------------------------------------------------------------------
107
+ const scoreAtsSchema = z.object({
108
+ resumeText: z.string(),
109
+ jdText: z.string(),
110
+ });
111
+ const scoreAtsHandler = async (args) => {
112
+ const result = scoreATS(args.resumeText, args.jdText);
113
+ return {
114
+ content: [{ type: 'text', text: JSON.stringify(result) }],
115
+ };
116
+ };
117
+ // -----------------------------------------------------------------------
118
+ // Return tool array
119
+ // -----------------------------------------------------------------------
120
+ return [
121
+ {
122
+ name: 'score_resume',
123
+ description: SCORE_RESUME_DESCRIPTION,
124
+ inputSchema: scoreResumeSchema,
125
+ handler: scoreResumeHandler,
126
+ },
127
+ {
128
+ name: 'score_ats',
129
+ description: SCORE_ATS_DESCRIPTION,
130
+ inputSchema: scoreAtsSchema,
131
+ handler: scoreAtsHandler,
132
+ },
133
+ ];
134
+ }
135
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../../src/mcp/tools/scoring.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@getkrafter/resume-toolkit",
3
+ "version": "1.0.1",
4
+ "description": "Deterministic resume scoring, ATS keyword matching, and AI-powered resume tailoring",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/lib/index.js",
9
+ "types": "./dist/lib/index.d.ts"
10
+ }
11
+ },
12
+ "bin": {
13
+ "resume-toolkit": "dist/bin/cli.js"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "skills",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "lint": "tsc --noEmit",
29
+ "prepare": "husky"
30
+ },
31
+ "keywords": [
32
+ "resume",
33
+ "ats",
34
+ "scoring",
35
+ "mcp",
36
+ "ai",
37
+ "skills",
38
+ "tailoring"
39
+ ],
40
+ "author": "Muhammad Kasim",
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/getkrafter/resume-toolkit.git"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "dependencies": {
50
+ "@modelcontextprotocol/sdk": "^1.0.0",
51
+ "natural": "^8.0.0",
52
+ "zod": "^3.23.0"
53
+ },
54
+ "devDependencies": {
55
+ "@commitlint/cli": "^19.0.0",
56
+ "@commitlint/config-conventional": "^19.0.0",
57
+ "@semantic-release/changelog": "^6.0.3",
58
+ "@semantic-release/git": "^10.0.1",
59
+ "@semantic-release/github": "^12.0.6",
60
+ "@semantic-release/npm": "^13.1.5",
61
+ "@semantic-release/release-notes-generator": "^14.1.0",
62
+ "husky": "^9.0.0",
63
+ "semantic-release": "^25.0.3",
64
+ "typescript": "^5.5.0",
65
+ "vitest": "^2.0.0"
66
+ }
67
+ }