careermate 0.0.3 → 0.0.5
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 +3 -0
- package/INSTALL.md +2 -1
- package/README.md +8 -6
- package/dist/doctor.mjs +526 -100
- package/dist/mcp.mjs +528 -102
- package/dist/migrate.mjs +23 -1
- package/dist/public/lib.js +6 -1
- package/dist/public/pages/applications.js +7 -0
- package/dist/public/pages/jobs.js +22 -15
- package/dist/public/pages/settings.js +160 -14
- package/dist/public/styles.css +19 -2
- package/dist/site/index.html +88 -228
- package/dist/site/landing.js +109 -0
- package/dist/site/start.html +154 -131
- package/dist/site/style.css +169 -63
- package/dist/web.mjs +503 -41
- package/docs/FAQ.md +3 -2
- package/docs/MCP_TOOLS.md +16 -8
- package/docs/START_WORKFLOW.md +2 -1
- package/docs/WORKFLOWS.md +6 -6
- package/package.json +2 -2
- package/packages/core/src/services.ts +69 -7
- package/packages/db/src/repositories.ts +0 -0
- package/packages/mcp-tools/src/bridge.ts +194 -13
- package/packages/mcp-tools/src/tools.ts +166 -35
- package/packages/mcp-tools/src/update.ts +1 -1
- package/packages/prompts/src/onboarding.ts +1 -1
- package/packages/prompts/src/system.ts +10 -2
- package/packages/shared/src/enums.ts +7 -2
- package/packages/shared/src/errors.ts +33 -0
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/schemas.ts +56 -2
- package/packages/workflows/src/definitions.ts +3 -3
package/dist/doctor.mjs
CHANGED
|
@@ -6477,9 +6477,9 @@ var require_timers = __commonJS({
|
|
|
6477
6477
|
clearTimeout(this.handle);
|
|
6478
6478
|
};
|
|
6479
6479
|
var afterValue = function(value) {
|
|
6480
|
-
return
|
|
6480
|
+
return delay2(+this).thenReturn(value);
|
|
6481
6481
|
};
|
|
6482
|
-
var
|
|
6482
|
+
var delay2 = Promise2.delay = function(ms, value) {
|
|
6483
6483
|
var ret2;
|
|
6484
6484
|
var handle;
|
|
6485
6485
|
if (value !== void 0) {
|
|
@@ -6501,7 +6501,7 @@ var require_timers = __commonJS({
|
|
|
6501
6501
|
return ret2;
|
|
6502
6502
|
};
|
|
6503
6503
|
Promise2.prototype.delay = function(ms) {
|
|
6504
|
-
return
|
|
6504
|
+
return delay2(ms, this);
|
|
6505
6505
|
};
|
|
6506
6506
|
var afterTimeout = function(promise, message, parent) {
|
|
6507
6507
|
var err2;
|
|
@@ -28297,7 +28297,7 @@ var require_path_is_absolute = __commonJS({
|
|
|
28297
28297
|
var require_files = __commonJS({
|
|
28298
28298
|
"node_modules/mammoth/lib/docx/files.js"(exports2) {
|
|
28299
28299
|
"use strict";
|
|
28300
|
-
var
|
|
28300
|
+
var fs9 = __require("fs");
|
|
28301
28301
|
var url = __require("url");
|
|
28302
28302
|
var os3 = __require("os");
|
|
28303
28303
|
var dirname = __require("path").dirname;
|
|
@@ -28338,7 +28338,7 @@ var require_files = __commonJS({
|
|
|
28338
28338
|
read
|
|
28339
28339
|
};
|
|
28340
28340
|
}
|
|
28341
|
-
var readFile = promises.promisify(
|
|
28341
|
+
var readFile = promises.promisify(fs9.readFile.bind(fs9));
|
|
28342
28342
|
function uriToPath(uriString, platform) {
|
|
28343
28343
|
if (!platform) {
|
|
28344
28344
|
platform = os3.platform();
|
|
@@ -31080,11 +31080,11 @@ var require_options_reader = __commonJS({
|
|
|
31080
31080
|
var require_unzip = __commonJS({
|
|
31081
31081
|
"node_modules/mammoth/lib/unzip.js"(exports2) {
|
|
31082
31082
|
"use strict";
|
|
31083
|
-
var
|
|
31083
|
+
var fs9 = __require("fs");
|
|
31084
31084
|
var promises = require_promises();
|
|
31085
31085
|
var zipfile = require_zipfile();
|
|
31086
31086
|
exports2.openZip = openZip;
|
|
31087
|
-
var readFile = promises.promisify(
|
|
31087
|
+
var readFile = promises.promisify(fs9.readFile);
|
|
31088
31088
|
function openZip(options) {
|
|
31089
31089
|
if (options.path) {
|
|
31090
31090
|
return readFile(options.path).then(zipfile.openArrayBuffer);
|
|
@@ -31809,9 +31809,9 @@ var require_cjs = __commonJS({
|
|
|
31809
31809
|
}
|
|
31810
31810
|
return o;
|
|
31811
31811
|
}
|
|
31812
|
-
var
|
|
31812
|
+
var fs9;
|
|
31813
31813
|
function get_fs() {
|
|
31814
|
-
return
|
|
31814
|
+
return fs9 || (fs9 = require$$0__default["default"]);
|
|
31815
31815
|
}
|
|
31816
31816
|
function parse2(file, options) {
|
|
31817
31817
|
if (file[0] == 80 && file[1] == 75) return parse_zip(file, options);
|
|
@@ -32096,7 +32096,7 @@ var require_cjs = __commonJS({
|
|
|
32096
32096
|
}
|
|
32097
32097
|
function read_file(filename2, options) {
|
|
32098
32098
|
get_fs();
|
|
32099
|
-
return parse2(
|
|
32099
|
+
return parse2(fs9.readFileSync(filename2), options);
|
|
32100
32100
|
}
|
|
32101
32101
|
function read(blob, options) {
|
|
32102
32102
|
switch (options && options.type || "base64") {
|
|
@@ -32411,7 +32411,7 @@ var require_cjs = __commonJS({
|
|
|
32411
32411
|
function write_file(cfb2, filename2, options) {
|
|
32412
32412
|
get_fs();
|
|
32413
32413
|
var o = _write(cfb2, options);
|
|
32414
|
-
|
|
32414
|
+
fs9.writeFileSync(filename2, o);
|
|
32415
32415
|
}
|
|
32416
32416
|
function a2s(o) {
|
|
32417
32417
|
var out = new Array(o.length);
|
|
@@ -32423,7 +32423,7 @@ var require_cjs = __commonJS({
|
|
|
32423
32423
|
switch (options && options.type || "buffer") {
|
|
32424
32424
|
case "file":
|
|
32425
32425
|
get_fs();
|
|
32426
|
-
|
|
32426
|
+
fs9.writeFileSync(options.filename, o);
|
|
32427
32427
|
return o;
|
|
32428
32428
|
case "binary":
|
|
32429
32429
|
return typeof o == "string" ? o : a2s(o);
|
|
@@ -40116,8 +40116,8 @@ function blend(fg, bg, alpha) {
|
|
|
40116
40116
|
return Math.round(alpha * fg + (1 - alpha) * bg);
|
|
40117
40117
|
}
|
|
40118
40118
|
async function node_utils_fetchData(url) {
|
|
40119
|
-
const
|
|
40120
|
-
const data = await
|
|
40119
|
+
const fs9 = process.getBuiltinModule("fs/promises");
|
|
40120
|
+
const data = await fs9.readFile(url);
|
|
40121
40121
|
return new Uint8Array(data);
|
|
40122
40122
|
}
|
|
40123
40123
|
function initGPU() {
|
|
@@ -40746,11 +40746,11 @@ function network_getArrayBuffer(val) {
|
|
|
40746
40746
|
return typeof val !== "string" ? val : stringToBytes(val).buffer;
|
|
40747
40747
|
}
|
|
40748
40748
|
function getReadableStream(url, opts = null) {
|
|
40749
|
-
const
|
|
40749
|
+
const fs9 = process.getBuiltinModule("fs");
|
|
40750
40750
|
const {
|
|
40751
40751
|
Readable
|
|
40752
40752
|
} = process.getBuiltinModule("stream");
|
|
40753
|
-
const readStream =
|
|
40753
|
+
const readStream = fs9.createReadStream(url, opts);
|
|
40754
40754
|
return Readable.toWeb(readStream);
|
|
40755
40755
|
}
|
|
40756
40756
|
function getNetworkStream(url) {
|
|
@@ -57747,8 +57747,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
57747
57747
|
url
|
|
57748
57748
|
} = stream._source;
|
|
57749
57749
|
this._isStreamingSupported = !disableStream;
|
|
57750
|
-
const
|
|
57751
|
-
|
|
57750
|
+
const fs9 = process.getBuiltinModule("fs/promises");
|
|
57751
|
+
fs9.lstat(url).then((stat) => {
|
|
57752
57752
|
const readableStream = getReadableStream(url);
|
|
57753
57753
|
this._reader = readableStream.getReader();
|
|
57754
57754
|
const {
|
|
@@ -59394,9 +59394,9 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
59394
59394
|
return;
|
|
59395
59395
|
}
|
|
59396
59396
|
if (reason instanceof RenderingCancelledException) {
|
|
59397
|
-
let
|
|
59397
|
+
let delay2 = RENDERING_CANCELLED_TIMEOUT;
|
|
59398
59398
|
if (reason.extraDelay > 0 && reason.extraDelay < 1e3) {
|
|
59399
|
-
|
|
59399
|
+
delay2 += reason.extraDelay;
|
|
59400
59400
|
}
|
|
59401
59401
|
intentState.streamReaderCancelTimeout = setTimeout(() => {
|
|
59402
59402
|
intentState.streamReaderCancelTimeout = null;
|
|
@@ -59405,7 +59405,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
59405
59405
|
reason,
|
|
59406
59406
|
force: true
|
|
59407
59407
|
});
|
|
59408
|
-
},
|
|
59408
|
+
}, delay2);
|
|
59409
59409
|
return;
|
|
59410
59410
|
}
|
|
59411
59411
|
}
|
|
@@ -68172,7 +68172,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
68172
68172
|
const ij = i2 * width + j;
|
|
68173
68173
|
const center = buf[ij];
|
|
68174
68174
|
let sum = 0;
|
|
68175
|
-
let
|
|
68175
|
+
let norm2 = 0;
|
|
68176
68176
|
for (let k = 0; k < kernelSize; k++) {
|
|
68177
68177
|
const y = i2 + k - halfSize;
|
|
68178
68178
|
if (y < 0 || y >= height) {
|
|
@@ -68186,10 +68186,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
68186
68186
|
const neighbour = buf[y * width + x2];
|
|
68187
68187
|
const w = kernel[k * kernelSize + l2] * rangeValues[Math.abs(neighbour - center)];
|
|
68188
68188
|
sum += neighbour * w;
|
|
68189
|
-
|
|
68189
|
+
norm2 += w;
|
|
68190
68190
|
}
|
|
68191
68191
|
}
|
|
68192
|
-
const pix = out[ij] = Math.round(sum /
|
|
68192
|
+
const pix = out[ij] = Math.round(sum / norm2);
|
|
68193
68193
|
histogram[pix]++;
|
|
68194
68194
|
}
|
|
68195
68195
|
}
|
|
@@ -71040,7 +71040,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
71040
71040
|
});
|
|
71041
71041
|
|
|
71042
71042
|
// scripts/doctor.ts
|
|
71043
|
-
import
|
|
71043
|
+
import fs8 from "node:fs";
|
|
71044
71044
|
|
|
71045
71045
|
// packages/db/src/paths.ts
|
|
71046
71046
|
import os from "node:os";
|
|
@@ -71451,6 +71451,24 @@ function setVerifyStrict(on) {
|
|
|
71451
71451
|
return on;
|
|
71452
71452
|
}
|
|
71453
71453
|
|
|
71454
|
+
// packages/shared/src/errors.ts
|
|
71455
|
+
var CareerMateError = class extends Error {
|
|
71456
|
+
constructor(message, httpStatus = 400, code) {
|
|
71457
|
+
super(message);
|
|
71458
|
+
this.httpStatus = httpStatus;
|
|
71459
|
+
this.code = code;
|
|
71460
|
+
this.name = "CareerMateError";
|
|
71461
|
+
}
|
|
71462
|
+
httpStatus;
|
|
71463
|
+
code;
|
|
71464
|
+
};
|
|
71465
|
+
function notFound(message) {
|
|
71466
|
+
return new CareerMateError(message, 404, "not_found");
|
|
71467
|
+
}
|
|
71468
|
+
function conflict(message) {
|
|
71469
|
+
return new CareerMateError(message, 409, "conflict");
|
|
71470
|
+
}
|
|
71471
|
+
|
|
71454
71472
|
// packages/shared/src/enums.ts
|
|
71455
71473
|
var APPLICATION_STATUSES = [
|
|
71456
71474
|
"draft",
|
|
@@ -71501,8 +71519,9 @@ function canTransitionStatus(from, to) {
|
|
|
71501
71519
|
}
|
|
71502
71520
|
function assertStatusTransition(from, to) {
|
|
71503
71521
|
if (!canTransitionStatus(from, to)) {
|
|
71504
|
-
|
|
71505
|
-
|
|
71522
|
+
const suffix = to === "draft" ? ` ('${APPLICATION_STATUS_LABELS[from]}' \uB2E8\uACC4\uC758 \uC9C0\uC6D0\uC740 \uC791\uC131 \uC911(\uBBF8\uCD94\uC801)\uC73C\uB85C \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uCD08\uAE30 \uB2E8\uACC4\uB85C \uC62E\uAE30\uB824\uBA74 '\uC9C0\uC6D0 \uC608\uC815'\uC744 \uC120\uD0DD\uD558\uC138\uC694.)` : "";
|
|
71523
|
+
throw conflict(
|
|
71524
|
+
`'${APPLICATION_STATUS_LABELS[from]}'\uC5D0\uC11C '${APPLICATION_STATUS_LABELS[to]}'(\uC73C)\uB85C\uB294 \uC0C1\uD0DC\uB97C \uBC14\uAFC0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.${suffix}`
|
|
71506
71525
|
);
|
|
71507
71526
|
}
|
|
71508
71527
|
}
|
|
@@ -75595,7 +75614,20 @@ var optLine = external_exports.string().max(MAX_LINE).optional();
|
|
|
75595
75614
|
var optNote = external_exports.string().max(MAX_NOTE).optional();
|
|
75596
75615
|
var optBody = external_exports.string().max(MAX_BODY).optional();
|
|
75597
75616
|
var reqBody = external_exports.string().max(MAX_BODY).refine((s) => s.trim().length > 0, { message: EMPTY_MSG });
|
|
75598
|
-
|
|
75617
|
+
function toStrList(v) {
|
|
75618
|
+
if (typeof v !== "string") return v;
|
|
75619
|
+
const s = v.trim();
|
|
75620
|
+
if (!s) return [];
|
|
75621
|
+
if (s.startsWith("[")) {
|
|
75622
|
+
try {
|
|
75623
|
+
const parsed = JSON.parse(s);
|
|
75624
|
+
if (Array.isArray(parsed)) return parsed;
|
|
75625
|
+
} catch {
|
|
75626
|
+
}
|
|
75627
|
+
}
|
|
75628
|
+
return s.split(/[\n,]/).map((x2) => x2.trim()).filter(Boolean);
|
|
75629
|
+
}
|
|
75630
|
+
var strList = external_exports.preprocess(toStrList, external_exports.array(external_exports.string().max(MAX_ITEM)).max(MAX_ITEMS));
|
|
75599
75631
|
var baseRecord = {
|
|
75600
75632
|
id,
|
|
75601
75633
|
created_at: isoDateTime,
|
|
@@ -75657,6 +75689,9 @@ var ExperienceRecordSchema = external_exports.object({
|
|
|
75657
75689
|
tech: external_exports.array(external_exports.string()),
|
|
75658
75690
|
order_index: external_exports.number()
|
|
75659
75691
|
});
|
|
75692
|
+
var ExperienceBatchInputSchema = external_exports.object({
|
|
75693
|
+
experiences: external_exports.array(ExperienceInputSchema).min(1).max(MAX_ITEMS).describe("\uCD94\uAC00\uD560 \uACBD\uB825 \uBAA9\uB85D(\uD55C \uAC74\uC774\uC5B4\uB3C4 \uBC30\uC5F4\uB85C). \uAC19\uC740 \uD68C\uC0AC\xB7\uC9C1\uBB34\xB7\uC785\uC0AC\uC77C\uC740 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.")
|
|
75694
|
+
});
|
|
75660
75695
|
var ProjectInputSchema = external_exports.object({
|
|
75661
75696
|
name: reqLine,
|
|
75662
75697
|
role: optLine,
|
|
@@ -75680,6 +75715,9 @@ var ProjectRecordSchema = external_exports.object({
|
|
|
75680
75715
|
end_date: external_exports.string().nullable(),
|
|
75681
75716
|
order_index: external_exports.number()
|
|
75682
75717
|
});
|
|
75718
|
+
var ProjectBatchInputSchema = external_exports.object({
|
|
75719
|
+
projects: external_exports.array(ProjectInputSchema).min(1).max(MAX_ITEMS).describe("\uCD94\uAC00\uD560 \uD504\uB85C\uC81D\uD2B8 \uBAA9\uB85D(\uD55C \uAC1C\uC5EC\uB3C4 \uBC30\uC5F4\uB85C). \uAC19\uC740 \uC774\uB984\uC758 \uD504\uB85C\uC81D\uD2B8\uB294 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.")
|
|
75720
|
+
});
|
|
75683
75721
|
var SkillInputSchema = external_exports.object({
|
|
75684
75722
|
name: reqLine,
|
|
75685
75723
|
category: external_exports.string().max(MAX_LINE).optional().describe("\uC5B8\uC5B4/\uD504\uB808\uC784\uC6CC\uD06C/\uD234/\uC18C\uD504\uD2B8\uC2A4\uD0AC \uB4F1"),
|
|
@@ -75695,6 +75733,9 @@ var SkillRecordSchema = external_exports.object({
|
|
|
75695
75733
|
years: external_exports.number().nullable(),
|
|
75696
75734
|
order_index: external_exports.number()
|
|
75697
75735
|
});
|
|
75736
|
+
var SkillBatchInputSchema = external_exports.object({
|
|
75737
|
+
skills: external_exports.array(SkillInputSchema).min(1).max(MAX_ITEMS).describe("\uCD94\uAC00\uD560 \uAE30\uC220\uC2A4\uD0DD \uBAA9\uB85D(\uD55C \uAC1C\uC5EC\uB3C4 \uBC30\uC5F4\uB85C). \uAC19\uC740 \uC774\uB984\uC758 \uAE30\uC220\uC740 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.")
|
|
75738
|
+
});
|
|
75698
75739
|
var DocumentInputSchema = external_exports.object({
|
|
75699
75740
|
kind: external_exports.enum(DOCUMENT_KINDS),
|
|
75700
75741
|
title: reqLine,
|
|
@@ -75891,7 +75932,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
75891
75932
|
});
|
|
75892
75933
|
|
|
75893
75934
|
// packages/shared/src/build-info.ts
|
|
75894
|
-
var APP_VERSION = true ? "0.0.
|
|
75935
|
+
var APP_VERSION = true ? "0.0.5" : "0.0.0-dev";
|
|
75895
75936
|
var BUNDLED = true;
|
|
75896
75937
|
|
|
75897
75938
|
// packages/shared/src/index.ts
|
|
@@ -75906,6 +75947,7 @@ function now() {
|
|
|
75906
75947
|
|
|
75907
75948
|
// packages/db/src/repositories.ts
|
|
75908
75949
|
var PROFILE_ID = "profile-singleton";
|
|
75950
|
+
var norm = (s) => (s ?? "").trim().toLowerCase();
|
|
75909
75951
|
function mapProfile(r) {
|
|
75910
75952
|
return {
|
|
75911
75953
|
id: r.id,
|
|
@@ -75983,6 +76025,9 @@ function mapExperience(r) {
|
|
|
75983
76025
|
updated_at: r.updated_at
|
|
75984
76026
|
};
|
|
75985
76027
|
}
|
|
76028
|
+
function expKey(company, role, start) {
|
|
76029
|
+
return [norm(company), norm(role), norm(start)].join("\0");
|
|
76030
|
+
}
|
|
75986
76031
|
var experienceRepo = {
|
|
75987
76032
|
list() {
|
|
75988
76033
|
return getDb().prepare(`SELECT * FROM experiences ORDER BY order_index ASC, start_date DESC`).all().map(mapExperience);
|
|
@@ -75991,6 +76036,32 @@ var experienceRepo = {
|
|
|
75991
76036
|
const r = getDb().prepare(`SELECT * FROM experiences WHERE id = ?`).get(id2);
|
|
75992
76037
|
return r ? mapExperience(r) : null;
|
|
75993
76038
|
},
|
|
76039
|
+
/** Existing experience with the same company+role+start_date, or null (for idempotent batch upserts). */
|
|
76040
|
+
findMatch(input) {
|
|
76041
|
+
const key = expKey(input.company, input.role ?? null, input.start_date ?? null);
|
|
76042
|
+
return this.list().find((e) => expKey(e.company, e.role, e.start_date) === key) ?? null;
|
|
76043
|
+
},
|
|
76044
|
+
/** Insert, or merge into the matching experience (omitted fields keep their stored value). */
|
|
76045
|
+
upsert(input) {
|
|
76046
|
+
const existing = this.findMatch(input);
|
|
76047
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
76048
|
+
return { record: this.add(input), created: true };
|
|
76049
|
+
},
|
|
76050
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
76051
|
+
addMany(inputs) {
|
|
76052
|
+
return tx(() => {
|
|
76053
|
+
const records = [];
|
|
76054
|
+
let created = 0;
|
|
76055
|
+
let updated = 0;
|
|
76056
|
+
for (const input of inputs) {
|
|
76057
|
+
const { record, created: isNew } = this.upsert(input);
|
|
76058
|
+
records.push(record);
|
|
76059
|
+
if (isNew) created += 1;
|
|
76060
|
+
else updated += 1;
|
|
76061
|
+
}
|
|
76062
|
+
return { records, created, updated };
|
|
76063
|
+
});
|
|
76064
|
+
},
|
|
75994
76065
|
add(input) {
|
|
75995
76066
|
const ts = now();
|
|
75996
76067
|
const id2 = newId("exp_");
|
|
@@ -76064,6 +76135,32 @@ var projectRepo = {
|
|
|
76064
76135
|
const r = getDb().prepare(`SELECT * FROM projects WHERE id = ?`).get(id2);
|
|
76065
76136
|
return r ? mapProject(r) : null;
|
|
76066
76137
|
},
|
|
76138
|
+
/** Existing project with the same name (case-insensitive), or null (for idempotent batch upserts). */
|
|
76139
|
+
findByName(name) {
|
|
76140
|
+
const key = norm(name);
|
|
76141
|
+
return this.list().find((p) => norm(p.name) === key) ?? null;
|
|
76142
|
+
},
|
|
76143
|
+
/** Insert, or merge into the same-named project (omitted fields keep their stored value). */
|
|
76144
|
+
upsert(input) {
|
|
76145
|
+
const existing = this.findByName(input.name);
|
|
76146
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
76147
|
+
return { record: this.add(input), created: true };
|
|
76148
|
+
},
|
|
76149
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
76150
|
+
addMany(inputs) {
|
|
76151
|
+
return tx(() => {
|
|
76152
|
+
const records = [];
|
|
76153
|
+
let created = 0;
|
|
76154
|
+
let updated = 0;
|
|
76155
|
+
for (const input of inputs) {
|
|
76156
|
+
const { record, created: isNew } = this.upsert(input);
|
|
76157
|
+
records.push(record);
|
|
76158
|
+
if (isNew) created += 1;
|
|
76159
|
+
else updated += 1;
|
|
76160
|
+
}
|
|
76161
|
+
return { records, created, updated };
|
|
76162
|
+
});
|
|
76163
|
+
},
|
|
76067
76164
|
add(input) {
|
|
76068
76165
|
const ts = now();
|
|
76069
76166
|
const id2 = newId("prj_");
|
|
@@ -76131,6 +76228,32 @@ var skillRepo = {
|
|
|
76131
76228
|
const r = getDb().prepare(`SELECT * FROM skills WHERE id = ?`).get(id2);
|
|
76132
76229
|
return r ? mapSkill(r) : null;
|
|
76133
76230
|
},
|
|
76231
|
+
/** Existing skill with the same name (case-insensitive), or null (for idempotent batch upserts). */
|
|
76232
|
+
findByName(name) {
|
|
76233
|
+
const key = norm(name);
|
|
76234
|
+
return this.list().find((s) => norm(s.name) === key) ?? null;
|
|
76235
|
+
},
|
|
76236
|
+
/** Insert, or merge into the same-named skill (omitted fields keep their stored value). */
|
|
76237
|
+
upsert(input) {
|
|
76238
|
+
const existing = this.findByName(input.name);
|
|
76239
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
76240
|
+
return { record: this.add(input), created: true };
|
|
76241
|
+
},
|
|
76242
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
76243
|
+
addMany(inputs) {
|
|
76244
|
+
return tx(() => {
|
|
76245
|
+
const records = [];
|
|
76246
|
+
let created = 0;
|
|
76247
|
+
let updated = 0;
|
|
76248
|
+
for (const input of inputs) {
|
|
76249
|
+
const { record, created: isNew } = this.upsert(input);
|
|
76250
|
+
records.push(record);
|
|
76251
|
+
if (isNew) created += 1;
|
|
76252
|
+
else updated += 1;
|
|
76253
|
+
}
|
|
76254
|
+
return { records, created, updated };
|
|
76255
|
+
});
|
|
76256
|
+
},
|
|
76134
76257
|
add(input) {
|
|
76135
76258
|
const ts = now();
|
|
76136
76259
|
const id2 = newId("skl_");
|
|
@@ -76321,6 +76444,7 @@ var coverLetterRepo = {
|
|
|
76321
76444
|
remove(id2) {
|
|
76322
76445
|
const db = getDb();
|
|
76323
76446
|
return tx(() => {
|
|
76447
|
+
db.prepare(`UPDATE applications SET cover_letter_id=NULL, updated_at=? WHERE cover_letter_id=?`).run(now(), id2);
|
|
76324
76448
|
db.prepare(`DELETE FROM cover_letter_versions WHERE cover_letter_id=?`).run(id2);
|
|
76325
76449
|
return db.prepare(`DELETE FROM cover_letters WHERE id=?`).run(id2).changes > 0;
|
|
76326
76450
|
});
|
|
@@ -76409,6 +76533,7 @@ var jobRepo = {
|
|
|
76409
76533
|
remove(id2) {
|
|
76410
76534
|
const db = getDb();
|
|
76411
76535
|
return tx(() => {
|
|
76536
|
+
db.prepare(`UPDATE cover_letters SET job_id=NULL, updated_at=? WHERE job_id=?`).run(now(), id2);
|
|
76412
76537
|
db.prepare(`DELETE FROM fit_analyses WHERE job_id=?`).run(id2);
|
|
76413
76538
|
db.prepare(`DELETE FROM applications WHERE job_id=?`).run(id2);
|
|
76414
76539
|
db.prepare(`DELETE FROM interview_preps WHERE job_id=?`).run(id2);
|
|
@@ -76607,7 +76732,7 @@ var activityRepo = {
|
|
|
76607
76732
|
};
|
|
76608
76733
|
|
|
76609
76734
|
// packages/mcp-tools/src/tools.ts
|
|
76610
|
-
import
|
|
76735
|
+
import fs7 from "node:fs";
|
|
76611
76736
|
import path7 from "node:path";
|
|
76612
76737
|
|
|
76613
76738
|
// packages/core/src/onboarding.ts
|
|
@@ -76960,7 +77085,7 @@ function styleSignals(text) {
|
|
|
76960
77085
|
}
|
|
76961
77086
|
var DISCLAIMER = "\uC774 \uC810\uAC80\uC740 LLM \uC5C6\uC774 \uC140 \uC218 \uC788\uB294 \uAC83\uB9CC \uBD05\uB2C8\uB2E4(\uC22B\uC790 \uCD9C\uCC98\xB7\uBB38\uCCB4 \uC2E0\uD638). \uD1B5\uACFC=\uD569\uACA9\uC774 \uC544\uB2C8\uBA70, \uC0AC\uC2E4\xB7\uB3D9\uBB38\uC11C\uB2F5\xB7\uC758\uBBF8 \uD310\uB2E8\uC740 \uB2F9\uC2E0(AI)\uC774 \uC9C1\uC811 \uD574\uC57C \uD569\uB2C8\uB2E4.";
|
|
76962
77087
|
function lintArtifact(kind, text, corpus, opts = {}) {
|
|
76963
|
-
const
|
|
77088
|
+
const norm2 = normalizeText(text);
|
|
76964
77089
|
const corpusAvailable = (corpus.documents + corpus.structured).trim().length > 0;
|
|
76965
77090
|
const provenance = analyzeProvenance(text, corpus);
|
|
76966
77091
|
const signals = styleSignals(text);
|
|
@@ -76984,7 +77109,7 @@ function lintArtifact(kind, text, corpus, opts = {}) {
|
|
|
76984
77109
|
}
|
|
76985
77110
|
return {
|
|
76986
77111
|
kind,
|
|
76987
|
-
charCount: [...
|
|
77112
|
+
charCount: [...norm2].length,
|
|
76988
77113
|
signals,
|
|
76989
77114
|
provenance,
|
|
76990
77115
|
blocking,
|
|
@@ -77044,20 +77169,40 @@ function addResume(input) {
|
|
|
77044
77169
|
activityRepo.log("resume_added", `${doc.title} \uBB38\uC11C\uB97C \uCD94\uAC00\uD588\uC2B5\uB2C8\uB2E4.`, "document", doc.id);
|
|
77045
77170
|
return doc;
|
|
77046
77171
|
}
|
|
77047
|
-
function
|
|
77048
|
-
const
|
|
77049
|
-
|
|
77050
|
-
return
|
|
77172
|
+
function batchNames(names) {
|
|
77173
|
+
const shown = names.filter(Boolean).slice(0, 8).join(", ");
|
|
77174
|
+
if (!shown) return "";
|
|
77175
|
+
return `: ${shown}${names.length > 8 ? " \uC678" : ""}`;
|
|
77051
77176
|
}
|
|
77052
|
-
function
|
|
77053
|
-
const
|
|
77054
|
-
activityRepo.log(
|
|
77055
|
-
|
|
77177
|
+
function addExperiences(inputs) {
|
|
77178
|
+
const res = experienceRepo.addMany(inputs);
|
|
77179
|
+
activityRepo.log(
|
|
77180
|
+
"profile_updated",
|
|
77181
|
+
`\uACBD\uB825 ${res.records.length}\uAC74\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4(\uC2E0\uADDC ${res.created} \xB7 \uAC31\uC2E0 ${res.updated})${batchNames(res.records.map((e) => e.company))}.`,
|
|
77182
|
+
"experience",
|
|
77183
|
+
res.records[0]?.id
|
|
77184
|
+
);
|
|
77185
|
+
return res;
|
|
77056
77186
|
}
|
|
77057
|
-
function
|
|
77058
|
-
const
|
|
77059
|
-
activityRepo.log(
|
|
77060
|
-
|
|
77187
|
+
function addProjects(inputs) {
|
|
77188
|
+
const res = projectRepo.addMany(inputs);
|
|
77189
|
+
activityRepo.log(
|
|
77190
|
+
"profile_updated",
|
|
77191
|
+
`\uD504\uB85C\uC81D\uD2B8 ${res.records.length}\uAC74\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4(\uC2E0\uADDC ${res.created} \xB7 \uAC31\uC2E0 ${res.updated})${batchNames(res.records.map((p) => p.name))}.`,
|
|
77192
|
+
"project",
|
|
77193
|
+
res.records[0]?.id
|
|
77194
|
+
);
|
|
77195
|
+
return res;
|
|
77196
|
+
}
|
|
77197
|
+
function addSkills(inputs) {
|
|
77198
|
+
const res = skillRepo.addMany(inputs);
|
|
77199
|
+
activityRepo.log(
|
|
77200
|
+
"profile_updated",
|
|
77201
|
+
`\uAE30\uC220 ${res.records.length}\uAC1C\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4(\uC2E0\uADDC ${res.created} \xB7 \uAC31\uC2E0 ${res.updated})${batchNames(res.records.map((s) => s.name))}.`,
|
|
77202
|
+
"skill",
|
|
77203
|
+
res.records[0]?.id
|
|
77204
|
+
);
|
|
77205
|
+
return res;
|
|
77061
77206
|
}
|
|
77062
77207
|
function saveJobPosting(input, id2) {
|
|
77063
77208
|
const job = jobRepo.upsert(input, id2);
|
|
@@ -77067,7 +77212,7 @@ function saveJobPosting(input, id2) {
|
|
|
77067
77212
|
}
|
|
77068
77213
|
function saveFitAnalysis(input) {
|
|
77069
77214
|
const job = jobRepo.get(input.job_id);
|
|
77070
|
-
if (!job) throw
|
|
77215
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \uACF5\uACE0\uB97C \uC800\uC7A5\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.");
|
|
77071
77216
|
applicationRepo.ensure(job.id, "draft");
|
|
77072
77217
|
const fit = fitRepo.save(input);
|
|
77073
77218
|
const scoreText = fit.score != null ? ` (\uC801\uD569\uB3C4 ${fit.score}\uC810)` : "";
|
|
@@ -77082,7 +77227,7 @@ function saveCoverLetterVersion(input) {
|
|
|
77082
77227
|
const detail = verification.blocking.map((b) => `${b.label}: ${b.detail}`).join("; ");
|
|
77083
77228
|
const strictHit = verification.blocking.some((b) => b.id === "unverified_numbers_strict");
|
|
77084
77229
|
const tail = strictHit ? `\uC5C4\uACA9 \uBAA8\uB4DC\uAC00 \uCF1C\uC838 \uC788\uC5B4, \uC62C\uB9B0 \uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uC5C6\uB294 \uC218\uCE58\uB294 \uB9C9\uD799\uB2C8\uB2E4. \uC774\uB825\uC11C\uB97C \uC62C\uB9AC\uAC70\uB098 \uC5C4\uACA9 \uBAA8\uB4DC\uB97C \uB044\uAC70\uB098, \uC758\uB3C4\uD55C \uAC12\uC774\uBA74 force: true\uB85C \uC800\uC7A5\uD558\uC138\uC694.` : `\uC774 \uC218\uCE58\uB294 \uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\xB7\uD504\uB85C\uC81D\uD2B8\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. \uC6D0\uBCF8 \uB370\uC774\uD130\uC758 \uC2E4\uC81C \uC218\uCE58\uB85C \uACE0\uCE58\uAC70\uB098, \uC758\uB3C4\uD55C \uAC12\uC774 \uB9DE\uB2E4\uBA74 \uBA3C\uC800 \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8\uC5D0 \uADF8 \uC218\uCE58\uB97C \uCD94\uAC00\uD55C \uB4A4 \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694(\uADF8\uB300\uB85C \uC800\uC7A5\uD558\uB824\uBA74 force: true).`;
|
|
77085
|
-
throw new
|
|
77230
|
+
throw new CareerMateError(`\uC800\uC7A5 \uC804 \uC790\uB3D9 \uC810\uAC80\uC5D0\uC11C \uB9C9\uD614\uC2B5\uB2C8\uB2E4 \u2014 ${detail}. ${tail}`, 400, "save_gate");
|
|
77086
77231
|
}
|
|
77087
77232
|
const { coverLetter, version: version2 } = coverLetterRepo.addVersion({
|
|
77088
77233
|
cover_letter_id: input.cover_letter_id,
|
|
@@ -77109,7 +77254,7 @@ function saveCoverLetterVersion(input) {
|
|
|
77109
77254
|
}
|
|
77110
77255
|
function updateApplicationStatus(jobId, status, note) {
|
|
77111
77256
|
const job = jobRepo.get(jobId);
|
|
77112
|
-
if (!job) throw
|
|
77257
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
77113
77258
|
const application = applicationRepo.setStatus(jobId, status, note);
|
|
77114
77259
|
activityRepo.log(
|
|
77115
77260
|
"application_status_changed",
|
|
@@ -77119,17 +77264,17 @@ function updateApplicationStatus(jobId, status, note) {
|
|
|
77119
77264
|
);
|
|
77120
77265
|
const interview_unlocked = INTERVIEW_UNLOCK_STATUSES.includes(status);
|
|
77121
77266
|
const hasPrep = !!interviewRepo.getByJob(jobId);
|
|
77122
|
-
const hint = interview_unlocked && !hasPrep ? "\uC11C\uB958 \uB2E8\uACC4\uB97C \uD1B5\uACFC\uD588\uC5B4\uC694. \uC774 \uACF5\uACE0 \uAE30\uC900\uC73C\uB85C \uC608\uC0C1 \uBA74\uC811 \uC9C8\uBB38\uACFC 1\uBD84 \uC790\uAE30\uC18C\uAC1C\uB97C \uC900\uBE44\uD560\uAE4C\uC694?
|
|
77267
|
+
const hint = interview_unlocked && !hasPrep ? "\uC11C\uB958 \uB2E8\uACC4\uB97C \uD1B5\uACFC\uD588\uC5B4\uC694. \uC774 \uACF5\uACE0 \uAE30\uC900\uC73C\uB85C \uC608\uC0C1 \uBA74\uC811 \uC9C8\uBB38\uACFC 1\uBD84 \uC790\uAE30\uC18C\uAC1C\uB97C \uC900\uBE44\uD560\uAE4C\uC694?" : null;
|
|
77123
77268
|
return { application, job, interview_unlocked, hint };
|
|
77124
77269
|
}
|
|
77125
77270
|
function saveInterviewPrep(input) {
|
|
77126
77271
|
const job = jobRepo.get(input.job_id);
|
|
77127
|
-
if (!job) throw
|
|
77272
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
77128
77273
|
const app = applicationRepo.getByJob(job.id);
|
|
77129
77274
|
if (!app || !INTERVIEW_UNLOCK_STATUSES.includes(app.status)) {
|
|
77130
77275
|
const current = app ? APPLICATION_STATUS_LABELS[app.status] : "\uBBF8\uC9C0\uC6D0";
|
|
77131
|
-
throw
|
|
77132
|
-
`\uBA74\uC811 \uC900\uBE44\uB294 '\uC11C\uB958 \uD569\uACA9' \uC774\uC0C1 \uC0C1\uD0DC\uC5D0\uC11C\uB9CC \uC800\uC7A5\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uC0C1\uD0DC: '${current}'. \uBA3C\uC800
|
|
77276
|
+
throw conflict(
|
|
77277
|
+
`\uBA74\uC811 \uC900\uBE44\uB294 '\uC11C\uB958 \uD569\uACA9' \uC774\uC0C1 \uC0C1\uD0DC\uC5D0\uC11C\uB9CC \uC800\uC7A5\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uC0C1\uD0DC: '${current}'. \uBA3C\uC800 \uC9C0\uC6D0 \uC0C1\uD0DC\uB97C '\uC11C\uB958 \uD569\uACA9' \uC774\uC0C1\uC73C\uB85C \uBC14\uAFBC \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.`
|
|
77133
77278
|
);
|
|
77134
77279
|
}
|
|
77135
77280
|
const prep = interviewRepo.save(input);
|
|
@@ -77209,7 +77354,7 @@ var WORKFLOWS = [
|
|
|
77209
77354
|
'\uD30C\uC77C \uC785\uB825 \uBD84\uAE30: \u2460 \uC0AC\uC6A9\uC790\uAC00 "\uD30C\uC77C\uC774 \uC788\uB2E4"\uACE0 \uD558\uBA74 `open_inbox`\uB85C \uC778\uC785 \uD3F4\uB354\uB97C \uC5F4\uC5B4 \uD30C\uC77C\uC744 \uB123\uAC8C \uD558\uACE0, "\uB2E4 \uB123\uC5C8\uB2E4"\uACE0 \uD558\uBA74 `read_inbox`\uB85C \uBCF8\uBB38\uC744 \uC77D\uB294\uB2E4(pdf\xB7\uC774\uBBF8\uC9C0\uB294 read_inbox\uAC00 \uACBD\uB85C\uB9CC \uC8FC\uBBC0\uB85C \uD074\uB77C\uC774\uC5B8\uD2B8\uC758 \uD30C\uC77C \uC77D\uAE30\uB85C \uC9C1\uC811 \uC77D\uB294\uB2E4). \u2461 \uC0AC\uC6A9\uC790\uAC00 \uD30C\uC77C \uACBD\uB85C\uB97C \uC9C1\uC811 \uC54C\uB824\uC8FC\uBA74 `read_document`\uB85C \uC77D\uB294\uB2E4. \u2462 "\uC5C6\uB2E4/\uC9C1\uC811 \uC785\uB825/\uD14D\uC2A4\uD2B8\uB85C \uBD99\uC5EC\uB123\uAE30"\uBA74 \uD3F4\uB354\uB97C \uC5F4\uC9C0 \uB9D0\uACE0 \uBC1B\uC740 \uD14D\uC2A4\uD2B8\uB97C \uADF8\uB300\uB85C \uC4F4\uB2E4. (\uBB3B\uC9C0\uB3C4 \uC54A\uACE0 open_inbox\uB85C \uD3F4\uB354\uB97C \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uC54A\uB294\uB2E4.)',
|
|
77210
77355
|
"\uC218\uC9D1\uD55C \uC815\uBCF4\uB97C \uAD6C\uC870\uD654\uD574 `save_profile`\uB85C \uC800\uC7A5\uD55C\uB2E4(\uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7headline\xB7summary\xB7desired_roles\xB7desired_conditions, \uADF8\uB9AC\uACE0 \uAE00\uC4F0\uAE30 \uC120\uD638\uC778 preferred_tone\uACFC emphasis_points \uD3EC\uD568). \uD30C\uC77C \uCD9C\uCC98\uB294 source=upload, \uC9C1\uC811 \uC785\uB825\uC740 manual.",
|
|
77211
77356
|
"\uC5C5\uB85C\uB4DC\uD55C \uC774\uB825\uC11C/\uACBD\uB825\uAE30\uC220\uC11C/\uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uBCF8\uBB38\uC744 `add_resume`\uB85C \uC800\uC7A5\uD55C\uB2E4(kind\xB7title \uC9C0\uC815, \uB300\uD45C \uBB38\uC11C\uB294 is_primary=true).",
|
|
77212
|
-
"\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC\uC774 \uD30C\uC545\uB418\uBA74 `add_experience`\xB7`add_project`\xB7`add_skill`\uB85C \
|
|
77357
|
+
"\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC\uC774 \uD30C\uC545\uB418\uBA74 `add_experience`\xB7`add_project`\xB7`add_skill`\uB85C \uC800\uC7A5\uD55C\uB2E4 \u2014 \uAC01 \uB3C4\uAD6C\uB294 \uBC30\uC5F4\uC744 \uBC1B\uC73C\uBBC0\uB85C \uD30C\uC545\uD55C \uD56D\uBAA9\uC744 \uD55C \uBC88\uC5D0 \uBAA8\uC544 \uB118\uAE34\uB2E4(\uD56D\uBAA9\uB9C8\uB2E4 \uBC18\uBCF5 \uD638\uCD9C\uD558\uC9C0 \uC54A\uB294\uB2E4). \uAC19\uC740 \uD56D\uBAA9\uC744 \uB2E4\uC2DC \uB123\uC5B4\uB3C4 \uC911\uBCF5 \uC5C6\uC774 \uAC31\uC2E0\uB41C\uB2E4(\uC644\uC131\uB3C4\uC758 has_experience/has_skills\uC5D0 \uBC18\uC601).",
|
|
77213
77358
|
"\uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C\uAC00 \uC788\uC73C\uBA74 `save_cover_letter_version`\uC73C\uB85C \uC800\uC7A5\uD55C\uB2E4(title+content\uBA74 v1\uB85C \uC800\uC7A5, \uC5C6\uC73C\uBA74 \uB098\uC911\uC5D0 \uC791\uC131 \uAC00\uB2A5\uD568\uC744 \uC548\uB0B4).",
|
|
77214
77359
|
"`open_dashboard`\uB97C \uD638\uCD9C\uD574 \uC0AC\uC6A9\uC790\uAC00 \uC790\uAE30 \uB370\uC774\uD130\uB97C \uD655\uC778\uD558\uAC8C \uD55C\uB2E4.",
|
|
77215
77360
|
"\uB2E4\uC2DC `get_onboarding_status`\uB85C \uC644\uC131\uB3C4\uB97C \uD655\uC778\uD558\uACE0, \uB2E4\uC74C \uB2E8\uACC4(\uACF5\uACE0 \uBD84\uC11D \uB4F1)\uB97C \uC81C\uC548\uD55C\uB2E4."
|
|
@@ -77227,8 +77372,8 @@ var WORKFLOWS = [
|
|
|
77227
77372
|
"\uC544\uC9C1 \uC800\uC7A5\uB418\uC9C0 \uC54A\uC740 \uACF5\uACE0\uB77C\uBA74 `save_job_posting`\uC73C\uB85C \uACF5\uACE0\uB97C \uC800\uC7A5\uD558\uACE0 job_id\uB97C \uD655\uBCF4\uD55C\uB2E4.",
|
|
77228
77373
|
"\uB3C4\uCD9C\uD55C \uBD84\uC11D \uACB0\uACFC\uB97C `save_fit_analysis`\uB85C \uC800\uC7A5\uD55C\uB2E4(job_id, score, summary, strengths, gaps, matched_keywords, missing_keywords, recommendations).",
|
|
77229
77374
|
"\uBD84\uC11D \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC124\uBA85\uD55C\uB2E4(\uC798 \uB9DE\uB294 \uC810, \uBCF4\uC644\uD560 \uC810, \uCD94\uCC9C \uC804\uB7B5). \uAE30\uC220 \uC6A9\uC5B4\uB294 \uBE7C\uACE0 \uC804\uB2EC\uD55C\uB2E4.",
|
|
77230
|
-
'"\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?"\uB77C\uACE0 \uC790\uAE30\uC18C\uAC1C\uC11C \
|
|
77231
|
-
'\uC0AC\uC6A9\uC790\uAC00 \
|
|
77375
|
+
'\uBD84\uC11D \uB4A4 \uACE7\uC7A5 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC4F0\uC9C0 \uB9D0\uACE0, "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?"\uB77C\uACE0 \uBB3B\uACE0 \uC120\uD0DD\uC9C0\uB97C \uC81C\uC2DC\uD55C\uB2E4: \u2460 "\uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918" \u2461 "\uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918".',
|
|
77376
|
+
'\uC0AC\uC6A9\uC790\uAC00 \u2460\uC744 \uC120\uD0DD\uD558\uBA74 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC791\uC131\uD558\uAE30 \uC9C1\uC804\uC5D0 `get_writing_style_guide`\uB97C \uD638\uCD9C\uD574 "AI \uD2F0 \uC548 \uB098\uB294 \uAE00\uC4F0\uAE30 \uADDC\uCE59"\uC744 \uAC00\uC838\uC628\uB2E4. \u2461\uB97C \uC120\uD0DD\uD558\uBA74 \uC790\uC18C\uC11C \uC791\uC131 \uC5C6\uC774 \uBA48\uCD94\uACE0 \uC800\uC7A5 \uACB0\uACFC\uC640 \uB300\uC2DC\uBCF4\uB4DC \uD655\uC778\uB9CC \uC548\uB0B4\uD55C\uB2E4.',
|
|
77232
77377
|
"\uC801\uD569\uB3C4 \uBD84\uC11D\xB7\uAE00\uC4F0\uAE30 \uC120\uD638\uC640 \uAE00\uC4F0\uAE30 \uADDC\uCE59\uC744 \uD568\uAED8 \uBC18\uC601\uD574 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC791\uC131\uD558\uACE0(\uBC88\uC5ED\uD22C\xB7\uD074\uB9AC\uC170\xB7\uAE30\uACC4\uC801 \uBCD1\uB82C \uC81C\uAC70, \uC0AC\uC2E4\xB7\uC218\uCE58\uB294 \uADF8\uB300\uB85C), `save_cover_letter_version`\uC73C\uB85C \uC800\uC7A5\uD55C\uB2E4(job_id \uC5F0\uACB0, note\uC5D0 \uC791\uC131 \uC758\uB3C4 \uC694\uC57D).",
|
|
77233
77378
|
"`open_application`\uC73C\uB85C \uD574\uB2F9 \uC9C0\uC6D0 \uAC74\uC744 \uC5F4\uC5B4 \uC0AC\uC6A9\uC790\uAC00 \uACB0\uACFC\uB97C \uD655\uC778\uD558\uAC8C \uD558\uACE0, \uC9C0\uC6D0 \uC0C1\uD0DC \uBCC0\uACBD(\uC608: \uC9C0\uC6D0 \uC608\uC815/\uC9C0\uC6D0 \uC644\uB8CC)\uC744 \uC81C\uC548\uD55C\uB2E4."
|
|
77234
77379
|
]
|
|
@@ -78496,14 +78641,94 @@ function fail(text) {
|
|
|
78496
78641
|
}
|
|
78497
78642
|
|
|
78498
78643
|
// packages/mcp-tools/src/bridge.ts
|
|
78499
|
-
import { spawn } from "node:child_process";
|
|
78644
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
78645
|
+
import fs5 from "node:fs";
|
|
78500
78646
|
import path5 from "node:path";
|
|
78501
78647
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
78502
78648
|
var __dirname = path5.dirname(fileURLToPath2(import.meta.url));
|
|
78503
78649
|
var REPO_ROOT = path5.resolve(__dirname, "..", "..", "..");
|
|
78504
|
-
|
|
78650
|
+
var HEALTH_TIMEOUT_MS = 800;
|
|
78651
|
+
var pendingStart = null;
|
|
78652
|
+
function dashboardLogPath() {
|
|
78653
|
+
return path5.join(getDataDir(), "server.log");
|
|
78654
|
+
}
|
|
78655
|
+
function launchdPlistPath() {
|
|
78656
|
+
return path5.join(getDataDir(), "dashboard.launchd.plist");
|
|
78657
|
+
}
|
|
78658
|
+
function launchdLabel() {
|
|
78659
|
+
let hash = 5381;
|
|
78660
|
+
for (const ch of getDataDir()) hash = (hash * 33 ^ ch.charCodeAt(0)) >>> 0;
|
|
78661
|
+
return `life.careermate.dashboard.${hash.toString(16)}`;
|
|
78662
|
+
}
|
|
78663
|
+
function xmlEscape(value) {
|
|
78664
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
78665
|
+
}
|
|
78666
|
+
function plistString(key, value) {
|
|
78667
|
+
return ` <key>${xmlEscape(key)}</key>
|
|
78668
|
+
<string>${xmlEscape(value)}</string>`;
|
|
78669
|
+
}
|
|
78670
|
+
function renderLaunchdPlist(bin, args, cwd, log) {
|
|
78671
|
+
const env2 = {
|
|
78672
|
+
CAREERMATE_DATA_DIR: getDataDir(),
|
|
78673
|
+
CAREERMATE_NO_OPEN: "1"
|
|
78674
|
+
};
|
|
78675
|
+
if (process.env.CAREERMATE_PORT) env2.CAREERMATE_PORT = process.env.CAREERMATE_PORT;
|
|
78676
|
+
if (process.env.PATH) env2.PATH = process.env.PATH;
|
|
78677
|
+
const programArgs = [bin, ...args].map((arg) => ` <string>${xmlEscape(arg)}</string>`).join("\n");
|
|
78678
|
+
const envEntries = Object.entries(env2).map(([key, value]) => `${plistString(key, value)}`).join("\n");
|
|
78679
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
78680
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
78681
|
+
<plist version="1.0">
|
|
78682
|
+
<dict>
|
|
78683
|
+
<key>Label</key>
|
|
78684
|
+
<string>${xmlEscape(launchdLabel())}</string>
|
|
78685
|
+
<key>ProgramArguments</key>
|
|
78686
|
+
<array>
|
|
78687
|
+
${programArgs}
|
|
78688
|
+
</array>
|
|
78689
|
+
<key>WorkingDirectory</key>
|
|
78690
|
+
<string>${xmlEscape(cwd)}</string>
|
|
78691
|
+
<key>EnvironmentVariables</key>
|
|
78692
|
+
<dict>
|
|
78693
|
+
${envEntries}
|
|
78694
|
+
</dict>
|
|
78695
|
+
<key>RunAtLoad</key>
|
|
78696
|
+
<true/>
|
|
78697
|
+
<key>KeepAlive</key>
|
|
78698
|
+
<false/>
|
|
78699
|
+
<key>StandardOutPath</key>
|
|
78700
|
+
<string>${xmlEscape(log)}</string>
|
|
78701
|
+
<key>StandardErrorPath</key>
|
|
78702
|
+
<string>${xmlEscape(log)}</string>
|
|
78703
|
+
</dict>
|
|
78704
|
+
</plist>
|
|
78705
|
+
`;
|
|
78706
|
+
}
|
|
78707
|
+
function delay(ms) {
|
|
78708
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
78709
|
+
}
|
|
78710
|
+
async function pingDashboard(url, timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
78711
|
+
const controller = new AbortController();
|
|
78712
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
78713
|
+
timer.unref?.();
|
|
78714
|
+
try {
|
|
78715
|
+
const healthUrl = new URL("/api/health", url);
|
|
78716
|
+
const res = await fetch(healthUrl, {
|
|
78717
|
+
signal: controller.signal,
|
|
78718
|
+
headers: { accept: "application/json" }
|
|
78719
|
+
});
|
|
78720
|
+
if (!res.ok) return false;
|
|
78721
|
+
const body = await res.json().catch(() => null);
|
|
78722
|
+
return body?.ok === true;
|
|
78723
|
+
} catch {
|
|
78724
|
+
return false;
|
|
78725
|
+
} finally {
|
|
78726
|
+
clearTimeout(timer);
|
|
78727
|
+
}
|
|
78728
|
+
}
|
|
78729
|
+
async function liveServer() {
|
|
78505
78730
|
const info3 = readRuntimeInfo();
|
|
78506
|
-
if (info3 && isProcessAlive(info3.pid)) return info3;
|
|
78731
|
+
if (info3 && isProcessAlive(info3.pid) && await pingDashboard(info3.url)) return info3;
|
|
78507
78732
|
return null;
|
|
78508
78733
|
}
|
|
78509
78734
|
function spawnDetached(cmd, args, opts = {}) {
|
|
@@ -78512,19 +78737,101 @@ function spawnDetached(cmd, args, opts = {}) {
|
|
|
78512
78737
|
child.on("error", () => {
|
|
78513
78738
|
});
|
|
78514
78739
|
child.unref();
|
|
78740
|
+
return child.pid ?? null;
|
|
78515
78741
|
} catch {
|
|
78742
|
+
return null;
|
|
78516
78743
|
}
|
|
78517
78744
|
}
|
|
78745
|
+
function spawnViaLaunchd(bin, args, cwd, log) {
|
|
78746
|
+
if (process.platform !== "darwin" || process.env.CAREERMATE_LAUNCHER === "detached") return false;
|
|
78747
|
+
if (typeof process.getuid !== "function") return false;
|
|
78748
|
+
const domain = `gui/${process.getuid()}`;
|
|
78749
|
+
const label = launchdLabel();
|
|
78750
|
+
const plist = launchdPlistPath();
|
|
78751
|
+
try {
|
|
78752
|
+
fs5.writeFileSync(plist, renderLaunchdPlist(bin, args, cwd, log), "utf8");
|
|
78753
|
+
spawnSync("launchctl", ["bootout", `${domain}/${label}`], { stdio: "ignore" });
|
|
78754
|
+
const res = spawnSync("launchctl", ["bootstrap", domain, plist], {
|
|
78755
|
+
encoding: "utf8",
|
|
78756
|
+
timeout: 5e3
|
|
78757
|
+
});
|
|
78758
|
+
if (res.status === 0) return true;
|
|
78759
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchctl bootstrap failed: ${res.stderr || res.stdout || res.status}
|
|
78760
|
+
`);
|
|
78761
|
+
} catch (e) {
|
|
78762
|
+
try {
|
|
78763
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchctl launch failed: ${e instanceof Error ? e.message : String(e)}
|
|
78764
|
+
`);
|
|
78765
|
+
} catch {
|
|
78766
|
+
}
|
|
78767
|
+
}
|
|
78768
|
+
return false;
|
|
78769
|
+
}
|
|
78770
|
+
function spawnDashboardDetached(bin, args, cwd, logFd) {
|
|
78771
|
+
spawnDetached(bin, args, {
|
|
78772
|
+
cwd,
|
|
78773
|
+
env: { ...process.env, CAREERMATE_NO_OPEN: "1" },
|
|
78774
|
+
stdio: logFd === null ? "ignore" : ["ignore", logFd, logFd]
|
|
78775
|
+
});
|
|
78776
|
+
}
|
|
78518
78777
|
async function ensureServer(timeoutMs = 12e3) {
|
|
78519
|
-
const existing = liveServer();
|
|
78778
|
+
const existing = await liveServer();
|
|
78520
78779
|
if (existing) return { url: existing.url };
|
|
78521
|
-
|
|
78522
|
-
|
|
78780
|
+
if (pendingStart) return pendingStart;
|
|
78781
|
+
pendingStart = startServerBackground(timeoutMs);
|
|
78782
|
+
try {
|
|
78783
|
+
return await pendingStart;
|
|
78784
|
+
} finally {
|
|
78785
|
+
pendingStart = null;
|
|
78786
|
+
}
|
|
78787
|
+
}
|
|
78788
|
+
async function startServerBackground(timeoutMs) {
|
|
78789
|
+
const [bin, args, cwd] = BUNDLED ? [process.execPath, ["--experimental-sqlite", path5.join(__dirname, "web.mjs")], __dirname] : [
|
|
78790
|
+
process.execPath,
|
|
78791
|
+
["--no-warnings", "--experimental-sqlite", "--import", "tsx", path5.join(REPO_ROOT, "apps/web/src/index.ts")],
|
|
78792
|
+
REPO_ROOT
|
|
78793
|
+
];
|
|
78794
|
+
const log = dashboardLogPath();
|
|
78795
|
+
let logFd = null;
|
|
78796
|
+
try {
|
|
78797
|
+
logFd = fs5.openSync(log, "a");
|
|
78798
|
+
fs5.writeSync(logFd, `
|
|
78799
|
+
[${(/* @__PURE__ */ new Date()).toISOString()}] CareerMate dashboard background launch
|
|
78800
|
+
`);
|
|
78801
|
+
} catch {
|
|
78802
|
+
logFd = null;
|
|
78803
|
+
}
|
|
78804
|
+
let launchedViaLaunchd = false;
|
|
78805
|
+
try {
|
|
78806
|
+
launchedViaLaunchd = spawnViaLaunchd(bin, args, cwd, log);
|
|
78807
|
+
if (!launchedViaLaunchd) spawnDashboardDetached(bin, args, cwd, logFd);
|
|
78808
|
+
} finally {
|
|
78809
|
+
if (logFd !== null) {
|
|
78810
|
+
try {
|
|
78811
|
+
fs5.closeSync(logFd);
|
|
78812
|
+
} catch {
|
|
78813
|
+
}
|
|
78814
|
+
}
|
|
78815
|
+
}
|
|
78523
78816
|
const start = Date.now();
|
|
78524
78817
|
while (Date.now() - start < timeoutMs) {
|
|
78525
|
-
const info3 = liveServer();
|
|
78818
|
+
const info3 = await liveServer();
|
|
78526
78819
|
if (info3) return { url: info3.url };
|
|
78527
|
-
await
|
|
78820
|
+
await delay(300);
|
|
78821
|
+
}
|
|
78822
|
+
if (launchedViaLaunchd) {
|
|
78823
|
+
try {
|
|
78824
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchd did not produce a healthy server; falling back to detached spawn
|
|
78825
|
+
`);
|
|
78826
|
+
} catch {
|
|
78827
|
+
}
|
|
78828
|
+
spawnDashboardDetached(bin, args, cwd, null);
|
|
78829
|
+
const fallbackStart = Date.now();
|
|
78830
|
+
while (Date.now() - fallbackStart < Math.min(timeoutMs, 8e3)) {
|
|
78831
|
+
const info3 = await liveServer();
|
|
78832
|
+
if (info3) return { url: info3.url };
|
|
78833
|
+
await delay(300);
|
|
78834
|
+
}
|
|
78528
78835
|
}
|
|
78529
78836
|
return null;
|
|
78530
78837
|
}
|
|
@@ -78548,7 +78855,7 @@ function openInFileManager(dir) {
|
|
|
78548
78855
|
else openOsTarget(dir);
|
|
78549
78856
|
}
|
|
78550
78857
|
async function resolveDashboardUrl(hash = "") {
|
|
78551
|
-
const live = liveServer();
|
|
78858
|
+
const live = await liveServer();
|
|
78552
78859
|
if (live) return { url: live.url + hash, running: true };
|
|
78553
78860
|
const started = await ensureServer();
|
|
78554
78861
|
if (started) return { url: started.url + hash, running: true };
|
|
@@ -78556,7 +78863,7 @@ async function resolveDashboardUrl(hash = "") {
|
|
|
78556
78863
|
}
|
|
78557
78864
|
|
|
78558
78865
|
// packages/mcp-tools/src/update.ts
|
|
78559
|
-
import
|
|
78866
|
+
import fs6 from "node:fs";
|
|
78560
78867
|
import path6 from "node:path";
|
|
78561
78868
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
78562
78869
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -78613,14 +78920,14 @@ function comparePrerelease(a, b) {
|
|
|
78613
78920
|
}
|
|
78614
78921
|
function readCache() {
|
|
78615
78922
|
try {
|
|
78616
|
-
return JSON.parse(
|
|
78923
|
+
return JSON.parse(fs6.readFileSync(cacheFile(), "utf8"));
|
|
78617
78924
|
} catch {
|
|
78618
78925
|
return null;
|
|
78619
78926
|
}
|
|
78620
78927
|
}
|
|
78621
78928
|
function writeCache(c) {
|
|
78622
78929
|
try {
|
|
78623
|
-
|
|
78930
|
+
fs6.writeFileSync(cacheFile(), JSON.stringify(c), "utf8");
|
|
78624
78931
|
} catch {
|
|
78625
78932
|
}
|
|
78626
78933
|
}
|
|
@@ -78777,16 +79084,18 @@ async function runSelfUpdate() {
|
|
|
78777
79084
|
ok: true,
|
|
78778
79085
|
from,
|
|
78779
79086
|
to: latest,
|
|
78780
|
-
message: `
|
|
79087
|
+
message: `CareerMate\uB97C ${latest ? `v${latest}` : "\uCD5C\uC2E0 \uBC84\uC804"}(\uC73C)\uB85C \uC5C5\uB370\uC774\uD2B8\uD588\uC2B5\uB2C8\uB2E4. \uC801\uC6A9\uD558\uB824\uBA74 AI \uC571(\uB610\uB294 MCP \uC5F0\uACB0)\uC744 \uC7AC\uC2DC\uC791\uD558\uC138\uC694. \uC7AC\uC2DC\uC791 \uC2DC \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB294 \uC790\uB3D9\uC73C\uB85C \uB9C8\uC774\uADF8\uB808\uC774\uC158\uB418\uBA70 \uAE30\uC874 \uB370\uC774\uD130\uB294 \uBCF4\uC874\uB429\uB2C8\uB2E4.`
|
|
78781
79088
|
};
|
|
78782
79089
|
}
|
|
78783
79090
|
|
|
78784
79091
|
// packages/mcp-tools/src/tools.ts
|
|
78785
79092
|
var STATUS_LIST = APPLICATION_STATUSES.map((s) => `${s}(${APPLICATION_STATUS_LABELS[s]})`).join(", ");
|
|
79093
|
+
var DELETE_CONFIRMATION = "DELETE";
|
|
79094
|
+
var DASHBOARD_URL = "http://127.0.0.1:4319";
|
|
78786
79095
|
function listInboxFiles(dir) {
|
|
78787
79096
|
let names;
|
|
78788
79097
|
try {
|
|
78789
|
-
names =
|
|
79098
|
+
names = fs7.readdirSync(dir);
|
|
78790
79099
|
} catch {
|
|
78791
79100
|
return [];
|
|
78792
79101
|
}
|
|
@@ -78796,7 +79105,7 @@ function listInboxFiles(dir) {
|
|
|
78796
79105
|
if (SKIP.test(name)) continue;
|
|
78797
79106
|
const p = path7.join(dir, name);
|
|
78798
79107
|
try {
|
|
78799
|
-
if (
|
|
79108
|
+
if (fs7.statSync(p).isFile()) out.push({ name, path: p });
|
|
78800
79109
|
} catch {
|
|
78801
79110
|
}
|
|
78802
79111
|
}
|
|
@@ -78959,9 +79268,17 @@ ${lines}`;
|
|
|
78959
79268
|
if (upd.update_available) {
|
|
78960
79269
|
text += `
|
|
78961
79270
|
|
|
78962
|
-
\
|
|
78963
|
-
}
|
|
78964
|
-
return ok(text, {
|
|
79271
|
+
\uC0C8 \uBC84\uC804 v${upd.latest}\uC774 \uB098\uC654\uC2B5\uB2C8\uB2E4(\uD604\uC7AC v${upd.current}). \uC0AC\uC6A9\uC790\uAC00 \uC6D0\uD558\uBA74 \uBC14\uB85C \uC5C5\uB370\uC774\uD2B8\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC5C5\uB370\uC774\uD2B8 \uD6C4\uC5D0\uB294 AI \uC571 \uB610\uB294 MCP \uC5F0\uACB0\uC744 \uC7AC\uC2DC\uC791\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.`;
|
|
79272
|
+
}
|
|
79273
|
+
return ok(text, {
|
|
79274
|
+
...s,
|
|
79275
|
+
verify_strict: strict,
|
|
79276
|
+
update: upd,
|
|
79277
|
+
suggested_next_action: upd.update_available ? {
|
|
79278
|
+
prompt: `\uC0C8 \uBC84\uC804 v${upd.latest}\uC774 \uB098\uC654\uC2B5\uB2C8\uB2E4. \uC9C0\uAE08 \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694?`,
|
|
79279
|
+
next_tool: "update_careermate"
|
|
79280
|
+
} : null
|
|
79281
|
+
});
|
|
78965
79282
|
}
|
|
78966
79283
|
},
|
|
78967
79284
|
/* --------------------------------------------------------------- profile */
|
|
@@ -79018,11 +79335,12 @@ ${lines}`;
|
|
|
79018
79335
|
{
|
|
79019
79336
|
name: "add_experience",
|
|
79020
79337
|
title: "\uACBD\uB825 \uCD94\uAC00",
|
|
79021
|
-
description: "\uAD6C\uC870\uD654\uB41C \uACBD\uB825(\uC9C1\uC7A5 \uB2E8\uC704)\uC744 \
|
|
79022
|
-
inputSchema:
|
|
79338
|
+
description: "\uAD6C\uC870\uD654\uB41C \uACBD\uB825(\uC9C1\uC7A5 \uB2E8\uC704)\uC744 \uC800\uC7A5\uD569\uB2C8\uB2E4. \uC774\uB825\uC11C\uC5D0\uC11C \uD30C\uC545\uD55C \uACBD\uB825\uC744 experiences \uBC30\uC5F4\uC5D0 \uD55C \uBC88\uC5D0 \uB2F4\uC544 \uD638\uCD9C\uD558\uC138\uC694(\uD55C \uAC74\uC774\uC5B4\uB3C4 \uBC30\uC5F4\uB85C \u2014 \uD56D\uBAA9\uB9C8\uB2E4 \uB3C4\uAD6C\uB97C \uBC18\uBCF5 \uD638\uCD9C\uD558\uC9C0 \uB9C8\uC138\uC694). \uC774\uB825\uC11C \uBCF8\uBB38(add_resume)\uACFC \uB2EC\uB9AC \uD68C\uC0AC\xB7\uC9C1\uBB34\xB7\uAE30\uAC04\xB7\uC131\uACFC\uB97C \uD544\uB4DC\uB85C \uB098\uB220 \uC800\uC7A5\uD574 \uC801\uD569\uB3C4 \uBD84\uC11D/\uC790\uC18C\uC11C \uC791\uC131 \uC2DC \uC815\uBC00\uD558\uAC8C \uD65C\uC6A9\uB429\uB2C8\uB2E4. \uAC01 \uD56D\uBAA9\uC740 company\uAC00 \uD544\uC218\uC774\uBA70, achievements\uC5D0\uB294 \uC815\uB7C9 \uC9C0\uD45C\uAC00 \uB2F4\uAE34 \uC131\uACFC\uB97C, tech\uC5D0\uB294 \uC0AC\uC6A9 \uAE30\uC220\uC744 \uBC30\uC5F4\uB85C \uB123\uC73C\uC138\uC694. \uAC19\uC740 \uD68C\uC0AC\xB7\uC9C1\uBB34\xB7\uC785\uC0AC\uC77C(start_date)\uC774 \uC77C\uCE58\uD558\uBA74 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC73C\uB2C8 \uC5EC\uB7EC \uBC88 \uC800\uC7A5\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4. \uC628\uBCF4\uB529 \uC644\uC131\uB3C4(get_onboarding_status)\uC758 has_experience\uB97C \uCC44\uC6B0\uB824\uBA74 1\uAC74 \uC774\uC0C1 \uCD94\uAC00\uD558\uC138\uC694.",
|
|
79339
|
+
inputSchema: ExperienceBatchInputSchema.shape,
|
|
79023
79340
|
handler: (args) => {
|
|
79024
|
-
const
|
|
79025
|
-
|
|
79341
|
+
const { records, created, updated } = addExperiences(args.experiences);
|
|
79342
|
+
const names = records.map((e) => `${e.company}${e.role ? ` \xB7 ${e.role}` : ""}`).join(", ");
|
|
79343
|
+
return ok(`\uACBD\uB825 ${records.length}\uAC74\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4 (\uC2E0\uADDC ${created} \xB7 \uAC31\uC2E0 ${updated}): ${names}`, records);
|
|
79026
79344
|
}
|
|
79027
79345
|
},
|
|
79028
79346
|
{
|
|
@@ -79040,11 +79358,12 @@ ${lines}`;
|
|
|
79040
79358
|
{
|
|
79041
79359
|
name: "add_project",
|
|
79042
79360
|
title: "\uD504\uB85C\uC81D\uD2B8 \uCD94\uAC00",
|
|
79043
|
-
description: "\uB300\uD45C \uD504\uB85C\uC81D\uD2B8\uB97C \
|
|
79044
|
-
inputSchema:
|
|
79361
|
+
description: "\uB300\uD45C \uD504\uB85C\uC81D\uD2B8\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. projects \uBC30\uC5F4\uC5D0 \uC5EC\uB7EC \uAC1C\uB97C \uD55C \uBC88\uC5D0 \uB2F4\uC544 \uD638\uCD9C\uD558\uC138\uC694(\uD55C \uAC1C\uC5EC\uB3C4 \uBC30\uC5F4\uB85C \u2014 \uD56D\uBAA9\uB9C8\uB2E4 \uBC18\uBCF5 \uD638\uCD9C\uD558\uC9C0 \uB9C8\uC138\uC694). \uAC01 \uD56D\uBAA9\uC740 name\uC774 \uD544\uC218\uC774\uBA70, highlights(\uD575\uC2EC \uC131\uACFC)\uC640 tech(\uC0AC\uC6A9 \uAE30\uC220)\uB97C \uBC30\uC5F4\uB85C \uB123\uC73C\uBA74 \uC790\uC18C\uC11C\xB7\uBA74\uC811 \uC900\uBE44\uC5D0\uC11C \uADFC\uAC70\uB85C \uD65C\uC6A9\uB429\uB2C8\uB2E4. url\uC5D0 \uACB0\uACFC\uBB3C \uB9C1\uD06C\uB97C \uB123\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uAC19\uC740 \uC774\uB984\uC758 \uD504\uB85C\uC81D\uD2B8\uB294 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC73C\uB2C8 \uC5EC\uB7EC \uBC88 \uC800\uC7A5\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4.",
|
|
79362
|
+
inputSchema: ProjectBatchInputSchema.shape,
|
|
79045
79363
|
handler: (args) => {
|
|
79046
|
-
const
|
|
79047
|
-
|
|
79364
|
+
const { records, created, updated } = addProjects(args.projects);
|
|
79365
|
+
const names = records.map((p) => p.name).join(", ");
|
|
79366
|
+
return ok(`\uD504\uB85C\uC81D\uD2B8 ${records.length}\uAC74\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4 (\uC2E0\uADDC ${created} \xB7 \uAC31\uC2E0 ${updated}): ${names}`, records);
|
|
79048
79367
|
}
|
|
79049
79368
|
},
|
|
79050
79369
|
{
|
|
@@ -79062,11 +79381,12 @@ ${lines}`;
|
|
|
79062
79381
|
{
|
|
79063
79382
|
name: "add_skill",
|
|
79064
79383
|
title: "\uAE30\uC220\uC2A4\uD0DD \uCD94\uAC00",
|
|
79065
|
-
description: "\uBCF4\uC720 \uAE30\uC220\uC2A4\uD0DD\uC744 \
|
|
79066
|
-
inputSchema:
|
|
79384
|
+
description: "\uBCF4\uC720 \uAE30\uC220\uC2A4\uD0DD\uC744 \uC800\uC7A5\uD569\uB2C8\uB2E4. \uC5EC\uB7EC \uAC1C\uB97C skills \uBC30\uC5F4\uC5D0 \uD55C \uBC88\uC5D0 \uB2F4\uC544 \uD638\uCD9C\uD558\uC138\uC694(\uD55C \uAC1C\uC5EC\uB3C4 \uBC30\uC5F4\uB85C \u2014 \uAE30\uC220\uB9C8\uB2E4 \uB3C4\uAD6C\uB97C \uBC18\uBCF5 \uD638\uCD9C\uD558\uC9C0 \uB9C8\uC138\uC694). \uAC01 \uD56D\uBAA9\uC740 name\uC774 \uD544\uC218\uC774\uBA70, category(\uC5B8\uC5B4/\uD504\uB808\uC784\uC6CC\uD06C/\uD234/\uC18C\uD504\uD2B8\uC2A4\uD0AC \uB4F1)\xB7level\xB7years\uB85C \uC219\uB828\uB3C4\uB97C \uD568\uAED8 \uAE30\uB85D\uD558\uBA74 \uACF5\uACE0 \uD0A4\uC6CC\uB4DC \uB9E4\uCE6D\uC774 \uC815\uD655\uD574\uC9D1\uB2C8\uB2E4. \uAC19\uC740 \uC774\uB984\uC758 \uAE30\uC220\uC740 \uAC31\uC2E0\uB418\uACE0 \uC911\uBCF5 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC73C\uB2C8 \uC5EC\uB7EC \uBC88 \uC800\uC7A5\uD574\uB3C4 \uC548\uC804\uD569\uB2C8\uB2E4. \uC628\uBCF4\uB529 \uC644\uC131\uB3C4\uC758 has_skills\uB97C \uCC44\uC6B0\uB824\uBA74 1\uAC1C \uC774\uC0C1 \uCD94\uAC00\uD558\uC138\uC694.",
|
|
79385
|
+
inputSchema: SkillBatchInputSchema.shape,
|
|
79067
79386
|
handler: (args) => {
|
|
79068
|
-
const
|
|
79069
|
-
|
|
79387
|
+
const { records, created, updated } = addSkills(args.skills);
|
|
79388
|
+
const names = records.map((s) => s.name).join(", ");
|
|
79389
|
+
return ok(`\uAE30\uC220 ${records.length}\uAC1C\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4 (\uC2E0\uADDC ${created} \xB7 \uAC31\uC2E0 ${updated}): ${names}`, records);
|
|
79070
79390
|
}
|
|
79071
79391
|
},
|
|
79072
79392
|
{
|
|
@@ -79111,6 +79431,31 @@ ${lines}`;
|
|
|
79111
79431
|
}
|
|
79112
79432
|
}
|
|
79113
79433
|
},
|
|
79434
|
+
{
|
|
79435
|
+
name: "delete_cover_letter",
|
|
79436
|
+
title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uC0AD\uC81C",
|
|
79437
|
+
description: "\uC0AC\uC6A9\uC790\uAC00 \uC800\uC7A5\uB41C \uC790\uAE30\uC18C\uAC1C\uC11C \uC0AD\uC81C\uB97C \uBA85\uD655\uD788 \uC694\uCCAD\uD588\uC744 \uB54C\uB9CC \uC0AC\uC6A9\uD569\uB2C8\uB2E4. \uBA3C\uC800 get_cover_letters\uB85C \uC804\uCCB4 \uBAA9\uB85D \uB610\uB294 \uACF5\uACE0\uBCC4 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uACE0, \uC0AD\uC81C\uD560 \uD56D\uBAA9\uC744 \uC0AC\uC6A9\uC790\uAC00 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD558\uC138\uC694. \uC0AD\uC81C\uD558\uBA74 \uD574\uB2F9 \uC790\uAE30\uC18C\uAC1C\uC11C\uC758 \uBAA8\uB4E0 \uBC84\uC804\uC774 \uD568\uAED8 \uC0AD\uC81C\uB418\uBA70 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
|
|
79438
|
+
inputSchema: {
|
|
79439
|
+
cover_letter_id: external_exports.string(),
|
|
79440
|
+
confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
|
|
79441
|
+
},
|
|
79442
|
+
handler: (args) => {
|
|
79443
|
+
if (args?.confirm !== DELETE_CONFIRMATION) {
|
|
79444
|
+
return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
|
|
79445
|
+
}
|
|
79446
|
+
const cl = coverLetterRepo.get(args.cover_letter_id, false);
|
|
79447
|
+
if (!cl) return fail("\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
79448
|
+
const removed = coverLetterRepo.remove(cl.id);
|
|
79449
|
+
if (!removed) return fail("\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
79450
|
+
const user_message = `'${cl.title}' \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC0AD\uC81C\uD588\uC5B4\uC694. \uC5F0\uACB0\uB41C \uC9C0\uC6D0 \uAE30\uB85D\uC5D0\uC11C\uB294 \uC790\uAE30\uC18C\uAC1C\uC11C \uC5F0\uACB0\uB9CC \uBE44\uC6CC\uB480\uC2B5\uB2C8\uB2E4.`;
|
|
79451
|
+
return ok(user_message, {
|
|
79452
|
+
deleted: true,
|
|
79453
|
+
cover_letter_id: cl.id,
|
|
79454
|
+
title: cl.title,
|
|
79455
|
+
user_message
|
|
79456
|
+
});
|
|
79457
|
+
}
|
|
79458
|
+
},
|
|
79114
79459
|
/* ------------------------------------------------------------------ jobs */
|
|
79115
79460
|
{
|
|
79116
79461
|
name: "save_job_posting",
|
|
@@ -79119,7 +79464,15 @@ ${lines}`;
|
|
|
79119
79464
|
inputSchema: JobInputSchema.shape,
|
|
79120
79465
|
handler: (args) => {
|
|
79121
79466
|
const { job } = saveJobPosting(args);
|
|
79122
|
-
|
|
79467
|
+
const user_message = `'${job.company} \xB7 ${job.position}' \uACF5\uACE0\uB97C \uC800\uC7A5\uD588\uC5B4\uC694.`;
|
|
79468
|
+
return ok(user_message, {
|
|
79469
|
+
...job,
|
|
79470
|
+
user_message,
|
|
79471
|
+
suggested_next_action: {
|
|
79472
|
+
prompt: "\uC774 \uACF5\uACE0\uC640 \uB0B4 \uD504\uB85C\uD544\uC744 \uBE44\uAD50\uD574 \uC801\uD569\uB3C4\uB97C \uBD84\uC11D\uD560\uAE4C\uC694?",
|
|
79473
|
+
next_workflow: "analyze_job"
|
|
79474
|
+
}
|
|
79475
|
+
});
|
|
79123
79476
|
}
|
|
79124
79477
|
},
|
|
79125
79478
|
{
|
|
@@ -79130,7 +79483,7 @@ ${lines}`;
|
|
|
79130
79483
|
readOnly: true,
|
|
79131
79484
|
handler: (args) => {
|
|
79132
79485
|
const job = jobRepo.get(args.job_id);
|
|
79133
|
-
if (!job) return fail(
|
|
79486
|
+
if (!job) return fail("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
79134
79487
|
return ok(`${job.company} \xB7 ${job.position}`, {
|
|
79135
79488
|
job: jobWithMeta(job),
|
|
79136
79489
|
fit: fitRepo.getByJob(job.id),
|
|
@@ -79151,6 +79504,35 @@ ${lines}`;
|
|
|
79151
79504
|
return ok(`\uACF5\uACE0 ${jobs.length}\uAC74`, jobs);
|
|
79152
79505
|
}
|
|
79153
79506
|
},
|
|
79507
|
+
{
|
|
79508
|
+
name: "delete_job_posting",
|
|
79509
|
+
title: "\uCC44\uC6A9\uACF5\uACE0 \uC0AD\uC81C",
|
|
79510
|
+
description: "\uC0AC\uC6A9\uC790\uAC00 \uC800\uC7A5\uB41C \uCC44\uC6A9\uACF5\uACE0 \uC0AD\uC81C\uB97C \uBA85\uD655\uD788 \uC694\uCCAD\uD588\uC744 \uB54C\uB9CC \uC0AC\uC6A9\uD569\uB2C8\uB2E4. \uBA3C\uC800 list_jobs\uB85C \uC804\uCCB4 \uACF5\uACE0 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uACE0, \uC0AD\uC81C\uD560 \uACF5\uACE0\uB97C \uC0AC\uC6A9\uC790\uAC00 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD558\uC138\uC694. \uC0AD\uC81C\uD558\uBA74 \uC5F0\uACB0\uB41C \uC9C0\uC6D0 \uC0C1\uD0DC\xB7\uC801\uD569\uB3C4 \uBD84\uC11D\xB7\uBA74\uC811 \uC900\uBE44\uAC00 \uD568\uAED8 \uC0AD\uC81C\uB429\uB2C8\uB2E4. \uC5F0\uACB0\uB41C \uC790\uAE30\uC18C\uAC1C\uC11C\uB294 \uC0AD\uC81C\uD558\uC9C0 \uC54A\uACE0 \uACF5\uACE0 \uC5F0\uACB0\uB9CC \uD574\uC81C\uD569\uB2C8\uB2E4. confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
|
|
79511
|
+
inputSchema: {
|
|
79512
|
+
job_id: external_exports.string(),
|
|
79513
|
+
confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
|
|
79514
|
+
},
|
|
79515
|
+
handler: (args) => {
|
|
79516
|
+
if (args?.confirm !== DELETE_CONFIRMATION) {
|
|
79517
|
+
return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
|
|
79518
|
+
}
|
|
79519
|
+
const job = jobRepo.get(args.job_id);
|
|
79520
|
+
if (!job) return fail("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
79521
|
+
const detachedCoverLetters = coverLetterRepo.listByJob(job.id).length;
|
|
79522
|
+
const removed = jobRepo.remove(job.id);
|
|
79523
|
+
if (!removed) return fail("\uACF5\uACE0\uB97C \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
79524
|
+
const detachedNote = detachedCoverLetters ? ` \uC5F0\uACB0\uB41C \uC790\uAE30\uC18C\uAC1C\uC11C ${detachedCoverLetters}\uAC74\uC740 \uC0AD\uC81C\uD558\uC9C0 \uC54A\uACE0 \uACF5\uACE0 \uC5F0\uACB0\uB9CC \uD574\uC81C\uD588\uC2B5\uB2C8\uB2E4.` : "";
|
|
79525
|
+
const user_message = `'${job.company} \xB7 ${job.position}' \uACF5\uACE0\uB97C \uC0AD\uC81C\uD588\uC5B4\uC694. \uC5F0\uACB0\uB41C \uC9C0\uC6D0 \uC0C1\uD0DC, \uC801\uD569\uB3C4 \uBD84\uC11D, \uBA74\uC811 \uC900\uBE44\uB3C4 \uD568\uAED8 \uC815\uB9AC\uD588\uC2B5\uB2C8\uB2E4.${detachedNote}`;
|
|
79526
|
+
return ok(user_message, {
|
|
79527
|
+
deleted: true,
|
|
79528
|
+
job_id: job.id,
|
|
79529
|
+
company: job.company,
|
|
79530
|
+
position: job.position,
|
|
79531
|
+
detached_cover_letters: detachedCoverLetters,
|
|
79532
|
+
user_message
|
|
79533
|
+
});
|
|
79534
|
+
}
|
|
79535
|
+
},
|
|
79154
79536
|
/* ----------------------------------------------------- application context */
|
|
79155
79537
|
{
|
|
79156
79538
|
name: "get_application_context",
|
|
@@ -79173,7 +79555,7 @@ ${lines}`;
|
|
|
79173
79555
|
`\uC774\uB825\uC11C ${ctx.resumes.length} \xB7 \uACBD\uB825 ${ctx.experiences.length} \xB7 \uD504\uB85C\uC81D\uD2B8 ${ctx.projects.length} \xB7 \uC2A4\uD0AC ${ctx.skills.length} \xB7 \uC790\uC18C\uC11C ${ctx.cover_letters.length}`,
|
|
79174
79556
|
ctx.job ? `\uB300\uC0C1 \uACF5\uACE0: ${ctx.job.company} \xB7 ${ctx.job.position}` : "\uB300\uC0C1 \uACF5\uACE0 \uC5C6\uC74C",
|
|
79175
79557
|
ctx.writing_preferences.preferred_tone ? `\uC120\uD638 \uBB38\uCCB4: ${ctx.writing_preferences.preferred_tone}` : "",
|
|
79176
|
-
recommended_route ? `\
|
|
79558
|
+
recommended_route ? `\uB0B4\uBD80 \uC548\uB0B4: \uC0AC\uC6A9\uC790\uC5D0\uAC8C\uB294 \uB3C4\uAD6C\uBA85\uC774\uB098 ID\uB97C \uB9D0\uD558\uC9C0 \uB9D0\uACE0, \uBA3C\uC800 get_workflow_guide({ workflow_id: "${recommended_route}" })\uB85C \uC2E4\uD589 \uC808\uCC28\uC640 \uAC80\uC99D \uC21C\uC11C\uB97C \uBC1B\uC740 \uB4A4 \uC26C\uC6B4 \uB9D0\uB85C \uC548\uB0B4\uD558\uC138\uC694.` : "\uB0B4\uBD80 \uC548\uB0B4: \uC0AC\uC6A9\uC790\uC5D0\uAC8C\uB294 \uB3C4\uAD6C\uBA85\uC744 \uB9D0\uD558\uC9C0 \uB9D0\uACE0, \uBA3C\uC800 get_workflow_guide\uB85C \uC2E4\uD589 \uC808\uCC28\uC640 \uAC80\uC99D \uC21C\uC11C\uB97C \uBC1B\uC740 \uB4A4 \uC26C\uC6B4 \uB9D0\uB85C \uC548\uB0B4\uD558\uC138\uC694."
|
|
79177
79559
|
].filter(Boolean).join("\n");
|
|
79178
79560
|
return ok(summary, enriched);
|
|
79179
79561
|
}
|
|
@@ -79186,7 +79568,34 @@ ${lines}`;
|
|
|
79186
79568
|
handler: (args) => {
|
|
79187
79569
|
try {
|
|
79188
79570
|
const fit = saveFitAnalysis(args);
|
|
79189
|
-
|
|
79571
|
+
const suggested_next_action = {
|
|
79572
|
+
prompt: "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?",
|
|
79573
|
+
options: [
|
|
79574
|
+
{
|
|
79575
|
+
label: "\uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
|
|
79576
|
+
next_workflow: "write_cover_letter"
|
|
79577
|
+
},
|
|
79578
|
+
{
|
|
79579
|
+
label: "\uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918",
|
|
79580
|
+
next_workflow: null
|
|
79581
|
+
}
|
|
79582
|
+
]
|
|
79583
|
+
};
|
|
79584
|
+
const user_message = `\uC801\uD569\uB3C4 \uBD84\uC11D\uC744 \uC800\uC7A5\uD588\uC5B4\uC694${fit.score != null ? ` (${fit.score}\uC810)` : ""}. \uC790\uC138\uD55C \uACB0\uACFC\uB294 \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C\uB3C4 \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4: ${DASHBOARD_URL}`;
|
|
79585
|
+
return ok(
|
|
79586
|
+
[
|
|
79587
|
+
user_message,
|
|
79588
|
+
"",
|
|
79589
|
+
"\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB2E4\uC74C \uC120\uD0DD\uC9C0\uB97C \uBCF4\uC5EC\uC8FC\uC138\uC694:",
|
|
79590
|
+
"1. \uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
|
|
79591
|
+
"2. \uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918"
|
|
79592
|
+
].join("\n"),
|
|
79593
|
+
{
|
|
79594
|
+
...fit,
|
|
79595
|
+
user_message,
|
|
79596
|
+
suggested_next_action
|
|
79597
|
+
}
|
|
79598
|
+
);
|
|
79190
79599
|
} catch (e) {
|
|
79191
79600
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
79192
79601
|
}
|
|
@@ -79205,11 +79614,19 @@ ${lines}`;
|
|
|
79205
79614
|
handler: (args) => {
|
|
79206
79615
|
try {
|
|
79207
79616
|
const res = updateApplicationStatus(args.job_id, args.status, args.note);
|
|
79208
|
-
|
|
79209
|
-
`\uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[args.status]}'(\uC73C)\uB85C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.${res.hint ? `
|
|
79617
|
+
const user_message = `\uC9C0\uC6D0 \uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[args.status]}'(\uC73C)\uB85C \uBC14\uAFE8\uC5B4\uC694.` + (res.hint ? `
|
|
79210
79618
|
|
|
79211
|
-
|
|
79212
|
-
|
|
79619
|
+
${res.hint}` : "");
|
|
79620
|
+
return ok(
|
|
79621
|
+
user_message,
|
|
79622
|
+
{
|
|
79623
|
+
...res,
|
|
79624
|
+
user_message,
|
|
79625
|
+
suggested_next_action: res.hint ? {
|
|
79626
|
+
prompt: res.hint,
|
|
79627
|
+
next_workflow: "prepare_interview"
|
|
79628
|
+
} : null
|
|
79629
|
+
}
|
|
79213
79630
|
);
|
|
79214
79631
|
} catch (e) {
|
|
79215
79632
|
return fail(e instanceof Error ? e.message : "\uBCC0\uACBD \uC2E4\uD328");
|
|
@@ -79225,7 +79642,8 @@ ${lines}`;
|
|
|
79225
79642
|
handler: (args) => {
|
|
79226
79643
|
try {
|
|
79227
79644
|
const prep = saveInterviewPrep(args);
|
|
79228
|
-
|
|
79645
|
+
const user_message = `\uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD588\uC5B4\uC694. \uC608\uC0C1 \uC9C8\uBB38 ${prep.questions.length}\uAC1C\uAC00 \uC900\uBE44\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.`;
|
|
79646
|
+
return ok(user_message, { ...prep, user_message });
|
|
79229
79647
|
} catch (e) {
|
|
79230
79648
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
79231
79649
|
}
|
|
@@ -79250,7 +79668,7 @@ ${lines}`;
|
|
|
79250
79668
|
const dir = getExportsDir();
|
|
79251
79669
|
const filePath = path7.join(dir, result2.filename);
|
|
79252
79670
|
try {
|
|
79253
|
-
|
|
79671
|
+
fs7.writeFileSync(filePath, result2.content, "utf8");
|
|
79254
79672
|
} catch (e) {
|
|
79255
79673
|
return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
|
|
79256
79674
|
}
|
|
@@ -79412,29 +79830,37 @@ ${report.disclaimer}`, report);
|
|
|
79412
79830
|
{
|
|
79413
79831
|
name: "check_for_update",
|
|
79414
79832
|
title: "\uC5C5\uB370\uC774\uD2B8 \uD655\uC778",
|
|
79415
|
-
description: 'CareerMate\uC5D0 \uC0C8 \uBC84\uC804\uC774 \uC788\uB294\uC9C0 npm \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0\uC11C \uC9C0\uAE08 \uD655\uC778\uD569\uB2C8\uB2E4(\uACF5\uAC1C \uBC84\uC804 \uC815\uBCF4\uB9CC GET\uD558\uBA70 \uC0AC\uC6A9\uC790 \uB370\uC774\uD130\uB294 \uC804\uC1A1\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4). \uD604\uC7AC \uBC84\uC804\xB7\uCD5C\uC2E0 \uBC84\uC804\xB7\uC5C5\uB370\uC774\uD2B8 \uAC00\uB2A5 \uC5EC\uBD80\uB97C \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 "\uCD5C\uC2E0\uC774\uC57C?/\uC5C5\uB370\uC774\uD2B8 \uC788\uC5B4?"\uB77C\uACE0 \uBB3B\uAC70\uB098, get_onboarding_status\uAC00 \uC0C8 \uBC84\uC804\uC744 \uC54C\uB9B4 \uB54C \uD638\uCD9C\uD558\uC138\uC694. \
|
|
79833
|
+
description: 'CareerMate\uC5D0 \uC0C8 \uBC84\uC804\uC774 \uC788\uB294\uC9C0 npm \uB808\uC9C0\uC2A4\uD2B8\uB9AC\uC5D0\uC11C \uC9C0\uAE08 \uD655\uC778\uD569\uB2C8\uB2E4(\uACF5\uAC1C \uBC84\uC804 \uC815\uBCF4\uB9CC GET\uD558\uBA70 \uC0AC\uC6A9\uC790 \uB370\uC774\uD130\uB294 \uC804\uC1A1\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4). \uD604\uC7AC \uBC84\uC804\xB7\uCD5C\uC2E0 \uBC84\uC804\xB7\uC5C5\uB370\uC774\uD2B8 \uAC00\uB2A5 \uC5EC\uBD80\uB97C \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 "\uCD5C\uC2E0\uC774\uC57C?/\uC5C5\uB370\uC774\uD2B8 \uC788\uC5B4?"\uB77C\uACE0 \uBB3B\uAC70\uB098, get_onboarding_status\uAC00 \uC0C8 \uBC84\uC804\uC744 \uC54C\uB9B4 \uB54C \uD638\uCD9C\uD558\uC138\uC694. \uD655\uC778\uB9CC \uD558\uACE0 \uC124\uCE58\uB294 \uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 "\uC5C5\uB370\uC774\uD2B8\uD574\uC918/\uCD5C\uC2E0\uC73C\uB85C \uC62C\uB824\uC918"\uCC98\uB7FC \uBA85\uC2DC\uC801\uC73C\uB85C \uC694\uCCAD\uD558\uBA74 update_careermate\uB97C \uD638\uCD9C\uD558\uC138\uC694.',
|
|
79416
79834
|
inputSchema: {},
|
|
79417
79835
|
readOnly: true,
|
|
79418
79836
|
handler: async () => {
|
|
79419
79837
|
const u = await getUpdateStatusAsync();
|
|
79420
79838
|
if (u.latest === null) return ok("\uC5C5\uB370\uC774\uD2B8 \uD655\uC778\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4(\uC624\uD504\uB77C\uC778\uC774\uAC70\uB098 \uC77C\uC2DC\uC801 \uC624\uB958). \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.", u);
|
|
79839
|
+
const user_message = u.update_available ? `\uC0C8 \uBC84\uC804 v${u.latest}\uC774 \uB098\uC654\uC5B4\uC694. \uD604\uC7AC \uBC84\uC804\uC740 v${u.current}\uC785\uB2C8\uB2E4. \uC6D0\uD558\uC2DC\uBA74 \uC9C0\uAE08 \uC5C5\uB370\uC774\uD2B8\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.` : `\uCD5C\uC2E0 \uBC84\uC804\uC785\uB2C8\uB2E4 (v${u.current}).`;
|
|
79421
79840
|
return ok(
|
|
79422
|
-
|
|
79423
|
-
|
|
79841
|
+
user_message,
|
|
79842
|
+
{
|
|
79843
|
+
...u,
|
|
79844
|
+
user_message,
|
|
79845
|
+
suggested_next_action: u.update_available ? {
|
|
79846
|
+
prompt: "\uC9C0\uAE08 CareerMate\uB97C \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694?",
|
|
79847
|
+
next_tool: "update_careermate"
|
|
79848
|
+
} : null
|
|
79849
|
+
}
|
|
79424
79850
|
);
|
|
79425
79851
|
}
|
|
79426
79852
|
},
|
|
79427
79853
|
{
|
|
79428
79854
|
name: "update_careermate",
|
|
79429
79855
|
title: "CareerMate \uC5C5\uB370\uC774\uD2B8",
|
|
79430
|
-
description: 'CareerMate\uB97C \uCD5C\uC2E0 \uBC84\uC804\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD569\uB2C8\uB2E4(\uC124\uCE58 \uD3F4\uB354\uC5D0 npm\uC73C\uB85C careermate@latest \uC124\uCE58). \uC0AC\uC6A9\uC790\uAC00 \uBA85\uC2DC\uC801\uC73C\uB85C "\uC5C5\uB370\uC774\uD2B8\uD574\uC918"\uB77C\uACE0 \uD560 \uB54C
|
|
79856
|
+
description: 'CareerMate\uB97C \uCD5C\uC2E0 \uBC84\uC804\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD569\uB2C8\uB2E4(\uC124\uCE58 \uD3F4\uB354\uC5D0 npm\uC73C\uB85C careermate@latest \uC124\uCE58). \uC0AC\uC6A9\uC790\uAC00 \uBA85\uC2DC\uC801\uC73C\uB85C "\uC5C5\uB370\uC774\uD2B8\uD574\uC918", "CareerMate \uC5C5\uB370\uC774\uD2B8\uD574\uC918", "\uCD5C\uC2E0\uC73C\uB85C \uC62C\uB824\uC918"\uB77C\uACE0 \uD560 \uB54C \uD638\uCD9C\uD558\uC138\uC694. \uC774 \uB3C4\uAD6C\uAC00 \uCD5C\uC2E0 \uBC84\uC804 \uD655\uC778\uB3C4 \uD568\uAED8 \uD558\uBBC0\uB85C \uBCC4\uB3C4 \uD655\uC778 \uC9C8\uBB38 \uC5C6\uC774 \uC2E4\uD589\uD574\uB3C4 \uB429\uB2C8\uB2E4. \uC131\uACF5\uD558\uBA74 \uC801\uC6A9\uC744 \uC704\uD574 AI \uC571(\uB610\uB294 MCP \uC5F0\uACB0) \uC7AC\uC2DC\uC791\uC774 \uD544\uC694\uD558\uBA70, \uC7AC\uC2DC\uC791 \uC2DC \uB370\uC774\uD130\uBCA0\uC774\uC2A4\uB294 \uC790\uB3D9 \uB9C8\uC774\uADF8\uB808\uC774\uC158\uB418\uC5B4 \uAE30\uC874 \uB370\uC774\uD130\uB294 \uBCF4\uC874\uB429\uB2C8\uB2E4. \uC790\uB3D9 \uC124\uCE58\uAC00 \uB9C9\uD788\uBA74(\uAC1C\uBC1C \uBAA8\uB4DC\xB7\uBE44\uD45C\uC900 \uC124\uCE58) \uC9C1\uC811 \uCE60 \uBA85\uB839\uC744 \uC548\uB0B4\uD569\uB2C8\uB2E4.',
|
|
79431
79857
|
inputSchema: {},
|
|
79432
79858
|
handler: async () => {
|
|
79433
79859
|
const r = await runSelfUpdate();
|
|
79434
79860
|
if (!r.ok) return fail(`${r.message}${r.manual ? `
|
|
79435
79861
|
|
|
79436
79862
|
\uC9C1\uC811 \uC2E4\uD589: ${r.manual}` : ""}`);
|
|
79437
|
-
return ok(r.message, r);
|
|
79863
|
+
return ok(r.message, { ...r, user_message: r.message });
|
|
79438
79864
|
}
|
|
79439
79865
|
}
|
|
79440
79866
|
];
|
|
@@ -79455,7 +79881,7 @@ async function main() {
|
|
|
79455
79881
|
const nodeOk = checkNode();
|
|
79456
79882
|
const dir = getDataDir();
|
|
79457
79883
|
try {
|
|
79458
|
-
|
|
79884
|
+
fs8.accessSync(dir, fs8.constants.W_OK);
|
|
79459
79885
|
ok2(`\uB370\uC774\uD130 \uD3F4\uB354 \uC4F0\uAE30 \uAC00\uB2A5: ${dir}`);
|
|
79460
79886
|
} catch {
|
|
79461
79887
|
warn2(`\uB370\uC774\uD130 \uD3F4\uB354\uC5D0 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${dir}`);
|