careermate 0.0.1 → 0.0.2
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/INSTALL.md +12 -8
- package/README.md +14 -8
- package/dist/career-os/knowledge/interview-behavioral.md +9 -1
- package/dist/career-os/knowledge/offer-evaluation-decision.md +2 -2
- package/dist/career-os/knowledge/onboarding-first-90-days.md +1 -1
- package/dist/career-os/knowledge/verifiers/human-voice.md +20 -0
- package/dist/doctor.mjs +421 -11
- package/dist/mcp.mjs +421 -11
- package/dist/migrate.mjs +3 -1
- package/dist/public/index.html +1 -0
- package/dist/public/pages/settings.js +45 -0
- package/dist/public/styles.css +2 -0
- package/dist/site/index.html +19 -12
- package/dist/site/llms-install.txt +11 -8
- package/dist/site/start.html +16 -9
- package/dist/site/style.css +9 -0
- package/dist/web.mjs +351 -6
- package/docs/SUPPORTED_AI_APPS.md +6 -6
- package/docs/career-os/knowledge/interview-behavioral.md +9 -1
- package/docs/career-os/knowledge/offer-evaluation-decision.md +2 -2
- package/docs/career-os/knowledge/onboarding-first-90-days.md +1 -1
- package/docs/career-os/knowledge/verifiers/human-voice.md +20 -0
- package/package.json +1 -1
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/services.ts +61 -2
- package/packages/core/src/verify/index.ts +11 -0
- package/packages/core/src/verify/lexicons.ts +149 -0
- package/packages/core/src/verify/lint.ts +248 -0
- package/packages/core/src/verify/normalize.ts +112 -0
- package/packages/db/src/index.ts +1 -0
- package/packages/db/src/settings.ts +41 -0
- package/packages/mcp-tools/src/tools.ts +80 -6
- package/packages/shared/src/schemas.ts +8 -0
package/dist/doctor.mjs
CHANGED
|
@@ -60747,8 +60747,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
|
|
|
60747
60747
|
return [g, g, g];
|
|
60748
60748
|
}
|
|
60749
60749
|
static G_HTML([g]) {
|
|
60750
|
-
const
|
|
60751
|
-
return `#${
|
|
60750
|
+
const G2 = makeColorComp(g);
|
|
60751
|
+
return `#${G2}${G2}${G2}`;
|
|
60752
60752
|
}
|
|
60753
60753
|
static RGB_G([r, g, b]) {
|
|
60754
60754
|
return ["G", 0.3 * r + 0.59 * g + 0.11 * b];
|
|
@@ -71431,6 +71431,26 @@ function fromJson(text, fallback) {
|
|
|
71431
71431
|
var toBit = (b) => b ? 1 : 0;
|
|
71432
71432
|
var fromBit = (n) => Number(n) === 1;
|
|
71433
71433
|
|
|
71434
|
+
// packages/db/src/settings.ts
|
|
71435
|
+
var SETTING_PREFIX = "setting.";
|
|
71436
|
+
function getSetting(key) {
|
|
71437
|
+
const row = getDb().prepare(`SELECT value FROM _meta WHERE key = ?`).get(SETTING_PREFIX + key);
|
|
71438
|
+
return row ? row.value : null;
|
|
71439
|
+
}
|
|
71440
|
+
function setSetting(key, value) {
|
|
71441
|
+
getDb().prepare(
|
|
71442
|
+
`INSERT INTO _meta (key, value) VALUES (?, ?)
|
|
71443
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`
|
|
71444
|
+
).run(SETTING_PREFIX + key, value);
|
|
71445
|
+
}
|
|
71446
|
+
function getVerifyStrict() {
|
|
71447
|
+
return getSetting("verify_strict") === "1";
|
|
71448
|
+
}
|
|
71449
|
+
function setVerifyStrict(on) {
|
|
71450
|
+
setSetting("verify_strict", on ? "1" : "0");
|
|
71451
|
+
return on;
|
|
71452
|
+
}
|
|
71453
|
+
|
|
71434
71454
|
// packages/shared/src/enums.ts
|
|
71435
71455
|
var APPLICATION_STATUSES = [
|
|
71436
71456
|
"draft",
|
|
@@ -75707,7 +75727,9 @@ var CoverLetterVersionInputSchema = external_exports.object({
|
|
|
75707
75727
|
content: reqBody,
|
|
75708
75728
|
note: optNote.describe("\uC774 \uBC84\uC804\uC758 \uBCC0\uACBD \uC694\uC57D (\uC608: \uC9C0\uC6D0\uB3D9\uAE30 \uBCF4\uAC15)"),
|
|
75709
75729
|
source: external_exports.enum(CONTENT_SOURCES).optional(),
|
|
75710
|
-
set_current: external_exports.boolean().optional().describe("\uC774 \uBC84\uC804\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uC9C0\uC815 (\uAE30\uBCF8 true)")
|
|
75730
|
+
set_current: external_exports.boolean().optional().describe("\uC774 \uBC84\uC804\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uC9C0\uC815 (\uAE30\uBCF8 true)"),
|
|
75731
|
+
force: external_exports.boolean().optional().describe("\uC800\uC7A5 \uC804 \uC790\uB3D9 \uC810\uAC80(\uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58)\uC5D0\uC11C \uB9C9\uD614\uC744 \uB54C, \uC758\uB3C4\uD55C \uAC12\uC784\uC744 \uD655\uC778\uD558\uACE0 \uADF8\uB300\uB85C \uC800\uC7A5"),
|
|
75732
|
+
strict: external_exports.boolean().optional().describe("\uC774\uBC88 \uC800\uC7A5\uB9CC \uC5C4\uACA9\uD558\uAC8C \uC810\uAC80(\uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58\uB3C4 \uCC28\uB2E8). \uC0DD\uB7B5\uD558\uBA74 \uC800\uC7A5\uB41C \uBAA8\uB4DC \uC124\uC815\uC744 \uB530\uB984")
|
|
75711
75733
|
});
|
|
75712
75734
|
var CoverLetterVersionRecordSchema = external_exports.object({
|
|
75713
75735
|
id,
|
|
@@ -75869,7 +75891,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
75869
75891
|
});
|
|
75870
75892
|
|
|
75871
75893
|
// packages/shared/src/build-info.ts
|
|
75872
|
-
var APP_VERSION = true ? "0.0.
|
|
75894
|
+
var APP_VERSION = true ? "0.0.2" : "0.0.0-dev";
|
|
75873
75895
|
var BUNDLED = true;
|
|
75874
75896
|
|
|
75875
75897
|
// packages/shared/src/index.ts
|
|
@@ -76685,7 +76707,333 @@ function getApplicationContext(opts = {}) {
|
|
|
76685
76707
|
};
|
|
76686
76708
|
}
|
|
76687
76709
|
|
|
76710
|
+
// packages/core/src/verify/normalize.ts
|
|
76711
|
+
var ZERO_WIDTH = /[-]/g;
|
|
76712
|
+
function normalizeText(s) {
|
|
76713
|
+
return (s ?? "").normalize("NFKC").replace(ZERO_WIDTH, "");
|
|
76714
|
+
}
|
|
76715
|
+
var MAGNITUDE = { "\uC5B5": 1e8, "\uB9CC": 1e4, "\uCC9C": 1e3 };
|
|
76716
|
+
var RISK_UNITS = /* @__PURE__ */ new Set([
|
|
76717
|
+
"%",
|
|
76718
|
+
"\uBC30",
|
|
76719
|
+
"\uC6D0",
|
|
76720
|
+
"\uAC74",
|
|
76721
|
+
"\uBA85",
|
|
76722
|
+
"\uC810",
|
|
76723
|
+
"\uC704",
|
|
76724
|
+
"\uB144\uCC28",
|
|
76725
|
+
"\uB144",
|
|
76726
|
+
"\uAC1C\uC6D4",
|
|
76727
|
+
"\uC8FC",
|
|
76728
|
+
"\uC2DC\uAC04",
|
|
76729
|
+
"\uD68C",
|
|
76730
|
+
"\uAC1C"
|
|
76731
|
+
]);
|
|
76732
|
+
var NUM_RE = /(\d{1,3}(?:,\d{3})+|\d+)(?:\.(\d+))?\s*(억|만|천)?\s*(원|%p|%|%|퍼센트|배|건|명|점|위|년차|개월|년|시간|주|회|개)?/g;
|
|
76733
|
+
var YEAR_RE = /^(?:19|20)\d{2}$/;
|
|
76734
|
+
function normUnit(u) {
|
|
76735
|
+
if (u === "\uFF05" || u === "\uD37C\uC13C\uD2B8" || u === "%p") return "%";
|
|
76736
|
+
return u;
|
|
76737
|
+
}
|
|
76738
|
+
function extractNumbers(text) {
|
|
76739
|
+
const t = normalizeText(text);
|
|
76740
|
+
const out = [];
|
|
76741
|
+
for (const m of t.matchAll(NUM_RE)) {
|
|
76742
|
+
const intPart = m[1].replace(/,/g, "");
|
|
76743
|
+
const frac = m[2] ? "." + m[2] : "";
|
|
76744
|
+
const base = Number(intPart + frac);
|
|
76745
|
+
if (!Number.isFinite(base)) continue;
|
|
76746
|
+
const mag = m[3] ?? "";
|
|
76747
|
+
let unit = normUnit(m[4] ?? "");
|
|
76748
|
+
if (!mag && (!unit || unit === "\uB144") && YEAR_RE.test(intPart) && !frac) continue;
|
|
76749
|
+
const scale = MAGNITUDE[mag] ?? 1;
|
|
76750
|
+
const value = base * scale;
|
|
76751
|
+
if (mag && !unit) unit = "\uC6D0";
|
|
76752
|
+
const surface = m[0].trim();
|
|
76753
|
+
if (!surface) continue;
|
|
76754
|
+
const risk = RISK_UNITS.has(unit) || !unit && value >= 1e3 || !!mag && !unit;
|
|
76755
|
+
out.push({ raw: surface, value, unit, risk });
|
|
76756
|
+
}
|
|
76757
|
+
return out;
|
|
76758
|
+
}
|
|
76759
|
+
function splitSegments(text) {
|
|
76760
|
+
return normalizeText(text).split(/[\n.。!?!?·••]|(?:\s-\s)/).map((s) => s.trim()).filter(Boolean);
|
|
76761
|
+
}
|
|
76762
|
+
function addToMap(map2, unit, value) {
|
|
76763
|
+
const arr = map2.get(unit);
|
|
76764
|
+
if (arr) arr.push(value);
|
|
76765
|
+
else map2.set(unit, [value]);
|
|
76766
|
+
}
|
|
76767
|
+
function buildCorpus(text) {
|
|
76768
|
+
const byUnit = /* @__PURE__ */ new Map();
|
|
76769
|
+
const segments = [];
|
|
76770
|
+
for (const seg of splitSegments(text)) {
|
|
76771
|
+
const segMap = /* @__PURE__ */ new Map();
|
|
76772
|
+
for (const n of extractNumbers(seg)) {
|
|
76773
|
+
addToMap(byUnit, n.unit, n.value);
|
|
76774
|
+
addToMap(segMap, n.unit, n.value);
|
|
76775
|
+
}
|
|
76776
|
+
if (segMap.size) segments.push(segMap);
|
|
76777
|
+
}
|
|
76778
|
+
return { byUnit, segments };
|
|
76779
|
+
}
|
|
76780
|
+
|
|
76781
|
+
// packages/core/src/verify/lexicons.ts
|
|
76782
|
+
var G = (src, flags = "g") => new RegExp(src, flags);
|
|
76783
|
+
var GENERIC_OPENERS = {
|
|
76784
|
+
id: "generic_opener",
|
|
76785
|
+
label: "\uC81C\uB108\uB9AD\xB7\uC0C1\uD22C\uC801 \uB3C4\uC785(\uD68C\uC0AC\uBA85 \uBC14\uAFD4\uB3C4 \uB9D0\uC774 \uB418\uB294 \uC2DC\uC791)",
|
|
76786
|
+
regex: G(
|
|
76787
|
+
[
|
|
76788
|
+
"i am writing to apply",
|
|
76789
|
+
"i have always been passionate",
|
|
76790
|
+
"as a recent graduate",
|
|
76791
|
+
"to whom it may concern",
|
|
76792
|
+
"\uC9C0\uC6D0\uD558\uAC8C \uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
76793
|
+
"\uC9C0\uC6D0\uD569\uB2C8\uB2E4",
|
|
76794
|
+
"\uC5B4\uB9B4 ?\uC801\uBD80\uD130",
|
|
76795
|
+
"\uBCF4\uBA70 \uC790\uB790\uC2B5\uB2C8\uB2E4",
|
|
76796
|
+
"\uC800\uB294 .{0,10}\uD55C \uC0AC\uB78C\uC785\uB2C8\uB2E4",
|
|
76797
|
+
"\uD3C9\uC18C .{0,14}\uAD00\uC2EC\uC774 \uB9CE\uC544",
|
|
76798
|
+
"\uD56D\uC0C1 .{0,12}\uBBFF\uC5B4",
|
|
76799
|
+
"\uB370\uC774\uD130\uC758 \uD798\uC744 \uBBFF"
|
|
76800
|
+
].join("|"),
|
|
76801
|
+
"gi"
|
|
76802
|
+
)
|
|
76803
|
+
};
|
|
76804
|
+
var EMPTY_ADJECTIVES = {
|
|
76805
|
+
id: "empty_adjective",
|
|
76806
|
+
label: "\uC99D\uAC70 \uC5C6\uB294 \uD3C9\uAC00\uD615 \uD615\uC6A9\uC0AC\xB7\uC790\uAE30\uC11C\uC220",
|
|
76807
|
+
regex: G(
|
|
76808
|
+
[
|
|
76809
|
+
"\uC131\uC2E4(\uD558|\uD55C|\uD568)",
|
|
76810
|
+
"\uCC45\uC784\uAC10\uC774 \uAC15",
|
|
76811
|
+
"\uC5F4\uC815(\uC744 \uAC00\uC9C0|\uC801)",
|
|
76812
|
+
"\uC18C\uD1B5\uC744 \uC798",
|
|
76813
|
+
"\uCEE4\uBBA4\uB2C8\uCF00\uC774\uC158\uC774 \uC6D0\uD65C",
|
|
76814
|
+
"\uAF3C\uAF3C(\uD558|\uD55C|\uD568)",
|
|
76815
|
+
"\uB048\uAE30(\uC788|\uAC00)",
|
|
76816
|
+
"\uD5CC\uC2E0\uC801",
|
|
76817
|
+
"\uC8FC\uB3C4\uC801\uC778",
|
|
76818
|
+
"\uC131\uC7A5\uD558\uB294 \uC778\uC7AC",
|
|
76819
|
+
"\uB77C\uACE0 \uC0DD\uAC01\uD569\uB2C8\uB2E4",
|
|
76820
|
+
"\uB9CE\uC740 \uAC83\uC744 \uBC30\uC6E0",
|
|
76821
|
+
"\uD1B5\uD574 \uC131\uC7A5",
|
|
76822
|
+
"\uAE30\uC5EC\uD558\uACE0 \uC2F6",
|
|
76823
|
+
"\uCD5C\uC120\uC744 \uB2E4",
|
|
76824
|
+
"\uBCF4\uD0EC\uC774 \uB418\uACA0",
|
|
76825
|
+
"team player",
|
|
76826
|
+
"hard-?working",
|
|
76827
|
+
"detail-?oriented",
|
|
76828
|
+
"motivated",
|
|
76829
|
+
"proactive",
|
|
76830
|
+
"dedicated",
|
|
76831
|
+
"diligent"
|
|
76832
|
+
].join("|"),
|
|
76833
|
+
"gi"
|
|
76834
|
+
)
|
|
76835
|
+
};
|
|
76836
|
+
var CLICHES = {
|
|
76837
|
+
id: "cliche",
|
|
76838
|
+
label: "AI \uD074\uB9AC\uC170\xB7\uACF5\uD5C8\uD55C \uC0C1\uD22C\uC5B4",
|
|
76839
|
+
regex: G(
|
|
76840
|
+
[
|
|
76841
|
+
"\uAE09\uBCC0\uD558\uB294 \uC2DC\uB300",
|
|
76842
|
+
"4\uCC28 \uC0B0\uC5C5\uD601\uBA85",
|
|
76843
|
+
"\uB04A\uC784\uC5C6\uB294 \uB178\uB825",
|
|
76844
|
+
"\uADC0\uC0AC\uC758 \uBC1C\uC804\uC5D0 \uAE30\uC5EC",
|
|
76845
|
+
"\uADC0\uC0AC",
|
|
76846
|
+
"\uC18C\uD1B5\uACFC \uD611\uC5C5",
|
|
76847
|
+
"\uAE00\uB85C\uBC8C \uC778\uC7AC",
|
|
76848
|
+
"\uBB34\uD55C\uD55C \uAC00\uB2A5\uC131",
|
|
76849
|
+
"\uD55C \uB2E8\uACC4 \uB354 \uC131\uC7A5"
|
|
76850
|
+
].join("|")
|
|
76851
|
+
)
|
|
76852
|
+
};
|
|
76853
|
+
var TRANSLATIONESE = {
|
|
76854
|
+
id: "translationese",
|
|
76855
|
+
label: "\uBC88\uC5ED\uD22C \uBB38\uBC95(\uC601\uC5B4 \uC9C1\uC5ED\uCCB4)",
|
|
76856
|
+
regex: G(
|
|
76857
|
+
[
|
|
76858
|
+
"\uC5D0 \uB300\uD55C",
|
|
76859
|
+
"\uC744 \uD1B5\uD574",
|
|
76860
|
+
"\uB97C \uD1B5\uD574",
|
|
76861
|
+
"\uC5D0 \uC788\uC5B4\uC11C",
|
|
76862
|
+
"\uB77C\uB294 \uC810\uC5D0\uC11C",
|
|
76863
|
+
"\uAC00\uC9C0\uACE0 \uC788\uC2B5\uB2C8\uB2E4",
|
|
76864
|
+
"\uB418\uC5B4\uC84C",
|
|
76865
|
+
"\uB418\uC5B4\uC9D1\uB2C8\uB2E4",
|
|
76866
|
+
"\uD568\uC73C\uB85C\uC368",
|
|
76867
|
+
"\uC5D0 \uB2E4\uB984 \uC544\uB2C8",
|
|
76868
|
+
"\uC9C4\uD589\uD558\uC600\uC2B5\uB2C8\uB2E4"
|
|
76869
|
+
].join("|")
|
|
76870
|
+
)
|
|
76871
|
+
};
|
|
76872
|
+
var HYPE = {
|
|
76873
|
+
id: "hype",
|
|
76874
|
+
label: "\uACFC\uC7A5 \uC218\uC2DD\uC5B4",
|
|
76875
|
+
regex: G(["\uB9E4\uC6B0", "\uC815\uB9D0\uB85C", "\uD0C1\uC6D4(\uD55C|\uD558\uAC8C)", "\uC131\uACF5\uC801\uC73C\uB85C", "\uC644\uBCBD(\uD55C|\uD558\uAC8C)", "\uC5C4\uCCAD\uB09C", "\uD68D\uAE30\uC801"].join("|"))
|
|
76876
|
+
};
|
|
76877
|
+
var BLIND_PII = {
|
|
76878
|
+
id: "blind_pii",
|
|
76879
|
+
label: "\uBE14\uB77C\uC778\uB4DC \uCC44\uC6A9 \uC704\uBC18 \uC18C\uC9C0(\uC9C1\uBB34\uBB34\uAD00 \uAC1C\uC778\uC815\uBCF4)",
|
|
76880
|
+
regex: G(["\\d{2,3}\\s?\uC138", "\uC0AC\uC9C4\\s?\uCCA8\uBD80", "\uAC00\uC871\uAD00\uACC4", "\uBCF8\uC801", "\uCD9C\uC2E0\uC9C0", "\uC0DD\uB144\uC6D4\uC77C"].join("|"))
|
|
76881
|
+
};
|
|
76882
|
+
var STYLE_LEXICONS = [
|
|
76883
|
+
GENERIC_OPENERS,
|
|
76884
|
+
EMPTY_ADJECTIVES,
|
|
76885
|
+
CLICHES,
|
|
76886
|
+
TRANSLATIONESE,
|
|
76887
|
+
HYPE,
|
|
76888
|
+
BLIND_PII
|
|
76889
|
+
];
|
|
76890
|
+
function countHits(lex, text, maxHits = 8) {
|
|
76891
|
+
const hits = [];
|
|
76892
|
+
let count = 0;
|
|
76893
|
+
for (const m of text.matchAll(lex.regex)) {
|
|
76894
|
+
count++;
|
|
76895
|
+
if (hits.length < maxHits) hits.push(m[0].trim());
|
|
76896
|
+
}
|
|
76897
|
+
return { count, hits };
|
|
76898
|
+
}
|
|
76899
|
+
|
|
76900
|
+
// packages/core/src/verify/lint.ts
|
|
76901
|
+
var within = (a, b) => Math.abs(a - b) <= Math.max(0.5, 0.02 * Math.max(Math.abs(a), Math.abs(b)));
|
|
76902
|
+
var approx = (a, b) => Math.abs(a - b) <= Math.max(0.5, 0.01 * Math.max(Math.abs(a), Math.abs(b)));
|
|
76903
|
+
function isExplained(token, corpus) {
|
|
76904
|
+
const v = token.value;
|
|
76905
|
+
for (const s of corpus.byUnit.get(token.unit) ?? []) if (within(v, s)) return true;
|
|
76906
|
+
for (const seg of corpus.segments) {
|
|
76907
|
+
const vals = seg.get(token.unit);
|
|
76908
|
+
if (vals && vals.length >= 2) {
|
|
76909
|
+
for (let i2 = 0; i2 < vals.length; i2++)
|
|
76910
|
+
for (let j = 0; j < vals.length; j++) {
|
|
76911
|
+
if (i2 === j) continue;
|
|
76912
|
+
if (approx(v, vals[i2] - vals[j]) || approx(v, vals[i2] + vals[j])) return true;
|
|
76913
|
+
}
|
|
76914
|
+
}
|
|
76915
|
+
}
|
|
76916
|
+
if (token.unit === "%") {
|
|
76917
|
+
for (const seg of corpus.segments) {
|
|
76918
|
+
for (const [u, vals] of seg) {
|
|
76919
|
+
if (u === "%" || vals.length < 2) continue;
|
|
76920
|
+
for (let i2 = 0; i2 < vals.length; i2++)
|
|
76921
|
+
for (let j = 0; j < vals.length; j++) {
|
|
76922
|
+
if (i2 === j) continue;
|
|
76923
|
+
const a = vals[i2];
|
|
76924
|
+
const b = vals[j];
|
|
76925
|
+
if (b !== 0 && (approx(v, a / b * 100) || approx(v, (a - b) / b * 100) || approx(v, (a - b) / a * 100)))
|
|
76926
|
+
return true;
|
|
76927
|
+
if (a + b !== 0 && approx(v, a / (a + b) * 100)) return true;
|
|
76928
|
+
}
|
|
76929
|
+
}
|
|
76930
|
+
}
|
|
76931
|
+
}
|
|
76932
|
+
return false;
|
|
76933
|
+
}
|
|
76934
|
+
function analyzeProvenance(outputText, corpus) {
|
|
76935
|
+
const documents = buildCorpus(corpus.documents);
|
|
76936
|
+
const structured = buildCorpus(corpus.structured);
|
|
76937
|
+
const job = buildCorpus(corpus.job);
|
|
76938
|
+
const nums = extractNumbers(outputText).filter((n) => n.risk);
|
|
76939
|
+
const res = { checked: nums.length, supported: 0, fabricated: [], unverified: [], jobSourced: [] };
|
|
76940
|
+
for (const n of nums) {
|
|
76941
|
+
const tok = { raw: n.raw, value: n.value, unit: n.unit };
|
|
76942
|
+
if (isExplained(n, documents)) res.supported++;
|
|
76943
|
+
else if (isExplained(n, structured)) res.unverified.push({ ...tok, reason: "structured_only" });
|
|
76944
|
+
else if (isExplained(n, job)) res.jobSourced.push({ ...tok, reason: "job_only" });
|
|
76945
|
+
else res.fabricated.push({ ...tok, reason: "fabricated" });
|
|
76946
|
+
}
|
|
76947
|
+
return res;
|
|
76948
|
+
}
|
|
76949
|
+
function styleSignals(text) {
|
|
76950
|
+
const t = normalizeText(text);
|
|
76951
|
+
const signals = [];
|
|
76952
|
+
for (const lex of STYLE_LEXICONS) {
|
|
76953
|
+
const { count, hits } = countHits(lex, t);
|
|
76954
|
+
if (count > 0) {
|
|
76955
|
+
const severity = lex.id === "blind_pii" || lex.id === "generic_opener" ? "warn" : "info";
|
|
76956
|
+
signals.push({ id: lex.id, label: lex.label, severity, count, hits });
|
|
76957
|
+
}
|
|
76958
|
+
}
|
|
76959
|
+
return signals;
|
|
76960
|
+
}
|
|
76961
|
+
var DISCLAIMER = "\uC774 \uC810\uAC80\uC740 LLM \uC5C6\uC774 \uC140 \uC218 \uC788\uB294 \uAC83\uB9CC \uBD05\uB2C8\uB2E4(\uC22B\uC790 \uCD9C\uCC98\xB7\uBB38\uCCB4 \uC2E0\uD638). \uD1B5\uACFC=\uD569\uACA9\uC774 \uC544\uB2C8\uBA70, \uC0AC\uC2E4\xB7\uB3D9\uBB38\uC11C\uB2F5\xB7\uC758\uBBF8 \uD310\uB2E8\uC740 \uB2F9\uC2E0(AI)\uC774 \uC9C1\uC811 \uD574\uC57C \uD569\uB2C8\uB2E4.";
|
|
76962
|
+
function lintArtifact(kind, text, corpus, opts = {}) {
|
|
76963
|
+
const norm = normalizeText(text);
|
|
76964
|
+
const corpusAvailable = (corpus.documents + corpus.structured).trim().length > 0;
|
|
76965
|
+
const provenance = analyzeProvenance(text, corpus);
|
|
76966
|
+
const signals = styleSignals(text);
|
|
76967
|
+
const strict = !!opts.strict;
|
|
76968
|
+
const blocking = [];
|
|
76969
|
+
if (corpusAvailable && kind === "cover_letter") {
|
|
76970
|
+
if (provenance.fabricated.length > 0) {
|
|
76971
|
+
blocking.push({
|
|
76972
|
+
id: "fabricated_numbers",
|
|
76973
|
+
label: "\uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58(\uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\uC5D0 \uC5C6\uC74C)",
|
|
76974
|
+
detail: provenance.fabricated.map((f) => f.raw).join(", ")
|
|
76975
|
+
});
|
|
76976
|
+
}
|
|
76977
|
+
if (strict && provenance.unverified.length > 0) {
|
|
76978
|
+
blocking.push({
|
|
76979
|
+
id: "unverified_numbers_strict",
|
|
76980
|
+
label: "\uC5C4\uACA9 \uBAA8\uB4DC: \uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58(\uAD6C\uC870\uD654 \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9\uC5D0\uB9CC \uC788\uC74C)",
|
|
76981
|
+
detail: provenance.unverified.map((u) => u.raw).join(", ")
|
|
76982
|
+
});
|
|
76983
|
+
}
|
|
76984
|
+
}
|
|
76985
|
+
return {
|
|
76986
|
+
kind,
|
|
76987
|
+
charCount: [...norm].length,
|
|
76988
|
+
signals,
|
|
76989
|
+
provenance,
|
|
76990
|
+
blocking,
|
|
76991
|
+
corpusAvailable,
|
|
76992
|
+
strict,
|
|
76993
|
+
disclaimer: DISCLAIMER
|
|
76994
|
+
};
|
|
76995
|
+
}
|
|
76996
|
+
function summarizeReport(r) {
|
|
76997
|
+
const parts = [];
|
|
76998
|
+
if (r.blocking.length)
|
|
76999
|
+
parts.push(`\u26D4 \uC800\uC7A5 \uCC28\uB2E8: ${r.blocking.map((b) => `${b.label}(${b.detail})`).join("; ")}`);
|
|
77000
|
+
if (r.provenance.unverified.length)
|
|
77001
|
+
parts.push(
|
|
77002
|
+
`\uBBF8\uD655\uC778 \uC218\uCE58 ${r.provenance.unverified.length}\uAC1C(${r.provenance.unverified.map((u) => u.raw).join(", ")}) \u2014 \uC774\uB825\uC11C \uBCF8\uBB38\uC5D4 \uC5C6\uACE0 \uAD6C\uC870\uD654 \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9\uC5D0\uB9CC \uC788\uC74C, \uC0AC\uC2E4\uC778\uC9C0 \uD655\uC778`
|
|
77003
|
+
);
|
|
77004
|
+
if (r.provenance.jobSourced.length)
|
|
77005
|
+
parts.push(`\uACF5\uACE0 \uCD9C\uCC98 \uC218\uCE58 ${r.provenance.jobSourced.length}\uAC1C(\uBCF8\uC778 \uC131\uACFC\uB85C \uC4F0\uC9C0 \uC54A\uC558\uB294\uC9C0 \uD655\uC778)`);
|
|
77006
|
+
const adv = r.signals.filter((s) => s.count > 0);
|
|
77007
|
+
if (adv.length) parts.push("\uBB38\uCCB4 \uC2E0\uD638: " + adv.map((s) => `${s.label.split("(")[0]}\xD7${s.count}`).join(", "));
|
|
77008
|
+
if (!parts.length) parts.push("\uC790\uB3D9 \uC810\uAC80 \uD1B5\uACFC(\uC140 \uC218 \uC788\uB294 \uD56D\uBAA9 \uAE30\uC900). \uC758\uBBF8 \uD310\uB2E8\uC740 \uC9C1\uC811 \uD655\uC778\uD558\uC138\uC694.");
|
|
77009
|
+
return parts.join(" \xB7 ");
|
|
77010
|
+
}
|
|
77011
|
+
|
|
76688
77012
|
// packages/core/src/services.ts
|
|
77013
|
+
function collectVerifyCorpus(jobId) {
|
|
77014
|
+
const documents = [];
|
|
77015
|
+
for (const d of documentRepo.list()) {
|
|
77016
|
+
if (d.source !== "ai") documents.push(d.content);
|
|
77017
|
+
}
|
|
77018
|
+
const structured = [];
|
|
77019
|
+
for (const e of experienceRepo.list()) {
|
|
77020
|
+
structured.push([e.company, e.role, e.description, ...e.achievements ?? [], ...e.tech ?? []].filter(Boolean).join("\n"));
|
|
77021
|
+
}
|
|
77022
|
+
for (const p of projectRepo.list()) {
|
|
77023
|
+
structured.push([p.name, p.description, ...p.highlights ?? [], ...p.tech ?? []].filter(Boolean).join("\n"));
|
|
77024
|
+
}
|
|
77025
|
+
for (const s of skillRepo.list()) {
|
|
77026
|
+
structured.push([s.name, s.level, s.years != null ? `${s.years}\uB144` : ""].filter(Boolean).join(" "));
|
|
77027
|
+
}
|
|
77028
|
+
const job = jobId ? jobRepo.get(jobId) : null;
|
|
77029
|
+
const jobText = job ? [job.description, ...job.requirements ?? [], ...job.keywords ?? []].filter(Boolean).join("\n") : "";
|
|
77030
|
+
return { documents: documents.join("\n"), structured: structured.join("\n"), job: jobText };
|
|
77031
|
+
}
|
|
77032
|
+
function previewCoverLetter(text, jobId, strict) {
|
|
77033
|
+
return lintArtifact("cover_letter", text, collectVerifyCorpus(jobId), {
|
|
77034
|
+
strict: strict ?? getVerifyStrict()
|
|
77035
|
+
});
|
|
77036
|
+
}
|
|
76689
77037
|
function saveProfile(input) {
|
|
76690
77038
|
const p = profileRepo.save(input);
|
|
76691
77039
|
activityRepo.log("profile_updated", `\uD504\uB85C\uD544\uC744 ${p.name ? `(${p.name}) ` : ""}\uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.`, "profile", p.id);
|
|
@@ -76727,6 +77075,15 @@ function saveFitAnalysis(input) {
|
|
|
76727
77075
|
return fit;
|
|
76728
77076
|
}
|
|
76729
77077
|
function saveCoverLetterVersion(input) {
|
|
77078
|
+
const strict = input.strict ?? getVerifyStrict();
|
|
77079
|
+
const verification = lintArtifact("cover_letter", input.content, collectVerifyCorpus(input.job_id), { strict });
|
|
77080
|
+
const forced = verification.blocking.length > 0 && input.force === true;
|
|
77081
|
+
if (verification.blocking.length > 0 && !forced) {
|
|
77082
|
+
const detail = verification.blocking.map((b) => `${b.label}: ${b.detail}`).join("; ");
|
|
77083
|
+
const strictHit = verification.blocking.some((b) => b.id === "unverified_numbers_strict");
|
|
77084
|
+
const tail = strictHit ? `\uC5C4\uACA9 \uBAA8\uB4DC\uAC00 \uCF1C\uC838 \uC788\uC5B4, \uC62C\uB9B0 \uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uC5C6\uB294 \uC218\uCE58\uB294 \uB9C9\uD799\uB2C8\uB2E4. \uC774\uB825\uC11C\uB97C \uC62C\uB9AC\uAC70\uB098 \uC5C4\uACA9 \uBAA8\uB4DC\uB97C \uB044\uAC70\uB098, \uC758\uB3C4\uD55C \uAC12\uC774\uBA74 force: true\uB85C \uC800\uC7A5\uD558\uC138\uC694.` : `\uC774 \uC218\uCE58\uB294 \uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\xB7\uD504\uB85C\uC81D\uD2B8\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. \uC6D0\uBCF8 \uB370\uC774\uD130\uC758 \uC2E4\uC81C \uC218\uCE58\uB85C \uACE0\uCE58\uAC70\uB098, \uC758\uB3C4\uD55C \uAC12\uC774 \uB9DE\uB2E4\uBA74 \uBA3C\uC800 \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8\uC5D0 \uADF8 \uC218\uCE58\uB97C \uCD94\uAC00\uD55C \uB4A4 \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694(\uADF8\uB300\uB85C \uC800\uC7A5\uD558\uB824\uBA74 force: true).`;
|
|
77085
|
+
throw new Error(`\uC800\uC7A5 \uC804 \uC790\uB3D9 \uC810\uAC80\uC5D0\uC11C \uB9C9\uD614\uC2B5\uB2C8\uB2E4 \u2014 ${detail}. ${tail}`);
|
|
77086
|
+
}
|
|
76730
77087
|
const { coverLetter, version: version2 } = coverLetterRepo.addVersion({
|
|
76731
77088
|
cover_letter_id: input.cover_letter_id,
|
|
76732
77089
|
title: input.title,
|
|
@@ -76748,7 +77105,7 @@ function saveCoverLetterVersion(input) {
|
|
|
76748
77105
|
"cover_letter",
|
|
76749
77106
|
coverLetter.id
|
|
76750
77107
|
);
|
|
76751
|
-
return { coverLetter, version: version2 };
|
|
77108
|
+
return { coverLetter, version: version2, verification, forced };
|
|
76752
77109
|
}
|
|
76753
77110
|
function updateApplicationStatus(jobId, status, note) {
|
|
76754
77111
|
const job = jobRepo.get(jobId);
|
|
@@ -78589,16 +78946,22 @@ ${summary}
|
|
|
78589
78946
|
const s = getOnboardingStatus();
|
|
78590
78947
|
const lines = s.next_steps.map((t, i2) => `${i2 + 1}. ${t}`).join("\n");
|
|
78591
78948
|
const upd = getUpdateStatus();
|
|
78949
|
+
const strict = getVerifyStrict();
|
|
78592
78950
|
let text = `\uC628\uBCF4\uB529 ${s.completed ? "\uC644\uB8CC\uB428" : "\uC9C4\uD589 \uD544\uC694"} \xB7 \uD504\uB85C\uD544 \uC644\uC131\uB3C4 ${s.profile_completeness}%
|
|
78593
78951
|
|
|
78594
78952
|
\uB2E4\uC74C \uB2E8\uACC4:
|
|
78595
78953
|
${lines}`;
|
|
78954
|
+
if (!s.completed) {
|
|
78955
|
+
text += `
|
|
78956
|
+
|
|
78957
|
+
\u{1F4A1} \uCC38\uACE0: \uC790\uC18C\uC11C\uB97C \uC800\uC7A5\uD560 \uB54C CareerMate\uAC00 \uBCF8\uBB38\uC758 \uC218\uCE58\uB97C \uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\uC640 \uC790\uB3D9 \uB300\uC870\uD574, \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58\uB294 \uB9C9\uC2B5\uB2C8\uB2E4. \uB354 \uAE50\uAE50\uD558\uAC8C \uBCF4\uAE38 \uC6D0\uD558\uBA74 "\uC5C4\uACA9\uD558\uAC8C \uBD10\uC918"\uB77C\uACE0 \uD558\uAC70\uB098 \uB300\uC2DC\uBCF4\uB4DC \uC124\uC815\uC5D0\uC11C \uC5C4\uACA9 \uBAA8\uB4DC\uB97C \uCF24 \uC218 \uC788\uC5B4\uC694(\uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uC5C6\uB294 \uC218\uCE58\uAE4C\uC9C0 \uCC28\uB2E8).`;
|
|
78958
|
+
}
|
|
78596
78959
|
if (upd.update_available) {
|
|
78597
78960
|
text += `
|
|
78598
78961
|
|
|
78599
78962
|
\u{1F195} \uC0C8 \uBC84\uC804 v${upd.latest} \uC0AC\uC6A9 \uAC00\uB2A5 (\uD604\uC7AC v${upd.current}). \uC0AC\uC6A9\uC790\uAC00 \uC6D0\uD558\uBA74 update_careermate \uB3C4\uAD6C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.`;
|
|
78600
78963
|
}
|
|
78601
|
-
return ok(text, { ...s, update: upd });
|
|
78964
|
+
return ok(text, { ...s, verify_strict: strict, update: upd });
|
|
78602
78965
|
}
|
|
78603
78966
|
},
|
|
78604
78967
|
/* --------------------------------------------------------------- profile */
|
|
@@ -78732,11 +79095,20 @@ ${lines}`;
|
|
|
78732
79095
|
{
|
|
78733
79096
|
name: "save_cover_letter_version",
|
|
78734
79097
|
title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uBC84\uC804 \uC800\uC7A5",
|
|
78735
|
-
description: '\uC790\uAE30\uC18C\uAC1C\uC11C\uC758 \uC0C8 \uBC84\uC804\uC744 \uC800\uC7A5\uD569\uB2C8\uB2E4. CareerMate \uC790\uC18C\uC11C \uC791\uC131 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uD575\uC2EC \uC800\uC7A5 \uB2E8\uACC4\uC785\uB2C8\uB2E4. cover_letter_id\uB97C \uC8FC\uBA74 \uAE30\uC874 \uC790\uC18C\uC11C\uC5D0 \uC0C8 \uBC84\uC804\uC744 \uCD94\uAC00\uD558\uACE0, \uC5C6\uC73C\uBA74 \uC0C8 \uC790\uC18C\uC11C\uB97C \uB9CC\uB4E4\uC5B4 v1\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4(\uC774\uB54C title \uAD8C\uC7A5). note\uC5D0 \uC774 \uBC84\uC804\uC758 \uBCC0\uACBD \uC694\uC57D(\uC608: "\uC9C0\uC6D0\uB3D9\uAE30 \uBCF4\uAC15")\uC744 \uB0A8\uAE30\uBA74 \uC0AC\uC6A9\uC790\uAC00 \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uBC84\uC804 \uD788\uC2A4\uD1A0\uB9AC\uB97C \uC774\uD574\uD558\uAE30 \uC27D\uC2B5\uB2C8\uB2E4. job_id\uB85C \uACF5\uACE0\uC5D0 \uC5F0\uACB0\uD558\uBA74 \uC9C0\uC6D0 \uD56D\uBAA9\uACFC \uC790\uB3D9 \uC5F0\uACB0\uB429\uB2C8\uB2E4.',
|
|
79098
|
+
description: '\uC790\uAE30\uC18C\uAC1C\uC11C\uC758 \uC0C8 \uBC84\uC804\uC744 \uC800\uC7A5\uD569\uB2C8\uB2E4. CareerMate \uC790\uC18C\uC11C \uC791\uC131 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uD575\uC2EC \uC800\uC7A5 \uB2E8\uACC4\uC785\uB2C8\uB2E4. cover_letter_id\uB97C \uC8FC\uBA74 \uAE30\uC874 \uC790\uC18C\uC11C\uC5D0 \uC0C8 \uBC84\uC804\uC744 \uCD94\uAC00\uD558\uACE0, \uC5C6\uC73C\uBA74 \uC0C8 \uC790\uC18C\uC11C\uB97C \uB9CC\uB4E4\uC5B4 v1\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4(\uC774\uB54C title \uAD8C\uC7A5). note\uC5D0 \uC774 \uBC84\uC804\uC758 \uBCC0\uACBD \uC694\uC57D(\uC608: "\uC9C0\uC6D0\uB3D9\uAE30 \uBCF4\uAC15")\uC744 \uB0A8\uAE30\uBA74 \uC0AC\uC6A9\uC790\uAC00 \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uBC84\uC804 \uD788\uC2A4\uD1A0\uB9AC\uB97C \uC774\uD574\uD558\uAE30 \uC27D\uC2B5\uB2C8\uB2E4. job_id\uB85C \uACF5\uACE0\uC5D0 \uC5F0\uACB0\uD558\uBA74 \uC9C0\uC6D0 \uD56D\uBAA9\uACFC \uC790\uB3D9 \uC5F0\uACB0\uB429\uB2C8\uB2E4. \uC800\uC7A5 \uC9C1\uC804 \uC790\uB3D9\uC73C\uB85C "\uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58" \uC810\uAC80\uC744 \uB3CC\uB9BD\uB2C8\uB2E4 \u2014 \uBCF8\uBB38\uC758 \uC815\uB7C9 \uC218\uCE58\uAC00 \uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\xB7\uD504\uB85C\uC81D\uD2B8\uC5D0 \uADFC\uAC70\uAC00 \uC5C6\uC73C\uBA74(\uD658\uAC01 \uC758\uC2EC) \uC800\uC7A5\uC774 \uB9C9\uD799\uB2C8\uB2E4. \uADF8\uB54C\uB294 \uC6D0\uBCF8\uC758 \uC2E4\uC81C \uC218\uCE58\uB85C \uACE0\uCE58\uAC70\uB098, \uC758\uB3C4\uD55C \uAC12\uC774\uBA74 force:true\uB85C \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694.',
|
|
78736
79099
|
inputSchema: CoverLetterVersionInputSchema.shape,
|
|
78737
79100
|
handler: (args) => {
|
|
78738
|
-
|
|
78739
|
-
|
|
79101
|
+
try {
|
|
79102
|
+
const { coverLetter, version: version2, verification, forced } = saveCoverLetterVersion(args);
|
|
79103
|
+
const advisory = summarizeReport(verification);
|
|
79104
|
+
const head = `'${coverLetter.title}' v${version2.version_no}\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.`;
|
|
79105
|
+
const hasAdvisory = verification.signals.length || verification.provenance.jobSourced.length || verification.provenance.unverified.length;
|
|
79106
|
+
const note = forced ? "\n\u26A0\uFE0F \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58\uAC00 \uC788\uB294\uB370\uB3C4 force\uB85C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4(\uAC80\uC99D \uBBF8\uD1B5\uACFC\uB85C \uAE30\uB85D). \uBA74\uC811 \uC804 \uC0AC\uC2E4 \uD655\uC778\uC744 \uAD8C\uD569\uB2C8\uB2E4." : hasAdvisory ? `
|
|
79107
|
+
\uC810\uAC80: ${advisory}` : "";
|
|
79108
|
+
return ok(head + note, { coverLetter, version: version2, verification });
|
|
79109
|
+
} catch (e) {
|
|
79110
|
+
return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
|
|
79111
|
+
}
|
|
78740
79112
|
}
|
|
78741
79113
|
},
|
|
78742
79114
|
/* ------------------------------------------------------------------ jobs */
|
|
@@ -78966,7 +79338,7 @@ ${lines}`;
|
|
|
78966
79338
|
handler: (args) => {
|
|
78967
79339
|
try {
|
|
78968
79340
|
const content = getPlaybook(args.domain);
|
|
78969
|
-
return ok(content, { domain: args.domain
|
|
79341
|
+
return ok(content, { domain: args.domain });
|
|
78970
79342
|
} catch (e) {
|
|
78971
79343
|
return fail(e instanceof Error ? e.message : "\uD50C\uB808\uC774\uBD81\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
78972
79344
|
}
|
|
@@ -78983,12 +79355,50 @@ ${lines}`;
|
|
|
78983
79355
|
handler: (args) => {
|
|
78984
79356
|
try {
|
|
78985
79357
|
const content = getVerifier(args.id);
|
|
78986
|
-
return ok(content, { id: args.id
|
|
79358
|
+
return ok(content, { id: args.id });
|
|
78987
79359
|
} catch (e) {
|
|
78988
79360
|
return fail(e instanceof Error ? e.message : "\uAC80\uC99D \uB8E8\uBE0C\uB9AD\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
78989
79361
|
}
|
|
78990
79362
|
}
|
|
78991
79363
|
},
|
|
79364
|
+
/* ----------------------------------------- career-os: deterministic lint */
|
|
79365
|
+
{
|
|
79366
|
+
name: "validate_cover_letter",
|
|
79367
|
+
title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uC790\uB3D9 \uC810\uAC80 (\uC800\uC7A5 \uC804 \uBBF8\uB9AC\uBCF4\uAE30)",
|
|
79368
|
+
description: "\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C save_cover_letter_version\uC73C\uB85C \uC800\uC7A5\uD558\uAE30 \uC9C1\uC804\uC5D0 \uD638\uCD9C\uD558\uBA74, \uC800\uC7A5\uD558\uC9C0 \uC54A\uACE0 \uBBF8\uB9AC \uC810\uAC80\uB9CC \uD569\uB2C8\uB2E4. CareerMate\uAC00 LLM \uC5C6\uC774 \uACB0\uC815\uB860\uC73C\uB85C (1) \uBCF8\uBB38\uC758 \uC815\uB7C9 \uC218\uCE58\uAC00 \uC800\uC7A5\uB41C \uACBD\uB825\xB7\uC774\uB825\uC11C\xB7\uD504\uB85C\uC81D\uD2B8\uC5D0 \uADFC\uAC70\uAC00 \uC788\uB294\uC9C0(\uC5C6\uC73C\uBA74 \uD658\uAC01 \uC758\uC2EC \u2192 \uC800\uC7A5 \uC2DC \uCC28\uB2E8\uB428), (2) \uACF5\uACE0\uC5D0\uC11C \uAC00\uC838\uC628 \uC218\uCE58\uB97C \uBCF8\uC778 \uC131\uACFC\uCC98\uB7FC \uC4F0\uC9C0 \uC54A\uC558\uB294\uC9C0, (3) \uBC88\uC5ED\uD22C\xB7\uC81C\uB108\uB9AD \uB3C4\uC785\xB7\uBE48 \uD615\uC6A9\uC0AC\xB7\uBE14\uB77C\uC778\uB4DC \uC704\uBC18 \uAC19\uC740 \uBB38\uCCB4 \uC2E0\uD638\uB97C \uC138\uC5B4 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC810\uAC80\uC740 \uC140 \uC218 \uC788\uB294 \uAC83\uB9CC \uBD05\uB2C8\uB2E4 \u2014 \uC0AC\uC2E4\uC131\xB7\uB3D9\uBB38\uC11C\uB2F5 \uAC19\uC740 \uC758\uBBF8 \uD310\uB2E8\uC740 \uB2F9\uC2E0(AI)\uC774 \uC9C1\uC811 \uD558\uC138\uC694. job_id\uB97C \uC8FC\uBA74 \uACF5\uACE0 \uC218\uCE58\uAE4C\uC9C0 \uBE44\uAD50\uD569\uB2C8\uB2E4.",
|
|
79369
|
+
inputSchema: {
|
|
79370
|
+
text: external_exports.string().max(2e5).describe("\uC810\uAC80\uD560 \uC790\uAE30\uC18C\uAC1C\uC11C \uBCF8\uBB38"),
|
|
79371
|
+
job_id: external_exports.string().optional().describe("\uC5F0\uACB0\uD560 \uACF5\uACE0(\uC788\uC73C\uBA74 \uACF5\uACE0 \uC218\uCE58\uAE4C\uC9C0 \uBE44\uAD50)"),
|
|
79372
|
+
strict: external_exports.boolean().optional().describe('\uC774\uBC88 \uC810\uAC80\uB9CC \uC5C4\uACA9\uD558\uAC8C(\uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58\uB3C4 \uCC28\uB2E8). \uC0AC\uC6A9\uC790\uAC00 "\uC5C4\uACA9\uD558\uAC8C \uBD10\uC918"\uB77C\uACE0 \uD560 \uB54C true. \uC0DD\uB7B5\uD558\uBA74 \uC800\uC7A5\uB41C \uBAA8\uB4DC\uB97C \uB530\uB984')
|
|
79373
|
+
},
|
|
79374
|
+
readOnly: true,
|
|
79375
|
+
handler: (args) => {
|
|
79376
|
+
const text = typeof args?.text === "string" ? args.text : "";
|
|
79377
|
+
if (!text.trim()) return fail("\uC810\uAC80\uD560 \uBCF8\uBB38\uC774 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
79378
|
+
const report = previewCoverLetter(text, args?.job_id ?? null, args?.strict);
|
|
79379
|
+
const verdict = report.blocking.length ? `\u26D4 \uC774\uB300\uB85C \uC800\uC7A5\uD558\uBA74 \uB9C9\uD799\uB2C8\uB2E4 \u2014 ${report.blocking.map((b) => `${b.label}: ${b.detail}`).join("; ")}` : "\u2705 \uC790\uB3D9 \uCC28\uB2E8 \uD56D\uBAA9 \uC5C6\uC74C(\uC140 \uC218 \uC788\uB294 \uD56D\uBAA9 \uAE30\uC900).";
|
|
79380
|
+
const modeLine = report.strict ? "\n(\uC5C4\uACA9 \uBAA8\uB4DC \uC801\uC6A9 \uC911)" : "";
|
|
79381
|
+
return ok(`${verdict}${modeLine}
|
|
79382
|
+
${summarizeReport(report)}
|
|
79383
|
+
|
|
79384
|
+
${report.disclaimer}`, report);
|
|
79385
|
+
}
|
|
79386
|
+
},
|
|
79387
|
+
{
|
|
79388
|
+
name: "set_verify_mode",
|
|
79389
|
+
title: "\uC810\uAC80 \uBAA8\uB4DC \uC124\uC815 (\uAE30\uBCF8/\uC5C4\uACA9)",
|
|
79390
|
+
description: '\uC800\uC7A5 \uC804 \uC790\uB3D9 \uC810\uAC80\uC758 \uC5C4\uACA9\uB3C4\uB97C \uBC14\uAFC9\uB2C8\uB2E4. \uC5C4\uACA9 \uBAA8\uB4DC(strict=true)\uB97C \uCF1C\uBA74, \uC774\uD6C4 \uBAA8\uB4E0 \uC790\uC18C\uC11C \uC800\uC7A5\uC5D0\uC11C "\uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uADFC\uAC70 \uC5C6\uB294 \uC218\uCE58"(\uAD6C\uC870\uD654 \uACBD\uB825 \uD56D\uBAA9\uC5D0\uB9CC \uC788\uB294 \uAC12)\uAE4C\uC9C0 \uCC28\uB2E8\uD569\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB4DC\uB294 \uCD9C\uCC98\uAC00 \uC544\uC608 \uC5C6\uB294 \uC218\uCE58\uB9CC \uCC28\uB2E8\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 "\uC5C4\uACA9\uD558\uAC8C \uBD10\uC918"\uB77C\uACE0 \uD558\uBA74 \uBC14\uB85C \uCF1C\uC9C0 \uB9D0\uACE0 "\uC55E\uC73C\uB85C \uD56D\uC0C1 \uC5C4\uACA9\uD558\uAC8C \uBCFC\uAE4C\uC694?"\uB77C\uACE0 \uBA3C\uC800 \uD655\uC778\uD55C \uB4A4 \uB3D9\uC758\uD558\uBA74 strict=true\uB85C \uD638\uCD9C\uD558\uC138\uC694. \uB044\uAE30(strict=false)\uB294 \uC548\uC804\uC7A5\uCE58\uB97C \uC57D\uD558\uAC8C \uB9CC\uB4DC\uB294 \uAC83\uC774\uBBC0\uB85C, \uC0AC\uC6A9\uC790\uAC00 \uBA85\uD655\uD788 \uB044\uACA0\uB2E4\uACE0 \uD560 \uB54C\uB9CC \uD638\uCD9C\uD558\uC138\uC694. \uC774\uBC88 \uD55C \uAC74\uB9CC \uC5C4\uACA9\uD558\uAC8C \uBCF4\uB824\uBA74 \uBAA8\uB4DC\uB97C \uBC14\uAFB8\uC9C0 \uB9D0\uACE0 validate_cover_letter / save_cover_letter_version\uC5D0 strict:true\uB97C \uD55C \uBC88\uB9CC \uB118\uAE30\uC138\uC694.',
|
|
79391
|
+
inputSchema: {
|
|
79392
|
+
strict: external_exports.boolean().describe("true=\uC5C4\uACA9 \uCF1C\uAE30, false=\uB044\uAE30(\uBA85\uD655\uD55C \uC0AC\uC6A9\uC790 \uC758\uC0AC\uC77C \uB54C\uB9CC)")
|
|
79393
|
+
},
|
|
79394
|
+
handler: (args) => {
|
|
79395
|
+
const on = setVerifyStrict(!!args?.strict);
|
|
79396
|
+
return ok(
|
|
79397
|
+
on ? '\uC5C4\uACA9 \uC810\uAC80 \uBAA8\uB4DC\uB97C \uCF30\uC2B5\uB2C8\uB2E4. \uC774\uC81C \uC790\uC18C\uC11C\uB97C \uC800\uC7A5\uD560 \uB54C, \uC62C\uB9B0 \uC774\uB825\uC11C \uBCF8\uBB38\uC5D0 \uADFC\uAC70\uAC00 \uC5C6\uB294 \uC218\uCE58\uB294 \uB9C9\uD799\uB2C8\uB2E4(\uAD6C\uC870\uD654 \uACBD\uB825 \uD56D\uBAA9\uC5D0\uB9CC \uC788\uB294 \uAC12 \uD3EC\uD568). \uB044\uB824\uBA74 "\uC5C4\uACA9 \uBAA8\uB4DC \uAEBC\uC918"\uB77C\uACE0 \uD558\uC138\uC694.' : "\uC5C4\uACA9 \uC810\uAC80 \uBAA8\uB4DC\uB97C \uAED0\uC2B5\uB2C8\uB2E4. \uC774\uC81C \uCD9C\uCC98\uAC00 \uC544\uC608 \uC5C6\uB294 \uC218\uCE58\uB9CC \uCC28\uB2E8\uD569\uB2C8\uB2E4(\uAD6C\uC870\uD654 \uD56D\uBAA9\uC5D0\uB9CC \uC788\uB294 \uAC12\uC740 \uACBD\uACE0\uB9CC).",
|
|
79398
|
+
{ strict: on }
|
|
79399
|
+
);
|
|
79400
|
+
}
|
|
79401
|
+
},
|
|
78992
79402
|
/* --------------------------------------------------- writing style guide */
|
|
78993
79403
|
{
|
|
78994
79404
|
name: "get_writing_style_guide",
|