careermate 0.0.4 → 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 +345 -65
- package/dist/mcp.mjs +344 -64
- package/dist/public/lib.js +1 -0
- package/dist/public/pages/settings.js +160 -14
- package/dist/public/styles.css +10 -2
- package/dist/site/index.html +88 -188
- package/dist/site/landing.js +109 -0
- package/dist/site/start.html +97 -94
- package/dist/site/style.css +169 -63
- package/dist/web.mjs +369 -32
- package/docs/FAQ.md +3 -2
- package/docs/MCP_TOOLS.md +10 -3
- package/docs/WORKFLOWS.md +5 -5
- package/package.json +2 -2
- package/packages/core/src/services.ts +5 -5
- package/packages/db/src/repositories.ts +0 -0
- package/packages/mcp-tools/src/bridge.ts +194 -13
- package/packages/mcp-tools/src/tools.ts +145 -17
- package/packages/mcp-tools/src/update.ts +1 -1
- package/packages/prompts/src/system.ts +10 -2
- package/packages/workflows/src/definitions.ts +2 -2
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
|
}
|
|
@@ -92956,7 +92956,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
92956
92956
|
});
|
|
92957
92957
|
|
|
92958
92958
|
// packages/shared/src/build-info.ts
|
|
92959
|
-
var APP_VERSION = true ? "0.0.
|
|
92959
|
+
var APP_VERSION = true ? "0.0.5" : "0.0.0-dev";
|
|
92960
92960
|
var BUNDLED = true;
|
|
92961
92961
|
|
|
92962
92962
|
// packages/shared/src/index.ts
|
|
@@ -93468,6 +93468,7 @@ var coverLetterRepo = {
|
|
|
93468
93468
|
remove(id2) {
|
|
93469
93469
|
const db = getDb();
|
|
93470
93470
|
return tx(() => {
|
|
93471
|
+
db.prepare(`UPDATE applications SET cover_letter_id=NULL, updated_at=? WHERE cover_letter_id=?`).run(now(), id2);
|
|
93471
93472
|
db.prepare(`DELETE FROM cover_letter_versions WHERE cover_letter_id=?`).run(id2);
|
|
93472
93473
|
return db.prepare(`DELETE FROM cover_letters WHERE id=?`).run(id2).changes > 0;
|
|
93473
93474
|
});
|
|
@@ -93556,6 +93557,7 @@ var jobRepo = {
|
|
|
93556
93557
|
remove(id2) {
|
|
93557
93558
|
const db = getDb();
|
|
93558
93559
|
return tx(() => {
|
|
93560
|
+
db.prepare(`UPDATE cover_letters SET job_id=NULL, updated_at=? WHERE job_id=?`).run(now(), id2);
|
|
93559
93561
|
db.prepare(`DELETE FROM fit_analyses WHERE job_id=?`).run(id2);
|
|
93560
93562
|
db.prepare(`DELETE FROM applications WHERE job_id=?`).run(id2);
|
|
93561
93563
|
db.prepare(`DELETE FROM interview_preps WHERE job_id=?`).run(id2);
|
|
@@ -93754,7 +93756,7 @@ var activityRepo = {
|
|
|
93754
93756
|
};
|
|
93755
93757
|
|
|
93756
93758
|
// packages/mcp-tools/src/tools.ts
|
|
93757
|
-
import
|
|
93759
|
+
import fs7 from "node:fs";
|
|
93758
93760
|
import path7 from "node:path";
|
|
93759
93761
|
|
|
93760
93762
|
// packages/core/src/onboarding.ts
|
|
@@ -94234,7 +94236,7 @@ function saveJobPosting(input, id2) {
|
|
|
94234
94236
|
}
|
|
94235
94237
|
function saveFitAnalysis(input) {
|
|
94236
94238
|
const job = jobRepo.get(input.job_id);
|
|
94237
|
-
if (!job) throw notFound(
|
|
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.");
|
|
94238
94240
|
applicationRepo.ensure(job.id, "draft");
|
|
94239
94241
|
const fit = fitRepo.save(input);
|
|
94240
94242
|
const scoreText = fit.score != null ? ` (\uC801\uD569\uB3C4 ${fit.score}\uC810)` : "";
|
|
@@ -94276,7 +94278,7 @@ function saveCoverLetterVersion(input) {
|
|
|
94276
94278
|
}
|
|
94277
94279
|
function updateApplicationStatus(jobId, status, note) {
|
|
94278
94280
|
const job = jobRepo.get(jobId);
|
|
94279
|
-
if (!job) throw notFound(
|
|
94281
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
94280
94282
|
const application = applicationRepo.setStatus(jobId, status, note);
|
|
94281
94283
|
activityRepo.log(
|
|
94282
94284
|
"application_status_changed",
|
|
@@ -94286,17 +94288,17 @@ function updateApplicationStatus(jobId, status, note) {
|
|
|
94286
94288
|
);
|
|
94287
94289
|
const interview_unlocked = INTERVIEW_UNLOCK_STATUSES.includes(status);
|
|
94288
94290
|
const hasPrep = !!interviewRepo.getByJob(jobId);
|
|
94289
|
-
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;
|
|
94290
94292
|
return { application, job, interview_unlocked, hint };
|
|
94291
94293
|
}
|
|
94292
94294
|
function saveInterviewPrep(input) {
|
|
94293
94295
|
const job = jobRepo.get(input.job_id);
|
|
94294
|
-
if (!job) throw notFound(
|
|
94296
|
+
if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
94295
94297
|
const app = applicationRepo.getByJob(job.id);
|
|
94296
94298
|
if (!app || !INTERVIEW_UNLOCK_STATUSES.includes(app.status)) {
|
|
94297
94299
|
const current = app ? APPLICATION_STATUS_LABELS[app.status] : "\uBBF8\uC9C0\uC6D0";
|
|
94298
94300
|
throw conflict(
|
|
94299
|
-
`\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
|
|
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.`
|
|
94300
94302
|
);
|
|
94301
94303
|
}
|
|
94302
94304
|
const prep = interviewRepo.save(input);
|
|
@@ -94394,8 +94396,8 @@ var WORKFLOWS = [
|
|
|
94394
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.",
|
|
94395
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).",
|
|
94396
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.",
|
|
94397
|
-
'"\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?"\uB77C\uACE0 \uC790\uAE30\uC18C\uAC1C\uC11C \
|
|
94398
|
-
'\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.',
|
|
94399
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).",
|
|
94400
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."
|
|
94401
94403
|
]
|
|
@@ -95675,14 +95677,94 @@ function toCallToolResult(r) {
|
|
|
95675
95677
|
}
|
|
95676
95678
|
|
|
95677
95679
|
// packages/mcp-tools/src/bridge.ts
|
|
95678
|
-
import { spawn } from "node:child_process";
|
|
95680
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
95681
|
+
import fs5 from "node:fs";
|
|
95679
95682
|
import path5 from "node:path";
|
|
95680
95683
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
95681
95684
|
var __dirname = path5.dirname(fileURLToPath2(import.meta.url));
|
|
95682
95685
|
var REPO_ROOT = path5.resolve(__dirname, "..", "..", "..");
|
|
95683
|
-
|
|
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() {
|
|
95684
95766
|
const info2 = readRuntimeInfo();
|
|
95685
|
-
if (info2 && isProcessAlive(info2.pid)) return info2;
|
|
95767
|
+
if (info2 && isProcessAlive(info2.pid) && await pingDashboard(info2.url)) return info2;
|
|
95686
95768
|
return null;
|
|
95687
95769
|
}
|
|
95688
95770
|
function spawnDetached(cmd, args, opts = {}) {
|
|
@@ -95691,19 +95773,101 @@ function spawnDetached(cmd, args, opts = {}) {
|
|
|
95691
95773
|
child.on("error", () => {
|
|
95692
95774
|
});
|
|
95693
95775
|
child.unref();
|
|
95776
|
+
return child.pid ?? null;
|
|
95694
95777
|
} catch {
|
|
95778
|
+
return null;
|
|
95695
95779
|
}
|
|
95696
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
|
+
}
|
|
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
|
+
});
|
|
95812
|
+
}
|
|
95697
95813
|
async function ensureServer(timeoutMs = 12e3) {
|
|
95698
|
-
const existing = liveServer();
|
|
95814
|
+
const existing = await liveServer();
|
|
95699
95815
|
if (existing) return { url: existing.url };
|
|
95700
|
-
|
|
95701
|
-
|
|
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
|
+
}
|
|
95702
95852
|
const start = Date.now();
|
|
95703
95853
|
while (Date.now() - start < timeoutMs) {
|
|
95704
|
-
const info2 = liveServer();
|
|
95854
|
+
const info2 = await liveServer();
|
|
95705
95855
|
if (info2) return { url: info2.url };
|
|
95706
|
-
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
|
+
}
|
|
95707
95871
|
}
|
|
95708
95872
|
return null;
|
|
95709
95873
|
}
|
|
@@ -95727,7 +95891,7 @@ function openInFileManager(dir) {
|
|
|
95727
95891
|
else openOsTarget(dir);
|
|
95728
95892
|
}
|
|
95729
95893
|
async function resolveDashboardUrl(hash = "") {
|
|
95730
|
-
const live = liveServer();
|
|
95894
|
+
const live = await liveServer();
|
|
95731
95895
|
if (live) return { url: live.url + hash, running: true };
|
|
95732
95896
|
const started = await ensureServer();
|
|
95733
95897
|
if (started) return { url: started.url + hash, running: true };
|
|
@@ -95735,7 +95899,7 @@ async function resolveDashboardUrl(hash = "") {
|
|
|
95735
95899
|
}
|
|
95736
95900
|
|
|
95737
95901
|
// packages/mcp-tools/src/update.ts
|
|
95738
|
-
import
|
|
95902
|
+
import fs6 from "node:fs";
|
|
95739
95903
|
import path6 from "node:path";
|
|
95740
95904
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
95741
95905
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -95792,14 +95956,14 @@ function comparePrerelease(a, b) {
|
|
|
95792
95956
|
}
|
|
95793
95957
|
function readCache() {
|
|
95794
95958
|
try {
|
|
95795
|
-
return JSON.parse(
|
|
95959
|
+
return JSON.parse(fs6.readFileSync(cacheFile(), "utf8"));
|
|
95796
95960
|
} catch {
|
|
95797
95961
|
return null;
|
|
95798
95962
|
}
|
|
95799
95963
|
}
|
|
95800
95964
|
function writeCache(c) {
|
|
95801
95965
|
try {
|
|
95802
|
-
|
|
95966
|
+
fs6.writeFileSync(cacheFile(), JSON.stringify(c), "utf8");
|
|
95803
95967
|
} catch {
|
|
95804
95968
|
}
|
|
95805
95969
|
}
|
|
@@ -95956,16 +96120,18 @@ async function runSelfUpdate() {
|
|
|
95956
96120
|
ok: true,
|
|
95957
96121
|
from,
|
|
95958
96122
|
to: latest,
|
|
95959
|
-
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.`
|
|
95960
96124
|
};
|
|
95961
96125
|
}
|
|
95962
96126
|
|
|
95963
96127
|
// packages/mcp-tools/src/tools.ts
|
|
95964
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";
|
|
95965
96131
|
function listInboxFiles(dir) {
|
|
95966
96132
|
let names;
|
|
95967
96133
|
try {
|
|
95968
|
-
names =
|
|
96134
|
+
names = fs7.readdirSync(dir);
|
|
95969
96135
|
} catch {
|
|
95970
96136
|
return [];
|
|
95971
96137
|
}
|
|
@@ -95975,7 +96141,7 @@ function listInboxFiles(dir) {
|
|
|
95975
96141
|
if (SKIP.test(name)) continue;
|
|
95976
96142
|
const p = path7.join(dir, name);
|
|
95977
96143
|
try {
|
|
95978
|
-
if (
|
|
96144
|
+
if (fs7.statSync(p).isFile()) out.push({ name, path: p });
|
|
95979
96145
|
} catch {
|
|
95980
96146
|
}
|
|
95981
96147
|
}
|
|
@@ -96138,9 +96304,17 @@ ${lines}`;
|
|
|
96138
96304
|
if (upd.update_available) {
|
|
96139
96305
|
text += `
|
|
96140
96306
|
|
|
96141
|
-
\
|
|
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.`;
|
|
96142
96308
|
}
|
|
96143
|
-
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
|
+
});
|
|
96144
96318
|
}
|
|
96145
96319
|
},
|
|
96146
96320
|
/* --------------------------------------------------------------- profile */
|
|
@@ -96293,6 +96467,31 @@ ${lines}`;
|
|
|
96293
96467
|
}
|
|
96294
96468
|
}
|
|
96295
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
|
+
},
|
|
96296
96495
|
/* ------------------------------------------------------------------ jobs */
|
|
96297
96496
|
{
|
|
96298
96497
|
name: "save_job_posting",
|
|
@@ -96301,7 +96500,15 @@ ${lines}`;
|
|
|
96301
96500
|
inputSchema: JobInputSchema.shape,
|
|
96302
96501
|
handler: (args) => {
|
|
96303
96502
|
const { job } = saveJobPosting(args);
|
|
96304
|
-
|
|
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
|
+
});
|
|
96305
96512
|
}
|
|
96306
96513
|
},
|
|
96307
96514
|
{
|
|
@@ -96312,7 +96519,7 @@ ${lines}`;
|
|
|
96312
96519
|
readOnly: true,
|
|
96313
96520
|
handler: (args) => {
|
|
96314
96521
|
const job = jobRepo.get(args.job_id);
|
|
96315
|
-
if (!job) return fail(
|
|
96522
|
+
if (!job) return fail("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
96316
96523
|
return ok(`${job.company} \xB7 ${job.position}`, {
|
|
96317
96524
|
job: jobWithMeta(job),
|
|
96318
96525
|
fit: fitRepo.getByJob(job.id),
|
|
@@ -96333,6 +96540,35 @@ ${lines}`;
|
|
|
96333
96540
|
return ok(`\uACF5\uACE0 ${jobs.length}\uAC74`, jobs);
|
|
96334
96541
|
}
|
|
96335
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
|
+
},
|
|
96336
96572
|
/* ----------------------------------------------------- application context */
|
|
96337
96573
|
{
|
|
96338
96574
|
name: "get_application_context",
|
|
@@ -96355,7 +96591,7 @@ ${lines}`;
|
|
|
96355
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}`,
|
|
96356
96592
|
ctx.job ? `\uB300\uC0C1 \uACF5\uACE0: ${ctx.job.company} \xB7 ${ctx.job.position}` : "\uB300\uC0C1 \uACF5\uACE0 \uC5C6\uC74C",
|
|
96357
96593
|
ctx.writing_preferences.preferred_tone ? `\uC120\uD638 \uBB38\uCCB4: ${ctx.writing_preferences.preferred_tone}` : "",
|
|
96358
|
-
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."
|
|
96359
96595
|
].filter(Boolean).join("\n");
|
|
96360
96596
|
return ok(summary, enriched);
|
|
96361
96597
|
}
|
|
@@ -96368,7 +96604,34 @@ ${lines}`;
|
|
|
96368
96604
|
handler: (args) => {
|
|
96369
96605
|
try {
|
|
96370
96606
|
const fit = saveFitAnalysis(args);
|
|
96371
|
-
|
|
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
|
+
);
|
|
96372
96635
|
} catch (e) {
|
|
96373
96636
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
96374
96637
|
}
|
|
@@ -96387,11 +96650,19 @@ ${lines}`;
|
|
|
96387
96650
|
handler: (args) => {
|
|
96388
96651
|
try {
|
|
96389
96652
|
const res = updateApplicationStatus(args.job_id, args.status, args.note);
|
|
96390
|
-
|
|
96391
|
-
`\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 ? `
|
|
96392
96654
|
|
|
96393
|
-
|
|
96394
|
-
|
|
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
|
+
}
|
|
96395
96666
|
);
|
|
96396
96667
|
} catch (e) {
|
|
96397
96668
|
return fail(e instanceof Error ? e.message : "\uBCC0\uACBD \uC2E4\uD328");
|
|
@@ -96407,7 +96678,8 @@ ${lines}`;
|
|
|
96407
96678
|
handler: (args) => {
|
|
96408
96679
|
try {
|
|
96409
96680
|
const prep = saveInterviewPrep(args);
|
|
96410
|
-
|
|
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 });
|
|
96411
96683
|
} catch (e) {
|
|
96412
96684
|
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
96413
96685
|
}
|
|
@@ -96432,7 +96704,7 @@ ${lines}`;
|
|
|
96432
96704
|
const dir = getExportsDir();
|
|
96433
96705
|
const filePath = path7.join(dir, result2.filename);
|
|
96434
96706
|
try {
|
|
96435
|
-
|
|
96707
|
+
fs7.writeFileSync(filePath, result2.content, "utf8");
|
|
96436
96708
|
} catch (e) {
|
|
96437
96709
|
return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
|
|
96438
96710
|
}
|
|
@@ -96594,29 +96866,37 @@ ${report.disclaimer}`, report);
|
|
|
96594
96866
|
{
|
|
96595
96867
|
name: "check_for_update",
|
|
96596
96868
|
title: "\uC5C5\uB370\uC774\uD2B8 \uD655\uC778",
|
|
96597
|
-
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.',
|
|
96598
96870
|
inputSchema: {},
|
|
96599
96871
|
readOnly: true,
|
|
96600
96872
|
handler: async () => {
|
|
96601
96873
|
const u = await getUpdateStatusAsync();
|
|
96602
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}).`;
|
|
96603
96876
|
return ok(
|
|
96604
|
-
|
|
96605
|
-
|
|
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
|
+
}
|
|
96606
96886
|
);
|
|
96607
96887
|
}
|
|
96608
96888
|
},
|
|
96609
96889
|
{
|
|
96610
96890
|
name: "update_careermate",
|
|
96611
96891
|
title: "CareerMate \uC5C5\uB370\uC774\uD2B8",
|
|
96612
|
-
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.',
|
|
96613
96893
|
inputSchema: {},
|
|
96614
96894
|
handler: async () => {
|
|
96615
96895
|
const r = await runSelfUpdate();
|
|
96616
96896
|
if (!r.ok) return fail(`${r.message}${r.manual ? `
|
|
96617
96897
|
|
|
96618
96898
|
\uC9C1\uC811 \uC2E4\uD589: ${r.manual}` : ""}`);
|
|
96619
|
-
return ok(r.message, r);
|
|
96899
|
+
return ok(r.message, { ...r, user_message: r.message });
|
|
96620
96900
|
}
|
|
96621
96901
|
}
|
|
96622
96902
|
];
|