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/mcp.mjs
CHANGED
|
@@ -6891,12 +6891,12 @@ var require_dist = __commonJS({
|
|
|
6891
6891
|
throw new Error(`Unknown format "${name}"`);
|
|
6892
6892
|
return f;
|
|
6893
6893
|
};
|
|
6894
|
-
function addFormats(ajv, list,
|
|
6894
|
+
function addFormats(ajv, list, fs8, exportName) {
|
|
6895
6895
|
var _a2;
|
|
6896
6896
|
var _b2;
|
|
6897
6897
|
(_a2 = (_b2 = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b2.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6898
6898
|
for (const f of list)
|
|
6899
|
-
ajv.addFormat(f,
|
|
6899
|
+
ajv.addFormat(f, fs8[f]);
|
|
6900
6900
|
}
|
|
6901
6901
|
module2.exports = exports2 = formatsPlugin;
|
|
6902
6902
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -13333,9 +13333,9 @@ var require_timers = __commonJS({
|
|
|
13333
13333
|
clearTimeout(this.handle);
|
|
13334
13334
|
};
|
|
13335
13335
|
var afterValue = function(value) {
|
|
13336
|
-
return
|
|
13336
|
+
return delay2(+this).thenReturn(value);
|
|
13337
13337
|
};
|
|
13338
|
-
var
|
|
13338
|
+
var delay2 = Promise2.delay = function(ms, value) {
|
|
13339
13339
|
var ret2;
|
|
13340
13340
|
var handle;
|
|
13341
13341
|
if (value !== void 0) {
|
|
@@ -13357,7 +13357,7 @@ var require_timers = __commonJS({
|
|
|
13357
13357
|
return ret2;
|
|
13358
13358
|
};
|
|
13359
13359
|
Promise2.prototype.delay = function(ms) {
|
|
13360
|
-
return
|
|
13360
|
+
return delay2(ms, this);
|
|
13361
13361
|
};
|
|
13362
13362
|
var afterTimeout = function(promise, message, parent) {
|
|
13363
13363
|
var err2;
|
|
@@ -35153,7 +35153,7 @@ var require_path_is_absolute = __commonJS({
|
|
|
35153
35153
|
var require_files = __commonJS({
|
|
35154
35154
|
"node_modules/mammoth/lib/docx/files.js"(exports2) {
|
|
35155
35155
|
"use strict";
|
|
35156
|
-
var
|
|
35156
|
+
var fs8 = __require("fs");
|
|
35157
35157
|
var url = __require("url");
|
|
35158
35158
|
var os3 = __require("os");
|
|
35159
35159
|
var dirname = __require("path").dirname;
|
|
@@ -35194,7 +35194,7 @@ var require_files = __commonJS({
|
|
|
35194
35194
|
read
|
|
35195
35195
|
};
|
|
35196
35196
|
}
|
|
35197
|
-
var readFile = promises.promisify(
|
|
35197
|
+
var readFile = promises.promisify(fs8.readFile.bind(fs8));
|
|
35198
35198
|
function uriToPath(uriString, platform) {
|
|
35199
35199
|
if (!platform) {
|
|
35200
35200
|
platform = os3.platform();
|
|
@@ -37936,11 +37936,11 @@ var require_options_reader = __commonJS({
|
|
|
37936
37936
|
var require_unzip = __commonJS({
|
|
37937
37937
|
"node_modules/mammoth/lib/unzip.js"(exports2) {
|
|
37938
37938
|
"use strict";
|
|
37939
|
-
var
|
|
37939
|
+
var fs8 = __require("fs");
|
|
37940
37940
|
var promises = require_promises();
|
|
37941
37941
|
var zipfile = require_zipfile();
|
|
37942
37942
|
exports2.openZip = openZip;
|
|
37943
|
-
var readFile = promises.promisify(
|
|
37943
|
+
var readFile = promises.promisify(fs8.readFile);
|
|
37944
37944
|
function openZip(options) {
|
|
37945
37945
|
if (options.path) {
|
|
37946
37946
|
return readFile(options.path).then(zipfile.openArrayBuffer);
|
|
@@ -38665,9 +38665,9 @@ var require_cjs = __commonJS({
|
|
|
38665
38665
|
}
|
|
38666
38666
|
return o;
|
|
38667
38667
|
}
|
|
38668
|
-
var
|
|
38668
|
+
var fs8;
|
|
38669
38669
|
function get_fs() {
|
|
38670
|
-
return
|
|
38670
|
+
return fs8 || (fs8 = require$$0__default["default"]);
|
|
38671
38671
|
}
|
|
38672
38672
|
function parse4(file, options) {
|
|
38673
38673
|
if (file[0] == 80 && file[1] == 75) return parse_zip(file, options);
|
|
@@ -38952,7 +38952,7 @@ var require_cjs = __commonJS({
|
|
|
38952
38952
|
}
|
|
38953
38953
|
function read_file(filename2, options) {
|
|
38954
38954
|
get_fs();
|
|
38955
|
-
return parse4(
|
|
38955
|
+
return parse4(fs8.readFileSync(filename2), options);
|
|
38956
38956
|
}
|
|
38957
38957
|
function read(blob, options) {
|
|
38958
38958
|
switch (options && options.type || "base64") {
|
|
@@ -39267,7 +39267,7 @@ var require_cjs = __commonJS({
|
|
|
39267
39267
|
function write_file(cfb2, filename2, options) {
|
|
39268
39268
|
get_fs();
|
|
39269
39269
|
var o = _write(cfb2, options);
|
|
39270
|
-
|
|
39270
|
+
fs8.writeFileSync(filename2, o);
|
|
39271
39271
|
}
|
|
39272
39272
|
function a2s(o) {
|
|
39273
39273
|
var out = new Array(o.length);
|
|
@@ -39279,7 +39279,7 @@ var require_cjs = __commonJS({
|
|
|
39279
39279
|
switch (options && options.type || "buffer") {
|
|
39280
39280
|
case "file":
|
|
39281
39281
|
get_fs();
|
|
39282
|
-
|
|
39282
|
+
fs8.writeFileSync(options.filename, o);
|
|
39283
39283
|
return o;
|
|
39284
39284
|
case "binary":
|
|
39285
39285
|
return typeof o == "string" ? o : a2s(o);
|
|
@@ -46972,8 +46972,8 @@ function blend(fg, bg, alpha) {
|
|
|
46972
46972
|
return Math.round(alpha * fg + (1 - alpha) * bg);
|
|
46973
46973
|
}
|
|
46974
46974
|
async function node_utils_fetchData(url) {
|
|
46975
|
-
const
|
|
46976
|
-
const data = await
|
|
46975
|
+
const fs8 = process.getBuiltinModule("fs/promises");
|
|
46976
|
+
const data = await fs8.readFile(url);
|
|
46977
46977
|
return new Uint8Array(data);
|
|
46978
46978
|
}
|
|
46979
46979
|
function initGPU() {
|
|
@@ -47602,11 +47602,11 @@ function network_getArrayBuffer(val) {
|
|
|
47602
47602
|
return typeof val !== "string" ? val : stringToBytes(val).buffer;
|
|
47603
47603
|
}
|
|
47604
47604
|
function getReadableStream(url, opts = null) {
|
|
47605
|
-
const
|
|
47605
|
+
const fs8 = process.getBuiltinModule("fs");
|
|
47606
47606
|
const {
|
|
47607
47607
|
Readable
|
|
47608
47608
|
} = process.getBuiltinModule("stream");
|
|
47609
|
-
const readStream =
|
|
47609
|
+
const readStream = fs8.createReadStream(url, opts);
|
|
47610
47610
|
return Readable.toWeb(readStream);
|
|
47611
47611
|
}
|
|
47612
47612
|
function getNetworkStream(url) {
|
|
@@ -64603,8 +64603,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
64603
64603
|
url
|
|
64604
64604
|
} = stream._source;
|
|
64605
64605
|
this._isStreamingSupported = !disableStream;
|
|
64606
|
-
const
|
|
64607
|
-
|
|
64606
|
+
const fs8 = process.getBuiltinModule("fs/promises");
|
|
64607
|
+
fs8.lstat(url).then((stat) => {
|
|
64608
64608
|
const readableStream = getReadableStream(url);
|
|
64609
64609
|
this._reader = readableStream.getReader();
|
|
64610
64610
|
const {
|
|
@@ -66250,9 +66250,9 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
66250
66250
|
return;
|
|
66251
66251
|
}
|
|
66252
66252
|
if (reason instanceof RenderingCancelledException) {
|
|
66253
|
-
let
|
|
66253
|
+
let delay2 = RENDERING_CANCELLED_TIMEOUT;
|
|
66254
66254
|
if (reason.extraDelay > 0 && reason.extraDelay < 1e3) {
|
|
66255
|
-
|
|
66255
|
+
delay2 += reason.extraDelay;
|
|
66256
66256
|
}
|
|
66257
66257
|
intentState.streamReaderCancelTimeout = setTimeout(() => {
|
|
66258
66258
|
intentState.streamReaderCancelTimeout = null;
|
|
@@ -66261,7 +66261,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
66261
66261
|
reason,
|
|
66262
66262
|
force: true
|
|
66263
66263
|
});
|
|
66264
|
-
},
|
|
66264
|
+
}, delay2);
|
|
66265
66265
|
return;
|
|
66266
66266
|
}
|
|
66267
66267
|
}
|
|
@@ -75028,7 +75028,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
75028
75028
|
const ij = i2 * width + j;
|
|
75029
75029
|
const center = buf[ij];
|
|
75030
75030
|
let sum = 0;
|
|
75031
|
-
let
|
|
75031
|
+
let norm2 = 0;
|
|
75032
75032
|
for (let k = 0; k < kernelSize; k++) {
|
|
75033
75033
|
const y = i2 + k - halfSize;
|
|
75034
75034
|
if (y < 0 || y >= height) {
|
|
@@ -75042,10 +75042,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
75042
75042
|
const neighbour = buf[y * width + x2];
|
|
75043
75043
|
const w = kernel[k * kernelSize + l2] * rangeValues[Math.abs(neighbour - center)];
|
|
75044
75044
|
sum += neighbour * w;
|
|
75045
|
-
|
|
75045
|
+
norm2 += w;
|
|
75046
75046
|
}
|
|
75047
75047
|
}
|
|
75048
|
-
const pix = out[ij] = Math.round(sum /
|
|
75048
|
+
const pix = out[ij] = Math.round(sum / norm2);
|
|
75049
75049
|
histogram[pix]++;
|
|
75050
75050
|
}
|
|
75051
75051
|
}
|
|
@@ -84952,13 +84952,13 @@ function _array(Class2, element, params) {
|
|
|
84952
84952
|
});
|
|
84953
84953
|
}
|
|
84954
84954
|
function _custom(Class2, fn, _params) {
|
|
84955
|
-
const
|
|
84956
|
-
|
|
84955
|
+
const norm2 = normalizeParams(_params);
|
|
84956
|
+
norm2.abort ?? (norm2.abort = true);
|
|
84957
84957
|
const schema = new Class2({
|
|
84958
84958
|
type: "custom",
|
|
84959
84959
|
check: "custom",
|
|
84960
84960
|
fn,
|
|
84961
|
-
...
|
|
84961
|
+
...norm2
|
|
84962
84962
|
});
|
|
84963
84963
|
return schema;
|
|
84964
84964
|
}
|
|
@@ -92516,6 +92516,24 @@ function setVerifyStrict(on) {
|
|
|
92516
92516
|
return on;
|
|
92517
92517
|
}
|
|
92518
92518
|
|
|
92519
|
+
// packages/shared/src/errors.ts
|
|
92520
|
+
var CareerMateError = class extends Error {
|
|
92521
|
+
constructor(message, httpStatus = 400, code) {
|
|
92522
|
+
super(message);
|
|
92523
|
+
this.httpStatus = httpStatus;
|
|
92524
|
+
this.code = code;
|
|
92525
|
+
this.name = "CareerMateError";
|
|
92526
|
+
}
|
|
92527
|
+
httpStatus;
|
|
92528
|
+
code;
|
|
92529
|
+
};
|
|
92530
|
+
function notFound(message) {
|
|
92531
|
+
return new CareerMateError(message, 404, "not_found");
|
|
92532
|
+
}
|
|
92533
|
+
function conflict(message) {
|
|
92534
|
+
return new CareerMateError(message, 409, "conflict");
|
|
92535
|
+
}
|
|
92536
|
+
|
|
92519
92537
|
// packages/shared/src/enums.ts
|
|
92520
92538
|
var APPLICATION_STATUSES = [
|
|
92521
92539
|
"draft",
|
|
@@ -92566,8 +92584,9 @@ function canTransitionStatus(from, to) {
|
|
|
92566
92584
|
}
|
|
92567
92585
|
function assertStatusTransition(from, to) {
|
|
92568
92586
|
if (!canTransitionStatus(from, to)) {
|
|
92569
|
-
|
|
92570
|
-
|
|
92587
|
+
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.)` : "";
|
|
92588
|
+
throw conflict(
|
|
92589
|
+
`'${APPLICATION_STATUS_LABELS[from]}'\uC5D0\uC11C '${APPLICATION_STATUS_LABELS[to]}'(\uC73C)\uB85C\uB294 \uC0C1\uD0DC\uB97C \uBC14\uAFC0 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.${suffix}`
|
|
92571
92590
|
);
|
|
92572
92591
|
}
|
|
92573
92592
|
}
|
|
@@ -92619,7 +92638,20 @@ var optLine = external_exports.string().max(MAX_LINE).optional();
|
|
|
92619
92638
|
var optNote = external_exports.string().max(MAX_NOTE).optional();
|
|
92620
92639
|
var optBody = external_exports.string().max(MAX_BODY).optional();
|
|
92621
92640
|
var reqBody = external_exports.string().max(MAX_BODY).refine((s) => s.trim().length > 0, { message: EMPTY_MSG });
|
|
92622
|
-
|
|
92641
|
+
function toStrList(v) {
|
|
92642
|
+
if (typeof v !== "string") return v;
|
|
92643
|
+
const s = v.trim();
|
|
92644
|
+
if (!s) return [];
|
|
92645
|
+
if (s.startsWith("[")) {
|
|
92646
|
+
try {
|
|
92647
|
+
const parsed = JSON.parse(s);
|
|
92648
|
+
if (Array.isArray(parsed)) return parsed;
|
|
92649
|
+
} catch {
|
|
92650
|
+
}
|
|
92651
|
+
}
|
|
92652
|
+
return s.split(/[\n,]/).map((x2) => x2.trim()).filter(Boolean);
|
|
92653
|
+
}
|
|
92654
|
+
var strList = external_exports.preprocess(toStrList, external_exports.array(external_exports.string().max(MAX_ITEM)).max(MAX_ITEMS));
|
|
92623
92655
|
var baseRecord = {
|
|
92624
92656
|
id,
|
|
92625
92657
|
created_at: isoDateTime,
|
|
@@ -92681,6 +92713,9 @@ var ExperienceRecordSchema = external_exports.object({
|
|
|
92681
92713
|
tech: external_exports.array(external_exports.string()),
|
|
92682
92714
|
order_index: external_exports.number()
|
|
92683
92715
|
});
|
|
92716
|
+
var ExperienceBatchInputSchema = external_exports.object({
|
|
92717
|
+
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.")
|
|
92718
|
+
});
|
|
92684
92719
|
var ProjectInputSchema = external_exports.object({
|
|
92685
92720
|
name: reqLine,
|
|
92686
92721
|
role: optLine,
|
|
@@ -92704,6 +92739,9 @@ var ProjectRecordSchema = external_exports.object({
|
|
|
92704
92739
|
end_date: external_exports.string().nullable(),
|
|
92705
92740
|
order_index: external_exports.number()
|
|
92706
92741
|
});
|
|
92742
|
+
var ProjectBatchInputSchema = external_exports.object({
|
|
92743
|
+
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.")
|
|
92744
|
+
});
|
|
92707
92745
|
var SkillInputSchema = external_exports.object({
|
|
92708
92746
|
name: reqLine,
|
|
92709
92747
|
category: external_exports.string().max(MAX_LINE).optional().describe("\uC5B8\uC5B4/\uD504\uB808\uC784\uC6CC\uD06C/\uD234/\uC18C\uD504\uD2B8\uC2A4\uD0AC \uB4F1"),
|
|
@@ -92719,6 +92757,9 @@ var SkillRecordSchema = external_exports.object({
|
|
|
92719
92757
|
years: external_exports.number().nullable(),
|
|
92720
92758
|
order_index: external_exports.number()
|
|
92721
92759
|
});
|
|
92760
|
+
var SkillBatchInputSchema = external_exports.object({
|
|
92761
|
+
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.")
|
|
92762
|
+
});
|
|
92722
92763
|
var DocumentInputSchema = external_exports.object({
|
|
92723
92764
|
kind: external_exports.enum(DOCUMENT_KINDS),
|
|
92724
92765
|
title: reqLine,
|
|
@@ -92915,7 +92956,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
92915
92956
|
});
|
|
92916
92957
|
|
|
92917
92958
|
// packages/shared/src/build-info.ts
|
|
92918
|
-
var APP_VERSION = true ? "0.0.
|
|
92959
|
+
var APP_VERSION = true ? "0.0.5" : "0.0.0-dev";
|
|
92919
92960
|
var BUNDLED = true;
|
|
92920
92961
|
|
|
92921
92962
|
// packages/shared/src/index.ts
|
|
@@ -92930,6 +92971,7 @@ function now() {
|
|
|
92930
92971
|
|
|
92931
92972
|
// packages/db/src/repositories.ts
|
|
92932
92973
|
var PROFILE_ID = "profile-singleton";
|
|
92974
|
+
var norm = (s) => (s ?? "").trim().toLowerCase();
|
|
92933
92975
|
function mapProfile(r) {
|
|
92934
92976
|
return {
|
|
92935
92977
|
id: r.id,
|
|
@@ -93007,6 +93049,9 @@ function mapExperience(r) {
|
|
|
93007
93049
|
updated_at: r.updated_at
|
|
93008
93050
|
};
|
|
93009
93051
|
}
|
|
93052
|
+
function expKey(company, role, start) {
|
|
93053
|
+
return [norm(company), norm(role), norm(start)].join("\0");
|
|
93054
|
+
}
|
|
93010
93055
|
var experienceRepo = {
|
|
93011
93056
|
list() {
|
|
93012
93057
|
return getDb().prepare(`SELECT * FROM experiences ORDER BY order_index ASC, start_date DESC`).all().map(mapExperience);
|
|
@@ -93015,6 +93060,32 @@ var experienceRepo = {
|
|
|
93015
93060
|
const r = getDb().prepare(`SELECT * FROM experiences WHERE id = ?`).get(id2);
|
|
93016
93061
|
return r ? mapExperience(r) : null;
|
|
93017
93062
|
},
|
|
93063
|
+
/** Existing experience with the same company+role+start_date, or null (for idempotent batch upserts). */
|
|
93064
|
+
findMatch(input) {
|
|
93065
|
+
const key = expKey(input.company, input.role ?? null, input.start_date ?? null);
|
|
93066
|
+
return this.list().find((e) => expKey(e.company, e.role, e.start_date) === key) ?? null;
|
|
93067
|
+
},
|
|
93068
|
+
/** Insert, or merge into the matching experience (omitted fields keep their stored value). */
|
|
93069
|
+
upsert(input) {
|
|
93070
|
+
const existing = this.findMatch(input);
|
|
93071
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
93072
|
+
return { record: this.add(input), created: true };
|
|
93073
|
+
},
|
|
93074
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
93075
|
+
addMany(inputs) {
|
|
93076
|
+
return tx(() => {
|
|
93077
|
+
const records = [];
|
|
93078
|
+
let created = 0;
|
|
93079
|
+
let updated = 0;
|
|
93080
|
+
for (const input of inputs) {
|
|
93081
|
+
const { record: record2, created: isNew } = this.upsert(input);
|
|
93082
|
+
records.push(record2);
|
|
93083
|
+
if (isNew) created += 1;
|
|
93084
|
+
else updated += 1;
|
|
93085
|
+
}
|
|
93086
|
+
return { records, created, updated };
|
|
93087
|
+
});
|
|
93088
|
+
},
|
|
93018
93089
|
add(input) {
|
|
93019
93090
|
const ts = now();
|
|
93020
93091
|
const id2 = newId("exp_");
|
|
@@ -93088,6 +93159,32 @@ var projectRepo = {
|
|
|
93088
93159
|
const r = getDb().prepare(`SELECT * FROM projects WHERE id = ?`).get(id2);
|
|
93089
93160
|
return r ? mapProject(r) : null;
|
|
93090
93161
|
},
|
|
93162
|
+
/** Existing project with the same name (case-insensitive), or null (for idempotent batch upserts). */
|
|
93163
|
+
findByName(name) {
|
|
93164
|
+
const key = norm(name);
|
|
93165
|
+
return this.list().find((p) => norm(p.name) === key) ?? null;
|
|
93166
|
+
},
|
|
93167
|
+
/** Insert, or merge into the same-named project (omitted fields keep their stored value). */
|
|
93168
|
+
upsert(input) {
|
|
93169
|
+
const existing = this.findByName(input.name);
|
|
93170
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
93171
|
+
return { record: this.add(input), created: true };
|
|
93172
|
+
},
|
|
93173
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
93174
|
+
addMany(inputs) {
|
|
93175
|
+
return tx(() => {
|
|
93176
|
+
const records = [];
|
|
93177
|
+
let created = 0;
|
|
93178
|
+
let updated = 0;
|
|
93179
|
+
for (const input of inputs) {
|
|
93180
|
+
const { record: record2, created: isNew } = this.upsert(input);
|
|
93181
|
+
records.push(record2);
|
|
93182
|
+
if (isNew) created += 1;
|
|
93183
|
+
else updated += 1;
|
|
93184
|
+
}
|
|
93185
|
+
return { records, created, updated };
|
|
93186
|
+
});
|
|
93187
|
+
},
|
|
93091
93188
|
add(input) {
|
|
93092
93189
|
const ts = now();
|
|
93093
93190
|
const id2 = newId("prj_");
|
|
@@ -93155,6 +93252,32 @@ var skillRepo = {
|
|
|
93155
93252
|
const r = getDb().prepare(`SELECT * FROM skills WHERE id = ?`).get(id2);
|
|
93156
93253
|
return r ? mapSkill(r) : null;
|
|
93157
93254
|
},
|
|
93255
|
+
/** Existing skill with the same name (case-insensitive), or null (for idempotent batch upserts). */
|
|
93256
|
+
findByName(name) {
|
|
93257
|
+
const key = norm(name);
|
|
93258
|
+
return this.list().find((s) => norm(s.name) === key) ?? null;
|
|
93259
|
+
},
|
|
93260
|
+
/** Insert, or merge into the same-named skill (omitted fields keep their stored value). */
|
|
93261
|
+
upsert(input) {
|
|
93262
|
+
const existing = this.findByName(input.name);
|
|
93263
|
+
if (existing) return { record: this.update(existing.id, input), created: false };
|
|
93264
|
+
return { record: this.add(input), created: true };
|
|
93265
|
+
},
|
|
93266
|
+
/** Batch insert/merge in one transaction; within-batch duplicates collapse onto one row. */
|
|
93267
|
+
addMany(inputs) {
|
|
93268
|
+
return tx(() => {
|
|
93269
|
+
const records = [];
|
|
93270
|
+
let created = 0;
|
|
93271
|
+
let updated = 0;
|
|
93272
|
+
for (const input of inputs) {
|
|
93273
|
+
const { record: record2, created: isNew } = this.upsert(input);
|
|
93274
|
+
records.push(record2);
|
|
93275
|
+
if (isNew) created += 1;
|
|
93276
|
+
else updated += 1;
|
|
93277
|
+
}
|
|
93278
|
+
return { records, created, updated };
|
|
93279
|
+
});
|
|
93280
|
+
},
|
|
93158
93281
|
add(input) {
|
|
93159
93282
|
const ts = now();
|
|
93160
93283
|
const id2 = newId("skl_");
|
|
@@ -93345,6 +93468,7 @@ var coverLetterRepo = {
|
|
|
93345
93468
|
remove(id2) {
|
|
93346
93469
|
const db = getDb();
|
|
93347
93470
|
return tx(() => {
|
|
93471
|
+
db.prepare(`UPDATE applications SET cover_letter_id=NULL, updated_at=? WHERE cover_letter_id=?`).run(now(), id2);
|
|
93348
93472
|
db.prepare(`DELETE FROM cover_letter_versions WHERE cover_letter_id=?`).run(id2);
|
|
93349
93473
|
return db.prepare(`DELETE FROM cover_letters WHERE id=?`).run(id2).changes > 0;
|
|
93350
93474
|
});
|
|
@@ -93433,6 +93557,7 @@ var jobRepo = {
|
|
|
93433
93557
|
remove(id2) {
|
|
93434
93558
|
const db = getDb();
|
|
93435
93559
|
return tx(() => {
|
|
93560
|
+
db.prepare(`UPDATE cover_letters SET job_id=NULL, updated_at=? WHERE job_id=?`).run(now(), id2);
|
|
93436
93561
|
db.prepare(`DELETE FROM fit_analyses WHERE job_id=?`).run(id2);
|
|
93437
93562
|
db.prepare(`DELETE FROM applications WHERE job_id=?`).run(id2);
|
|
93438
93563
|
db.prepare(`DELETE FROM interview_preps WHERE job_id=?`).run(id2);
|
|
@@ -93631,7 +93756,7 @@ var activityRepo = {
|
|
|
93631
93756
|
};
|
|
93632
93757
|
|
|
93633
93758
|
// packages/mcp-tools/src/tools.ts
|
|
93634
|
-
import
|
|
93759
|
+
import fs7 from "node:fs";
|
|
93635
93760
|
import path7 from "node:path";
|
|
93636
93761
|
|
|
93637
93762
|
// packages/core/src/onboarding.ts
|
|
@@ -93984,7 +94109,7 @@ function styleSignals(text) {
|
|
|
93984
94109
|
}
|
|
93985
94110
|
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.";
|
|
93986
94111
|
function lintArtifact(kind, text, corpus, opts = {}) {
|
|
93987
|
-
const
|
|
94112
|
+
const norm2 = normalizeText(text);
|
|
93988
94113
|
const corpusAvailable = (corpus.documents + corpus.structured).trim().length > 0;
|
|
93989
94114
|
const provenance = analyzeProvenance(text, corpus);
|
|
93990
94115
|
const signals = styleSignals(text);
|
|
@@ -94008,7 +94133,7 @@ function lintArtifact(kind, text, corpus, opts = {}) {
|
|
|
94008
94133
|
}
|
|
94009
94134
|
return {
|
|
94010
94135
|
kind,
|
|
94011
|
-
charCount: [...
|
|
94136
|
+
charCount: [...norm2].length,
|
|
94012
94137
|
signals,
|
|
94013
94138
|
provenance,
|
|
94014
94139
|
blocking,
|
|
@@ -94068,20 +94193,40 @@ function addResume(input) {
|
|
|
94068
94193
|
activityRepo.log("resume_added", `${doc.title} \uBB38\uC11C\uB97C \uCD94\uAC00\uD588\uC2B5\uB2C8\uB2E4.`, "document", doc.id);
|
|
94069
94194
|
return doc;
|
|
94070
94195
|
}
|
|
94071
|
-
function
|
|
94072
|
-
const
|
|
94073
|
-
|
|
94074
|
-
return
|
|
94196
|
+
function batchNames(names) {
|
|
94197
|
+
const shown = names.filter(Boolean).slice(0, 8).join(", ");
|
|
94198
|
+
if (!shown) return "";
|
|
94199
|
+
return `: ${shown}${names.length > 8 ? " \uC678" : ""}`;
|
|
94075
94200
|
}
|
|
94076
|
-
function
|
|
94077
|
-
const
|
|
94078
|
-
activityRepo.log(
|
|
94079
|
-
|
|
94201
|
+
function addExperiences(inputs) {
|
|
94202
|
+
const res = experienceRepo.addMany(inputs);
|
|
94203
|
+
activityRepo.log(
|
|
94204
|
+
"profile_updated",
|
|
94205
|
+
`\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))}.`,
|
|
94206
|
+
"experience",
|
|
94207
|
+
res.records[0]?.id
|
|
94208
|
+
);
|
|
94209
|
+
return res;
|
|
94080
94210
|
}
|
|
94081
|
-
function
|
|
94082
|
-
const
|
|
94083
|
-
activityRepo.log(
|
|
94084
|
-
|
|
94211
|
+
function addProjects(inputs) {
|
|
94212
|
+
const res = projectRepo.addMany(inputs);
|
|
94213
|
+
activityRepo.log(
|
|
94214
|
+
"profile_updated",
|
|
94215
|
+
`\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))}.`,
|
|
94216
|
+
"project",
|
|
94217
|
+
res.records[0]?.id
|
|
94218
|
+
);
|
|
94219
|
+
return res;
|
|
94220
|
+
}
|
|
94221
|
+
function addSkills(inputs) {
|
|
94222
|
+
const res = skillRepo.addMany(inputs);
|
|
94223
|
+
activityRepo.log(
|
|
94224
|
+
"profile_updated",
|
|
94225
|
+
`\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))}.`,
|
|
94226
|
+
"skill",
|
|
94227
|
+
res.records[0]?.id
|
|
94228
|
+
);
|
|
94229
|
+
return res;
|
|
94085
94230
|
}
|
|
94086
94231
|
function saveJobPosting(input, id2) {
|
|
94087
94232
|
const job = jobRepo.upsert(input, id2);
|
|
@@ -94091,7 +94236,7 @@ function saveJobPosting(input, id2) {
|
|
|
94091
94236
|
}
|
|
94092
94237
|
function saveFitAnalysis(input) {
|
|
94093
94238
|
const job = jobRepo.get(input.job_id);
|
|
94094
|
-
if (!job) throw
|
|
94239
|
+
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.");
|
|
94095
94240
|
applicationRepo.ensure(job.id, "draft");
|
|
94096
94241
|
const fit = fitRepo.save(input);
|
|
94097
94242
|
const scoreText = fit.score != null ? ` (\uC801\uD569\uB3C4 ${fit.score}\uC810)` : "";
|
|
@@ -94106,7 +94251,7 @@ function saveCoverLetterVersion(input) {
|
|
|
94106
94251
|
const detail = verification.blocking.map((b) => `${b.label}: ${b.detail}`).join("; ");
|
|
94107
94252
|
const strictHit = verification.blocking.some((b) => b.id === "unverified_numbers_strict");
|
|
94108
94253
|
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).`;
|
|
94109
|
-
throw new
|
|
94254
|
+
throw new CareerMateError(`\uC800\uC7A5 \uC804 \uC790\uB3D9 \uC810\uAC80\uC5D0\uC11C \uB9C9\uD614\uC2B5\uB2C8\uB2E4 \u2014 ${detail}. ${tail}`, 400, "save_gate");
|
|
94110
94255
|
}
|
|
94111
94256
|
const { coverLetter, version: version3 } = coverLetterRepo.addVersion({
|
|
94112
94257
|
cover_letter_id: input.cover_letter_id,
|
|
@@ -94133,7 +94278,7 @@ function saveCoverLetterVersion(input) {
|
|
|
94133
94278
|
}
|
|
94134
94279
|
function updateApplicationStatus(jobId, status, note) {
|
|
94135
94280
|
const job = jobRepo.get(jobId);
|
|
94136
|
-
if (!job) throw
|
|
94281
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
94137
94282
|
const application = applicationRepo.setStatus(jobId, status, note);
|
|
94138
94283
|
activityRepo.log(
|
|
94139
94284
|
"application_status_changed",
|
|
@@ -94143,17 +94288,17 @@ function updateApplicationStatus(jobId, status, note) {
|
|
|
94143
94288
|
);
|
|
94144
94289
|
const interview_unlocked = INTERVIEW_UNLOCK_STATUSES.includes(status);
|
|
94145
94290
|
const hasPrep = !!interviewRepo.getByJob(jobId);
|
|
94146
|
-
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?
|
|
94291
|
+
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;
|
|
94147
94292
|
return { application, job, interview_unlocked, hint };
|
|
94148
94293
|
}
|
|
94149
94294
|
function saveInterviewPrep(input) {
|
|
94150
94295
|
const job = jobRepo.get(input.job_id);
|
|
94151
|
-
if (!job) throw
|
|
94296
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
94152
94297
|
const app = applicationRepo.getByJob(job.id);
|
|
94153
94298
|
if (!app || !INTERVIEW_UNLOCK_STATUSES.includes(app.status)) {
|
|
94154
94299
|
const current = app ? APPLICATION_STATUS_LABELS[app.status] : "\uBBF8\uC9C0\uC6D0";
|
|
94155
|
-
throw
|
|
94156
|
-
`\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
|
|
94300
|
+
throw conflict(
|
|
94301
|
+
`\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.`
|
|
94157
94302
|
);
|
|
94158
94303
|
}
|
|
94159
94304
|
const prep = interviewRepo.save(input);
|
|
@@ -94233,7 +94378,7 @@ var WORKFLOWS = [
|
|
|
94233
94378
|
'\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.)',
|
|
94234
94379
|
"\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.",
|
|
94235
94380
|
"\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).",
|
|
94236
|
-
"\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC\uC774 \uD30C\uC545\uB418\uBA74 `add_experience`\xB7`add_project`\xB7`add_skill`\uB85C \
|
|
94381
|
+
"\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).",
|
|
94237
94382
|
"\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).",
|
|
94238
94383
|
"`open_dashboard`\uB97C \uD638\uCD9C\uD574 \uC0AC\uC6A9\uC790\uAC00 \uC790\uAE30 \uB370\uC774\uD130\uB97C \uD655\uC778\uD558\uAC8C \uD55C\uB2E4.",
|
|
94239
94384
|
"\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."
|
|
@@ -94251,8 +94396,8 @@ var WORKFLOWS = [
|
|
|
94251
94396
|
"\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.",
|
|
94252
94397
|
"\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).",
|
|
94253
94398
|
"\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.",
|
|
94254
|
-
'"\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?"\uB77C\uACE0 \uC790\uAE30\uC18C\uAC1C\uC11C \
|
|
94255
|
-
'\uC0AC\uC6A9\uC790\uAC00 \
|
|
94399
|
+
'\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".',
|
|
94400
|
+
'\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.',
|
|
94256
94401
|
"\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).",
|
|
94257
94402
|
"`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."
|
|
94258
94403
|
]
|
|
@@ -95532,14 +95677,94 @@ function toCallToolResult(r) {
|
|
|
95532
95677
|
}
|
|
95533
95678
|
|
|
95534
95679
|
// packages/mcp-tools/src/bridge.ts
|
|
95535
|
-
import { spawn } from "node:child_process";
|
|
95680
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
95681
|
+
import fs5 from "node:fs";
|
|
95536
95682
|
import path5 from "node:path";
|
|
95537
95683
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
95538
95684
|
var __dirname = path5.dirname(fileURLToPath2(import.meta.url));
|
|
95539
95685
|
var REPO_ROOT = path5.resolve(__dirname, "..", "..", "..");
|
|
95540
|
-
|
|
95686
|
+
var HEALTH_TIMEOUT_MS = 800;
|
|
95687
|
+
var pendingStart = null;
|
|
95688
|
+
function dashboardLogPath() {
|
|
95689
|
+
return path5.join(getDataDir(), "server.log");
|
|
95690
|
+
}
|
|
95691
|
+
function launchdPlistPath() {
|
|
95692
|
+
return path5.join(getDataDir(), "dashboard.launchd.plist");
|
|
95693
|
+
}
|
|
95694
|
+
function launchdLabel() {
|
|
95695
|
+
let hash = 5381;
|
|
95696
|
+
for (const ch of getDataDir()) hash = (hash * 33 ^ ch.charCodeAt(0)) >>> 0;
|
|
95697
|
+
return `life.careermate.dashboard.${hash.toString(16)}`;
|
|
95698
|
+
}
|
|
95699
|
+
function xmlEscape(value) {
|
|
95700
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
95701
|
+
}
|
|
95702
|
+
function plistString(key, value) {
|
|
95703
|
+
return ` <key>${xmlEscape(key)}</key>
|
|
95704
|
+
<string>${xmlEscape(value)}</string>`;
|
|
95705
|
+
}
|
|
95706
|
+
function renderLaunchdPlist(bin, args, cwd, log) {
|
|
95707
|
+
const env2 = {
|
|
95708
|
+
CAREERMATE_DATA_DIR: getDataDir(),
|
|
95709
|
+
CAREERMATE_NO_OPEN: "1"
|
|
95710
|
+
};
|
|
95711
|
+
if (process.env.CAREERMATE_PORT) env2.CAREERMATE_PORT = process.env.CAREERMATE_PORT;
|
|
95712
|
+
if (process.env.PATH) env2.PATH = process.env.PATH;
|
|
95713
|
+
const programArgs = [bin, ...args].map((arg) => ` <string>${xmlEscape(arg)}</string>`).join("\n");
|
|
95714
|
+
const envEntries = Object.entries(env2).map(([key, value]) => `${plistString(key, value)}`).join("\n");
|
|
95715
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
95716
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
95717
|
+
<plist version="1.0">
|
|
95718
|
+
<dict>
|
|
95719
|
+
<key>Label</key>
|
|
95720
|
+
<string>${xmlEscape(launchdLabel())}</string>
|
|
95721
|
+
<key>ProgramArguments</key>
|
|
95722
|
+
<array>
|
|
95723
|
+
${programArgs}
|
|
95724
|
+
</array>
|
|
95725
|
+
<key>WorkingDirectory</key>
|
|
95726
|
+
<string>${xmlEscape(cwd)}</string>
|
|
95727
|
+
<key>EnvironmentVariables</key>
|
|
95728
|
+
<dict>
|
|
95729
|
+
${envEntries}
|
|
95730
|
+
</dict>
|
|
95731
|
+
<key>RunAtLoad</key>
|
|
95732
|
+
<true/>
|
|
95733
|
+
<key>KeepAlive</key>
|
|
95734
|
+
<false/>
|
|
95735
|
+
<key>StandardOutPath</key>
|
|
95736
|
+
<string>${xmlEscape(log)}</string>
|
|
95737
|
+
<key>StandardErrorPath</key>
|
|
95738
|
+
<string>${xmlEscape(log)}</string>
|
|
95739
|
+
</dict>
|
|
95740
|
+
</plist>
|
|
95741
|
+
`;
|
|
95742
|
+
}
|
|
95743
|
+
function delay(ms) {
|
|
95744
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
95745
|
+
}
|
|
95746
|
+
async function pingDashboard(url, timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
95747
|
+
const controller = new AbortController();
|
|
95748
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
95749
|
+
timer.unref?.();
|
|
95750
|
+
try {
|
|
95751
|
+
const healthUrl = new URL("/api/health", url);
|
|
95752
|
+
const res = await fetch(healthUrl, {
|
|
95753
|
+
signal: controller.signal,
|
|
95754
|
+
headers: { accept: "application/json" }
|
|
95755
|
+
});
|
|
95756
|
+
if (!res.ok) return false;
|
|
95757
|
+
const body = await res.json().catch(() => null);
|
|
95758
|
+
return body?.ok === true;
|
|
95759
|
+
} catch {
|
|
95760
|
+
return false;
|
|
95761
|
+
} finally {
|
|
95762
|
+
clearTimeout(timer);
|
|
95763
|
+
}
|
|
95764
|
+
}
|
|
95765
|
+
async function liveServer() {
|
|
95541
95766
|
const info2 = readRuntimeInfo();
|
|
95542
|
-
if (info2 && isProcessAlive(info2.pid)) return info2;
|
|
95767
|
+
if (info2 && isProcessAlive(info2.pid) && await pingDashboard(info2.url)) return info2;
|
|
95543
95768
|
return null;
|
|
95544
95769
|
}
|
|
95545
95770
|
function spawnDetached(cmd, args, opts = {}) {
|
|
@@ -95548,19 +95773,101 @@ function spawnDetached(cmd, args, opts = {}) {
|
|
|
95548
95773
|
child.on("error", () => {
|
|
95549
95774
|
});
|
|
95550
95775
|
child.unref();
|
|
95776
|
+
return child.pid ?? null;
|
|
95551
95777
|
} catch {
|
|
95778
|
+
return null;
|
|
95779
|
+
}
|
|
95780
|
+
}
|
|
95781
|
+
function spawnViaLaunchd(bin, args, cwd, log) {
|
|
95782
|
+
if (process.platform !== "darwin" || process.env.CAREERMATE_LAUNCHER === "detached") return false;
|
|
95783
|
+
if (typeof process.getuid !== "function") return false;
|
|
95784
|
+
const domain = `gui/${process.getuid()}`;
|
|
95785
|
+
const label = launchdLabel();
|
|
95786
|
+
const plist = launchdPlistPath();
|
|
95787
|
+
try {
|
|
95788
|
+
fs5.writeFileSync(plist, renderLaunchdPlist(bin, args, cwd, log), "utf8");
|
|
95789
|
+
spawnSync("launchctl", ["bootout", `${domain}/${label}`], { stdio: "ignore" });
|
|
95790
|
+
const res = spawnSync("launchctl", ["bootstrap", domain, plist], {
|
|
95791
|
+
encoding: "utf8",
|
|
95792
|
+
timeout: 5e3
|
|
95793
|
+
});
|
|
95794
|
+
if (res.status === 0) return true;
|
|
95795
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchctl bootstrap failed: ${res.stderr || res.stdout || res.status}
|
|
95796
|
+
`);
|
|
95797
|
+
} catch (e) {
|
|
95798
|
+
try {
|
|
95799
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchctl launch failed: ${e instanceof Error ? e.message : String(e)}
|
|
95800
|
+
`);
|
|
95801
|
+
} catch {
|
|
95802
|
+
}
|
|
95552
95803
|
}
|
|
95804
|
+
return false;
|
|
95805
|
+
}
|
|
95806
|
+
function spawnDashboardDetached(bin, args, cwd, logFd) {
|
|
95807
|
+
spawnDetached(bin, args, {
|
|
95808
|
+
cwd,
|
|
95809
|
+
env: { ...process.env, CAREERMATE_NO_OPEN: "1" },
|
|
95810
|
+
stdio: logFd === null ? "ignore" : ["ignore", logFd, logFd]
|
|
95811
|
+
});
|
|
95553
95812
|
}
|
|
95554
95813
|
async function ensureServer(timeoutMs = 12e3) {
|
|
95555
|
-
const existing = liveServer();
|
|
95814
|
+
const existing = await liveServer();
|
|
95556
95815
|
if (existing) return { url: existing.url };
|
|
95557
|
-
|
|
95558
|
-
|
|
95816
|
+
if (pendingStart) return pendingStart;
|
|
95817
|
+
pendingStart = startServerBackground(timeoutMs);
|
|
95818
|
+
try {
|
|
95819
|
+
return await pendingStart;
|
|
95820
|
+
} finally {
|
|
95821
|
+
pendingStart = null;
|
|
95822
|
+
}
|
|
95823
|
+
}
|
|
95824
|
+
async function startServerBackground(timeoutMs) {
|
|
95825
|
+
const [bin, args, cwd] = BUNDLED ? [process.execPath, ["--experimental-sqlite", path5.join(__dirname, "web.mjs")], __dirname] : [
|
|
95826
|
+
process.execPath,
|
|
95827
|
+
["--no-warnings", "--experimental-sqlite", "--import", "tsx", path5.join(REPO_ROOT, "apps/web/src/index.ts")],
|
|
95828
|
+
REPO_ROOT
|
|
95829
|
+
];
|
|
95830
|
+
const log = dashboardLogPath();
|
|
95831
|
+
let logFd = null;
|
|
95832
|
+
try {
|
|
95833
|
+
logFd = fs5.openSync(log, "a");
|
|
95834
|
+
fs5.writeSync(logFd, `
|
|
95835
|
+
[${(/* @__PURE__ */ new Date()).toISOString()}] CareerMate dashboard background launch
|
|
95836
|
+
`);
|
|
95837
|
+
} catch {
|
|
95838
|
+
logFd = null;
|
|
95839
|
+
}
|
|
95840
|
+
let launchedViaLaunchd = false;
|
|
95841
|
+
try {
|
|
95842
|
+
launchedViaLaunchd = spawnViaLaunchd(bin, args, cwd, log);
|
|
95843
|
+
if (!launchedViaLaunchd) spawnDashboardDetached(bin, args, cwd, logFd);
|
|
95844
|
+
} finally {
|
|
95845
|
+
if (logFd !== null) {
|
|
95846
|
+
try {
|
|
95847
|
+
fs5.closeSync(logFd);
|
|
95848
|
+
} catch {
|
|
95849
|
+
}
|
|
95850
|
+
}
|
|
95851
|
+
}
|
|
95559
95852
|
const start = Date.now();
|
|
95560
95853
|
while (Date.now() - start < timeoutMs) {
|
|
95561
|
-
const info2 = liveServer();
|
|
95854
|
+
const info2 = await liveServer();
|
|
95562
95855
|
if (info2) return { url: info2.url };
|
|
95563
|
-
await
|
|
95856
|
+
await delay(300);
|
|
95857
|
+
}
|
|
95858
|
+
if (launchedViaLaunchd) {
|
|
95859
|
+
try {
|
|
95860
|
+
fs5.appendFileSync(log, `[${(/* @__PURE__ */ new Date()).toISOString()}] launchd did not produce a healthy server; falling back to detached spawn
|
|
95861
|
+
`);
|
|
95862
|
+
} catch {
|
|
95863
|
+
}
|
|
95864
|
+
spawnDashboardDetached(bin, args, cwd, null);
|
|
95865
|
+
const fallbackStart = Date.now();
|
|
95866
|
+
while (Date.now() - fallbackStart < Math.min(timeoutMs, 8e3)) {
|
|
95867
|
+
const info2 = await liveServer();
|
|
95868
|
+
if (info2) return { url: info2.url };
|
|
95869
|
+
await delay(300);
|
|
95870
|
+
}
|
|
95564
95871
|
}
|
|
95565
95872
|
return null;
|
|
95566
95873
|
}
|
|
@@ -95584,7 +95891,7 @@ function openInFileManager(dir) {
|
|
|
95584
95891
|
else openOsTarget(dir);
|
|
95585
95892
|
}
|
|
95586
95893
|
async function resolveDashboardUrl(hash = "") {
|
|
95587
|
-
const live = liveServer();
|
|
95894
|
+
const live = await liveServer();
|
|
95588
95895
|
if (live) return { url: live.url + hash, running: true };
|
|
95589
95896
|
const started = await ensureServer();
|
|
95590
95897
|
if (started) return { url: started.url + hash, running: true };
|
|
@@ -95592,7 +95899,7 @@ async function resolveDashboardUrl(hash = "") {
|
|
|
95592
95899
|
}
|
|
95593
95900
|
|
|
95594
95901
|
// packages/mcp-tools/src/update.ts
|
|
95595
|
-
import
|
|
95902
|
+
import fs6 from "node:fs";
|
|
95596
95903
|
import path6 from "node:path";
|
|
95597
95904
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
95598
95905
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -95649,14 +95956,14 @@ function comparePrerelease(a, b) {
|
|
|
95649
95956
|
}
|
|
95650
95957
|
function readCache() {
|
|
95651
95958
|
try {
|
|
95652
|
-
return JSON.parse(
|
|
95959
|
+
return JSON.parse(fs6.readFileSync(cacheFile(), "utf8"));
|
|
95653
95960
|
} catch {
|
|
95654
95961
|
return null;
|
|
95655
95962
|
}
|
|
95656
95963
|
}
|
|
95657
95964
|
function writeCache(c) {
|
|
95658
95965
|
try {
|
|
95659
|
-
|
|
95966
|
+
fs6.writeFileSync(cacheFile(), JSON.stringify(c), "utf8");
|
|
95660
95967
|
} catch {
|
|
95661
95968
|
}
|
|
95662
95969
|
}
|
|
@@ -95813,16 +96120,18 @@ async function runSelfUpdate() {
|
|
|
95813
96120
|
ok: true,
|
|
95814
96121
|
from,
|
|
95815
96122
|
to: latest,
|
|
95816
|
-
message: `
|
|
96123
|
+
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.`
|
|
95817
96124
|
};
|
|
95818
96125
|
}
|
|
95819
96126
|
|
|
95820
96127
|
// packages/mcp-tools/src/tools.ts
|
|
95821
96128
|
var STATUS_LIST = APPLICATION_STATUSES.map((s) => `${s}(${APPLICATION_STATUS_LABELS[s]})`).join(", ");
|
|
96129
|
+
var DELETE_CONFIRMATION = "DELETE";
|
|
96130
|
+
var DASHBOARD_URL = "http://127.0.0.1:4319";
|
|
95822
96131
|
function listInboxFiles(dir) {
|
|
95823
96132
|
let names;
|
|
95824
96133
|
try {
|
|
95825
|
-
names =
|
|
96134
|
+
names = fs7.readdirSync(dir);
|
|
95826
96135
|
} catch {
|
|
95827
96136
|
return [];
|
|
95828
96137
|
}
|
|
@@ -95832,7 +96141,7 @@ function listInboxFiles(dir) {
|
|
|
95832
96141
|
if (SKIP.test(name)) continue;
|
|
95833
96142
|
const p = path7.join(dir, name);
|
|
95834
96143
|
try {
|
|
95835
|
-
if (
|
|
96144
|
+
if (fs7.statSync(p).isFile()) out.push({ name, path: p });
|
|
95836
96145
|
} catch {
|
|
95837
96146
|
}
|
|
95838
96147
|
}
|
|
@@ -95995,9 +96304,17 @@ ${lines}`;
|
|
|
95995
96304
|
if (upd.update_available) {
|
|
95996
96305
|
text += `
|
|
95997
96306
|
|
|
95998
|
-
\
|
|
96307
|
+
\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.`;
|
|
95999
96308
|
}
|
|
96000
|
-
return ok(text, {
|
|
96309
|
+
return ok(text, {
|
|
96310
|
+
...s,
|
|
96311
|
+
verify_strict: strict,
|
|
96312
|
+
update: upd,
|
|
96313
|
+
suggested_next_action: upd.update_available ? {
|
|
96314
|
+
prompt: `\uC0C8 \uBC84\uC804 v${upd.latest}\uC774 \uB098\uC654\uC2B5\uB2C8\uB2E4. \uC9C0\uAE08 \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694?`,
|
|
96315
|
+
next_tool: "update_careermate"
|
|
96316
|
+
} : null
|
|
96317
|
+
});
|
|
96001
96318
|
}
|
|
96002
96319
|
},
|
|
96003
96320
|
/* --------------------------------------------------------------- profile */
|
|
@@ -96054,11 +96371,12 @@ ${lines}`;
|
|
|
96054
96371
|
{
|
|
96055
96372
|
name: "add_experience",
|
|
96056
96373
|
title: "\uACBD\uB825 \uCD94\uAC00",
|
|
96057
|
-
description: "\uAD6C\uC870\uD654\uB41C \uACBD\uB825(\uC9C1\uC7A5 \uB2E8\uC704)\uC744 \
|
|
96058
|
-
inputSchema:
|
|
96374
|
+
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.",
|
|
96375
|
+
inputSchema: ExperienceBatchInputSchema.shape,
|
|
96059
96376
|
handler: (args) => {
|
|
96060
|
-
const
|
|
96061
|
-
|
|
96377
|
+
const { records, created, updated } = addExperiences(args.experiences);
|
|
96378
|
+
const names = records.map((e) => `${e.company}${e.role ? ` \xB7 ${e.role}` : ""}`).join(", ");
|
|
96379
|
+
return ok(`\uACBD\uB825 ${records.length}\uAC74\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4 (\uC2E0\uADDC ${created} \xB7 \uAC31\uC2E0 ${updated}): ${names}`, records);
|
|
96062
96380
|
}
|
|
96063
96381
|
},
|
|
96064
96382
|
{
|
|
@@ -96076,11 +96394,12 @@ ${lines}`;
|
|
|
96076
96394
|
{
|
|
96077
96395
|
name: "add_project",
|
|
96078
96396
|
title: "\uD504\uB85C\uC81D\uD2B8 \uCD94\uAC00",
|
|
96079
|
-
description: "\uB300\uD45C \uD504\uB85C\uC81D\uD2B8\uB97C \
|
|
96080
|
-
inputSchema:
|
|
96397
|
+
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.",
|
|
96398
|
+
inputSchema: ProjectBatchInputSchema.shape,
|
|
96081
96399
|
handler: (args) => {
|
|
96082
|
-
const
|
|
96083
|
-
|
|
96400
|
+
const { records, created, updated } = addProjects(args.projects);
|
|
96401
|
+
const names = records.map((p) => p.name).join(", ");
|
|
96402
|
+
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);
|
|
96084
96403
|
}
|
|
96085
96404
|
},
|
|
96086
96405
|
{
|
|
@@ -96098,11 +96417,12 @@ ${lines}`;
|
|
|
96098
96417
|
{
|
|
96099
96418
|
name: "add_skill",
|
|
96100
96419
|
title: "\uAE30\uC220\uC2A4\uD0DD \uCD94\uAC00",
|
|
96101
|
-
description: "\uBCF4\uC720 \uAE30\uC220\uC2A4\uD0DD\uC744 \
|
|
96102
|
-
inputSchema:
|
|
96420
|
+
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.",
|
|
96421
|
+
inputSchema: SkillBatchInputSchema.shape,
|
|
96103
96422
|
handler: (args) => {
|
|
96104
|
-
const
|
|
96105
|
-
|
|
96423
|
+
const { records, created, updated } = addSkills(args.skills);
|
|
96424
|
+
const names = records.map((s) => s.name).join(", ");
|
|
96425
|
+
return ok(`\uAE30\uC220 ${records.length}\uAC1C\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4 (\uC2E0\uADDC ${created} \xB7 \uAC31\uC2E0 ${updated}): ${names}`, records);
|
|
96106
96426
|
}
|
|
96107
96427
|
},
|
|
96108
96428
|
{
|
|
@@ -96147,6 +96467,31 @@ ${lines}`;
|
|
|
96147
96467
|
}
|
|
96148
96468
|
}
|
|
96149
96469
|
},
|
|
96470
|
+
{
|
|
96471
|
+
name: "delete_cover_letter",
|
|
96472
|
+
title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uC0AD\uC81C",
|
|
96473
|
+
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.",
|
|
96474
|
+
inputSchema: {
|
|
96475
|
+
cover_letter_id: external_exports.string(),
|
|
96476
|
+
confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
|
|
96477
|
+
},
|
|
96478
|
+
handler: (args) => {
|
|
96479
|
+
if (args?.confirm !== DELETE_CONFIRMATION) {
|
|
96480
|
+
return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
|
|
96481
|
+
}
|
|
96482
|
+
const cl = coverLetterRepo.get(args.cover_letter_id, false);
|
|
96483
|
+
if (!cl) return fail("\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
96484
|
+
const removed = coverLetterRepo.remove(cl.id);
|
|
96485
|
+
if (!removed) return fail("\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
96486
|
+
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.`;
|
|
96487
|
+
return ok(user_message, {
|
|
96488
|
+
deleted: true,
|
|
96489
|
+
cover_letter_id: cl.id,
|
|
96490
|
+
title: cl.title,
|
|
96491
|
+
user_message
|
|
96492
|
+
});
|
|
96493
|
+
}
|
|
96494
|
+
},
|
|
96150
96495
|
/* ------------------------------------------------------------------ jobs */
|
|
96151
96496
|
{
|
|
96152
96497
|
name: "save_job_posting",
|
|
@@ -96155,7 +96500,15 @@ ${lines}`;
|
|
|
96155
96500
|
inputSchema: JobInputSchema.shape,
|
|
96156
96501
|
handler: (args) => {
|
|
96157
96502
|
const { job } = saveJobPosting(args);
|
|
96158
|
-
|
|
96503
|
+
const user_message = `'${job.company} \xB7 ${job.position}' \uACF5\uACE0\uB97C \uC800\uC7A5\uD588\uC5B4\uC694.`;
|
|
96504
|
+
return ok(user_message, {
|
|
96505
|
+
...job,
|
|
96506
|
+
user_message,
|
|
96507
|
+
suggested_next_action: {
|
|
96508
|
+
prompt: "\uC774 \uACF5\uACE0\uC640 \uB0B4 \uD504\uB85C\uD544\uC744 \uBE44\uAD50\uD574 \uC801\uD569\uB3C4\uB97C \uBD84\uC11D\uD560\uAE4C\uC694?",
|
|
96509
|
+
next_workflow: "analyze_job"
|
|
96510
|
+
}
|
|
96511
|
+
});
|
|
96159
96512
|
}
|
|
96160
96513
|
},
|
|
96161
96514
|
{
|
|
@@ -96166,7 +96519,7 @@ ${lines}`;
|
|
|
96166
96519
|
readOnly: true,
|
|
96167
96520
|
handler: (args) => {
|
|
96168
96521
|
const job = jobRepo.get(args.job_id);
|
|
96169
|
-
if (!job) return fail(
|
|
96522
|
+
if (!job) return fail("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
96170
96523
|
return ok(`${job.company} \xB7 ${job.position}`, {
|
|
96171
96524
|
job: jobWithMeta(job),
|
|
96172
96525
|
fit: fitRepo.getByJob(job.id),
|
|
@@ -96187,6 +96540,35 @@ ${lines}`;
|
|
|
96187
96540
|
return ok(`\uACF5\uACE0 ${jobs.length}\uAC74`, jobs);
|
|
96188
96541
|
}
|
|
96189
96542
|
},
|
|
96543
|
+
{
|
|
96544
|
+
name: "delete_job_posting",
|
|
96545
|
+
title: "\uCC44\uC6A9\uACF5\uACE0 \uC0AD\uC81C",
|
|
96546
|
+
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.",
|
|
96547
|
+
inputSchema: {
|
|
96548
|
+
job_id: external_exports.string(),
|
|
96549
|
+
confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
|
|
96550
|
+
},
|
|
96551
|
+
handler: (args) => {
|
|
96552
|
+
if (args?.confirm !== DELETE_CONFIRMATION) {
|
|
96553
|
+
return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
|
|
96554
|
+
}
|
|
96555
|
+
const job = jobRepo.get(args.job_id);
|
|
96556
|
+
if (!job) return fail("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
96557
|
+
const detachedCoverLetters = coverLetterRepo.listByJob(job.id).length;
|
|
96558
|
+
const removed = jobRepo.remove(job.id);
|
|
96559
|
+
if (!removed) return fail("\uACF5\uACE0\uB97C \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
96560
|
+
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.` : "";
|
|
96561
|
+
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}`;
|
|
96562
|
+
return ok(user_message, {
|
|
96563
|
+
deleted: true,
|
|
96564
|
+
job_id: job.id,
|
|
96565
|
+
company: job.company,
|
|
96566
|
+
position: job.position,
|
|
96567
|
+
detached_cover_letters: detachedCoverLetters,
|
|
96568
|
+
user_message
|
|
96569
|
+
});
|
|
96570
|
+
}
|
|
96571
|
+
},
|
|
96190
96572
|
/* ----------------------------------------------------- application context */
|
|
96191
96573
|
{
|
|
96192
96574
|
name: "get_application_context",
|
|
@@ -96209,7 +96591,7 @@ ${lines}`;
|
|
|
96209
96591
|
`\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}`,
|
|
96210
96592
|
ctx.job ? `\uB300\uC0C1 \uACF5\uACE0: ${ctx.job.company} \xB7 ${ctx.job.position}` : "\uB300\uC0C1 \uACF5\uACE0 \uC5C6\uC74C",
|
|
96211
96593
|
ctx.writing_preferences.preferred_tone ? `\uC120\uD638 \uBB38\uCCB4: ${ctx.writing_preferences.preferred_tone}` : "",
|
|
96212
|
-
recommended_route ? `\
|
|
96594
|
+
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."
|
|
96213
96595
|
].filter(Boolean).join("\n");
|
|
96214
96596
|
return ok(summary, enriched);
|
|
96215
96597
|
}
|
|
@@ -96222,7 +96604,34 @@ ${lines}`;
|
|
|
96222
96604
|
handler: (args) => {
|
|
96223
96605
|
try {
|
|
96224
96606
|
const fit = saveFitAnalysis(args);
|
|
96225
|
-
|
|
96607
|
+
const suggested_next_action = {
|
|
96608
|
+
prompt: "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?",
|
|
96609
|
+
options: [
|
|
96610
|
+
{
|
|
96611
|
+
label: "\uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
|
|
96612
|
+
next_workflow: "write_cover_letter"
|
|
96613
|
+
},
|
|
96614
|
+
{
|
|
96615
|
+
label: "\uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918",
|
|
96616
|
+
next_workflow: null
|
|
96617
|
+
}
|
|
96618
|
+
]
|
|
96619
|
+
};
|
|
96620
|
+
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}`;
|
|
96621
|
+
return ok(
|
|
96622
|
+
[
|
|
96623
|
+
user_message,
|
|
96624
|
+
"",
|
|
96625
|
+
"\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB2E4\uC74C \uC120\uD0DD\uC9C0\uB97C \uBCF4\uC5EC\uC8FC\uC138\uC694:",
|
|
96626
|
+
"1. \uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
|
|
96627
|
+
"2. \uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918"
|
|
96628
|
+
].join("\n"),
|
|
96629
|
+
{
|
|
96630
|
+
...fit,
|
|
96631
|
+
user_message,
|
|
96632
|
+
suggested_next_action
|
|
96633
|
+
}
|
|
96634
|
+
);
|
|
96226
96635
|
} catch (e) {
|
|
96227
96636
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
96228
96637
|
}
|
|
@@ -96241,11 +96650,19 @@ ${lines}`;
|
|
|
96241
96650
|
handler: (args) => {
|
|
96242
96651
|
try {
|
|
96243
96652
|
const res = updateApplicationStatus(args.job_id, args.status, args.note);
|
|
96244
|
-
|
|
96245
|
-
`\uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[args.status]}'(\uC73C)\uB85C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.${res.hint ? `
|
|
96653
|
+
const user_message = `\uC9C0\uC6D0 \uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[args.status]}'(\uC73C)\uB85C \uBC14\uAFE8\uC5B4\uC694.` + (res.hint ? `
|
|
96246
96654
|
|
|
96247
|
-
|
|
96248
|
-
|
|
96655
|
+
${res.hint}` : "");
|
|
96656
|
+
return ok(
|
|
96657
|
+
user_message,
|
|
96658
|
+
{
|
|
96659
|
+
...res,
|
|
96660
|
+
user_message,
|
|
96661
|
+
suggested_next_action: res.hint ? {
|
|
96662
|
+
prompt: res.hint,
|
|
96663
|
+
next_workflow: "prepare_interview"
|
|
96664
|
+
} : null
|
|
96665
|
+
}
|
|
96249
96666
|
);
|
|
96250
96667
|
} catch (e) {
|
|
96251
96668
|
return fail(e instanceof Error ? e.message : "\uBCC0\uACBD \uC2E4\uD328");
|
|
@@ -96261,7 +96678,8 @@ ${lines}`;
|
|
|
96261
96678
|
handler: (args) => {
|
|
96262
96679
|
try {
|
|
96263
96680
|
const prep = saveInterviewPrep(args);
|
|
96264
|
-
|
|
96681
|
+
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.`;
|
|
96682
|
+
return ok(user_message, { ...prep, user_message });
|
|
96265
96683
|
} catch (e) {
|
|
96266
96684
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
96267
96685
|
}
|
|
@@ -96286,7 +96704,7 @@ ${lines}`;
|
|
|
96286
96704
|
const dir = getExportsDir();
|
|
96287
96705
|
const filePath = path7.join(dir, result2.filename);
|
|
96288
96706
|
try {
|
|
96289
|
-
|
|
96707
|
+
fs7.writeFileSync(filePath, result2.content, "utf8");
|
|
96290
96708
|
} catch (e) {
|
|
96291
96709
|
return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
|
|
96292
96710
|
}
|
|
@@ -96448,29 +96866,37 @@ ${report.disclaimer}`, report);
|
|
|
96448
96866
|
{
|
|
96449
96867
|
name: "check_for_update",
|
|
96450
96868
|
title: "\uC5C5\uB370\uC774\uD2B8 \uD655\uC778",
|
|
96451
|
-
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. \
|
|
96869
|
+
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.',
|
|
96452
96870
|
inputSchema: {},
|
|
96453
96871
|
readOnly: true,
|
|
96454
96872
|
handler: async () => {
|
|
96455
96873
|
const u = await getUpdateStatusAsync();
|
|
96456
96874
|
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);
|
|
96875
|
+
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}).`;
|
|
96457
96876
|
return ok(
|
|
96458
|
-
|
|
96459
|
-
|
|
96877
|
+
user_message,
|
|
96878
|
+
{
|
|
96879
|
+
...u,
|
|
96880
|
+
user_message,
|
|
96881
|
+
suggested_next_action: u.update_available ? {
|
|
96882
|
+
prompt: "\uC9C0\uAE08 CareerMate\uB97C \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694?",
|
|
96883
|
+
next_tool: "update_careermate"
|
|
96884
|
+
} : null
|
|
96885
|
+
}
|
|
96460
96886
|
);
|
|
96461
96887
|
}
|
|
96462
96888
|
},
|
|
96463
96889
|
{
|
|
96464
96890
|
name: "update_careermate",
|
|
96465
96891
|
title: "CareerMate \uC5C5\uB370\uC774\uD2B8",
|
|
96466
|
-
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
|
|
96892
|
+
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.',
|
|
96467
96893
|
inputSchema: {},
|
|
96468
96894
|
handler: async () => {
|
|
96469
96895
|
const r = await runSelfUpdate();
|
|
96470
96896
|
if (!r.ok) return fail(`${r.message}${r.manual ? `
|
|
96471
96897
|
|
|
96472
96898
|
\uC9C1\uC811 \uC2E4\uD589: ${r.manual}` : ""}`);
|
|
96473
|
-
return ok(r.message, r);
|
|
96899
|
+
return ok(r.message, { ...r, user_message: r.message });
|
|
96474
96900
|
}
|
|
96475
96901
|
}
|
|
96476
96902
|
];
|