careermate 0.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.
- package/AGENTS.md +33 -0
- package/INSTALL.md +230 -0
- package/LICENSE +21 -0
- package/README.md +532 -0
- package/THIRD_PARTY_NOTICES.md +57 -0
- package/bin/careermate.mjs +77 -0
- package/dist/career-os/README.md +78 -0
- package/dist/career-os/eop/cover-letter.md +46 -0
- package/dist/career-os/eop/fit-analysis.md +48 -0
- package/dist/career-os/eop/interview-prep.md +39 -0
- package/dist/career-os/eop/job-analysis.md +42 -0
- package/dist/career-os/eop/profile-extraction.md +37 -0
- package/dist/career-os/knowledge/ats.md +131 -0
- package/dist/career-os/knowledge/company-research.md +137 -0
- package/dist/career-os/knowledge/cover-letter.md +135 -0
- package/dist/career-os/knowledge/fit-matching.md +121 -0
- package/dist/career-os/knowledge/human-writing.md +118 -0
- package/dist/career-os/knowledge/interview-behavioral.md +132 -0
- package/dist/career-os/knowledge/interview-technical.md +126 -0
- package/dist/career-os/knowledge/linkedin-profile.md +152 -0
- package/dist/career-os/knowledge/networking-referrals.md +166 -0
- package/dist/career-os/knowledge/offer-evaluation-decision.md +121 -0
- package/dist/career-os/knowledge/onboarding-first-90-days.md +126 -0
- package/dist/career-os/knowledge/portfolio.md +121 -0
- package/dist/career-os/knowledge/recruiter-screen.md +105 -0
- package/dist/career-os/knowledge/rejection-triage-iteration.md +115 -0
- package/dist/career-os/knowledge/resume.md +123 -0
- package/dist/career-os/knowledge/salary-negotiation.md +123 -0
- package/dist/career-os/knowledge/verifiers/ats-compat.md +64 -0
- package/dist/career-os/knowledge/verifiers/consistency.md +61 -0
- package/dist/career-os/knowledge/verifiers/human-voice.md +82 -0
- package/dist/career-os/knowledge/verifiers/recency-staleness.md +72 -0
- package/dist/career-os/knowledge/verifiers/responsiveness-on-target.md +82 -0
- package/dist/career-os/knowledge/verifiers/truthfulness.md +67 -0
- package/dist/doctor.mjs +79094 -0
- package/dist/mcp.mjs +96108 -0
- package/dist/migrate.mjs +4735 -0
- package/dist/pdf.worker.min.mjs +28 -0
- package/dist/public/app.js +150 -0
- package/dist/public/fonts/PretendardVariable.woff2 +0 -0
- package/dist/public/icon-180.png +0 -0
- package/dist/public/index.html +52 -0
- package/dist/public/lib.js +394 -0
- package/dist/public/pages/applications.js +107 -0
- package/dist/public/pages/documents.js +467 -0
- package/dist/public/pages/home.js +261 -0
- package/dist/public/pages/interview.js +227 -0
- package/dist/public/pages/jobs.js +493 -0
- package/dist/public/pages/profile.js +556 -0
- package/dist/public/pages/settings.js +240 -0
- package/dist/public/styles.css +498 -0
- package/dist/site/analytics.js +97 -0
- package/dist/site/favicon.svg +1 -0
- package/dist/site/fonts/PretendardVariable.woff2 +0 -0
- package/dist/site/icon-180.png +0 -0
- package/dist/site/icon-512.png +0 -0
- package/dist/site/index.html +598 -0
- package/dist/site/landing.js +54 -0
- package/dist/site/llms-install.txt +217 -0
- package/dist/site/robots.txt +4 -0
- package/dist/site/sitemap.xml +21 -0
- package/dist/site/start.html +326 -0
- package/dist/site/style.css +550 -0
- package/dist/site/vercel.json +20 -0
- package/dist/web.mjs +46852 -0
- package/docs/FAQ.md +101 -0
- package/docs/MCP_TOOLS.md +311 -0
- package/docs/README.md +28 -0
- package/docs/START_WORKFLOW.md +137 -0
- package/docs/SUPPORTED_AI_APPS.md +112 -0
- package/docs/WORKFLOWS.md +202 -0
- package/docs/career-os/README.md +78 -0
- package/docs/career-os/eop/cover-letter.md +46 -0
- package/docs/career-os/eop/fit-analysis.md +48 -0
- package/docs/career-os/eop/interview-prep.md +39 -0
- package/docs/career-os/eop/job-analysis.md +42 -0
- package/docs/career-os/eop/profile-extraction.md +37 -0
- package/docs/career-os/knowledge/ats.md +131 -0
- package/docs/career-os/knowledge/company-research.md +137 -0
- package/docs/career-os/knowledge/cover-letter.md +135 -0
- package/docs/career-os/knowledge/fit-matching.md +121 -0
- package/docs/career-os/knowledge/human-writing.md +118 -0
- package/docs/career-os/knowledge/interview-behavioral.md +132 -0
- package/docs/career-os/knowledge/interview-technical.md +126 -0
- package/docs/career-os/knowledge/linkedin-profile.md +152 -0
- package/docs/career-os/knowledge/networking-referrals.md +166 -0
- package/docs/career-os/knowledge/offer-evaluation-decision.md +121 -0
- package/docs/career-os/knowledge/onboarding-first-90-days.md +126 -0
- package/docs/career-os/knowledge/portfolio.md +121 -0
- package/docs/career-os/knowledge/recruiter-screen.md +105 -0
- package/docs/career-os/knowledge/rejection-triage-iteration.md +115 -0
- package/docs/career-os/knowledge/resume.md +123 -0
- package/docs/career-os/knowledge/salary-negotiation.md +123 -0
- package/docs/career-os/knowledge/verifiers/ats-compat.md +64 -0
- package/docs/career-os/knowledge/verifiers/consistency.md +61 -0
- package/docs/career-os/knowledge/verifiers/human-voice.md +82 -0
- package/docs/career-os/knowledge/verifiers/recency-staleness.md +72 -0
- package/docs/career-os/knowledge/verifiers/responsiveness-on-target.md +82 -0
- package/docs/career-os/knowledge/verifiers/truthfulness.md +67 -0
- package/package.json +89 -0
- package/packages/core/src/context.ts +74 -0
- package/packages/core/src/index.ts +8 -0
- package/packages/core/src/onboarding.ts +81 -0
- package/packages/core/src/services.ts +187 -0
- package/packages/core/src/summary.ts +104 -0
- package/packages/db/src/connection.ts +76 -0
- package/packages/db/src/index.ts +23 -0
- package/packages/db/src/paths.ts +52 -0
- package/packages/db/src/repositories.ts +891 -0
- package/packages/db/src/runtime.ts +58 -0
- package/packages/db/src/schema.ts +307 -0
- package/packages/exporters/src/html.ts +110 -0
- package/packages/exporters/src/index.ts +364 -0
- package/packages/exporters/src/markdown.ts +178 -0
- package/packages/knowledge/src/index.ts +168 -0
- package/packages/mcp-tools/src/bridge.ts +106 -0
- package/packages/mcp-tools/src/index.ts +17 -0
- package/packages/mcp-tools/src/result.ts +49 -0
- package/packages/mcp-tools/src/tools.ts +747 -0
- package/packages/mcp-tools/src/update.ts +330 -0
- package/packages/parsers/src/documents.ts +533 -0
- package/packages/parsers/src/html.ts +86 -0
- package/packages/parsers/src/index.ts +231 -0
- package/packages/parsers/src/keywords.ts +151 -0
- package/packages/prompts/src/humanize.ts +59 -0
- package/packages/prompts/src/index.ts +82 -0
- package/packages/prompts/src/install.ts +43 -0
- package/packages/prompts/src/onboarding.ts +35 -0
- package/packages/prompts/src/system.ts +57 -0
- package/packages/shared/src/build-info.ts +22 -0
- package/packages/shared/src/enums.ts +142 -0
- package/packages/shared/src/index.ts +19 -0
- package/packages/shared/src/schemas.ts +453 -0
- package/packages/workflows/src/definitions.ts +109 -0
- package/packages/workflows/src/index.ts +39 -0
- package/scripts/init.ts +371 -0
- package/tsconfig.json +32 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge from the MCP process to the local dashboard process.
|
|
3
|
+
*
|
|
4
|
+
* `open_dashboard` / `open_application` need the running web server's URL. The
|
|
5
|
+
* web server publishes it to a runtime file (see @careermate/db runtime). If the
|
|
6
|
+
* server isn't running we start it (detached) and wait for it to register.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn, type SpawnOptions } from 'node:child_process';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { readRuntimeInfo, isProcessAlive } from '@careermate/db';
|
|
12
|
+
import { BUNDLED } from '@careermate/shared';
|
|
13
|
+
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
// packages/mcp-tools/src -> repo root (dev). 번들에서는 __dirname이 dist/ 이다.
|
|
16
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
17
|
+
|
|
18
|
+
export function projectRoot(): string {
|
|
19
|
+
return REPO_ROOT;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function liveServer() {
|
|
23
|
+
const info = readRuntimeInfo();
|
|
24
|
+
if (info && isProcessAlive(info.pid)) return info;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Fire-and-forget detached spawn that NEVER throws — synchronously OR
|
|
30
|
+
* asynchronously. A missing binary (e.g. `xdg-open` on a headless Linux box)
|
|
31
|
+
* makes spawn emit an async `'error'` event; with no listener that becomes an
|
|
32
|
+
* uncaughtException and crashes the MCP process. A surrounding try/catch only
|
|
33
|
+
* guards the synchronous spawn() call, not the later event — so attach the
|
|
34
|
+
* listener here. stdio defaults to 'ignore'; callers may override via opts.
|
|
35
|
+
*/
|
|
36
|
+
function spawnDetached(cmd: string, args: string[], opts: SpawnOptions = {}): void {
|
|
37
|
+
try {
|
|
38
|
+
const child = spawn(cmd, args, { stdio: 'ignore', detached: true, ...opts });
|
|
39
|
+
child.on('error', () => {
|
|
40
|
+
/* binary missing / spawn failed — best-effort, never crash */
|
|
41
|
+
});
|
|
42
|
+
child.unref();
|
|
43
|
+
} catch {
|
|
44
|
+
/* best-effort */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Start the dashboard server detached and wait until it publishes its address. */
|
|
49
|
+
export async function ensureServer(timeoutMs = 12000): Promise<{ url: string } | null> {
|
|
50
|
+
const existing = liveServer();
|
|
51
|
+
if (existing) return { url: existing.url };
|
|
52
|
+
|
|
53
|
+
// prod(번들): dist/web.mjs를 플레인 node로 실행. dev: tsx로 소스 실행.
|
|
54
|
+
const [bin, args, cwd] = BUNDLED
|
|
55
|
+
? [process.execPath, ['--experimental-sqlite', path.join(__dirname, 'web.mjs')], __dirname]
|
|
56
|
+
: [process.execPath, ['--no-warnings', '--experimental-sqlite', '--import', 'tsx', 'apps/web/src/index.ts'], REPO_ROOT];
|
|
57
|
+
// Spawn failures (sync or async) just leave the server down; the poll loop
|
|
58
|
+
// below then times out and returns null — no crash.
|
|
59
|
+
spawnDetached(bin as string, args as string[], { cwd: cwd as string, env: { ...process.env, CAREERMATE_NO_OPEN: '1' } });
|
|
60
|
+
|
|
61
|
+
const start = Date.now();
|
|
62
|
+
while (Date.now() - start < timeoutMs) {
|
|
63
|
+
const info = liveServer();
|
|
64
|
+
if (info) return { url: info.url };
|
|
65
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Open a URL or a local folder via the OS default handler. Best-effort, never throws. */
|
|
71
|
+
function openOsTarget(target: string): void {
|
|
72
|
+
switch (process.platform) {
|
|
73
|
+
case 'win32':
|
|
74
|
+
// `start` is a cmd builtin; the empty "" is the window-title arg so a
|
|
75
|
+
// quoted target isn't mistaken for the title. (explorer also opens URLs,
|
|
76
|
+
// but `start` is the canonical default-handler launcher.)
|
|
77
|
+
spawnDetached('cmd', ['/c', 'start', '', target]);
|
|
78
|
+
break;
|
|
79
|
+
case 'darwin':
|
|
80
|
+
spawnDetached('open', [target]);
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
spawnDetached('xdg-open', [target]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function openInBrowser(url: string): void {
|
|
88
|
+
openOsTarget(url);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Open a local folder in the OS file manager (Explorer/Finder/xdg). Best-effort. */
|
|
92
|
+
export function openInFileManager(dir: string): void {
|
|
93
|
+
// Windows: `explorer <dir>` is the idiomatic folder opener (start "" <dir>
|
|
94
|
+
// also works, but explorer focuses an existing window if already open).
|
|
95
|
+
if (process.platform === 'win32') spawnDetached('explorer', [dir]);
|
|
96
|
+
else openOsTarget(dir);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Resolve the dashboard URL, starting the server if needed. */
|
|
100
|
+
export async function resolveDashboardUrl(hash = ''): Promise<{ url: string; running: boolean }> {
|
|
101
|
+
const live = liveServer();
|
|
102
|
+
if (live) return { url: live.url + hash, running: true };
|
|
103
|
+
const started = await ensureServer();
|
|
104
|
+
if (started) return { url: started.url + hash, running: true };
|
|
105
|
+
return { url: 'http://127.0.0.1:4319' + hash, running: false };
|
|
106
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @careermate/mcp-tools — the CareerMate tool registry + the conversion helpers
|
|
3
|
+
* the MCP server (apps/mcp) uses to expose them. Kept separate from the server
|
|
4
|
+
* so tools can also be unit-tested or reused in other transports later.
|
|
5
|
+
*/
|
|
6
|
+
export { TOOLS, EXPORTS_LOCATION } from './tools.ts';
|
|
7
|
+
export { ok, fail, toCallToolResult, type ToolDef, type ToolResult } from './result.ts';
|
|
8
|
+
export { resolveDashboardUrl, openInBrowser, ensureServer, projectRoot } from './bridge.ts';
|
|
9
|
+
export {
|
|
10
|
+
getUpdateStatus,
|
|
11
|
+
getUpdateStatusAsync,
|
|
12
|
+
runSelfUpdate,
|
|
13
|
+
installPrefix,
|
|
14
|
+
compareVersions,
|
|
15
|
+
type UpdateStatus,
|
|
16
|
+
type UpdateResult,
|
|
17
|
+
} from './update.ts';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool result shape shared by every CareerMate MCP tool, plus the conversion to
|
|
3
|
+
* the MCP CallToolResult the SDK expects.
|
|
4
|
+
*
|
|
5
|
+
* We always embed the structured payload as pretty JSON inside the text content
|
|
6
|
+
* (so *any* model/client can read it) AND expose it as `structuredContent` for
|
|
7
|
+
* clients that support it. No output schema is declared, so structuredContent is
|
|
8
|
+
* passed through without validation.
|
|
9
|
+
*/
|
|
10
|
+
import type { ZodRawShape } from 'zod';
|
|
11
|
+
|
|
12
|
+
export interface ToolResult {
|
|
13
|
+
text: string;
|
|
14
|
+
data?: unknown;
|
|
15
|
+
isError?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ToolDef {
|
|
19
|
+
name: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
inputSchema: ZodRawShape;
|
|
23
|
+
/** Hint flags for clients (readOnly tools don't mutate). */
|
|
24
|
+
readOnly?: boolean;
|
|
25
|
+
handler: (args: any) => ToolResult | Promise<ToolResult>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ok(text: string, data?: unknown): ToolResult {
|
|
29
|
+
return { text, data };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function fail(text: string): ToolResult {
|
|
33
|
+
return { text, isError: true };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Convert a ToolResult into the MCP SDK's CallToolResult. */
|
|
37
|
+
export function toCallToolResult(r: ToolResult) {
|
|
38
|
+
const blocks: { type: 'text'; text: string }[] = [{ type: 'text', text: r.text }];
|
|
39
|
+
if (r.data !== undefined) {
|
|
40
|
+
blocks.push({ type: 'text', text: '```json\n' + JSON.stringify(r.data, null, 2) + '\n```' });
|
|
41
|
+
}
|
|
42
|
+
const isPlainObject =
|
|
43
|
+
typeof r.data === 'object' && r.data !== null && !Array.isArray(r.data);
|
|
44
|
+
return {
|
|
45
|
+
content: blocks,
|
|
46
|
+
...(isPlainObject ? { structuredContent: r.data as Record<string, unknown> } : {}),
|
|
47
|
+
...(r.isError ? { isError: true } : {}),
|
|
48
|
+
};
|
|
49
|
+
}
|