@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Muhammad Kasim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @getkrafter/resume-toolkit
2
+
3
+ Deterministic resume scoring, ATS keyword matching, and AI-powered resume tailoring. Works as an MCP server, a scoring library, and AI skills for Claude Code, Cursor, and Windsurf.
4
+
5
+ **Same input always produces the same score.** The AI handles parsing and explanation — the scoring is pure math.
6
+
7
+ ## Quick Start — Skills (no account needed)
8
+
9
+ ### Claude Code
10
+
11
+ ```bash
12
+ /install-skill @getkrafter/resume-toolkit
13
+ ```
14
+
15
+ Then use `/score` or `/tailor` in any conversation.
16
+
17
+ ### Cursor
18
+
19
+ Add to Settings → Remote Rule:
20
+
21
+ ```
22
+ https://github.com/getkrafter/resume-toolkit/blob/master/skills/score/SKILL.md
23
+ https://github.com/getkrafter/resume-toolkit/blob/master/skills/tailor/SKILL.md
24
+ ```
25
+
26
+ Or copy the `skills/` directory to `.cursor/skills/` in your project.
27
+
28
+ ### Windsurf
29
+
30
+ Copy the `skills/` directory to `.windsurf/skills/` or `.agents/skills/` in your project.
31
+
32
+ ## Quick Start — MCP Server
33
+
34
+ ### Without API key (scoring tools only)
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "krafter": {
40
+ "command": "npx",
41
+ "args": ["@getkrafter/resume-toolkit"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### With API key (scoring + Krafter CRUD)
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "krafter": {
53
+ "command": "npx",
54
+ "args": ["@getkrafter/resume-toolkit"],
55
+ "env": {
56
+ "KRAFTER_API_KEY": "sk-your-key-here"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ Generate an API key at [krafter.app](https://krafter.app) → Settings → AI Integrations.
64
+
65
+ ## Library Usage
66
+
67
+ ```bash
68
+ npm install @getkrafter/resume-toolkit
69
+ ```
70
+
71
+ ```typescript
72
+ import { scoreResume, scoreATS, toResumeData } from '@getkrafter/resume-toolkit';
73
+
74
+ // Score a resume
75
+ const result = scoreResume(
76
+ { rawText: '...', bullets: ['...'], sections: ['experience', 'skills'] },
77
+ 'Job description text...' // optional
78
+ );
79
+
80
+ console.log(result.total); // 0-100
81
+ console.log(result.mode); // 'with-jd' or 'without-jd'
82
+ console.log(result.breakdown); // per-dimension scores
83
+ console.log(result.flags); // diagnostic messages
84
+
85
+ // ATS keyword match only
86
+ const ats = scoreATS(resumeText, jdText);
87
+ console.log(ats?.matched); // keywords found
88
+ console.log(ats?.missing); // keywords missing
89
+
90
+ // Convert Krafter resume object to scoreable format
91
+ const resumeData = toResumeData(krafterResumeObject);
92
+ ```
93
+
94
+ ## MCP Tools
95
+
96
+ ### Public (no auth)
97
+
98
+ | Tool | Description |
99
+ |---|---|
100
+ | `score_resume` | Full quality score (0-100) across 5 dimensions with breakdown and flags |
101
+ | `score_ats` | ATS keyword match with bigram/unigram analysis |
102
+
103
+ ### Krafter (API key required)
104
+
105
+ | Tool | Description |
106
+ |---|---|
107
+ | `score_krafter_resume` | Fetch resume from Krafter → score in one call |
108
+ | `get_resume` | Fetch a resume by ID |
109
+ | `list_resumes` | List all your resumes |
110
+ | `create_resume` | Create a new resume |
111
+ | `update_resume` | Update an existing resume |
112
+ | `delete_resume` | Delete a resume |
113
+ | `duplicate_resume` | Clone a resume |
114
+ | `update_settings` | Update visual settings |
115
+ | `update_section` | Update a specific section |
116
+ | `list_templates` | List available templates |
117
+ | `get_resume_schema` | Get the resume data schema |
118
+
119
+ ## Skills
120
+
121
+ | Skill | Description |
122
+ |---|---|
123
+ | `/score` | Guided resume scoring — paste or provide a resume, optionally add a JD, get a detailed score breakdown with actionable advice |
124
+ | `/tailor` | Gap analysis against a JD — identifies missing keywords, suggests truth-preserving rewrites with before/after format |
125
+
126
+ ## Scoring Dimensions
127
+
128
+ | Dimension | Weight (with JD) | What it measures |
129
+ |---|---|---|
130
+ | Quantification | 25% | Fraction of bullets with numbers/metrics |
131
+ | Verb Strength | 20% | Quality of action verbs (tier1 > tier2 > tier3) |
132
+ | ATS Match | 30% | Keyword overlap with job description |
133
+ | Bullet Structure | 15% | Verb + number + detail pattern |
134
+ | Section Completeness | 10% | Presence of expected resume sections |
135
+
136
+ When no JD is provided, the 30% ATS weight redistributes proportionally across the other dimensions.
137
+
138
+ ## Contributing
139
+
140
+ ```bash
141
+ git clone https://github.com/getkrafter/resume-toolkit.git
142
+ cd resume-toolkit
143
+ npm install
144
+ npm test # run tests
145
+ npm run build # compile TypeScript
146
+ ```
147
+
148
+ Commits follow [Conventional Commits](https://www.conventionalcommits.org/):
149
+ - `feat: ...` → minor version bump
150
+ - `fix: ...` → patch version bump
151
+ - `feat!: ...` → major version bump
152
+
153
+ ## License
154
+
155
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { startServer } from '../mcp/server.js';
3
+ startServer();
4
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,WAAW,EAAE,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Thin HTTP client wrapping Krafter's `/api/mcp` tool-call endpoint.
3
+ *
4
+ * Every public method delegates to {@link callTool} which handles
5
+ * authentication, timeout, and error mapping so callers get
6
+ * strongly-typed errors they can pattern-match on.
7
+ */
8
+ export declare class KrafterClient {
9
+ private apiKey;
10
+ private baseUrl;
11
+ private schemaCache;
12
+ constructor(apiKey: string, baseUrl?: string);
13
+ /** Fetch a single resume by id. */
14
+ getResume(id: string): Promise<unknown>;
15
+ /** List all resumes for the authenticated user. */
16
+ listResumes(): Promise<unknown>;
17
+ /** Create a new resume. */
18
+ createResume(data: unknown): Promise<unknown>;
19
+ /** Update an existing resume. */
20
+ updateResume(id: string, data: unknown): Promise<unknown>;
21
+ /** Delete a resume. */
22
+ deleteResume(id: string): Promise<unknown>;
23
+ /** Duplicate a resume. */
24
+ duplicateResume(id: string): Promise<unknown>;
25
+ /** Update resume settings (template, colors, etc.). */
26
+ updateSettings(id: string, settings: unknown): Promise<unknown>;
27
+ /** Update a specific resume section (experience, education, etc.). */
28
+ updateSection(id: string, type: string, items: unknown[]): Promise<unknown>;
29
+ /** List available templates. */
30
+ listTemplates(): Promise<unknown>;
31
+ /**
32
+ * Fetch the resume JSON schema.
33
+ *
34
+ * The schema is cached after the first successful call because it
35
+ * doesn't change during a client's lifetime.
36
+ */
37
+ getResumeSchema(): Promise<unknown>;
38
+ /**
39
+ * Execute a single tool call against the Krafter MCP endpoint.
40
+ *
41
+ * Handles:
42
+ * - Bearer authentication
43
+ * - 10-second timeout via AbortSignal
44
+ * - HTTP status → typed error mapping
45
+ * - Network / timeout errors → KrafterNetworkError
46
+ */
47
+ private callTool;
48
+ /**
49
+ * Map an HTTP error status code to the appropriate typed error.
50
+ * Always throws — the return type is `never`.
51
+ */
52
+ private throwForStatus;
53
+ }
54
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/krafter/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAwB;gBAE/B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAS5C,mCAAmC;IAC7B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7C,mDAAmD;IAC7C,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC,2BAA2B;IACrB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAInD,iCAAiC;IAC3B,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAI/D,uBAAuB;IACjB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhD,0BAA0B;IACpB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAInD,uDAAuD;IACjD,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrE,sEAAsE;IAChE,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EAAE,GACf,OAAO,CAAC,OAAO,CAAC;IAInB,gCAAgC;IAC1B,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAIvC;;;;;OAKG;IACG,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAczC;;;;;;;;OAQG;YACW,QAAQ;IA8BtB;;;OAGG;IACH,OAAO,CAAC,cAAc;CAiBvB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Thin HTTP client wrapping Krafter's `/api/mcp` tool-call endpoint.
3
+ *
4
+ * Every public method delegates to {@link callTool} which handles
5
+ * authentication, timeout, and error mapping so callers get
6
+ * strongly-typed errors they can pattern-match on.
7
+ */
8
+ import { KrafterAuthError, KrafterNetworkError, KrafterNotFoundError, KrafterRateLimitError, KrafterServerError, } from './errors.js';
9
+ /** Default request timeout in milliseconds. */
10
+ const REQUEST_TIMEOUT_MS = 10_000;
11
+ export class KrafterClient {
12
+ apiKey;
13
+ baseUrl;
14
+ schemaCache = null;
15
+ constructor(apiKey, baseUrl) {
16
+ this.apiKey = apiKey;
17
+ this.baseUrl = baseUrl ?? 'https://krafter.app';
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Public API
21
+ // ---------------------------------------------------------------------------
22
+ /** Fetch a single resume by id. */
23
+ async getResume(id) {
24
+ return this.callTool('get_resume', { id });
25
+ }
26
+ /** List all resumes for the authenticated user. */
27
+ async listResumes() {
28
+ return this.callTool('list_resumes', {});
29
+ }
30
+ /** Create a new resume. */
31
+ async createResume(data) {
32
+ return this.callTool('create_resume', { data });
33
+ }
34
+ /** Update an existing resume. */
35
+ async updateResume(id, data) {
36
+ return this.callTool('update_resume', { id, data });
37
+ }
38
+ /** Delete a resume. */
39
+ async deleteResume(id) {
40
+ return this.callTool('delete_resume', { id });
41
+ }
42
+ /** Duplicate a resume. */
43
+ async duplicateResume(id) {
44
+ return this.callTool('duplicate_resume', { id });
45
+ }
46
+ /** Update resume settings (template, colors, etc.). */
47
+ async updateSettings(id, settings) {
48
+ return this.callTool('update_settings', { id, settings });
49
+ }
50
+ /** Update a specific resume section (experience, education, etc.). */
51
+ async updateSection(id, type, items) {
52
+ return this.callTool('update_section', { id, type, items });
53
+ }
54
+ /** List available templates. */
55
+ async listTemplates() {
56
+ return this.callTool('list_templates', {});
57
+ }
58
+ /**
59
+ * Fetch the resume JSON schema.
60
+ *
61
+ * The schema is cached after the first successful call because it
62
+ * doesn't change during a client's lifetime.
63
+ */
64
+ async getResumeSchema() {
65
+ if (this.schemaCache !== null) {
66
+ return this.schemaCache;
67
+ }
68
+ const schema = await this.callTool('get_resume_schema', {});
69
+ this.schemaCache = schema;
70
+ return schema;
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Internals
74
+ // ---------------------------------------------------------------------------
75
+ /**
76
+ * Execute a single tool call against the Krafter MCP endpoint.
77
+ *
78
+ * Handles:
79
+ * - Bearer authentication
80
+ * - 10-second timeout via AbortSignal
81
+ * - HTTP status → typed error mapping
82
+ * - Network / timeout errors → KrafterNetworkError
83
+ */
84
+ async callTool(tool, args) {
85
+ const url = `${this.baseUrl}/api/mcp`;
86
+ let response;
87
+ try {
88
+ response = await fetch(url, {
89
+ method: 'POST',
90
+ headers: {
91
+ Authorization: `Bearer ${this.apiKey}`,
92
+ 'Content-Type': 'application/json',
93
+ },
94
+ body: JSON.stringify({ tool, args }),
95
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
96
+ });
97
+ }
98
+ catch {
99
+ // Network failures and AbortError (timeout) both land here.
100
+ throw new KrafterNetworkError();
101
+ }
102
+ if (!response.ok) {
103
+ this.throwForStatus(response.status);
104
+ }
105
+ const json = (await response.json());
106
+ return json.result;
107
+ }
108
+ /**
109
+ * Map an HTTP error status code to the appropriate typed error.
110
+ * Always throws — the return type is `never`.
111
+ */
112
+ throwForStatus(status) {
113
+ switch (status) {
114
+ case 401:
115
+ throw new KrafterAuthError();
116
+ case 404:
117
+ throw new KrafterNotFoundError();
118
+ case 429:
119
+ throw new KrafterRateLimitError();
120
+ default:
121
+ // Treat any 5xx (or unexpected status) as a server error.
122
+ if (status >= 500) {
123
+ throw new KrafterServerError();
124
+ }
125
+ // Fallback for unexpected 4xx codes we don't have a class for.
126
+ throw new KrafterServerError();
127
+ }
128
+ }
129
+ }
130
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/krafter/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Typed error classes for the Krafter HTTP client.
3
+ *
4
+ * Each error maps to a specific HTTP failure mode so callers can
5
+ * pattern-match on the class (instanceof) or inspect `statusCode`.
6
+ */
7
+ export declare class KrafterError extends Error {
8
+ statusCode?: number | undefined;
9
+ constructor(message: string, statusCode?: number | undefined);
10
+ }
11
+ export declare class KrafterAuthError extends KrafterError {
12
+ constructor();
13
+ }
14
+ export declare class KrafterNotFoundError extends KrafterError {
15
+ constructor();
16
+ }
17
+ export declare class KrafterServerError extends KrafterError {
18
+ constructor();
19
+ }
20
+ export declare class KrafterRateLimitError extends KrafterError {
21
+ constructor();
22
+ }
23
+ export declare class KrafterNetworkError extends KrafterError {
24
+ constructor();
25
+ }
26
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/krafter/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,YAAa,SAAQ,KAAK;IAG5B,UAAU,CAAC,EAAE,MAAM;gBAD1B,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B;AAED,qBAAa,gBAAiB,SAAQ,YAAY;;CAQjD;AAED,qBAAa,oBAAqB,SAAQ,YAAY;;CAKrD;AAED,qBAAa,kBAAmB,SAAQ,YAAY;;CAKnD;AAED,qBAAa,qBAAsB,SAAQ,YAAY;;CAKtD;AAED,qBAAa,mBAAoB,SAAQ,YAAY;;CAKpD"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Typed error classes for the Krafter HTTP client.
3
+ *
4
+ * Each error maps to a specific HTTP failure mode so callers can
5
+ * pattern-match on the class (instanceof) or inspect `statusCode`.
6
+ */
7
+ export class KrafterError extends Error {
8
+ statusCode;
9
+ constructor(message, statusCode) {
10
+ super(message);
11
+ this.statusCode = statusCode;
12
+ this.name = 'KrafterError';
13
+ }
14
+ }
15
+ export class KrafterAuthError extends KrafterError {
16
+ constructor() {
17
+ super('Invalid API key. Generate one at krafter.app → Settings → AI Integrations.', 401);
18
+ this.name = 'KrafterAuthError';
19
+ }
20
+ }
21
+ export class KrafterNotFoundError extends KrafterError {
22
+ constructor() {
23
+ super('Resume not found. It may have been deleted.', 404);
24
+ this.name = 'KrafterNotFoundError';
25
+ }
26
+ }
27
+ export class KrafterServerError extends KrafterError {
28
+ constructor() {
29
+ super('Krafter service error. Try again shortly.', 500);
30
+ this.name = 'KrafterServerError';
31
+ }
32
+ }
33
+ export class KrafterRateLimitError extends KrafterError {
34
+ constructor() {
35
+ super('Too many requests. Please wait a moment.', 429);
36
+ this.name = 'KrafterRateLimitError';
37
+ }
38
+ }
39
+ export class KrafterNetworkError extends KrafterError {
40
+ constructor() {
41
+ super('Unable to reach Krafter. Check your connection or try again.');
42
+ this.name = 'KrafterNetworkError';
43
+ }
44
+ }
45
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/krafter/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAG5B;IAFT,YACE,OAAe,EACR,UAAmB;QAE1B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,eAAU,GAAV,UAAU,CAAS;QAG1B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAChD;QACE,KAAK,CACH,4EAA4E,EAC5E,GAAG,CACJ,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD;QACE,KAAK,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAClD;QACE,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,YAAY;IACrD;QACE,KAAK,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnD;QACE,KAAK,CAAC,8DAA8D,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { ATSResult } from './types.js';
2
+ /**
3
+ * Score a resume against a job description for ATS keyword match.
4
+ *
5
+ * Uses bigram + stemmed unigram matching with weighted scoring:
6
+ * - Bigram match = 1.5 points
7
+ * - Unigram match = 1.0 point
8
+ *
9
+ * Returns null if jdText is falsy (no JD provided).
10
+ */
11
+ export declare function scoreATS(resumeText: string, jdText: string): ATSResult | null;
12
+ //# sourceMappingURL=ats-scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ats-scorer.d.ts","sourceRoot":"","sources":["../../src/lib/ats-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAiF7E"}
@@ -0,0 +1,83 @@
1
+ import { stem, extractTerms } from './text-utils.js';
2
+ /**
3
+ * Score a resume against a job description for ATS keyword match.
4
+ *
5
+ * Uses bigram + stemmed unigram matching with weighted scoring:
6
+ * - Bigram match = 1.5 points
7
+ * - Unigram match = 1.0 point
8
+ *
9
+ * Returns null if jdText is falsy (no JD provided).
10
+ */
11
+ export function scoreATS(resumeText, jdText) {
12
+ if (!jdText)
13
+ return null;
14
+ const resumeTerms = extractTerms(resumeText);
15
+ const jdTerms = extractTerms(jdText);
16
+ // Separate JD terms into bigrams and unigrams
17
+ const jdBigrams = [];
18
+ const jdUnigrams = [];
19
+ for (const term of jdTerms) {
20
+ if (term.includes(' ')) {
21
+ jdBigrams.push(term);
22
+ }
23
+ else {
24
+ jdUnigrams.push(term);
25
+ }
26
+ }
27
+ // Match bigrams
28
+ const bigramsMatched = [];
29
+ const bigramsMissing = [];
30
+ for (const bigram of jdBigrams) {
31
+ if (resumeTerms.has(bigram)) {
32
+ bigramsMatched.push(bigram);
33
+ }
34
+ else {
35
+ // Fallback: check if both unigrams in the bigram match individually
36
+ const parts = bigram.split(' ');
37
+ const bothMatch = parts.every((part) => resumeTerms.has(stem(part)));
38
+ if (bothMatch) {
39
+ bigramsMatched.push(bigram);
40
+ }
41
+ else {
42
+ bigramsMissing.push(bigram);
43
+ }
44
+ }
45
+ }
46
+ // Match unigrams (stemmed)
47
+ const unigramsMatched = [];
48
+ const unigramsMissing = [];
49
+ // Track which stemmed resume unigrams we have for unigram matching
50
+ const resumeUnigrams = new Set();
51
+ for (const term of resumeTerms) {
52
+ if (!term.includes(' ')) {
53
+ resumeUnigrams.add(term);
54
+ }
55
+ }
56
+ for (const unigram of jdUnigrams) {
57
+ if (resumeUnigrams.has(unigram)) {
58
+ unigramsMatched.push(unigram);
59
+ }
60
+ else {
61
+ unigramsMissing.push(unigram);
62
+ }
63
+ }
64
+ // Weighted scoring: bigram = 1.5, unigram = 1.0
65
+ const totalPoints = jdBigrams.length * 1.5 + jdUnigrams.length * 1.0;
66
+ const earnedPoints = bigramsMatched.length * 1.5 + unigramsMatched.length * 1.0;
67
+ const score = totalPoints === 0 ? 0 : Math.round((earnedPoints / totalPoints) * 100);
68
+ // Build human-readable matched/missing lists
69
+ const matched = [...bigramsMatched, ...unigramsMatched];
70
+ const missing = [...bigramsMissing, ...unigramsMissing];
71
+ return {
72
+ score,
73
+ matched,
74
+ missing,
75
+ details: {
76
+ bigramsMatched,
77
+ unigramsMatched,
78
+ bigramsMissing,
79
+ unigramsMissing,
80
+ },
81
+ };
82
+ }
83
+ //# sourceMappingURL=ats-scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ats-scorer.js","sourceRoot":"","sources":["../../src/lib/ats-scorer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAa,YAAY,EAAc,MAAM,iBAAiB,CAAC;AAE5E;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,UAAkB,EAAE,MAAc;IACzD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,WAAW,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAErC,8CAA8C;IAC9C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;QAC/B,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,oEAAoE;YACpE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,SAAS,EAAE,CAAC;gBACd,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9B,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,mEAAmE;IACnE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;QACjC,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,MAAM,WAAW,GACf,SAAS,CAAC,MAAM,GAAG,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC;IAEnD,MAAM,YAAY,GAChB,cAAc,CAAC,MAAM,GAAG,GAAG,GAAG,eAAe,CAAC,MAAM,GAAG,GAAG,CAAC;IAE7D,MAAM,KAAK,GAAG,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC;IAErF,6CAA6C;IAC7C,MAAM,OAAO,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,eAAe,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,eAAe,CAAC,CAAC;IAExD,OAAO;QACL,KAAK;QACL,OAAO;QACP,OAAO;QACP,OAAO,EAAE;YACP,cAAc;YACd,eAAe;YACf,cAAc;YACd,eAAe;SAChB;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { scoreATS } from './ats-scorer.js';
2
+ export { scoreResume, getVerbTier } from './resume-scorer.js';
3
+ export { toResumeData } from './resume-transformer.js';
4
+ export type { ResumeData, ATSResult, ResumeScore, ScoreDimension, ScoreMode, VerbTier, } from './types.js';
5
+ export { stem, tokenize, normalise, extractTerms } from './text-utils.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC;AAIpB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Stable public API — covered by semver guarantees
2
+ export { scoreATS } from './ats-scorer.js';
3
+ export { scoreResume, getVerbTier } from './resume-scorer.js';
4
+ export { toResumeData } from './resume-transformer.js';
5
+ // Internal utilities — NOT part of the stable API, may change in minor versions
6
+ // Exported for advanced consumers who accept the risk
7
+ export { stem, tokenize, normalise, extractTerms } from './text-utils.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAUvD,gFAAgF;AAChF,sDAAsD;AACtD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Resume scoring engine.
3
+ *
4
+ * Provides a deterministic, multi-dimensional resume score composed of
5
+ * five sub-scorers: quantification, verb strength, bullet structure,
6
+ * section completeness, and ATS keyword matching.
7
+ *
8
+ * Main export: `scoreResume(resumeData, jdText?)` returns a `ResumeScore`.
9
+ */
10
+ import type { ResumeData, ResumeScore, VerbTier } from './types.js';
11
+ /**
12
+ * Fraction of bullets that contain at least one number or metric.
13
+ * Returns 0-100. Returns 0 for empty bullets array.
14
+ */
15
+ export declare function scoreQuantification(bullets: string[]): number;
16
+ /**
17
+ * Determine the verb tier for a bullet based on its first non-stop-word token.
18
+ *
19
+ * Tokenizes the bullet, skips stop words, takes the first meaningful token,
20
+ * stems it, and looks it up in the pre-computed stemmed verb map.
21
+ *
22
+ * Returns 1 (strong), 2 (solid), 3 (weak), or null (unrecognized).
23
+ */
24
+ export declare function getVerbTier(bullet: string): VerbTier;
25
+ /**
26
+ * Average verb tier quality across bullets.
27
+ * Scoring: tier1=100, tier2=60, tier3=20, null=40.
28
+ * Returns 0-100. Returns 0 for empty bullets array.
29
+ */
30
+ export declare function scoreVerbStrength(bullets: string[]): number;
31
+ /**
32
+ * Fraction of "strong" bullets. A bullet is strong if it:
33
+ * - Starts with a recognized verb (tier 1, 2, or 3)
34
+ * - Contains a number (`/\d+/`)
35
+ * - Has 8+ words
36
+ *
37
+ * Returns 0-100. Returns 0 for empty bullets array.
38
+ */
39
+ export declare function scoreBulletStructure(bullets: string[]): number;
40
+ /**
41
+ * Presence of expected resume sections.
42
+ *
43
+ * Required sections ("experience", "education", "skills") are worth 20 points each.
44
+ * Recommended sections ("summary", "projects", "certifications") are worth ~13.33 points each.
45
+ * Match by substring: a section name includes the keyword.
46
+ * Capped at 100.
47
+ */
48
+ export declare function scoreSectionCompleteness(sections: string[]): number;
49
+ /**
50
+ * Score a resume across five dimensions: quantification, verb strength,
51
+ * ATS keyword match, bullet structure, and section completeness.
52
+ *
53
+ * When a job description is provided, the ATS dimension is active and
54
+ * carries 30% weight. Without a JD, the ATS weight is redistributed
55
+ * proportionally across the other four dimensions.
56
+ *
57
+ * @param resumeData - Parsed resume data (raw text, bullets, sections)
58
+ * @param jdText - Optional job description text for ATS matching
59
+ * @returns A `ResumeScore` with total (0-100), mode, breakdown, ATS result, and flags.
60
+ */
61
+ export declare function scoreResume(resumeData: ResumeData, jdText?: string): ResumeScore;
62
+ //# sourceMappingURL=resume-scorer.d.ts.map