careermate 0.0.5 → 0.0.7

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.
Files changed (125) hide show
  1. package/AGENTS.md +13 -10
  2. package/INSTALL.md +16 -15
  3. package/README.md +24 -24
  4. package/THIRD_PARTY_NOTICES.md +2 -3
  5. package/bin/careermate.mjs +8 -1
  6. package/dist/career-os/README.md +12 -6
  7. package/dist/career-os/eop/career-description.md +139 -0
  8. package/dist/career-os/eop/cover-letter.md +10 -5
  9. package/dist/career-os/eop/fit-analysis.md +16 -6
  10. package/dist/career-os/eop/interview-prep.md +209 -21
  11. package/dist/career-os/eop/job-analysis.md +6 -4
  12. package/dist/career-os/eop/profile-extraction.md +5 -4
  13. package/dist/career-os/knowledge/cover-letter.md +5 -4
  14. package/dist/career-os/knowledge/fit-matching.md +8 -8
  15. package/dist/career-os/knowledge/human-writing.md +2 -0
  16. package/dist/career-os/knowledge/interview-behavioral.md +76 -8
  17. package/dist/career-os/knowledge/interview-technical.md +106 -4
  18. package/dist/career-os/knowledge/linkedin-profile.md +1 -1
  19. package/dist/career-os/knowledge/networking-referrals.md +1 -1
  20. package/dist/career-os/knowledge/offer-evaluation-decision.md +10 -10
  21. package/dist/career-os/knowledge/portfolio.md +3 -3
  22. package/dist/career-os/knowledge/verifiers/ats-compat.md +8 -4
  23. package/dist/career-os/knowledge/verifiers/human-voice.md +4 -2
  24. package/dist/career-os/knowledge/verifiers/recency-staleness.md +1 -1
  25. package/dist/career-os/knowledge/verifiers/responsiveness-on-target.md +2 -2
  26. package/dist/career-os/knowledge/verifiers/truthfulness.md +1 -1
  27. package/dist/doctor.mjs +692 -71
  28. package/dist/mcp.mjs +710 -71
  29. package/dist/migrate.mjs +52 -1
  30. package/dist/public/app.js +42 -16
  31. package/dist/public/i18n/en/applications.js +23 -0
  32. package/dist/public/i18n/en/common.js +22 -0
  33. package/dist/public/i18n/en/documents.js +133 -0
  34. package/dist/public/i18n/en/home.js +75 -0
  35. package/dist/public/i18n/en/interview.js +69 -0
  36. package/dist/public/i18n/en/jobs.js +152 -0
  37. package/dist/public/i18n/en/nav.js +18 -0
  38. package/dist/public/i18n/en/profile.js +201 -0
  39. package/dist/public/i18n/en/settings.js +127 -0
  40. package/dist/public/i18n/en/status.js +22 -0
  41. package/dist/public/i18n/en.js +17 -0
  42. package/dist/public/i18n/ko/applications.js +23 -0
  43. package/dist/public/i18n/ko/common.js +22 -0
  44. package/dist/public/i18n/ko/documents.js +133 -0
  45. package/dist/public/i18n/ko/home.js +63 -0
  46. package/dist/public/i18n/ko/interview.js +69 -0
  47. package/dist/public/i18n/ko/jobs.js +152 -0
  48. package/dist/public/i18n/ko/nav.js +18 -0
  49. package/dist/public/i18n/ko/profile.js +201 -0
  50. package/dist/public/i18n/ko/settings.js +127 -0
  51. package/dist/public/i18n/ko/status.js +23 -0
  52. package/dist/public/i18n/ko.js +18 -0
  53. package/dist/public/i18n.js +55 -0
  54. package/dist/public/index.html +1 -0
  55. package/dist/public/lib.js +24 -17
  56. package/dist/public/pages/applications.js +17 -21
  57. package/dist/public/pages/documents.js +153 -107
  58. package/dist/public/pages/home.js +88 -53
  59. package/dist/public/pages/interview.js +105 -51
  60. package/dist/public/pages/jobs.js +330 -106
  61. package/dist/public/pages/profile.js +157 -152
  62. package/dist/public/pages/settings.js +154 -102
  63. package/dist/public/styles.css +28 -1
  64. package/dist/web.mjs +495 -75
  65. package/docs/FAQ.md +23 -3
  66. package/docs/MCP_TOOLS.md +22 -13
  67. package/docs/START_WORKFLOW.md +3 -3
  68. package/docs/SUPPORTED_AI_APPS.md +13 -0
  69. package/docs/WORKFLOWS.md +77 -20
  70. package/docs/career-os/README.md +12 -6
  71. package/docs/career-os/eop/career-description.md +139 -0
  72. package/docs/career-os/eop/cover-letter.md +10 -5
  73. package/docs/career-os/eop/fit-analysis.md +16 -6
  74. package/docs/career-os/eop/interview-prep.md +209 -21
  75. package/docs/career-os/eop/job-analysis.md +6 -4
  76. package/docs/career-os/eop/profile-extraction.md +5 -4
  77. package/docs/career-os/knowledge/cover-letter.md +5 -4
  78. package/docs/career-os/knowledge/fit-matching.md +8 -8
  79. package/docs/career-os/knowledge/human-writing.md +2 -0
  80. package/docs/career-os/knowledge/interview-behavioral.md +76 -8
  81. package/docs/career-os/knowledge/interview-technical.md +106 -4
  82. package/docs/career-os/knowledge/linkedin-profile.md +1 -1
  83. package/docs/career-os/knowledge/networking-referrals.md +1 -1
  84. package/docs/career-os/knowledge/offer-evaluation-decision.md +10 -10
  85. package/docs/career-os/knowledge/portfolio.md +3 -3
  86. package/docs/career-os/knowledge/verifiers/ats-compat.md +8 -4
  87. package/docs/career-os/knowledge/verifiers/human-voice.md +4 -2
  88. package/docs/career-os/knowledge/verifiers/recency-staleness.md +1 -1
  89. package/docs/career-os/knowledge/verifiers/responsiveness-on-target.md +2 -2
  90. package/docs/career-os/knowledge/verifiers/truthfulness.md +1 -1
  91. package/package.json +2 -2
  92. package/packages/core/src/onboarding.ts +2 -1
  93. package/packages/core/src/services.ts +134 -17
  94. package/packages/core/src/summary.ts +59 -1
  95. package/packages/core/src/verify/lint.ts +4 -0
  96. package/packages/db/src/index.ts +1 -0
  97. package/packages/db/src/repositories.ts +0 -0
  98. package/packages/db/src/schema.ts +17 -0
  99. package/packages/exporters/src/index.ts +28 -17
  100. package/packages/knowledge/src/index.ts +55 -9
  101. package/packages/mcp-tools/src/tools.ts +250 -24
  102. package/packages/mcp-tools/src/update.ts +30 -15
  103. package/packages/parsers/src/documents.ts +12 -1
  104. package/packages/prompts/src/humanize.ts +46 -0
  105. package/packages/prompts/src/index.ts +5 -1
  106. package/packages/prompts/src/install.ts +4 -4
  107. package/packages/prompts/src/onboarding.ts +4 -4
  108. package/packages/prompts/src/system.ts +9 -7
  109. package/packages/shared/src/enums.ts +14 -4
  110. package/packages/shared/src/schemas.ts +41 -0
  111. package/packages/workflows/src/definitions.ts +45 -8
  112. package/scripts/init.ts +284 -13
  113. package/dist/site/analytics.js +0 -97
  114. package/dist/site/favicon.svg +0 -1
  115. package/dist/site/fonts/PretendardVariable.woff2 +0 -0
  116. package/dist/site/icon-180.png +0 -0
  117. package/dist/site/icon-512.png +0 -0
  118. package/dist/site/index.html +0 -465
  119. package/dist/site/landing.js +0 -163
  120. package/dist/site/llms-install.txt +0 -218
  121. package/dist/site/robots.txt +0 -4
  122. package/dist/site/sitemap.xml +0 -21
  123. package/dist/site/start.html +0 -356
  124. package/dist/site/style.css +0 -665
  125. package/dist/site/vercel.json +0 -20
package/dist/doctor.mjs CHANGED
@@ -71366,6 +71366,22 @@ var MIGRATIONS = [
71366
71366
 
71367
71367
  COMMIT;
71368
71368
  PRAGMA foreign_keys=ON;
71369
+ `,
71370
+ // v3 — per-job timeline entries. Document/cover-letter refs live in payload
71371
+ // snapshots instead of FKs so deleting a document does not erase the history.
71372
+ `
71373
+ CREATE TABLE IF NOT EXISTS application_timeline_events (
71374
+ id TEXT PRIMARY KEY,
71375
+ job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
71376
+ type TEXT NOT NULL,
71377
+ title TEXT NOT NULL,
71378
+ summary TEXT,
71379
+ payload TEXT NOT NULL DEFAULT '{}',
71380
+ occurred_at TEXT NOT NULL,
71381
+ created_at TEXT NOT NULL
71382
+ );
71383
+
71384
+ CREATE INDEX IF NOT EXISTS idx_timeline_job ON application_timeline_events(job_id, occurred_at ASC);
71369
71385
  `
71370
71386
  ];
71371
71387
  function migrate(db) {
@@ -71526,6 +71542,12 @@ function assertStatusTransition(from, to) {
71526
71542
  }
71527
71543
  }
71528
71544
  var DOCUMENT_KINDS = ["resume", "career_description", "portfolio", "other"];
71545
+ var DOCUMENT_KIND_LABELS = {
71546
+ resume: "\uC774\uB825\uC11C",
71547
+ career_description: "\uACBD\uB825\uAE30\uC220\uC11C",
71548
+ portfolio: "\uD3EC\uD2B8\uD3F4\uB9AC\uC624",
71549
+ other: "\uAE30\uD0C0 \uBB38\uC11C"
71550
+ };
71529
71551
  var CONTENT_SOURCES = ["manual", "upload", "ai", "edit"];
71530
71552
  var ACTIVITY_TYPES = [
71531
71553
  "profile_updated",
@@ -71538,6 +71560,13 @@ var ACTIVITY_TYPES = [
71538
71560
  "interview_prep_saved",
71539
71561
  "document_exported"
71540
71562
  ];
71563
+ var APPLICATION_TIMELINE_TYPES = [
71564
+ "job_saved",
71565
+ "fit_analysis_saved",
71566
+ "cover_letter_version_saved",
71567
+ "application_status_changed",
71568
+ "interview_prep_saved"
71569
+ ];
71541
71570
  var ENTITY_TYPES = [
71542
71571
  "profile",
71543
71572
  "experience",
@@ -75845,11 +75874,19 @@ var ApplicationInputSchema = external_exports.object({
75845
75874
  applied_at: optLine,
75846
75875
  notes: optNote
75847
75876
  });
75877
+ var ApplicationSubmissionSchema = external_exports.object({
75878
+ submitted_at: optLine.describe("\uC2E4\uC81C \uC81C\uCD9C\uC77C YYYY-MM-DD"),
75879
+ channel: optLine.describe("\uC81C\uCD9C \uCC44\uB110(\uC6D0\uD2F0\uB4DC/\uC0AC\uB78C\uC778/\uD68C\uC0AC \uCC44\uC6A9\uD398\uC774\uC9C0 \uB4F1)"),
75880
+ cover_letter_id: optLine,
75881
+ cover_letter_version_id: optLine,
75882
+ document_ids: strList.optional().describe("\uC81C\uCD9C\uD55C \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uBB38\uC11C ID \uBAA9\uB85D")
75883
+ });
75848
75884
  var ApplicationStatusUpdateSchema = external_exports.object({
75849
75885
  job_id: optLine,
75850
75886
  application_id: optLine,
75851
75887
  status: external_exports.enum(APPLICATION_STATUSES),
75852
- note: optNote.describe("\uC0C1\uD0DC \uBCC0\uACBD \uC0AC\uC720/\uBA54\uBAA8")
75888
+ note: optNote.describe("\uC0C1\uD0DC \uBCC0\uACBD \uC0AC\uC720/\uBA54\uBAA8"),
75889
+ submission: ApplicationSubmissionSchema.optional().describe("\uC9C0\uC6D0 \uC644\uB8CC \uAE30\uB85D\uC5D0 \uB0A8\uAE38 \uC81C\uCD9C \uC790\uB8CC \uC2A4\uB0C5\uC0F7")
75853
75890
  });
75854
75891
  var ApplicationRecordSchema = external_exports.object({
75855
75892
  ...baseRecord,
@@ -75867,8 +75904,10 @@ var StarGuideSchema = external_exports.object({
75867
75904
  action: optNote,
75868
75905
  result: optNote
75869
75906
  });
75907
+ var INTERVIEW_CATEGORIES = ["technical", "behavioral"];
75870
75908
  var InterviewQuestionSchema = external_exports.object({
75871
75909
  question: external_exports.string().max(MAX_NOTE),
75910
+ category: external_exports.enum(INTERVIEW_CATEGORIES).optional().describe("\uC9C8\uBB38 \uAC08\uB798: 'technical'(\uAE30\uC220\xB7\uC9C1\uBB34 1\uCC28) | 'behavioral'(\uC778\uC131\xB7\uCEEC\uCC98\uD54F\xB7\uC784\uC6D0 2\uCC28, \uC790\uAE30\uC18C\uAC1C\uC11C \uAE30\uBC18). \uC0DD\uB7B5 \uC2DC \uAE30\uC220\uB85C \uAC04\uC8FC."),
75872
75911
  intent: external_exports.string().max(MAX_NOTE).optional().describe("\uC9C8\uBB38 \uC758\uB3C4"),
75873
75912
  followups: strList.optional().describe("\uC608\uC0C1 \uAF2C\uB9AC \uC9C8\uBB38"),
75874
75913
  answer_outline: optBody.describe("\uB2F5\uBCC0 \uAC00\uC774\uB4DC/\uD575\uC2EC \uD3EC\uC778\uD2B8")
@@ -75896,6 +75935,24 @@ var ActivityRecordSchema = external_exports.object({
75896
75935
  summary: external_exports.string(),
75897
75936
  created_at: isoDateTime
75898
75937
  });
75938
+ var ApplicationTimelineInputSchema = external_exports.object({
75939
+ job_id: reqLine,
75940
+ type: external_exports.enum(APPLICATION_TIMELINE_TYPES),
75941
+ title: reqLine,
75942
+ summary: optNote,
75943
+ payload: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
75944
+ occurred_at: optLine
75945
+ });
75946
+ var ApplicationTimelineRecordSchema = external_exports.object({
75947
+ id,
75948
+ job_id: external_exports.string(),
75949
+ type: external_exports.enum(APPLICATION_TIMELINE_TYPES),
75950
+ title: external_exports.string(),
75951
+ summary: external_exports.string().nullable(),
75952
+ payload: external_exports.record(external_exports.string(), external_exports.unknown()),
75953
+ occurred_at: isoDateTime,
75954
+ created_at: isoDateTime
75955
+ });
75899
75956
  var OnboardingStatusSchema = external_exports.object({
75900
75957
  completed: external_exports.boolean(),
75901
75958
  has_profile: external_exports.boolean(),
@@ -75932,7 +75989,7 @@ var ApplicationContextSchema = external_exports.object({
75932
75989
  });
75933
75990
 
75934
75991
  // packages/shared/src/build-info.ts
75935
- var APP_VERSION = true ? "0.0.5" : "0.0.0-dev";
75992
+ var APP_VERSION = true ? "0.0.7" : "0.0.0-dev";
75936
75993
  var BUNDLED = true;
75937
75994
 
75938
75995
  // packages/shared/src/index.ts
@@ -76026,7 +76083,7 @@ function mapExperience(r) {
76026
76083
  };
76027
76084
  }
76028
76085
  function expKey(company, role, start) {
76029
- return [norm(company), norm(role), norm(start)].join("\0");
76086
+ return [norm(company), norm(role), norm(start)].join("");
76030
76087
  }
76031
76088
  var experienceRepo = {
76032
76089
  list() {
@@ -76537,6 +76594,7 @@ var jobRepo = {
76537
76594
  db.prepare(`DELETE FROM fit_analyses WHERE job_id=?`).run(id2);
76538
76595
  db.prepare(`DELETE FROM applications WHERE job_id=?`).run(id2);
76539
76596
  db.prepare(`DELETE FROM interview_preps WHERE job_id=?`).run(id2);
76597
+ db.prepare(`DELETE FROM application_timeline_events WHERE job_id=?`).run(id2);
76540
76598
  return db.prepare(`DELETE FROM jobs WHERE id=?`).run(id2).changes > 0;
76541
76599
  });
76542
76600
  }
@@ -76649,7 +76707,7 @@ var applicationRepo = {
76649
76707
  const m = { ...app, ...input };
76650
76708
  getDb().prepare(
76651
76709
  `UPDATE applications SET status=?,resume_id=?,cover_letter_id=?,applied_at=?,notes=?,updated_at=? WHERE id=?`
76652
- ).run(m.status, m.resume_id, m.cover_letter_id, m.applied_at, m.notes, now(), app.id);
76710
+ ).run(m.status, m.resume_id ?? null, m.cover_letter_id ?? null, m.applied_at ?? null, m.notes ?? null, now(), app.id);
76653
76711
  return this.get(app.id);
76654
76712
  },
76655
76713
  setStatus(jobId, status, note) {
@@ -76730,6 +76788,48 @@ var activityRepo = {
76730
76788
  return getDb().prepare(`SELECT * FROM activities ORDER BY created_at DESC LIMIT ?`).all(limit);
76731
76789
  }
76732
76790
  };
76791
+ function mapTimelineEvent(r) {
76792
+ return {
76793
+ id: r.id,
76794
+ job_id: r.job_id,
76795
+ type: r.type,
76796
+ title: r.title,
76797
+ summary: r.summary,
76798
+ payload: fromJson(r.payload, {}),
76799
+ occurred_at: r.occurred_at,
76800
+ created_at: r.created_at
76801
+ };
76802
+ }
76803
+ var timelineRepo = {
76804
+ add(input) {
76805
+ const ts = now();
76806
+ const id2 = newId("tl_");
76807
+ getDb().prepare(
76808
+ `INSERT INTO application_timeline_events (id,job_id,type,title,summary,payload,occurred_at,created_at)
76809
+ VALUES (?,?,?,?,?,?,?,?)`
76810
+ ).run(
76811
+ id2,
76812
+ input.job_id,
76813
+ input.type,
76814
+ input.title,
76815
+ input.summary ?? null,
76816
+ toJson(input.payload ?? {}),
76817
+ input.occurred_at ?? ts,
76818
+ ts
76819
+ );
76820
+ return this.get(id2);
76821
+ },
76822
+ get(id2) {
76823
+ const r = getDb().prepare(`SELECT * FROM application_timeline_events WHERE id=?`).get(id2);
76824
+ return r ? mapTimelineEvent(r) : null;
76825
+ },
76826
+ listByJob(jobId) {
76827
+ return getDb().prepare(`SELECT * FROM application_timeline_events WHERE job_id=? ORDER BY occurred_at ASC, created_at ASC`).all(jobId).map(mapTimelineEvent);
76828
+ },
76829
+ remove(id2) {
76830
+ return getDb().prepare(`DELETE FROM application_timeline_events WHERE id=?`).run(id2).changes > 0;
76831
+ }
76832
+ };
76733
76833
 
76734
76834
  // packages/mcp-tools/src/tools.ts
76735
76835
  import fs7 from "node:fs";
@@ -76756,12 +76856,13 @@ function profileCompleteness(p) {
76756
76856
  function getOnboardingStatus() {
76757
76857
  const profile = profileRepo.get();
76758
76858
  const resumes = documentRepo.list("resume");
76859
+ const careerDescriptions = documentRepo.list("career_description");
76759
76860
  const coverLetters = coverLetterRepo.list();
76760
76861
  const experiences = experienceRepo.list();
76761
76862
  const skills = skillRepo.list();
76762
76863
  const jobs = jobRepo.list();
76763
76864
  const has_profile = !!(profile && profile.name);
76764
- const has_resume = resumes.length > 0;
76865
+ const has_resume = resumes.length > 0 || careerDescriptions.length > 0;
76765
76866
  const has_cover_letter = coverLetters.length > 0;
76766
76867
  const has_experience = experiences.length > 0;
76767
76868
  const has_skills = skills.length > 0;
@@ -77174,6 +77275,29 @@ function batchNames(names) {
77174
77275
  if (!shown) return "";
77175
77276
  return `: ${shown}${names.length > 8 ? " \uC678" : ""}`;
77176
77277
  }
77278
+ function coverLetterTimelineRef(coverLetter, version2, requestedVersionId) {
77279
+ const resolvedVersion = version2 ?? coverLetter.versions?.find((v) => v.id === requestedVersionId || v.id === coverLetter.current_version_id) ?? null;
77280
+ return {
77281
+ kind: "cover_letter",
77282
+ id: coverLetter.id,
77283
+ title: coverLetter.title,
77284
+ version_id: resolvedVersion?.id ?? requestedVersionId ?? coverLetter.current_version_id,
77285
+ version_no: resolvedVersion?.version_no ?? coverLetter.version_count
77286
+ };
77287
+ }
77288
+ function documentTimelineRef(doc) {
77289
+ return {
77290
+ kind: "document",
77291
+ id: doc.id,
77292
+ title: doc.title,
77293
+ document_kind: doc.kind
77294
+ };
77295
+ }
77296
+ function submittedAtToOccurrence(value) {
77297
+ if (!value) return void 0;
77298
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return `${value}T00:00:00.000Z`;
77299
+ return void 0;
77300
+ }
77177
77301
  function addExperiences(inputs) {
77178
77302
  const res = experienceRepo.addMany(inputs);
77179
77303
  activityRepo.log(
@@ -77217,6 +77341,17 @@ function saveFitAnalysis(input) {
77217
77341
  const fit = fitRepo.save(input);
77218
77342
  const scoreText = fit.score != null ? ` (\uC801\uD569\uB3C4 ${fit.score}\uC810)` : "";
77219
77343
  activityRepo.log("fit_analysis_saved", `${job.company} \xB7 ${job.position} \uC801\uD569\uB3C4 \uBD84\uC11D\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4${scoreText}.`, "fit_analysis", fit.id);
77344
+ timelineRepo.add({
77345
+ job_id: job.id,
77346
+ type: "fit_analysis_saved",
77347
+ title: "\uC801\uD569\uB3C4 \uBD84\uC11D",
77348
+ summary: fit.score != null ? `\uC885\uD569 ${fit.score}\uC810` : fit.summary ?? void 0,
77349
+ payload: {
77350
+ fit_id: fit.id,
77351
+ score: fit.score
77352
+ },
77353
+ occurred_at: fit.updated_at
77354
+ });
77220
77355
  return fit;
77221
77356
  }
77222
77357
  function saveCoverLetterVersion(input) {
@@ -77250,18 +77385,67 @@ function saveCoverLetterVersion(input) {
77250
77385
  "cover_letter",
77251
77386
  coverLetter.id
77252
77387
  );
77388
+ if (coverLetter.job_id) {
77389
+ timelineRepo.add({
77390
+ job_id: coverLetter.job_id,
77391
+ type: "cover_letter_version_saved",
77392
+ title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uC791\uC131",
77393
+ summary: `${coverLetter.title} v${version2.version_no}`,
77394
+ payload: {
77395
+ cover_letter: coverLetterTimelineRef(coverLetter, version2)
77396
+ },
77397
+ occurred_at: version2.created_at
77398
+ });
77399
+ }
77253
77400
  return { coverLetter, version: version2, verification, forced };
77254
77401
  }
77255
- function updateApplicationStatus(jobId, status, note) {
77402
+ function updateApplicationStatus(jobId, status, note, submission) {
77256
77403
  const job = jobRepo.get(jobId);
77257
77404
  if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
77258
- const application = applicationRepo.setStatus(jobId, status, note);
77259
- activityRepo.log(
77260
- "application_status_changed",
77261
- `${job.company} \xB7 ${job.position} \uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[status]}'(\uC73C)\uB85C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.`,
77262
- "application",
77263
- application.id
77264
- );
77405
+ const before2 = applicationRepo.getByJob(jobId);
77406
+ const application = tx(() => {
77407
+ let application2 = applicationRepo.setStatus(jobId, status, note);
77408
+ const submittedDocs = (submission?.document_ids ?? []).map((docId) => documentRepo.get(docId)).filter((doc) => !!doc);
77409
+ const submittedCoverLetter = submission?.cover_letter_id ? coverLetterRepo.get(submission.cover_letter_id, true) : null;
77410
+ if (status === "applied" && submission) {
77411
+ const resumeLike = submittedDocs.find((doc) => doc.kind === "resume" || doc.kind === "career_description") ?? submittedDocs[0] ?? null;
77412
+ application2 = applicationRepo.upsert({
77413
+ job_id: jobId,
77414
+ resume_id: resumeLike?.id ?? application2.resume_id ?? void 0,
77415
+ cover_letter_id: submittedCoverLetter?.id ?? application2.cover_letter_id ?? void 0,
77416
+ applied_at: submission.submitted_at ?? application2.applied_at ?? void 0
77417
+ });
77418
+ }
77419
+ activityRepo.log(
77420
+ "application_status_changed",
77421
+ `${job.company} \xB7 ${job.position} \uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[status]}'(\uC73C)\uB85C \uBCC0\uACBD\uD588\uC2B5\uB2C8\uB2E4.`,
77422
+ "application",
77423
+ application2.id
77424
+ );
77425
+ const submittedAt = submission?.submitted_at?.trim();
77426
+ const channel = submission?.channel?.trim();
77427
+ const submissionPayload = submission && (submittedAt || channel || submittedCoverLetter || submittedDocs.length > 0) ? {
77428
+ submitted_at: submittedAt || null,
77429
+ channel: channel || null,
77430
+ cover_letter: submittedCoverLetter ? coverLetterTimelineRef(submittedCoverLetter, null, submission.cover_letter_version_id) : null,
77431
+ documents: submittedDocs.map(documentTimelineRef)
77432
+ } : null;
77433
+ timelineRepo.add({
77434
+ job_id: job.id,
77435
+ type: "application_status_changed",
77436
+ title: APPLICATION_STATUS_LABELS[status],
77437
+ summary: channel && status === "applied" ? `${channel}\uB85C \uC81C\uCD9C` : note ?? void 0,
77438
+ payload: {
77439
+ from_status: before2?.status ?? null,
77440
+ status,
77441
+ status_label: APPLICATION_STATUS_LABELS[status],
77442
+ note: note ?? null,
77443
+ submission: submissionPayload
77444
+ },
77445
+ occurred_at: submittedAtToOccurrence(submittedAt)
77446
+ });
77447
+ return application2;
77448
+ });
77265
77449
  const interview_unlocked = INTERVIEW_UNLOCK_STATUSES.includes(status);
77266
77450
  const hasPrep = !!interviewRepo.getByJob(jobId);
77267
77451
  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;
@@ -77270,15 +77454,19 @@ function updateApplicationStatus(jobId, status, note) {
77270
77454
  function saveInterviewPrep(input) {
77271
77455
  const job = jobRepo.get(input.job_id);
77272
77456
  if (!job) throw notFound("\uACF5\uACE0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
77273
- const app = applicationRepo.getByJob(job.id);
77274
- if (!app || !INTERVIEW_UNLOCK_STATUSES.includes(app.status)) {
77275
- const current = app ? APPLICATION_STATUS_LABELS[app.status] : "\uBBF8\uC9C0\uC6D0";
77276
- throw conflict(
77277
- `\uBA74\uC811 \uC900\uBE44\uB294 '\uC11C\uB958 \uD569\uACA9' \uC774\uC0C1 \uC0C1\uD0DC\uC5D0\uC11C\uB9CC \uC800\uC7A5\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD604\uC7AC \uC0C1\uD0DC: '${current}'. \uBA3C\uC800 \uC9C0\uC6D0 \uC0C1\uD0DC\uB97C '\uC11C\uB958 \uD569\uACA9' \uC774\uC0C1\uC73C\uB85C \uBC14\uAFBC \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.`
77278
- );
77279
- }
77280
77457
  const prep = interviewRepo.save(input);
77281
77458
  activityRepo.log("interview_prep_saved", `${job.company} \xB7 ${job.position} \uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.`, "interview_prep", prep.id);
77459
+ timelineRepo.add({
77460
+ job_id: job.id,
77461
+ type: "interview_prep_saved",
77462
+ title: "\uBA74\uC811 \uC900\uBE44",
77463
+ summary: prep.questions.length > 0 ? `\uC608\uC0C1 \uC9C8\uBB38 ${prep.questions.length}\uAC1C` : prep.notes ?? void 0,
77464
+ payload: {
77465
+ interview_prep_id: prep.id,
77466
+ question_count: prep.questions.length
77467
+ },
77468
+ occurred_at: prep.updated_at
77469
+ });
77282
77470
  return prep;
77283
77471
  }
77284
77472
 
@@ -77299,6 +77487,8 @@ var HUMANIZE_WRITING_GUIDE = `# \uC0AC\uB78C\uC774 \uC4F4 \uAC83\uCC98\uB7FC: \u
77299
77487
  \uBAA9\uD45C: \uC0AC\uC2E4\uACFC \uACBD\uD5D8\uC740 100% \uADF8\uB300\uB85C \uB450\uBA74\uC11C, "AI\uAC00 \uC4F4 \uD2F0"\uAC00 \uB098\uB294 \uBB38\uC7A5 \uC2B5\uAD00\uB9CC \uC81C\uAC70\uD55C\uB2E4.
77300
77488
  \uAC80\uC5F4\uAE30\uB97C \uC18D\uC774\uB294 \uAC8C \uC544\uB2C8\uB77C, \uCC44\uC6A9 \uB2F4\uB2F9\uC790\uAC00 \uC77D\uAE30\uC5D0 \uC790\uC5F0\uC2A4\uB7FD\uACE0 \uC0AC\uB78C \uB0C4\uC0C8 \uB098\uB294 \uAE00\uC744 \uC4F0\uB294 \uAC83\uC774 \uBAA9\uC801\uC774\uB2E4.
77301
77489
 
77490
+ > **\uC5B8\uC5B4 \uBC94\uC704:** \uC544\uB798 AI-tell \uBAA9\uB85D\uC740 \uD55C\uAD6D\uC5B4 \uAE00 \uAE30\uC900\uC774\uB2E4. \uC601\uC5B4 \uB4F1 \uB2E4\uB978 \uC5B8\uC5B4\uB85C \uC4F8 \uB54C\uB294 \uC774 \uBAA9\uB85D\uC744 \uADF8\uB300\uB85C \uC801\uC6A9\uD558\uC9C0 \uB9D0\uACE0, **\uAC19\uC740 \uC6D0\uB9AC**(\uD074\uB9AC\uC170\xB7\uAE30\uACC4\uC801 \uBCD1\uB82C\xB7\uACFC\uC7A5 \uC218\uC2DD\xB7\uACF5\uD5C8\uD55C \uC77C\uBC18\uB860 \uC81C\uAC70, \uAD6C\uCCB4\uC131, \uC0AC\uC2E4\xB7\uC218\uCE58 \uBCF4\uC874)\uB97C \uADF8 \uC5B8\uC5B4\uC758 \uC790\uC5F0\uC2A4\uB7EC\uC6B4 \uAD00\uC2B5\uC73C\uB85C \uC801\uC6A9\uD55C\uB2E4. \uACB0\uACFC\uBB3C\uC758 \uC5B8\uC5B4\uB294 \uB300\uC0C1 \uACF5\uACE0\xB7\uC2DC\uC7A5\uC744 \uB530\uB978\uB2E4.
77491
+
77302
77492
  ## \uC808\uB300 \uC6D0\uCE59
77303
77493
  - \uC800\uC7A5\uB41C \uC2E4\uC81C \uACBD\uD5D8\xB7\uC218\uCE58\xB7\uD68C\uC0AC\uBA85\xB7\uACE0\uC720\uBA85\uC0AC\xB7\uC9C1\uC811 \uC778\uC6A9\uC740 \uC808\uB300 \uBC14\uAFB8\uAC70\uB098 \uC9C0\uC5B4\uB0B4\uC9C0 \uC54A\uB294\uB2E4. \uBB38\uC7A5 \uACB0\uB9CC \uB2E4\uB4EC\uB294\uB2E4.
77304
77494
  - \uBE48\uCE78\uC774\uB098 \uD655\uC778\uC774 \uD544\uC694\uD55C \uBD80\uBD84\uC740 \uB9E4\uB044\uB7FD\uAC8C \uCC44\uC6CC \uB123\uC9C0 \uB9D0\uACE0 \uADF8\uB300\uB85C \uD45C\uC2DC\uD574 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3B\uB294\uB2E4.
@@ -77340,6 +77530,33 @@ var HUMANIZE_WRITING_GUIDE = `# \uC0AC\uB78C\uC774 \uC4F4 \uAC83\uCC98\uB7FC: \u
77340
77530
  - \uC18C\uB9AC \uB0B4\uC5B4 \uC77D\uC5C8\uC744 \uB54C \uC5B4\uC0C9\uD558\uAC70\uB098 "\uC0AC\uB78C\uC774 \uC774\uB807\uAC8C \uB9D0 \uC548 \uD558\uB294\uB370" \uC2F6\uC740 \uACF3\uC744 \uB2E4\uB4EC\uB294\uB2E4.
77341
77531
  - \uC0AC\uC2E4\xB7\uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uAC00 \uC6D0\uBCF8\uACFC 100% \uC77C\uCE58\uD558\uB294\uAC00?
77342
77532
  - \uC0AC\uC6A9\uC790\uC758 \uD1A4\uACFC \uAC15\uC870 \uD3EC\uC778\uD2B8\uAC00 \uC0B4\uC544 \uC788\uB294\uAC00?`;
77533
+ var STRUCTURED_DOC_WRITING_GUIDE = `# \uAD6C\uC870\uD615 \uBB38\uC11C(\uACBD\uB825\uAE30\uC220\uC11C\xB7\uC774\uB825\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624) \uBCF4\uC815
77534
+
77535
+ \uACBD\uB825\uAE30\uC220\uC11C\xB7\uC774\uB825\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\uB294 \uCC44\uC6A9 \uB2F4\uB2F9\uC790\uAC00 \uCC98\uC74C\uBD80\uD130 \uB05D\uAE4C\uC9C0 \uC77D\uB294 \uAE00\uC774 \uC544\uB2C8\uB77C \uBA87 \uCD08 \uC548\uC5D0 "\uC2A4\uCE94"\uD558\uB294 \uBB38\uC11C\uB2E4. \uBD88\uB9BF, \uBC88\uD638 \uB9E4\uAE34 \uC131\uACFC, \uC9C1\uBB34\xB7\uAE30\uAC04\xB7\uC5ED\uD560\uC744 \uAD6C\uBD84\uD55C \uC139\uC158 \uAD6C\uC870\uB294 AI\uAC00 \uC4F4 \uD2F0\uAC00 \uC544\uB2C8\uB77C \uC774 \uBB38\uC11C\uC758 \uC815\uC11D\uC774\uB2E4. \uC790\uAE30\uC18C\uAC1C\uC11C\uCC98\uB7FC \uC904\uAE00(\uC0B0\uBB38)\uB85C \uD480\uC9C0 \uB9D0\uACE0 \uAD6C\uC870\uB97C \uBCF4\uC874\uD55C\uB2E4.
77536
+
77537
+ ## \uC704 8\uAC1C AI-tell \uC911 \uAD6C\uC870\uD615\uC5D0\uC11C \uB2E4\uB974\uAC8C \uC801\uC6A9\uD558\uB294 \uAC83
77538
+ - 3\uBC88(\uAE30\uACC4\uC801 \uBCD1\uB82C)\xB78\uBC88(\uD615\uC2DD \uACFC\uC6A9)\uC740 \uC0B0\uBB38 \uBB38\uC7A5\uC5D0\uB9CC \uC801\uC6A9\uD55C\uB2E4. \uC131\uACFC\uB97C \uB098\uC5F4\uD558\uB294 \uBD88\uB9BF\xB7\uBC88\uD638 \uBAA9\uB85D \uAD6C\uC870 \uC790\uCCB4\uC5D0\uB294 \uC801\uC6A9\uD558\uC9C0 \uC54A\uB294\uB2E4 \u2014 \uBD88\uB9BF\uB85C \uB04A\uC5B4 \uC4F0\uB294 \uAC83\uC740 \uAC00\uB3C5\uC131\uC744 \uC704\uD55C \uC815\uC0C1 \uAD6C\uC870\uB2E4.
77539
+ - \uB2E8 \uC758\uBBF8 \uC5C6\uB294 "\uCCAB\uC9F8\xB7\uB458\uC9F8\xB7\uC14B\uC9F8" \uC11C\uC218 \uB098\uC5F4, \uBAA8\uB4E0 \uBD88\uB9BF\uC744 \uB611\uAC19\uC740 \uACE8\uACA9("~\uC744 \uD1B5\uD574 ~\uC744 \uD568")\uC73C\uB85C \uCC0D\uC5B4\uB0B4\uB294 \uAC83, \uACFC\uD55C \uAD75\uAC8C\xB7\uC774\uBAA8\uC9C0\xB7\uAC00\uC6B4\uB383\uC810 \uB5A1\uCE60\uC740 \uAD6C\uC870\uD615\uC5D0\uC11C\uB3C4 \uC81C\uAC70\uD55C\uB2E4.
77540
+
77541
+ ## \uAD6C\uC870\uB294 \uC0B4\uB9AC\uACE0, \uBD88\uB9BF '\uC548\uC758 \uC5B8\uC5B4'\uB9CC \uC0AC\uB78C\uB2F5\uAC8C
77542
+ - \uAC01 \uBD88\uB9BF\uC740 \uB3D9\uC0AC\uB098 \uC218\uCE58\uB85C \uC2DC\uC791\uD558\uACE0, \uAC80\uC99D \uAC00\uB2A5\uD55C \uC0AC\uC2E4(\uC22B\uC790\xB7\uAE30\uAC04\xB7\uB3C4\uAD6C\xB7\uC5ED\uD560\xB7\uACB0\uACFC)\uC744 \uD55C \uC904\uC5D0 \uB2F4\uB294\uB2E4.
77543
+ - \uBD88\uB9BF \uC548\uC758 \uBC88\uC5ED\uD22C\xB7\uD074\uB9AC\uC170\xB7\uACF5\uD5C8\uD55C \uC77C\uBC18\uB860\xB7\uC218\uB3D9\uD0DC\uB294 \uC790\uAE30\uC18C\uAC1C\uC11C\uC640 \uB611\uAC19\uC774 \uC81C\uAC70\uD55C\uB2E4. (\uC608: "\uBD84\uC11D\uC744 \uC9C4\uD589\uD558\uC600\uC2B5\uB2C8\uB2E4" \u2192 "\uBD84\uC11D\uD588\uB2E4", "\uB9CE\uC740 \uC131\uACFC\uB97C \uB0C8\uC2B5\uB2C8\uB2E4" \u2192 \uC2E4\uC81C \uC218\uCE58)
77544
+ - STAR\uC744 \uD55C\uB450 \uC904\uB85C \uC555\uCD95\uD55C\uB2E4: \uBB34\uC5C7\uC744 \uC65C \uD588\uACE0 \uACB0\uACFC \uC218\uCE58\uAC00 \uC5B4\uB5BB\uAC8C \uB410\uB294\uC9C0.
77545
+
77546
+ ## Do / Don't
77547
+ - Do: \uB450\uAD04\uC2DD \uBD88\uB9BF(\uACB0\uACFC\xB7\uC218\uCE58\uB97C \uC55E\uC138\uC6C0), \uC9C1\uBB34\xB7\uAE30\uAC04\xB7\uC5ED\uD560 \uAD6C\uBD84, \uC131\uACFC\uB97C \uC22B\uC790\uB85C.
77548
+ - Don't: \uACBD\uB825\uAE30\uC220\uC11C\uB97C \uC790\uAE30\uC18C\uAC1C\uC11C\uCC98\uB7FC \uC904\uAE00\uB85C \uD3C9\uD0C4\uD654\uD558\uC9C0 \uC54A\uB294\uB2E4. \uBD88\uB9BF\uC744 \uC5C6\uC560 \uC2A4\uCE94\uD558\uAE30 \uC5B4\uB835\uAC8C \uB9CC\uB4E4\uC9C0 \uC54A\uB294\uB2E4. \uB77C\uBCA8\xB7\uAD6C\uC870\uB97C \uB2E4 \uAC77\uC5B4\uB0B4 \uAC00\uB3C5\uC131\uC744 \uB5A8\uC5B4\uB728\uB9AC\uC9C0 \uC54A\uB294\uB2E4.
77549
+
77550
+ \uD575\uC2EC: \uC790\uAE30\uC18C\uAC1C\uC11C\uB294 \uC0AC\uB78C\uC758 \uBAA9\uC18C\uB9AC(\uC0B0\uBB38)\uB85C, \uACBD\uB825\uAE30\uC220\uC11C\xB7\uC774\uB825\uC11C\uB294 \uC0AC\uB78C\uC758 \uC5B8\uC5B4\uB85C \uC4F4 \uAE54\uB054\uD55C \uAD6C\uC870\uB85C. \uB458 \uB2E4 \uC0AC\uC2E4\xB7\uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uB294 100% \uBCF4\uC874\uD55C\uB2E4.`;
77551
+ var STRUCTURED_DOC_TYPES = /* @__PURE__ */ new Set(["career_description", "resume", "portfolio"]);
77552
+ function getWritingStyleGuide(docType) {
77553
+ if (docType && STRUCTURED_DOC_TYPES.has(docType)) {
77554
+ return `${HUMANIZE_WRITING_GUIDE}
77555
+
77556
+ ${STRUCTURED_DOC_WRITING_GUIDE}`;
77557
+ }
77558
+ return HUMANIZE_WRITING_GUIDE;
77559
+ }
77343
77560
 
77344
77561
  // packages/workflows/src/definitions.ts
77345
77562
  var WORKFLOWS = [
@@ -77350,7 +77567,7 @@ var WORKFLOWS = [
77350
77567
  trigger: '\uC0AC\uC6A9\uC790\uAC00 \uCC98\uC74C CareerMate\uC5D0 \uC5F0\uACB0\uD588\uAC70\uB098, "\uC2DC\uC791\uD558\uC790 / \uC14B\uC5C5\uD574\uC918 / \uD504\uB85C\uD544 \uB4F1\uB85D"\uC774\uB77C\uACE0 \uC694\uCCAD\uD560 \uB54C.',
77351
77568
  steps: [
77352
77569
  "`get_onboarding_status`\uB97C \uD638\uCD9C\uD574 \uD604\uC7AC \uB4F1\uB85D \uC0C1\uD0DC(has_profile, has_resume, has_cover_letter, has_experience, has_skills, profile_completeness, next_steps)\uB97C \uD655\uC778\uD55C\uB2E4.",
77353
- '\uBE44\uC5B4 \uC788\uB294 \uD56D\uBAA9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC548\uB0B4\uD558\uACE0, \uBA3C\uC800 "\uAE30\uC874\uC5D0 \uC791\uC131\uD574 \uB454 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C \uD30C\uC77C\uC774 \uC788\uB294\uC9C0" \uBB3B\uB294\uB2E4(hwp/docx/pdf \uBAA8\uB450 \uAC00\uB2A5).',
77570
+ '\uBE44\uC5B4 \uC788\uB294 \uD56D\uBAA9\uC744 \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC27D\uAC8C \uC548\uB0B4\uD558\uACE0, \uBA3C\uC800 "\uAE30\uC874\uC5D0 \uC791\uC131\uD574 \uB454 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uC790\uAE30\uC18C\uAC1C\uC11C \uD30C\uC77C\uC774 \uC788\uB294\uC9C0" \uBB3B\uB294\uB2E4(hwp/docx/pdf \uBAA8\uB450 \uAC00\uB2A5).',
77354
77571
  '\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.)',
77355
77572
  "\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.",
77356
77573
  "\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).",
@@ -77371,7 +77588,7 @@ var WORKFLOWS = [
77371
77588
  "\uACF5\uACE0 \uC694\uAD6C\uC0AC\uD56D\uACFC \uC0AC\uC6A9\uC790 \uACBD\uB825/\uC2A4\uD0AC/\uD504\uB85C\uC81D\uD2B8\uB97C \uBE44\uAD50\uD55C\uB2E4: \uC77C\uCE58\uD558\uB294 \uAC15\uC810(strengths)\uACFC \uBD80\uC871\uD55C \uBD80\uBD84(gaps), \uB9E4\uCE6D \uD0A4\uC6CC\uB4DC(matched_keywords)\uC640 \uB204\uB77D \uD0A4\uC6CC\uB4DC(missing_keywords)\uB97C \uB3C4\uCD9C\uD558\uACE0, \uC885\uD569 \uC801\uD569\uB3C4 \uC810\uC218(score 0~100)\uC640 \uC694\uC57D(summary), \uC9C0\uC6D0 \uC804\uB7B5 \uC81C\uC548(recommendations)\uC744 \uC815\uB9AC\uD55C\uB2E4. \uC5C6\uB294 \uACBD\uD5D8\uC744 \uC9C0\uC5B4\uB0B4\uC9C0 \uC54A\uB294\uB2E4.",
77372
77589
  "\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.",
77373
77590
  "\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).",
77374
- "\uBD84\uC11D \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC124\uBA85\uD55C\uB2E4(\uC798 \uB9DE\uB294 \uC810, \uBCF4\uC644\uD560 \uC810, \uCD94\uCC9C \uC804\uB7B5). \uAE30\uC220 \uC6A9\uC5B4\uB294 \uBE7C\uACE0 \uC804\uB2EC\uD55C\uB2E4.",
77591
+ "\uBD84\uC11D \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC27D\uAC8C \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.",
77375
77592
  '\uBD84\uC11D \uB4A4 \uACE7\uC7A5 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC4F0\uC9C0 \uB9D0\uACE0, "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?"\uB77C\uACE0 \uBB3B\uACE0 \uC120\uD0DD\uC9C0\uB97C \uC81C\uC2DC\uD55C\uB2E4: \u2460 "\uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918" \u2461 "\uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918".',
77376
77593
  '\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.',
77377
77594
  "\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).",
@@ -77390,7 +77607,24 @@ var WORKFLOWS = [
77390
77607
  "\uC800\uC7A5\uB41C \uC2E4\uC81C \uACBD\uD5D8\xB7\uC131\uACFC\uB9CC\uC73C\uB85C \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC791\uC131\uD558\uB418, \uC704 \uAE00\uC4F0\uAE30 \uADDC\uCE59\uC744 \uC801\uC6A9\uD574 \uC0AC\uB78C\uC774 \uC4F4 \uB4EF \uC790\uC5F0\uC2A4\uB7FD\uAC8C \uC4F4\uB2E4(\uC0AC\uC2E4\xB7\uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uB294 \uADF8\uB300\uB85C). \uBE48\uCE78\uC774\uB098 \uD655\uC778\uC774 \uD544\uC694\uD55C \uBD80\uBD84\uC740 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 \uD45C\uC2DC\uD574 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3B\uB294\uB2E4.",
77391
77608
  "\uC644\uC131\uBCF8\uC744 `save_cover_letter_version`\uC73C\uB85C \uC800\uC7A5\uD55C\uB2E4(\uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C\uBA74 cover_letter_id, \uC0C8\uB85C \uB9CC\uB4E4\uBA74 title, \uACF5\uACE0\uC6A9\uC774\uBA74 job_id, \uBCC0\uACBD \uC694\uC57D\uC740 note, source=ai).",
77392
77609
  "\uC0AC\uC6A9\uC790\uAC00 \uC6D0\uD558\uBA74 `export_cover_letter`\uB85C \uD30C\uC77C\uB85C \uB0B4\uBCF4\uB0B4\uACE0, \uCD94\uAC00 \uC218\uC815 \uC694\uCCAD\uC774 \uC788\uC73C\uBA74 \uC0C8 \uBC84\uC804\uC73C\uB85C \uB2E4\uC2DC \uC800\uC7A5\uD55C\uB2E4.",
77393
- "\uC800\uC7A5 \uACB0\uACFC\uB97C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC54C\uB9AC\uACE0, \uC9C0\uC6D0 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8(`update_application_status`)\uB098 \uBA74\uC811 \uC900\uBE44 \uB4F1 \uB2E4\uC74C \uB2E8\uACC4\uB97C \uC81C\uC548\uD55C\uB2E4."
77610
+ "\uC800\uC7A5 \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC54C\uB9AC\uACE0, \uC9C0\uC6D0 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8(`update_application_status`)\uB098 \uBA74\uC811 \uC900\uBE44 \uB4F1 \uB2E4\uC74C \uB2E8\uACC4\uB97C \uC81C\uC548\uD55C\uB2E4."
77611
+ ]
77612
+ },
77613
+ {
77614
+ id: "write_career_description",
77615
+ title: "\uACBD\uB825\uAE30\uC220\uC11C \uC791\uC131",
77616
+ description: "\uD504\uB85C\uD544\xB7\uC774\uB825\uC11C\xB7\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC\uC744 \uADFC\uAC70\uB85C \uC2E4\uC81C \uC81C\uCD9C \uAC00\uB2A5\uD55C \uACBD\uB825\uAE30\uC220\uC11C\uB97C \uC791\uC131\uD558\uACE0 \uBB38\uC11C\uD568\uC5D0 \uC800\uC7A5\uD558\uB294 \uD750\uB984.",
77617
+ trigger: '\uC0AC\uC6A9\uC790\uAC00 "\uACBD\uB825\uAE30\uC220\uC11C \uC368\uC918 / \uACBD\uB825\uAE30\uC220\uC11C \uB9CC\uB4E4\uC5B4\uC918 / \uB0B4 \uACBD\uB825 \uC815\uB9AC\uD574\uC918"\uB77C\uACE0 \uC694\uCCAD\uD560 \uB54C.',
77618
+ steps: [
77619
+ "`get_onboarding_status`\uB85C \uC900\uBE44 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uACE0, `get_profile`\xB7`get_resumes`\xB7`get_experiences`\xB7`get_projects`\xB7`get_skills`\uB97C \uD638\uCD9C\uD574 \uAE30\uC874 \uD504\uB85C\uD544, \uC774\uB825\uC11C, \uACBD\uB825\uAE30\uC220\uC11C(kind=career_description), \uACBD\uB825, \uD504\uB85C\uC81D\uD2B8, \uAE30\uC220\uC2A4\uD0DD\uC744 \uBAA8\uB450 \uD655\uC778\uD55C\uB2E4.",
77620
+ "\uC0AC\uC6A9\uC790\uAC00 \uD30C\uC77C \uACBD\uB85C\uB97C \uC8FC\uBA74 `read_document`\uB85C \uC77D\uACE0, \uC778\uC785 \uD3F4\uB354\uB97C \uC0AC\uC6A9\uD588\uB2E4\uBA74 `read_inbox`\uB85C \uBCF8\uBB38\uC744 \uC77D\uB294\uB2E4. \uC774\uBBF8 \uC800\uC7A5\uB41C \uC790\uB8CC\uC640 \uC0C8 \uD30C\uC77C\uC744 \uBE44\uAD50\uD574 \uC911\uBCF5\xB7\uC0C1\uCDA9\uB418\uB294 \uC0AC\uC2E4\uC740 \uD45C\uC2DC\uD558\uACE0 \uCD94\uCE21\uD558\uC9C0 \uC54A\uB294\uB2E4.",
77621
+ '`get_workflow_guide({ workflow_id: "write_career_description" })`\uAC00 \uC548\uB0B4\uD558\uB294 \uC804\uBB38\uAC00 \uC808\uCC28\uB97C \uB530\uB978\uB2E4. \uC791\uC131 \uC9C1\uC804 `get_playbook({ domain: "resume" })`\uC640 `get_playbook({ domain: "ats" })`\uB97C \uBC1B\uC544 \uC2E4\uC81C \uACBD\uB825\uAE30\uC220\uC11C \uD615\uC2DD\uACFC ATS \uCE5C\uD654\uC131\uC744 \uC801\uC6A9\uD55C\uB2E4.',
77622
+ "\uC791\uC131 \uC804\uC5D0 \uBAA9\uC801\uC744 \uD655\uC778\uD55C\uB2E4: \uBC94\uC6A9 \uB9C8\uC2A4\uD130\uBCF8\uC778\uC9C0, \uD2B9\uC815 \uC9C1\uBB34/\uACF5\uACE0\uC6A9\uC778\uC9C0, \uC2E0\uC785/\uBB34\uACBD\uB825\uC774\uB77C \uD504\uB85C\uC81D\uD2B8\xB7\uAD50\uC721\xB7\uD65C\uB3D9 \uC911\uC2EC \uC5ED\uB7C9\uAE30\uC220\uC11C\uB85C \uC4F8\uC9C0, \uBD84\uB7C9\uACFC \uD1A4\uC740 \uC5B4\uB5BB\uAC8C \uD560\uC9C0 \uBB3B\uB294\uB2E4.",
77623
+ "\uACBD\uB825\uAE30\uC220\uC11C\uB294 \uC790\uAE30\uC18C\uAC1C\uC11C\uCC98\uB7FC \uC11C\uC0AC\uB85C \uC4F0\uC9C0 \uC54A\uB294\uB2E4. \uC81C\uBAA9, \uD575\uC2EC \uC694\uC57D, \uD575\uC2EC \uC5ED\uB7C9, \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8\uBCC4 \uC5ED\uD560\xB7\uAE30\uAC04\xB7\uB3C4\uAD6C\xB7\uBB38\uC81C\xB7\uD589\uB3D9\xB7\uC131\uACFC\uB97C \uD45C\uB098 \uBD88\uB9BF \uC911\uC2EC\uC73C\uB85C \uC815\uB9AC\uD55C\uB2E4. \uC218\uCE58\xB7\uD68C\uC0AC\uBA85\xB7\uAE30\uAC04\xB7\uC9C1\uCC45\uC740 \uC800\uC7A5\uB41C \uC0AC\uC2E4\uB9CC \uC4F0\uACE0, \uC5C6\uB294 \uC131\uACFC \uC218\uCE58\uB294 \uB9CC\uB4E4\uC9C0 \uC54A\uB294\uB2E4.",
77624
+ '\uBB34\uACBD\uB825/\uBE44\uAC1C\uBC1C\uC790\uB77C\uBA74 \uACBD\uB825\uC744 \uB0A0\uC870\uD558\uC9C0 \uB9D0\uACE0 \uAD50\uC721\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC6B4\uC601 \uACBD\uD5D8\xB7\uC5C5\uBB34 \uB3C4\uAD6C\xB7\uD611\uC5C5 \uACBD\uD5D8\xB7\uC131\uACFC \uC99D\uAC70 \uC911\uC2EC\uC758 "\uC5ED\uB7C9\uAE30\uC220\uC11C"\uB85C \uAD6C\uC131\uD55C\uB2E4.',
77625
+ '\uC800\uC7A5 \uC9C1\uC804 `get_verifier({ id: "truthfulness" })`, `get_verifier({ id: "consistency" })`, `get_verifier({ id: "ats-compat" })`\uB97C \uBC1B\uC544 \uB2F9\uC2E0\uC774 \uC9C1\uC811 \uC810\uAC80\uD558\uACE0, \uD5C8\uC704\xB7\uC0C1\uCDA9\xB7\uD0A4\uC6CC\uB4DC \uB204\uB77D\uC744 \uACE0\uCE5C\uB2E4. \uD655\uC778\uC774 \uD544\uC694\uD55C \uC0AC\uC2E4\uC740 \uBCF8\uBB38\uC5D0 \uD45C\uC2DC\uD558\uACE0 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3B\uB294\uB2E4.',
77626
+ "\uC644\uC131\uBCF8\uC744 `add_resume`\uC73C\uB85C \uC800\uC7A5\uD55C\uB2E4(kind=career_description, source=ai, title\uC740 \uC0AC\uC6A9 \uBAA9\uC801\uC774 \uB4DC\uB7EC\uB098\uAC8C \uC791\uC131, tags\uC5D0 \uC9C1\uBB34/\uC6A9\uB3C4 \uD0A4\uC6CC\uB4DC \uD3EC\uD568). \uB300\uD45C \uBB38\uC11C\uB85C \uC0BC\uC544\uB3C4 \uB418\uB294\uC9C0 \uD655\uC778\uB41C \uACBD\uC6B0\uC5D0\uB9CC is_primary=true\uB97C \uC4F4\uB2E4.",
77627
+ "\uC800\uC7A5 \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC54C\uB9AC\uACE0, \uBB38\uC11C \uD0ED\uC5D0\uC11C \uD655\uC778\uD560 \uC218 \uC788\uC74C\uC744 \uC548\uB0B4\uD55C\uB2E4. \uD2B9\uC815 \uACF5\uACE0\uC6A9\uC73C\uB85C \uC791\uC131\uD588\uB2E4\uBA74 \uC774\uC5B4\uC11C \uC790\uAE30\uC18C\uAC1C\uC11C\uB098 \uBA74\uC811 \uC900\uBE44\uB97C \uC81C\uC548\uD55C\uB2E4."
77394
77628
  ]
77395
77629
  },
77396
77630
  {
@@ -77401,7 +77635,7 @@ var WORKFLOWS = [
77401
77635
  steps: [
77402
77636
  "\uD544\uC694\uD558\uBA74 `get_application_context` \uB610\uB294 `get_job_posting`\uC73C\uB85C \uB300\uC0C1 \uC9C0\uC6D0 \uAC74\uACFC \uACF5\uACE0\uB97C \uD655\uC778\uD55C\uB2E4.",
77403
77637
  "\uC801\uC808\uD55C \uC0C1\uD0DC\uB85C `update_application_status`\uB97C \uD638\uCD9C\uD55C\uB2E4. 8\uB2E8\uACC4: draft(\uC791\uC131 \uC911), planned(\uC9C0\uC6D0 \uC608\uC815), applied(\uC9C0\uC6D0 \uC644\uB8CC), document_passed(\uC11C\uB958 \uD569\uACA9), interview(\uBA74\uC811 \uC9C4\uD589), final_passed(\uCD5C\uC885 \uD569\uACA9), rejected(\uBD88\uD569\uACA9), on_hold(\uBCF4\uB958). \uBCC0\uACBD \uC0AC\uC720\uB294 note\uC5D0 \uB0A8\uAE34\uB2E4.",
77404
- "\uBCC0\uACBD \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC54C\uB9B0\uB2E4.",
77638
+ "\uBCC0\uACBD \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC27D\uAC8C \uC54C\uB9B0\uB2E4.",
77405
77639
  "\uC0C1\uD0DC\uC5D0 \uB9DE\uB294 \uB2E4\uC74C \uB2E8\uACC4\uB97C \uC81C\uC548\uD55C\uB2E4: applied \u2192 \uACB0\uACFC \uAE30\uB2E4\uB9AC\uAE30 \uC548\uB0B4, document_passed/interview \u2192 \uBA74\uC811 \uC900\uBE44(prepare_interview) \uC81C\uC548, final_passed \u2192 \uCD95\uD558 \uBC0F \uB9C8\uBB34\uB9AC, rejected/on_hold \u2192 \uD68C\uACE0 \uB610\uB294 \uB2E4\uB978 \uACF5\uACE0 \uD0D0\uC0C9 \uC81C\uC548.",
77406
77640
  "\uD544\uC694\uD558\uBA74 `open_application`\uC73C\uB85C \uD574\uB2F9 \uC9C0\uC6D0 \uAC74\uC744 \uC5F4\uC5B4 \uBCF4\uC5EC\uC900\uB2E4."
77407
77641
  ]
@@ -77409,14 +77643,29 @@ var WORKFLOWS = [
77409
77643
  {
77410
77644
  id: "prepare_interview",
77411
77645
  title: "\uBA74\uC811 \uC900\uBE44",
77412
- description: "\uC11C\uB958 \uD569\uACA9 \uC774\uD6C4 \uC608\uC0C1 \uC9C8\uBB38\xB7STAR \uB2F5\uBCC0\xB71\uBD84 \uC790\uAE30\uC18C\uAC1C\uB97C \uC900\uBE44\uD574 \uC800\uC7A5\uD558\uB294 \uD750\uB984.",
77413
- trigger: '\uC9C0\uC6D0 \uC0C1\uD0DC\uAC00 \uC11C\uB958 \uD569\uACA9(document_passed) \uB610\uB294 \uBA74\uC811 \uC9C4\uD589(interview)\uC73C\uB85C \uBC14\uB00C\uC5C8\uC744 \uB54C, \uB610\uB294 \uC0AC\uC6A9\uC790\uAC00 "\uBA74\uC811 \uC900\uBE44 \uB3C4\uC640\uC918"\uB77C\uACE0 \uC694\uCCAD\uD560 \uB54C.',
77646
+ description: "\uACF5\uACE0 \uAE30\uC900 \uC608\uC0C1 \uC9C8\uBB38\xB7STAR \uB2F5\uBCC0\xB71\uBD84 \uC790\uAE30\uC18C\uAC1C\uB97C \uC900\uBE44\uD574 \uC800\uC7A5\uD558\uB294 \uD750\uB984.",
77647
+ trigger: '\uC0AC\uC6A9\uC790\uAC00 "\uBA74\uC811 \uC900\uBE44 \uB3C4\uC640\uC918"\uB77C\uACE0 \uC694\uCCAD\uD558\uAC70\uB098, \uC9C0\uC6D0 \uC0C1\uD0DC\uAC00 \uC11C\uB958 \uD569\uACA9(document_passed) \uB610\uB294 \uBA74\uC811 \uC9C4\uD589(interview)\uC73C\uB85C \uBC14\uB00C\uC5C8\uC744 \uB54C.',
77414
77648
  steps: [
77415
77649
  "`get_application_context`(job_id \uD3EC\uD568)\uB97C \uD638\uCD9C\uD574 \uACF5\uACE0, \uD504\uB85C\uD544, \uACBD\uB825/\uD504\uB85C\uC81D\uD2B8, \uC801\uD569\uB3C4 \uBD84\uC11D(\uAC15\uC810\xB7\uAC2D), \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uAC00\uC838\uC628\uB2E4.",
77416
77650
  "\uACF5\uACE0\uC640 \uC0AC\uC6A9\uC790 \uACBD\uD5D8\uC744 \uBC14\uD0D5\uC73C\uB85C \uC608\uC0C1 \uBA74\uC811 \uC9C8\uBB38(question, intent, followups, answer_outline)\uC744 \uB3C4\uCD9C\uD55C\uB2E4.",
77417
77651
  "\uD575\uC2EC \uACBD\uD5D8\uC5D0 \uB300\uD55C STAR \uAC00\uC774\uB4DC(question, situation, task, action, result)\uC640 1\uBD84 \uC790\uAE30\uC18C\uAC1C(self_introduction) \uCD08\uC548\uC744 \uC791\uC131\uD55C\uB2E4. \uC2E4\uC81C \uACBD\uD5D8\uB9CC \uC0AC\uC6A9\uD55C\uB2E4.",
77418
77652
  "\uC900\uBE44 \uB0B4\uC6A9\uC744 `save_interview_prep`\uB85C \uC800\uC7A5\uD55C\uB2E4(job_id, questions, star_guides, self_introduction, notes).",
77419
- "\uC900\uBE44 \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC26C\uC6B4 \uD55C\uAD6D\uC5B4\uB85C \uC694\uC57D\uD574 \uC804\uB2EC\uD558\uACE0, \uBAA8\uC758 \uBA74\uC811/\uCD94\uAC00 \uC9C8\uBB38 \uC5F0\uC2B5\uC774\uB098 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8(`update_application_status`\uB85C interview/final_passed)\uB97C \uC81C\uC548\uD55C\uB2E4."
77653
+ "\uC900\uBE44 \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC27D\uAC8C \uC694\uC57D\uD574 \uC804\uB2EC\uD558\uACE0, \uBAA8\uC758 \uBA74\uC811/\uCD94\uAC00 \uC9C8\uBB38 \uC5F0\uC2B5\uC774\uB098 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8(`update_application_status`\uB85C interview/final_passed)\uB97C \uC81C\uC548\uD55C\uB2E4."
77654
+ ]
77655
+ },
77656
+ {
77657
+ id: "build_personal_brand",
77658
+ title: "\uD37C\uC2A4\uB110 \uBE0C\uB79C\uB4DC (LinkedIn\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624)",
77659
+ description: "LinkedIn \uD504\uB85C\uD544\uACFC \uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uAC19\uC740 \uC790\uAE30\uD45C\uD604 \uC790\uC0B0\uC744 \uC9C1\uBB34\uC5D0 \uB9DE\uCDB0 \uC791\uC131\xB7\uCD5C\uC801\uD654\uD558\uB294 \uD750\uB984. \uC774\uB825\uC11C \uC784\uD3EC\uD2B8(\uC628\uBCF4\uB529)\uC640 \uBD84\uB9AC\uB41C \uBCC4\uB3C4 \uC791\uC5C5.",
77660
+ trigger: '\uC0AC\uC6A9\uC790\uAC00 "\uB9C1\uD06C\uB4DC\uC778 \uD504\uB85C\uD544 \uBD10\uC918 / \uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uC815\uB9AC\uD574\uC918 / \uD37C\uC2A4\uB110 \uBE0C\uB79C\uB529 \uB3C4\uC640\uC918"\uB77C\uACE0 \uC694\uCCAD\uD560 \uB54C.',
77661
+ steps: [
77662
+ "`get_application_context`(\uAC00\uB2A5\uD558\uBA74 \uB300\uC0C1 job_id \uD3EC\uD568)\uB97C \uD638\uCD9C\uD574 \uD504\uB85C\uD544\xB7\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC\xB7\uB300\uD45C \uC774\uB825\uC11C\xB7\uAE00\uC4F0\uAE30 \uC120\uD638\uB97C \uAC00\uC838\uC628\uB2E4. \uD0C0\uAE43 \uACF5\uACE0\uAC00 \uC788\uC73C\uBA74 \uADF8 \uD0A4\uC6CC\uB4DC\uB97C \uC0AC\uC804 \uC785\uB825\uC73C\uB85C \uC4F4\uB2E4.",
77663
+ '`get_workflow_guide({ workflow_id: "build_personal_brand" })`\uAC00 \uC548\uB0B4\uD558\uB294 \uC804\uBB38\uAC00 \uC808\uCC28\uB97C \uB530\uB978\uB2E4. \uC791\uC131 \uC9C1\uC804 `get_playbook({ domain: "linkedin-profile" })`\xB7`get_playbook({ domain: "portfolio" })`\uB97C \uBC1B\uC544 \uD5E4\uB4DC\uB77C\uC778\xB7About\xB7Featured\xB73\uB9C9(problem\u2192approach\u2192impact) \uADDC\uBC94\uC744 \uC801\uC6A9\uD55C\uB2E4.',
77664
+ "\uBB34\uC5C7\uC744 \uB9CC\uB4E4\uC9C0 \uD655\uC778\uD55C\uB2E4(LinkedIn \uD504\uB85C\uD544\uB9CC/\uD3EC\uD2B8\uD3F4\uB9AC\uC624\uB9CC/\uB458 \uB2E4, \uD0C0\uAE43 \uC9C1\uBB34, \uAC15\uC870 \uD3EC\uC778\uD2B8). \uC800\uC7A5\uB41C \uC2E4\uC81C \uACBD\uD5D8\xB7\uC131\uACFC\uB9CC \uC4F0\uACE0, \uC5C6\uB294 \uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uB294 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 `[\uD655\uC778 \uD544\uC694]`\uB85C \uD45C\uC2DC\uD574 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3B\uB294\uB2E4.",
77665
+ "LinkedIn: \uD5E4\uB4DC\uB77C\uC778(\uD575\uC2EC \uD0A4\uC6CC\uB4DC\uB97C \uC55E 120\uC790\uC5D0 front-load, \uD558\uB4DC \uC0C1\uD55C 220\uC790)\xB7About \uCCAB \uBB38\uC7A5 \uD6C5\xB7\uC815\uB7C9 \uC131\uACFC\xB7\uC9C1\uBB34 \uD0A4\uC6CC\uB4DC\uB97C \uC791\uC131. \uD3EC\uD2B8\uD3F4\uB9AC\uC624: \uC9C1\uBB34\uC5D0 \uB9DE\uB294 3~6\uAC1C \uD56D\uBAA9\uC744 problem\u2192approach\u2192impact 3\uB9C9\uC73C\uB85C \uAD6C\uC131\uD558\uACE0 \uBCF8\uC778 \uAE30\uC5EC(my_role)\uC640 \uC815\uB7C9 \uC784\uD329\uD2B8\uB97C \uBA85\uC2DC\uD55C\uB2E4.",
77666
+ '\uC800\uC7A5 \uC9C1\uC804 `get_verifier({ id: "human-voice" })`\xB7`get_verifier({ id: "truthfulness" })`\xB7`get_verifier({ id: "consistency" })`\uB97C \uBC1B\uC544 \uB2F9\uC2E0\uC774 \uC9C1\uC811 \uC810\uAC80\uD55C\uB2E4(AI \uD2F0\xB7\uD658\uAC01\xB7\uC0AC\uC2E4 \uBCF4\uC874). \uD0A4\uC6CC\uB4DC \uC0AC\uC804\uC774 \uBE44\uBA74 \uD0A4\uC6CC\uB4DC \uCCB4\uD06C\uB294 \uBCF4\uB958\uD55C\uB2E4.',
77667
+ "\uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uBCF8\uBB38\uC740 `add_resume`(kind=portfolio)\uB85C \uC800\uC7A5\uD55C\uB2E4. LinkedIn \uD504\uB85C\uD544 \uCD08\uC548\uC740 \uC0AC\uC6A9\uC790\uAC00 \uBCF5\uC0AC\uD574 \uC4F0\uB3C4\uB85D \uC81C\uC2DC\uD558\uACE0(\uC804\uC6A9 \uC800\uC7A5\xB7\uAC80\uC99D \uB3C4\uAD6C validate_linkedin_profile\uC740 Phase B \uBBF8\uAD6C\uD604), \uC6D0\uD558\uBA74 \uD30C\uC77C\uB85C \uB0B4\uBCF4\uB0B8\uB2E4.",
77668
+ "\uC800\uC7A5 \uACB0\uACFC\uB97C \uC0AC\uC6A9\uC790\uC758 \uC5B8\uC5B4\uB85C \uC54C\uB9AC\uACE0 \uB300\uC2DC\uBCF4\uB4DC \uB9C1\uD06C\uB97C \uC548\uB0B4\uD558\uBA70, \uB124\uD2B8\uC6CC\uD0B9(\uCD94\uCC9C \uACBD\uB85C)\uC774\uB098 \uACF5\uACE0 \uC9C0\uC6D0\uC73C\uB85C \uC774\uC5B4\uAC08\uC9C0 \uC81C\uC548\uD55C\uB2E4."
77420
77669
  ]
77421
77670
  }
77422
77671
  ];
@@ -77500,22 +77749,64 @@ var CAREER_ROUTES = {
77500
77749
  verifierSequence: ["truthfulness", "consistency"]
77501
77750
  },
77502
77751
  analyze_job: {
77503
- eop: "job-analysis",
77752
+ eop: ["job-analysis", "fit-analysis"],
77504
77753
  expertSequence: ["fit-matching", "company-research"],
77505
77754
  verifierSequence: ["truthfulness", "consistency", "responsiveness-on-target"],
77506
77755
  loop: "draft_verify_revise"
77507
77756
  },
77757
+ // R22(audit): responsiveness-on-target는 한국 문항형 자소서 전용 검증기(문항별 1:1 응답·
77758
+ // 글자수 상·하한 = "핵심 탈락 사유")인데 analyze_job에만 라우팅돼 있어 정작 자소서 자가검증
77759
+ // 루프에서 빠져 있었다. 동문서답·미응답 문항·글자수 초과를 잡도록 write_cover_letter에 추가.
77508
77760
  write_cover_letter: {
77509
77761
  eop: "cover-letter",
77510
77762
  expertSequence: ["cover-letter", "human-writing", "company-research"],
77511
- verifierSequence: ["human-voice", "truthfulness", "ats-compat", "consistency"],
77763
+ verifierSequence: ["human-voice", "truthfulness", "responsiveness-on-target", "ats-compat", "consistency"],
77764
+ loop: "draft_verify_revise"
77765
+ },
77766
+ write_career_description: {
77767
+ eop: "career-description",
77768
+ expertSequence: ["resume", "ats"],
77769
+ verifierSequence: ["truthfulness", "consistency", "ats-compat"],
77512
77770
  loop: "draft_verify_revise"
77513
77771
  },
77514
77772
  prepare_interview: {
77515
77773
  eop: "interview-prep",
77516
- expertSequence: ["interview-behavioral", "interview-technical", "company-research"],
77517
- verifierSequence: ["truthfulness", "consistency"],
77774
+ expertSequence: ["recruiter-screen", "interview-behavioral", "interview-technical", "company-research"],
77775
+ // R22(audit): recency-staleness 추가 — 면접의 "최근 소식"·회사 근황이 낡으면 거짓 신선도가
77776
+ // 되므로(company-research) 저장 전 신선도 점검을 푸시한다.
77777
+ verifierSequence: ["truthfulness", "consistency", "recency-staleness"],
77518
77778
  loop: "draft_verify_revise"
77779
+ },
77780
+ // R7 A2: manage_application_status had no route → rejection-triage / offer-evaluation /
77781
+ // salary-negotiation were orphaned (served only on-demand via get_playbook). Route the
77782
+ // decision-stage playbooks so they are pushed when the user manages application outcomes.
77783
+ // R7 A4: A2 routed the decision-stage playbooks, but the EOP-free lifecycle domains
77784
+ // onboarding-first-90-days and networking-referrals were still on-demand-only. Anchor them
77785
+ // here (the only EOP-free lifecycle route). NOTE: networking's strongest lever is *before*
77786
+ // applied (pre-referral, networking-referrals §2) — this route is the surfacing point, not
77787
+ // the recommended timing, so surface networking early when the user is pre-application.
77788
+ // linkedin-profile/portfolio stay on-demand pending a dedicated personal-brand workflow id
77789
+ // (FIXES.md / STATUS §7.9 follow-up — onboarding EOP is résumé-import-only, so brand-
77790
+ // creation playbooks would blur its stage meaning). Additive wiring (A1/A2 precedent).
77791
+ manage_application_status: {
77792
+ expertSequence: [
77793
+ "rejection-triage-iteration",
77794
+ "offer-evaluation-decision",
77795
+ "salary-negotiation",
77796
+ "onboarding-first-90-days",
77797
+ "networking-referrals"
77798
+ ],
77799
+ // R22(audit): recency-staleness 추가 — 연봉 벤치마크·오퍼 비교는 시점이 지나면 낡은 기준이
77800
+ // 되므로(salary-negotiation/offer-evaluation) 저장 전 신선도 점검을 푸시한다.
77801
+ verifierSequence: ["truthfulness", "consistency", "recency-staleness"]
77802
+ },
77803
+ // R7 후속: linkedin-profile·portfolio는 onboarding(이력서 임포트)과 단계 의미가
77804
+ // 달라(개인 브랜드 자산 *생성*) 전용 워크플로우로 분리(consensus 권고). networking은
77805
+ // manage_application_status에 이미 정박. 저장은 add_resume(kind=portfolio); linkedin
77806
+ // 전용 저장/검증은 Phase B.
77807
+ build_personal_brand: {
77808
+ expertSequence: ["linkedin-profile", "portfolio"],
77809
+ verifierSequence: ["truthfulness", "human-voice", "consistency"]
77519
77810
  }
77520
77811
  };
77521
77812
  function getRoute(id2) {
@@ -77525,12 +77816,15 @@ function renderRouteGuide(id2) {
77525
77816
  const route = CAREER_ROUTES[id2];
77526
77817
  if (!route) return void 0;
77527
77818
  const lines = [];
77528
- if (route.eop) {
77819
+ const eops = route.eop ? Array.isArray(route.eop) ? route.eop : [route.eop] : [];
77820
+ if (eops.length) {
77529
77821
  lines.push("---", "");
77530
77822
  lines.push("## \uC804\uBB38\uAC00 \uC2E4\uD589 \uC808\uCC28 (EOP) \u2014 \uC989\uB2F5\uD558\uC9C0 \uB9D0\uACE0 \uC774 \uC808\uCC28\uB97C \uB530\uB974\uC138\uC694");
77531
77823
  lines.push("");
77532
- lines.push(getEop(route.eop));
77533
- lines.push("");
77824
+ for (const e of eops) {
77825
+ lines.push(getEop(e));
77826
+ lines.push("");
77827
+ }
77534
77828
  }
77535
77829
  lines.push("## \uC774 \uC791\uC5C5\uC5D0 \uC801\uC6A9\uD560 \uC804\uBB38\uAC00 \uD50C\uB808\uC774\uBD81");
77536
77830
  lines.push("\uC791\uC131 \uC9C1\uC804, \uC544\uB798 \uB3C4\uBA54\uC778\uC758 \uAE4A\uC740 \uC9C0\uC2DD\uC744 \uBC1B\uC544 \uC801\uC6A9\uD558\uC138\uC694:");
@@ -77644,10 +77938,22 @@ function slugify(input, fallback = "document") {
77644
77938
  function joinBlocks(blocks) {
77645
77939
  return blocks.filter((b) => typeof b === "string" && b.trim().length > 0).join("\n\n");
77646
77940
  }
77941
+ function bulletList(items) {
77942
+ const lines = items.filter((i2) => typeof i2 === "string" && i2.trim().length > 0).map((i2) => `- ${i2.trim()}`);
77943
+ return lines.join("\n");
77944
+ }
77647
77945
  function kv(label, value) {
77648
77946
  if (!value || !value.trim()) return "";
77649
77947
  return `**${label}**: ${value.trim()}`;
77650
77948
  }
77949
+ function dateRange(start, end, current = false) {
77950
+ const s = (start ?? "").trim();
77951
+ const e = current ? "\uD604\uC7AC" : (end ?? "").trim();
77952
+ if (!s && !e) return "";
77953
+ if (!s) return e;
77954
+ if (!e) return s;
77955
+ return `${s} ~ ${e}`;
77956
+ }
77651
77957
  function renderInline(escaped) {
77652
77958
  let out = escaped;
77653
77959
  out = out.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
@@ -77756,6 +78062,123 @@ function coverLetterToHtml(cl, opts) {
77756
78062
  content: toPrintableHtml(cl.title, coverLetterBody(cl, opts))
77757
78063
  };
77758
78064
  }
78065
+ function resumeToMarkdown(doc, profile) {
78066
+ const kindLabel = DOCUMENT_KIND_LABELS[doc.kind] ?? doc.kind;
78067
+ const header = [];
78068
+ if (profile?.name) header.push(kv("\uC774\uB984", profile.name));
78069
+ if (profile?.email) header.push(kv("\uC774\uBA54\uC77C", profile.email));
78070
+ if (profile?.phone) header.push(kv("\uC5F0\uB77D\uCC98", profile.phone));
78071
+ const body = joinBlocks([
78072
+ `# ${doc.title}`,
78073
+ `_${kindLabel}_`,
78074
+ header.length ? header.filter(Boolean).join("\n\n") : "",
78075
+ header.length ? "---" : "",
78076
+ (doc.content ?? "").trim() || "_(\uB0B4\uC6A9 \uC5C6\uC74C)_"
78077
+ ]);
78078
+ return {
78079
+ filename: `${slugify(doc.title, doc.kind)}.md`,
78080
+ mimeType: MD_MIME,
78081
+ content: body
78082
+ };
78083
+ }
78084
+ function resumeToHtml(doc, profile) {
78085
+ const md = resumeToMarkdown(doc, profile);
78086
+ return {
78087
+ filename: `${slugify(doc.title, doc.kind)}.html`,
78088
+ mimeType: HTML_MIME,
78089
+ content: toPrintableHtml(doc.title, md.content)
78090
+ };
78091
+ }
78092
+ function profileToMarkdown(profile, experiences = [], projects = [], skills = []) {
78093
+ const name = profile.name?.trim() || "\uC774\uB825\uC11C";
78094
+ const contact = [];
78095
+ if (profile.email) contact.push(profile.email);
78096
+ if (profile.phone) contact.push(profile.phone);
78097
+ if (profile.location) contact.push(profile.location);
78098
+ const links = (profile.links ?? []).filter((l2) => l2.url).map((l2) => `[${l2.label || l2.url}](${l2.url})`);
78099
+ const headerBlocks = joinBlocks([
78100
+ `# ${name}`,
78101
+ profile.headline ? `## ${profile.headline}` : "",
78102
+ contact.length ? contact.join(" \xB7 ") : "",
78103
+ links.length ? links.join(" \xB7 ") : ""
78104
+ ]);
78105
+ const summaryBlock = profile.summary?.trim() ? joinBlocks(["## \uC18C\uAC1C", profile.summary.trim()]) : "";
78106
+ const desiredLines = [];
78107
+ if (profile.desired_roles?.length) {
78108
+ desiredLines.push(kv("\uD76C\uB9DD \uC9C1\uBB34", profile.desired_roles.join(", ")));
78109
+ }
78110
+ if (profile.desired_conditions?.trim()) {
78111
+ desiredLines.push(kv("\uD76C\uB9DD \uC870\uAC74", profile.desired_conditions));
78112
+ }
78113
+ const desiredBlock = desiredLines.length ? joinBlocks(["## \uD76C\uB9DD \uC0AC\uD56D", desiredLines.filter(Boolean).join("\n\n")]) : "";
78114
+ const expBlocks = experiences.length ? joinBlocks([
78115
+ "## \uACBD\uB825",
78116
+ ...experiences.map((e) => {
78117
+ const range2 = dateRange(e.start_date, e.end_date, e.is_current);
78118
+ const titleParts = [e.company, e.role].filter(Boolean).join(" \u2014 ");
78119
+ const subParts = [e.employment_type, range2].filter(Boolean).join(" \xB7 ");
78120
+ return joinBlocks([
78121
+ `### ${titleParts}`,
78122
+ subParts ? `_${subParts}_` : "",
78123
+ e.description?.trim() ? e.description.trim() : "",
78124
+ e.achievements?.length ? bulletList(e.achievements) : "",
78125
+ e.tech?.length ? kv("\uAE30\uC220", e.tech.join(", ")) : ""
78126
+ ]);
78127
+ })
78128
+ ]) : "";
78129
+ const projBlocks = projects.length ? joinBlocks([
78130
+ "## \uD504\uB85C\uC81D\uD2B8",
78131
+ ...projects.map((p) => {
78132
+ const range2 = dateRange(p.start_date, p.end_date);
78133
+ const subParts = [p.role, range2].filter(Boolean).join(" \xB7 ");
78134
+ return joinBlocks([
78135
+ `### ${p.name}`,
78136
+ subParts ? `_${subParts}_` : "",
78137
+ p.description?.trim() ? p.description.trim() : "",
78138
+ p.highlights?.length ? bulletList(p.highlights) : "",
78139
+ p.tech?.length ? kv("\uAE30\uC220", p.tech.join(", ")) : "",
78140
+ p.url ? kv("\uB9C1\uD06C", p.url) : ""
78141
+ ]);
78142
+ })
78143
+ ]) : "";
78144
+ let skillsBlock = "";
78145
+ if (skills.length) {
78146
+ const groups = /* @__PURE__ */ new Map();
78147
+ for (const s of skills) {
78148
+ const cat = s.category?.trim() || "\uAE30\uD0C0";
78149
+ const label = s.level?.trim() ? `${s.name} (${s.level.trim()})` : s.name;
78150
+ if (!groups.has(cat)) groups.set(cat, []);
78151
+ groups.get(cat).push(label);
78152
+ }
78153
+ const lines = [...groups.entries()].map(
78154
+ ([cat, items]) => kv(cat, items.join(", "))
78155
+ );
78156
+ skillsBlock = joinBlocks(["## \uBCF4\uC720 \uAE30\uC220", lines.filter(Boolean).join("\n\n")]);
78157
+ }
78158
+ const content = joinBlocks([
78159
+ headerBlocks,
78160
+ "---",
78161
+ summaryBlock,
78162
+ desiredBlock,
78163
+ expBlocks,
78164
+ projBlocks,
78165
+ skillsBlock
78166
+ ]);
78167
+ return {
78168
+ filename: `${slugify(name, "resume")}-resume.md`,
78169
+ mimeType: MD_MIME,
78170
+ content
78171
+ };
78172
+ }
78173
+ function profileToHtml(profile, experiences = [], projects = [], skills = []) {
78174
+ const md = profileToMarkdown(profile, experiences, projects, skills);
78175
+ const title = profile.name?.trim() || "\uC774\uB825\uC11C";
78176
+ return {
78177
+ filename: `${slugify(title, "resume")}-resume.html`,
78178
+ mimeType: HTML_MIME,
78179
+ content: toPrintableHtml(title, md.content)
78180
+ };
78181
+ }
77759
78182
 
77760
78183
  // packages/parsers/src/html.ts
77761
78184
  var NAMED_ENTITIES = {
@@ -78316,7 +78739,12 @@ async function extractDocument(input, baseDir) {
78316
78739
  path: filePath,
78317
78740
  ...over
78318
78741
  });
78319
- if (SENSITIVE_PATH_RE.test(filePath)) {
78742
+ let realPath = filePath;
78743
+ try {
78744
+ realPath = fs4.realpathSync.native(filePath);
78745
+ } catch {
78746
+ }
78747
+ if (SENSITIVE_PATH_RE.test(filePath) || SENSITIVE_PATH_RE.test(realPath)) {
78320
78748
  return base("unsupported", {
78321
78749
  warnings: [
78322
78750
  "\uBCF4\uC548\uC0C1 \uBBFC\uAC10\uD560 \uC218 \uC788\uB294 \uD30C\uC77C(\uAC1C\uC778 \uD0A4\xB7\uC790\uACA9\uC99D\uBA85 \uB4F1)\uC740 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uC790\uAE30\uC18C\uAC1C\uC11C \uAC19\uC740 \uBB38\uC11C \uD30C\uC77C\uC744 \uC9C0\uC815\uD574 \uC8FC\uC138\uC694."
@@ -78986,14 +79414,20 @@ function getUpdateStatus() {
78986
79414
  if (cacheExpired(cache2)) refreshInBackground();
78987
79415
  return buildStatus(cache2);
78988
79416
  }
78989
- async function getUpdateStatusAsync() {
79417
+ async function getUpdateStatusAsync(force = false) {
78990
79418
  if (checkDisabled()) return buildStatus(null);
78991
- let cache2 = readCache();
78992
- if (cacheExpired(cache2)) {
78993
- cache2 = { checkedAt: Date.now(), latest: await fetchLatest() };
78994
- writeCache(cache2);
78995
- }
78996
- return buildStatus(cache2);
79419
+ const cache2 = readCache();
79420
+ if (!force && !cacheExpired(cache2)) return buildStatus(cache2);
79421
+ const latest = await fetchLatest();
79422
+ if (latest !== null) {
79423
+ const fresh = { checkedAt: Date.now(), latest };
79424
+ writeCache(fresh);
79425
+ return buildStatus(fresh);
79426
+ }
79427
+ if (force) return buildStatus(null);
79428
+ const failed = { checkedAt: Date.now(), latest: null };
79429
+ writeCache(failed);
79430
+ return buildStatus(failed);
78997
79431
  }
78998
79432
  function killTree(child) {
78999
79433
  if (process.platform === "win32" && child.pid) {
@@ -79051,12 +79485,8 @@ async function runSelfUpdate() {
79051
79485
  manual: manualCommand()
79052
79486
  };
79053
79487
  }
79054
- let cache2 = readCache();
79055
- if (cacheExpired(cache2)) {
79056
- cache2 = { checkedAt: Date.now(), latest: await fetchLatest() };
79057
- writeCache(cache2);
79058
- }
79059
- const latest = cache2?.latest ?? null;
79488
+ const latest = await fetchLatest();
79489
+ if (latest !== null) writeCache({ checkedAt: Date.now(), latest });
79060
79490
  if (latest === null) {
79061
79491
  return {
79062
79492
  ok: false,
@@ -79099,13 +79529,23 @@ function listInboxFiles(dir) {
79099
79529
  } catch {
79100
79530
  return [];
79101
79531
  }
79532
+ let realDir;
79533
+ try {
79534
+ realDir = fs7.realpathSync.native(dir);
79535
+ } catch {
79536
+ realDir = dir;
79537
+ }
79102
79538
  const SKIP = /^[.~]|^(thumbs\.db|desktop\.ini)$/i;
79103
79539
  const out = [];
79104
79540
  for (const name of names) {
79105
79541
  if (SKIP.test(name)) continue;
79106
79542
  const p = path7.join(dir, name);
79107
79543
  try {
79108
- if (fs7.statSync(p).isFile()) out.push({ name, path: p });
79544
+ if (!fs7.statSync(p).isFile()) continue;
79545
+ const real = fs7.realpathSync.native(p);
79546
+ const rel = path7.relative(realDir, real);
79547
+ if (rel.startsWith("..") || path7.isAbsolute(rel)) continue;
79548
+ out.push({ name, path: p });
79109
79549
  } catch {
79110
79550
  }
79111
79551
  }
@@ -79175,8 +79615,8 @@ ${r.warnings.join("\n")}`, {
79175
79615
  /* --------------------------------------------------------- inbox (파일 인입) */
79176
79616
  {
79177
79617
  name: "open_inbox",
79178
- title: "\uC774\uB825\uC11C \uC778\uC785 \uD3F4\uB354 \uC5F4\uAE30",
79179
- description: 'CLI \uD074\uB77C\uC774\uC5B8\uD2B8\uB294 \uD30C\uC77C \uCCA8\uBD80\uAC00 \uC548 \uB418\uBBC0\uB85C, \uC0AC\uC6A9\uC790\uAC00 \uAE30\uC874 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C \uD30C\uC77C(hwp/hwpx/docx/pdf \uB4F1)\uC744 \uB04C\uC5B4\uB2E4 \uB123\uC744 \uC218 \uC788\uB294 \uB85C\uCEEC \uC778\uC785 \uD3F4\uB354(~/.careermate/inbox)\uB97C \uBCF4\uC7A5\uD558\uACE0 \uD30C\uC77C \uD0D0\uC0C9\uAE30\uB85C \uC5FD\uB2C8\uB2E4. \uC628\uBCF4\uB529\uC5D0\uC11C "\uAE30\uC874\uC5D0 \uC791\uC131\uD574 \uB454 \uC774\uB825\uC11C \uD30C\uC77C\uC774 \uC788\uB2E4"\uACE0 \uC0AC\uC6A9\uC790\uAC00 \uB2F5\uD588\uC744 \uB54C\uB9CC \uD638\uCD9C\uD558\uC138\uC694 \u2014 \uBB3B\uC9C0\uB3C4 \uC54A\uACE0 \uD3F4\uB354\uB97C \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uB9C8\uC138\uC694. \uD30C\uC77C \uACBD\uB85C\uB97C \uC9C1\uC811 \uC54C\uB824\uC8FC\uB294 \uC0AC\uC6A9\uC790\uC5D0\uAC8C\uB294 \uC774 \uB3C4\uAD6C \uB300\uC2E0 read_document\uB97C \uC4F0\uC138\uC694. \uD638\uCD9C\uD558\uBA74 \uD3F4\uB354 \uACBD\uB85C\uC640 \uD604\uC7AC \uD3F4\uB354\uC5D0 \uB4E4\uC5B4 \uC788\uB294 \uD30C\uC77C \uBAA9\uB85D\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uD30C\uC77C\uC744 \uB2E4 \uB123\uC5C8\uB2E4\uACE0 \uD558\uBA74 read_inbox\uB85C \uBCF8\uBB38\uC744 \uC77D\uC73C\uC138\uC694.',
79618
+ title: "\uBB38\uC11C \uC778\uC785 \uD3F4\uB354 \uC5F4\uAE30",
79619
+ description: 'CLI \uD074\uB77C\uC774\uC5B8\uD2B8\uB294 \uD30C\uC77C \uCCA8\uBD80\uAC00 \uC548 \uB418\uBBC0\uB85C, \uC0AC\uC6A9\uC790\uAC00 \uAE30\uC874 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\xB7\uC790\uAE30\uC18C\uAC1C\uC11C \uD30C\uC77C(hwp/hwpx/docx/pdf \uB4F1)\uC744 \uB04C\uC5B4\uB2E4 \uB123\uC744 \uC218 \uC788\uB294 \uB85C\uCEEC \uC778\uC785 \uD3F4\uB354(~/.careermate/inbox)\uB97C \uBCF4\uC7A5\uD558\uACE0 \uD30C\uC77C \uD0D0\uC0C9\uAE30\uB85C \uC5FD\uB2C8\uB2E4. \uC628\uBCF4\uB529\uC5D0\uC11C "\uAE30\uC874\uC5D0 \uC791\uC131\uD574 \uB454 \uBB38\uC11C \uD30C\uC77C\uC774 \uC788\uB2E4"\uACE0 \uC0AC\uC6A9\uC790\uAC00 \uB2F5\uD588\uC744 \uB54C\uB9CC \uD638\uCD9C\uD558\uC138\uC694 \u2014 \uBB3B\uC9C0\uB3C4 \uC54A\uACE0 \uD3F4\uB354\uB97C \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uB9C8\uC138\uC694. \uD30C\uC77C \uACBD\uB85C\uB97C \uC9C1\uC811 \uC54C\uB824\uC8FC\uB294 \uC0AC\uC6A9\uC790\uC5D0\uAC8C\uB294 \uC774 \uB3C4\uAD6C \uB300\uC2E0 read_document\uB97C \uC4F0\uC138\uC694. \uD638\uCD9C\uD558\uBA74 \uD3F4\uB354 \uACBD\uB85C\uC640 \uD604\uC7AC \uD3F4\uB354\uC5D0 \uB4E4\uC5B4 \uC788\uB294 \uD30C\uC77C \uBAA9\uB85D\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uD30C\uC77C\uC744 \uB2E4 \uB123\uC5C8\uB2E4\uACE0 \uD558\uBA74 read_inbox\uB85C \uBCF8\uBB38\uC744 \uC77D\uC73C\uC138\uC694.',
79180
79620
  inputSchema: {},
79181
79621
  handler: () => {
79182
79622
  const dir = getInboxDir();
@@ -79184,10 +79624,10 @@ ${r.warnings.join("\n")}`, {
79184
79624
  const files = listInboxFiles(dir);
79185
79625
  const list = files.length ? files.map((f) => `- ${f.name}`).join("\n") : "(\uC544\uC9C1 \uBE44\uC5B4 \uC788\uC74C)";
79186
79626
  return ok(
79187
- `\uC774\uB825\uC11C \uC778\uC785 \uD3F4\uB354\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4:
79627
+ `\uBB38\uC11C \uC778\uC785 \uD3F4\uB354\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4:
79188
79628
  ${dir}
79189
79629
 
79190
- \uC5EC\uAE30\uC5D0 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C \uD30C\uC77C\uC744 \uB123\uACE0 "\uB2E4 \uB123\uC5C8\uC5B4"\uB77C\uACE0 \uC54C\uB824\uC8FC\uC138\uC694. (hwp/hwpx/docx\uB294 \uC790\uB3D9\uC73C\uB85C \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD558\uACE0, pdf\xB7\uC774\uBBF8\uC9C0\uB294 \uC81C\uAC00 \uC9C1\uC811 \uC77D\uC2B5\uB2C8\uB2E4.)
79630
+ \uC5EC\uAE30\uC5D0 \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\xB7\uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C \uD30C\uC77C\uC744 \uB123\uACE0 "\uB2E4 \uB123\uC5C8\uC5B4"\uB77C\uACE0 \uC54C\uB824\uC8FC\uC138\uC694. (hwp\xB7hwpx\xB7docx\xB7pdf\uB294 \uC790\uB3D9\uC73C\uB85C \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD558\uACE0, \uD14D\uC2A4\uD2B8 \uB808\uC774\uC5B4\uAC00 \uC5C6\uB294 \uC774\uBBF8\uC9C0\xB7\uC2A4\uCE94 PDF\uB9CC \uC81C\uAC00 \uC9C1\uC811 \uC77D\uC2B5\uB2C8\uB2E4.)
79191
79631
 
79192
79632
  \uD604\uC7AC \uD30C\uC77C:
79193
79633
  ${list}`,
@@ -79198,7 +79638,7 @@ ${list}`,
79198
79638
  {
79199
79639
  name: "read_inbox",
79200
79640
  title: "\uC778\uC785 \uD3F4\uB354 \uD30C\uC77C \uC77D\uAE30",
79201
- description: '\uC778\uC785 \uD3F4\uB354(~/.careermate/inbox)\uC5D0 \uC0AC\uC6A9\uC790\uAC00 \uB123\uC5B4 \uB454 \uBB38\uC11C\uB4E4\uC758 \uBCF8\uBB38\uC744 \uD55C \uBC88\uC5D0 \uC77D\uC5B4 \uB3CC\uB824\uC90D\uB2C8\uB2E4. open_inbox\uB85C \uD3F4\uB354\uB97C \uC548\uB0B4\uD55C \uB4A4 \uC0AC\uC6A9\uC790\uAC00 "\uB2E4 \uB123\uC5C8\uC5B4"\uB77C\uACE0 \uD558\uBA74 \uD638\uCD9C\uD558\uC138\uC694. docx/hwp/hwpx/\uD14D\uC2A4\uD2B8\uB294 \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD558\uACE0, pdf\xB7\uC774\uBBF8\uC9C0\uB294 \uCD94\uCD9C\uD558\uC9C0 \uC54A\uACE0 \uD30C\uC77C \uACBD\uB85C\uB97C \uB3CC\uB824\uC8FC\uB2C8 AI \uD074\uB77C\uC774\uC5B8\uD2B8\uC758 \uD30C\uC77C \uC77D\uAE30 \uAE30\uB2A5\uC73C\uB85C \uADF8 \uACBD\uB85C\uB97C \uC9C1\uC811 \uC5F4\uC5B4 \uC77D\uC73C\uC138\uC694. \uC77D\uC740 \uB0B4\uC6A9\uC744 \uAD6C\uC870\uD654\uD574 save_profile\xB7add_resume \uB4F1 \uC54C\uB9DE\uC740 \uB3C4\uAD6C\uB85C \uC800\uC7A5\uD558\uC138\uC694(\uD30C\uC77C \uB0B4\uC6A9\uC744 \uC0C8 \uD30C\uC77C\uB85C \uB2E4\uC2DC \uC4F0\uC9C0 \uB9C8\uC138\uC694). filename\uC744 \uC8FC\uBA74 \uD574\uB2F9 \uD30C\uC77C\uB9CC \uC77D\uC2B5\uB2C8\uB2E4.',
79641
+ description: '\uC778\uC785 \uD3F4\uB354(~/.careermate/inbox)\uC5D0 \uC0AC\uC6A9\uC790\uAC00 \uB123\uC5B4 \uB454 \uBB38\uC11C\uB4E4\uC758 \uBCF8\uBB38\uC744 \uD55C \uBC88\uC5D0 \uC77D\uC5B4 \uB3CC\uB824\uC90D\uB2C8\uB2E4. open_inbox\uB85C \uD3F4\uB354\uB97C \uC548\uB0B4\uD55C \uB4A4 \uC0AC\uC6A9\uC790\uAC00 "\uB2E4 \uB123\uC5C8\uC5B4"\uB77C\uACE0 \uD558\uBA74 \uD638\uCD9C\uD558\uC138\uC694. docx\xB7hwp\xB7hwpx\xB7pdf\xB7\uD14D\uC2A4\uD2B8(.txt/.md)\uC5D0\uC11C \uBCF8\uBB38 \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD574 \uB3CC\uB824\uC90D\uB2C8\uB2E4(read_document\uC640 \uB3D9\uC77C\uD55C \uCD94\uCD9C \uC2A4\uD0DD). \uB2E8 \uD14D\uC2A4\uD2B8 \uB808\uC774\uC5B4\uAC00 \uC5C6\uB294 \uC774\uBBF8\uC9C0\xB7\uC2A4\uCE94 PDF\uB294 \uCD94\uCD9C\uB418\uC9C0 \uC54A\uC544(unsupported=true) \uD30C\uC77C \uACBD\uB85C\uB9CC \uB3CC\uB824\uC8FC\uB2C8, \uADF8 \uACBD\uB85C\uB294 AI \uD074\uB77C\uC774\uC5B8\uD2B8\uC758 \uD30C\uC77C \uC77D\uAE30 \uAE30\uB2A5\uC73C\uB85C \uC9C1\uC811 \uC5F4\uC5B4 \uC77D\uC73C\uC138\uC694. \uC77D\uC740 \uB0B4\uC6A9\uC744 \uAD6C\uC870\uD654\uD574 \uD504\uB85C\uD544\uC740 save_profile, \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\uB294 add_resume, \uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C\uB294 save_cover_letter_version\uC73C\uB85C \uC800\uC7A5\uD558\uC138\uC694(\uD30C\uC77C \uB0B4\uC6A9\uC744 \uC0C8 \uD30C\uC77C\uB85C \uB2E4\uC2DC \uC4F0\uC9C0 \uB9C8\uC138\uC694). filename\uC744 \uC8FC\uBA74 \uD574\uB2F9 \uD30C\uC77C\uB9CC \uC77D\uC2B5\uB2C8\uB2E4.',
79202
79642
  inputSchema: {
79203
79643
  filename: external_exports.string().optional().describe("\uD2B9\uC815 \uD30C\uC77C\uB9CC \uC77D\uC744 \uB54C \uD30C\uC77C\uBA85(\uB300\uC18C\uBB38\uC790 \uBB34\uC2DC). \uC0DD\uB7B5\uD558\uBA74 \uD3F4\uB354 \uC548 \uBAA8\uB4E0 \uD30C\uC77C\uC744 \uC77D\uC2B5\uB2C8\uB2E4."),
79204
79644
  max_chars: external_exports.number().optional().describe("\uD30C\uC77C\uBCC4 \uBC18\uD658 \uD14D\uC2A4\uD2B8 \uCD5C\uB300 \uAE38\uC774(\uCD08\uACFC \uC2DC \uC798\uB77C\uB0C4). \uAE30\uBCF8 20000\uC790")
@@ -79239,7 +79679,7 @@ ${dir}
79239
79679
  `\uC778\uC785 \uD3F4\uB354 \uD30C\uC77C ${files.length}\uAC74\uC744 \uC77D\uC5C8\uC2B5\uB2C8\uB2E4:
79240
79680
  ${summary}
79241
79681
 
79242
- \uCD94\uCD9C\uB41C \uB0B4\uC6A9\uC744 \uAD6C\uC870\uD654\uD574 save_profile\xB7add_resume \uB4F1\uC73C\uB85C \uC800\uC7A5\uD558\uC138\uC694.`,
79682
+ \uCD94\uCD9C\uB41C \uB0B4\uC6A9\uC744 \uAD6C\uC870\uD654\uD574 \uD504\uB85C\uD544\uC740 save_profile, \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\uB294 add_resume, \uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C\uB294 save_cover_letter_version\uC73C\uB85C \uC800\uC7A5\uD558\uC138\uC694.`,
79243
79683
  { dir, files }
79244
79684
  );
79245
79685
  }
@@ -79307,7 +79747,7 @@ ${lines}`;
79307
79747
  {
79308
79748
  name: "add_resume",
79309
79749
  title: "\uC774\uB825\uC11C/\uACBD\uB825\uAE30\uC220\uC11C \uCD94\uAC00",
79310
- description: "\uC774\uB825\uC11C, \uACBD\uB825\uAE30\uC220\uC11C, \uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uB4F1 \uBB38\uC11C\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. content\uC5D0\uB294 \uC0AC\uC6A9\uC790\uAC00 \uC5C5\uB85C\uB4DC/\uBD99\uC5EC\uB123\uC740 \uD14D\uC2A4\uD2B8(\uB610\uB294 \uC815\uB9AC\uD55C Markdown)\uB97C \uB123\uC73C\uC138\uC694. kind \uAE30\uBCF8\uAC12\uC740 resume\uC785\uB2C8\uB2E4. is_primary=true\uB85C \uB300\uD45C \uBB38\uC11C\uB97C \uC9C0\uC815\uD558\uBA74 get_application_context\uC758 primary_resume\uB85C \uB178\uCD9C\uB429\uB2C8\uB2E4.",
79750
+ description: "\uC774\uB825\uC11C, \uACBD\uB825\uAE30\uC220\uC11C, \uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uB4F1 \uBB38\uC11C\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. content\uC5D0\uB294 \uC0AC\uC6A9\uC790\uAC00 \uC5C5\uB85C\uB4DC/\uBD99\uC5EC\uB123\uC740 \uD14D\uC2A4\uD2B8 \uB610\uB294 AI\uAC00 \uC804\uBB38\uAC00 \uC808\uCC28\uB85C \uC815\uB9AC\uD55C Markdown\uC744 \uB123\uC73C\uC138\uC694. \uACBD\uB825\uAE30\uC220\uC11C\uB97C \uC791\uC131\uD574 \uC800\uC7A5\uD560 \uB54C\uB294 kind=career_description, source=ai\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4. \u26A0\uFE0F content\uC5D0\uB294 \uC774 \uBB38\uC11C \uD55C \uC885\uB958\uC758 \uBCF8\uBB38\uB9CC \uB123\uACE0, \uC790\uAE30\uC18C\uAC1C\uC11C \uB4F1 \uB2E4\uB978 \uC885\uB958 \uBB38\uC11C\uB97C \uAC19\uC740 content\uC5D0 \uC774\uC5B4\uBD99\uC774\uC9C0 \uB9C8\uC138\uC694 \u2014 \uC790\uAE30\uC18C\uAC1C\uC11C\uB294 save_cover_letter_version\uC73C\uB85C \uB530\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4(\uD55C \uBC88\uC5D0 \uB458 \uB2E4 \uC694\uCCAD\uBC1B\uC558\uC5B4\uB3C4 \uD55C \uC800\uC7A5 \uD638\uCD9C\uC5D0 \uB450 \uBB38\uC11C\uB97C \uD569\uCE58\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4). kind \uAE30\uBCF8\uAC12\uC740 resume\uC785\uB2C8\uB2E4. is_primary=true\uB85C \uB300\uD45C \uBB38\uC11C\uB97C \uC9C0\uC815\uD558\uBA74 get_application_context\uC758 primary_resume\uB85C \uB178\uCD9C\uB429\uB2C8\uB2E4.",
79311
79751
  // Reuse the shared (length-bounded, whitespace-rejecting) Document schema so
79312
79752
  // the MCP ingestion path — the primary route for résumé text — inherits the
79313
79753
  // same caps as the web API. kind stays optional here (defaults to resume).
@@ -79331,6 +79771,23 @@ ${lines}`;
79331
79771
  return ok(`\uBB38\uC11C ${docs.length}\uAC74`, docs);
79332
79772
  }
79333
79773
  },
79774
+ {
79775
+ name: "delete_resume",
79776
+ title: "\uC774\uB825\uC11C/\uBB38\uC11C \uC0AD\uC81C",
79777
+ description: "\uC800\uC7A5\uB41C \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624 \uB4F1 \uBB38\uC11C\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uBA85\uD655\uD788 \uC0AD\uC81C\uB97C \uC694\uCCAD\uD588\uC744 \uB54C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694. \uBA3C\uC800 get_resumes\uB85C \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uACE0 \uC5B4\uB5A4 \uBB38\uC11C\uC778\uC9C0 \uC0AC\uC6A9\uC790\uC640 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD569\uB2C8\uB2E4. confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
79778
+ inputSchema: {
79779
+ document_id: external_exports.string(),
79780
+ confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
79781
+ },
79782
+ handler: (args) => {
79783
+ if (args?.confirm !== DELETE_CONFIRMATION) return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
79784
+ const doc = documentRepo.get(args.document_id);
79785
+ if (!doc) return fail("\uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
79786
+ if (!documentRepo.remove(doc.id)) return fail("\uBB38\uC11C\uB97C \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
79787
+ const user_message = `'${doc.title}' \uBB38\uC11C\uB97C \uC0AD\uC81C\uD588\uC5B4\uC694.`;
79788
+ return ok(user_message, { deleted: true, document_id: doc.id, user_message });
79789
+ }
79790
+ },
79334
79791
  /* ----------------------------------------------------------- experiences */
79335
79792
  {
79336
79793
  name: "add_experience",
@@ -79400,6 +79857,57 @@ ${lines}`;
79400
79857
  return ok(`\uAE30\uC220 ${list.length}\uAC74`, list);
79401
79858
  }
79402
79859
  },
79860
+ {
79861
+ name: "delete_experience",
79862
+ title: "\uACBD\uB825 \uD56D\uBAA9 \uC0AD\uC81C",
79863
+ description: "\uAD6C\uC870\uD654\uB41C \uACBD\uB825(\uC9C1\uC7A5) \uD56D\uBAA9 \uD558\uB098\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uC798\uBABB \uCD94\uCD9C/\uC785\uB825\uB41C \uACBD\uB825\uC744 \uC9C0\uC6B8 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. \uBA3C\uC800 get_experiences\uB85C \uBAA9\uB85D\uACFC id\uB97C \uD655\uC778\uD558\uACE0 \uC0AC\uC6A9\uC790\uC640 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD569\uB2C8\uB2E4. (\uB0B4\uC6A9 \uC218\uC815\uC740 add_experience\uB85C \uAC19\uC740 \uD56D\uBAA9\uC744 \uB2E4\uC2DC \uC800\uC7A5\uD558\uBA74 \uAC31\uC2E0\uB429\uB2C8\uB2E4.) confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
79864
+ inputSchema: {
79865
+ experience_id: external_exports.string(),
79866
+ confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
79867
+ },
79868
+ handler: (args) => {
79869
+ if (args?.confirm !== DELETE_CONFIRMATION) return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
79870
+ const exp = experienceRepo.get(args.experience_id);
79871
+ if (!exp) return fail("\uD574\uB2F9 \uACBD\uB825 \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
79872
+ if (!experienceRepo.remove(exp.id)) return fail("\uACBD\uB825 \uD56D\uBAA9\uC744 \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
79873
+ const user_message = `'${exp.company}' \uACBD\uB825\uC744 \uC0AD\uC81C\uD588\uC5B4\uC694.`;
79874
+ return ok(user_message, { deleted: true, experience_id: exp.id, user_message });
79875
+ }
79876
+ },
79877
+ {
79878
+ name: "delete_project",
79879
+ title: "\uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9 \uC0AD\uC81C",
79880
+ description: "\uAD6C\uC870\uD654\uB41C \uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9 \uD558\uB098\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uC798\uBABB \uCD94\uCD9C/\uC785\uB825\uB41C \uD504\uB85C\uC81D\uD2B8\uB97C \uC9C0\uC6B8 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. \uBA3C\uC800 get_projects\uB85C \uBAA9\uB85D\uACFC id\uB97C \uD655\uC778\uD558\uACE0 \uC0AC\uC6A9\uC790\uC640 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD569\uB2C8\uB2E4. (\uB0B4\uC6A9 \uC218\uC815\uC740 add_project\uB85C \uAC19\uC740 \uD56D\uBAA9\uC744 \uB2E4\uC2DC \uC800\uC7A5\uD558\uBA74 \uAC31\uC2E0\uB429\uB2C8\uB2E4.) confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
79881
+ inputSchema: {
79882
+ project_id: external_exports.string(),
79883
+ confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
79884
+ },
79885
+ handler: (args) => {
79886
+ if (args?.confirm !== DELETE_CONFIRMATION) return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
79887
+ const proj = projectRepo.get(args.project_id);
79888
+ if (!proj) return fail("\uD574\uB2F9 \uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
79889
+ if (!projectRepo.remove(proj.id)) return fail("\uD504\uB85C\uC81D\uD2B8 \uD56D\uBAA9\uC744 \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
79890
+ const user_message = `'${proj.name}' \uD504\uB85C\uC81D\uD2B8\uB97C \uC0AD\uC81C\uD588\uC5B4\uC694.`;
79891
+ return ok(user_message, { deleted: true, project_id: proj.id, user_message });
79892
+ }
79893
+ },
79894
+ {
79895
+ name: "delete_skill",
79896
+ title: "\uAE30\uC220\uC2A4\uD0DD \uD56D\uBAA9 \uC0AD\uC81C",
79897
+ description: "\uAD6C\uC870\uD654\uB41C \uAE30\uC220\uC2A4\uD0DD \uD56D\uBAA9 \uD558\uB098\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uC798\uBABB \uCD94\uCD9C/\uC785\uB825\uB41C \uAE30\uC220\uC744 \uC9C0\uC6B8 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. \uBA3C\uC800 get_skills\uB85C \uBAA9\uB85D\uACFC id\uB97C \uD655\uC778\uD558\uACE0 \uC0AC\uC6A9\uC790\uC640 \uD655\uC778\uD55C \uB4A4 \uD638\uCD9C\uD569\uB2C8\uB2E4. (\uB0B4\uC6A9 \uC218\uC815\uC740 add_skill\uB85C \uAC19\uC740 \uD56D\uBAA9\uC744 \uB2E4\uC2DC \uC800\uC7A5\uD558\uBA74 \uAC31\uC2E0\uB429\uB2C8\uB2E4.) confirm\uC5D0\uB294 DELETE\uB97C \uB123\uC73C\uC138\uC694.",
79898
+ inputSchema: {
79899
+ skill_id: external_exports.string(),
79900
+ confirm: external_exports.string().describe("\uC0AD\uC81C \uD655\uC778\uAC12. \uC815\uD655\uD788 DELETE\uB97C \uB123\uC5B4\uC57C \uC0AD\uC81C\uB429\uB2C8\uB2E4.")
79901
+ },
79902
+ handler: (args) => {
79903
+ if (args?.confirm !== DELETE_CONFIRMATION) return fail("\uC0AD\uC81C\uD558\uB824\uBA74 confirm\uC5D0 DELETE\uB97C \uB123\uC5B4 \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.");
79904
+ const skill = skillRepo.get(args.skill_id);
79905
+ if (!skill) return fail("\uD574\uB2F9 \uAE30\uC220 \uD56D\uBAA9\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
79906
+ if (!skillRepo.remove(skill.id)) return fail("\uAE30\uC220 \uD56D\uBAA9\uC744 \uC0AD\uC81C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
79907
+ const user_message = `'${skill.name}' \uAE30\uC220\uC744 \uC0AD\uC81C\uD588\uC5B4\uC694.`;
79908
+ return ok(user_message, { deleted: true, skill_id: skill.id, user_message });
79909
+ }
79910
+ },
79403
79911
  /* ---------------------------------------------------------- cover letters */
79404
79912
  {
79405
79913
  name: "get_cover_letters",
@@ -79415,7 +79923,7 @@ ${lines}`;
79415
79923
  {
79416
79924
  name: "save_cover_letter_version",
79417
79925
  title: "\uC790\uAE30\uC18C\uAC1C\uC11C \uBC84\uC804 \uC800\uC7A5",
79418
- 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.',
79926
+ 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. \u26A0\uFE0F content\uC5D0\uB294 \uC790\uAE30\uC18C\uAC1C\uC11C \uBCF8\uBB38\uB9CC \uB123\uACE0, \uACBD\uB825\uAE30\uC220\uC11C \uB4F1 \uB2E4\uB978 \uC885\uB958 \uBB38\uC11C\uB97C \uC774\uC5B4\uBD99\uC774\uC9C0 \uB9C8\uC138\uC694(\uACBD\uB825\uAE30\uC220\uC11C\uB294 add_resume(kind=career_description)\uB85C \uB530\uB85C \uC800\uC7A5). 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.',
79419
79927
  inputSchema: CoverLetterVersionInputSchema.shape,
79420
79928
  handler: (args) => {
79421
79929
  try {
@@ -79478,7 +79986,7 @@ ${lines}`;
79478
79986
  {
79479
79987
  name: "get_job_posting",
79480
79988
  title: "\uCC44\uC6A9\uACF5\uACE0 \uC0C1\uC138 \uC870\uD68C",
79481
- description: "\uACF5\uACE0 1\uAC74\uC758 \uC0C1\uC138\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. \uACF5\uACE0 \uC815\uBCF4\uC640 \uD568\uAED8 \uC801\uD569\uB3C4 \uBD84\uC11D, \uC9C0\uC6D0 \uC0C1\uD0DC, \uC5F0\uACB0\uB41C \uC790\uAE30\uC18C\uAC1C\uC11C, \uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uD55C \uBC88\uC5D0 \uB3CC\uB824\uC90D\uB2C8\uB2E4.",
79989
+ description: "\uACF5\uACE0 1\uAC74\uC758 \uC0C1\uC138\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. \uACF5\uACE0 \uC815\uBCF4\uC640 \uD568\uAED8 \uC801\uD569\uB3C4 \uBD84\uC11D, \uC9C0\uC6D0 \uC0C1\uD0DC, \uC790\uAE30\uC18C\uAC1C\uC11C, \uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uD55C \uBC88\uC5D0 \uB3CC\uB824\uC90D\uB2C8\uB2E4.",
79482
79990
  inputSchema: { job_id: external_exports.string() },
79483
79991
  readOnly: true,
79484
79992
  handler: (args) => {
@@ -79544,13 +80052,42 @@ ${lines}`;
79544
80052
  const ctx = getApplicationContext({ job_id: args?.job_id });
79545
80053
  const recommended_route = pickRoute(ctx);
79546
80054
  const route = recommended_route ? getRoute(recommended_route) : void 0;
80055
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
80056
+ const ym = (s) => {
80057
+ const m = s ? /^(\d{4})-(\d{2})/.exec(s) : null;
80058
+ return m ? Number(m[1]) * 12 + Number(m[2]) : null;
80059
+ };
80060
+ const monthsBetween = (a, b) => {
80061
+ const x2 = ym(a), y = ym(b);
80062
+ return x2 != null && y != null ? y - x2 : null;
80063
+ };
80064
+ const tenure = ctx.experiences.map((e) => {
80065
+ if (!e.start_date) return null;
80066
+ const asOf = e.is_current ? e.updated_at ?? today : e.end_date;
80067
+ const months = monthsBetween(e.start_date, asOf);
80068
+ if (months == null || months < 0) return null;
80069
+ return {
80070
+ company: e.company,
80071
+ is_current: e.is_current,
80072
+ start_date: e.start_date,
80073
+ as_of: (asOf ?? "").slice(0, 7),
80074
+ // 재직중=updated_at(정보 확인 시점) / 종료=end_date
80075
+ months,
80076
+ years: Math.round(months / 12 * 10) / 10,
80077
+ // 음수 방지(미래 updated_at·시계 오차) — 0 미만은 0으로 클램프
80078
+ data_age_months: e.is_current ? Math.max(0, monthsBetween(e.updated_at, today) ?? 0) : null
80079
+ };
80080
+ }).filter((t) => t != null);
79547
80081
  const enriched = {
79548
80082
  ...ctx,
80083
+ today,
80084
+ tenure,
79549
80085
  recommended_route,
79550
80086
  verifier_sequence: route?.verifierSequence ?? [],
79551
80087
  next_tool: recommended_route ? "get_workflow_guide" : null
79552
80088
  };
79553
80089
  const summary = [
80090
+ `\uC624\uB298 \uB0A0\uC9DC: ${today}. \uACBD\uB825 \uC5F0\uCC28\xB7\uC7AC\uC9C1\uAE30\uAC04\uC740 \uC9C1\uC811 \uACC4\uC0B0\uD558\uC9C0 \uB9D0\uACE0 \uC81C\uACF5\uB41C tenure[](\uC11C\uBC84 \uACC4\uC0B0: \uC7AC\uC9C1\uC911=\uC815\uBCF4\uD655\uC778\uC77C \uAE30\uC900 \uC5F0\uCC28, data_age_months \uD06C\uBA74 \uD604\uC7AC \uC7AC\uC9C1 \uD655\uC778 \uD544\uC694)\uB97C \uADF8\uB300\uB85C \uC4F0\uC138\uC694.`,
79554
80091
  `\uD504\uB85C\uD544: ${ctx.profile?.name ?? "\uBBF8\uC785\uB825"}`,
79555
80092
  `\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}`,
79556
80093
  ctx.job ? `\uB300\uC0C1 \uACF5\uACE0: ${ctx.job.company} \xB7 ${ctx.job.position}` : "\uB300\uC0C1 \uACF5\uACE0 \uC5C6\uC74C",
@@ -79569,7 +80106,7 @@ ${lines}`;
79569
80106
  try {
79570
80107
  const fit = saveFitAnalysis(args);
79571
80108
  const suggested_next_action = {
79572
- prompt: "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694?",
80109
+ prompt: "\uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uB4DC\uB9B4\uAE4C\uC694? (\uD68C\uC0AC \uC9C0\uC815 \uBB38\uD56D\xB7\uC591\uC2DD\xB7\uAE00\uC790\uC218\uAC00 \uC788\uC73C\uBA74 \uD568\uAED8 \uC54C\uB824\uC8FC\uC2DC\uBA74 \uADF8\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD569\uB2C8\uB2E4)",
79573
80110
  options: [
79574
80111
  {
79575
80112
  label: "\uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
@@ -79588,7 +80125,8 @@ ${lines}`;
79588
80125
  "",
79589
80126
  "\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB2E4\uC74C \uC120\uD0DD\uC9C0\uB97C \uBCF4\uC5EC\uC8FC\uC138\uC694:",
79590
80127
  "1. \uB124, \uC774 \uACF5\uACE0\uC5D0 \uB9DE\uCD98 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC368\uC918",
79591
- "2. \uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918"
80128
+ "2. \uC544\uB2C8\uC694, \uBD84\uC11D\uB9CC \uC800\uC7A5\uD574\uC918",
80129
+ "(1\uBC88\uC774\uBA74, \uD68C\uC0AC \uC9C0\uC815 \uBB38\uD56D\xB7\uC591\uC2DD\xB7\uAE00\uC790\uC218\uAC00 \uC788\uC73C\uBA74 \uC54C\uB824\uB2EC\uB77C\uACE0 \uC694\uCCAD\uD558\uC138\uC694 \u2014 \uD55C\uAD6D \uC790\uC18C\uC11C\uB294 \uBB38\uD56D\uD615\uC774 \uB9CE\uC2B5\uB2C8\uB2E4. \uC5C6\uC73C\uBA74 \uC77C\uBC18 \uC591\uC2DD\uC73C\uB85C \uC9C4\uD589\uD569\uB2C8\uB2E4.)"
79592
80130
  ].join("\n"),
79593
80131
  {
79594
80132
  ...fit,
@@ -79609,11 +80147,12 @@ ${lines}`;
79609
80147
  inputSchema: {
79610
80148
  job_id: external_exports.string(),
79611
80149
  status: external_exports.enum(APPLICATION_STATUSES),
79612
- note: external_exports.string().optional()
80150
+ note: external_exports.string().optional(),
80151
+ submission: ApplicationSubmissionSchema.optional()
79613
80152
  },
79614
80153
  handler: (args) => {
79615
80154
  try {
79616
- const res = updateApplicationStatus(args.job_id, args.status, args.note);
80155
+ const res = updateApplicationStatus(args.job_id, args.status, args.note, args.submission);
79617
80156
  const user_message = `\uC9C0\uC6D0 \uC0C1\uD0DC\uB97C '${APPLICATION_STATUS_LABELS[args.status]}'(\uC73C)\uB85C \uBC14\uAFE8\uC5B4\uC694.` + (res.hint ? `
79618
80157
 
79619
80158
  ${res.hint}` : "");
@@ -79637,12 +80176,14 @@ ${res.hint}` : "");
79637
80176
  {
79638
80177
  name: "save_interview_prep",
79639
80178
  title: "\uBA74\uC811 \uC900\uBE44 \uC790\uB8CC \uC800\uC7A5",
79640
- description: "\uC608\uC0C1 \uBA74\uC811 \uC9C8\uBB38, \uAF2C\uB9AC \uC9C8\uBB38, STAR \uB2F5\uBCC0 \uAC00\uC774\uB4DC, 1\uBD84 \uC790\uAE30\uC18C\uAC1C \uCD08\uC548 \uB4F1 \uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. \uBCF4\uD1B5 \uC9C0\uC6D0 \uC0C1\uD0DC\uAC00 \uC11C\uB958 \uD569\uACA9\uC73C\uB85C \uBC14\uB010 \uB4A4, \uD574\uB2F9 \uACF5\uACE0/\uC9C1\uBB34/\uC790\uC18C\uC11C\uB97C \uADFC\uAC70\uB85C \uB2F9\uC2E0(AI)\uC774 \uC0DD\uC131\uD55C \uC790\uB8CC\uB97C \uC800\uC7A5\uD558\uB294 \uB370 \uC0AC\uC6A9\uD569\uB2C8\uB2E4. job_id\uB294 \uD544\uC218\uC785\uB2C8\uB2E4. \uAC19\uC740 \uACF5\uACE0\uC5D0 \uB2E4\uC2DC \uC800\uC7A5\uD558\uBA74 \uAC31\uC2E0\uB429\uB2C8\uB2E4.",
80179
+ description: "\uC608\uC0C1 \uBA74\uC811 \uC9C8\uBB38, \uAF2C\uB9AC \uC9C8\uBB38, STAR \uB2F5\uBCC0 \uAC00\uC774\uB4DC, 1\uBD84 \uC790\uAE30\uC18C\uAC1C \uCD08\uC548 \uB4F1 \uD574\uB2F9 \uACF5\uACE0 \uAE30\uC900 \uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. \uACF5\uACE0/\uC9C1\uBB34/\uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uADFC\uAC70\uB85C \uB2F9\uC2E0(AI)\uC774 \uC0DD\uC131\uD55C \uC790\uB8CC\uB97C \uC800\uC7A5\uD558\uB294 \uB370 \uC0AC\uC6A9\uD569\uB2C8\uB2E4. \uC9C8\uBB38\uC740 \uB450 \uAC08\uB798\uB85C \uC900\uBE44\uD558\uC138\uC694 \u2014 \uAC01 \uC9C8\uBB38\uC758 category\uB97C 'technical'(\uAE30\uC220\xB7\uC9C1\uBB34 1\uCC28 \uBA74\uC811) \uB610\uB294 'behavioral'(\uC778\uC131\xB7\uCEEC\uCC98\uD54F\xB7\uC784\uC6D0 2\uCC28 \uBA74\uC811, \uC790\uAE30\uC18C\uAC1C\uC11C\xB7\uD504\uB85C\uD544 \uAE30\uBC18)\uB85C \uC9C0\uC815\uD569\uB2C8\uB2E4. \uAC00\uB2A5\uD558\uBA74 \uB450 \uAC08\uB798 \uBAA8\uB450 \uCC44\uC6CC \uD55C \uBC88\uC5D0 \uC800\uC7A5\uD558\uC138\uC694(\uB300\uC2DC\uBCF4\uB4DC\uAC00 \uAE30\uC220/\uC778\uC131\xB7\uCEEC\uCC98\uD54F \uD0ED\uC73C\uB85C \uB098\uB220 \uBCF4\uC5EC\uC90D\uB2C8\uB2E4). job_id\uB294 \uD544\uC218\uC785\uB2C8\uB2E4. \uAC19\uC740 \uACF5\uACE0\uC5D0 \uB2E4\uC2DC \uC800\uC7A5\uD558\uBA74 \uAC31\uC2E0\uB429\uB2C8\uB2E4.",
79641
80180
  inputSchema: InterviewPrepInputSchema.shape,
79642
80181
  handler: (args) => {
79643
80182
  try {
79644
80183
  const prep = saveInterviewPrep(args);
79645
- const user_message = `\uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD588\uC5B4\uC694. \uC608\uC0C1 \uC9C8\uBB38 ${prep.questions.length}\uAC1C\uAC00 \uC900\uBE44\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.`;
80184
+ const tech = prep.questions.filter((q) => (q.category ?? "technical") === "technical").length;
80185
+ const behavioral = prep.questions.filter((q) => q.category === "behavioral").length;
80186
+ const user_message = `\uBA74\uC811 \uC900\uBE44 \uC790\uB8CC\uB97C \uC800\uC7A5\uD588\uC5B4\uC694. \uC608\uC0C1 \uC9C8\uBB38 ${prep.questions.length}\uAC1C` + (behavioral > 0 ? ` (\uAE30\uC220 ${tech}\uAC1C \xB7 \uC778\uC131\xB7\uCEEC\uCC98\uD54F ${behavioral}\uAC1C)` : "") + "\uAC00 \uC900\uBE44\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.";
79646
80187
  return ok(user_message, { ...prep, user_message });
79647
80188
  } catch (e) {
79648
80189
  return fail(e instanceof Error ? e.message : "\uC800\uC7A5 \uC2E4\uD328");
@@ -79673,6 +80214,65 @@ ${res.hint}` : "");
79673
80214
  return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
79674
80215
  }
79675
80216
  return ok(`'${cl.title}'\uB97C ${format.toUpperCase()}\uB85C \uB0B4\uBCF4\uB0C8\uC2B5\uB2C8\uB2E4.
80217
+ \uC800\uC7A5 \uC704\uCE58: ${filePath}`, {
80218
+ path: filePath,
80219
+ filename: result2.filename,
80220
+ content: result2.content
80221
+ });
80222
+ }
80223
+ },
80224
+ {
80225
+ name: "export_resume",
80226
+ title: "\uC774\uB825\uC11C/\uACBD\uB825\uAE30\uC220\uC11C \uB0B4\uBCF4\uB0B4\uAE30",
80227
+ description: '\uC800\uC7A5\uB41C \uC774\uB825\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C \uB4F1 \uBB38\uC11C\uB97C Markdown \uB610\uB294 \uC778\uC1C4\uC6A9 HTML(\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C PDF\uB85C \uC800\uC7A5) \uD30C\uC77C\uB85C \uB0B4\uBCF4\uB0B4 \uB370\uC774\uD130 \uD3F4\uB354\uC758 exports\uC5D0 \uC800\uC7A5\uD558\uACE0, \uD30C\uC77C \uACBD\uB85C\uC640 \uBCF8\uBB38\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 \uACF5\uACE0\uC5D0 \uB9DE\uCDB0 \uC815\uB9AC\uD55C \uC774\uB825\uC11C\uB97C \uBA3C\uC800 add_resume\uB85C \uC800\uC7A5\uD55C \uB4A4, "\uC774\uB825\uC11C \uD30C\uC77C\uB85C \uBC1B\uACE0 \uC2F6\uC5B4"\uB77C\uACE0 \uD560 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. document_id\uB294 get_resumes\uB85C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uC9C1\uC811 \uB2E4\uC6B4\uB85C\uB4DC\uD560 \uC218\uB3C4 \uC788\uC2B5\uB2C8\uB2E4.',
80228
+ inputSchema: {
80229
+ document_id: external_exports.string(),
80230
+ format: external_exports.enum(["md", "html"]).optional().describe("\uAE30\uBCF8 md")
80231
+ },
80232
+ handler: (args) => {
80233
+ const doc = documentRepo.get(args.document_id);
80234
+ if (!doc) return fail("\uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
80235
+ const profile = profileRepo.get();
80236
+ const format = args.format ?? "md";
80237
+ const result2 = format === "html" ? resumeToHtml(doc, profile) : resumeToMarkdown(doc, profile);
80238
+ const dir = getExportsDir();
80239
+ const filePath = path7.join(dir, result2.filename);
80240
+ try {
80241
+ fs7.writeFileSync(filePath, result2.content, "utf8");
80242
+ } catch (e) {
80243
+ return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
80244
+ }
80245
+ return ok(`'${doc.title}'\uB97C ${format.toUpperCase()}\uB85C \uB0B4\uBCF4\uB0C8\uC2B5\uB2C8\uB2E4.
80246
+ \uC800\uC7A5 \uC704\uCE58: ${filePath}`, {
80247
+ path: filePath,
80248
+ filename: result2.filename,
80249
+ content: result2.content
80250
+ });
80251
+ }
80252
+ },
80253
+ {
80254
+ name: "export_profile",
80255
+ title: "\uD504\uB85C\uD544\uC744 \uC774\uB825\uC11C\uB85C \uB0B4\uBCF4\uB0B4\uAE30",
80256
+ description: '\uC800\uC7A5\uB41C \uD504\uB85C\uD544\xB7\uACBD\uB825\xB7\uD504\uB85C\uC81D\uD2B8\xB7\uBCF4\uC720 \uAE30\uC220\uC744 \uD55C \uC7A5\uC758 \uC774\uB825\uC11C \uD615\uC2DD\uC73C\uB85C \uBAA8\uC544 Markdown \uB610\uB294 \uC778\uC1C4\uC6A9 HTML(\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C PDF\uB85C \uC800\uC7A5) \uD30C\uC77C\uB85C \uB0B4\uBCF4\uB0B4 \uB370\uC774\uD130 \uD3F4\uB354\uC758 exports\uC5D0 \uC800\uC7A5\uD558\uACE0, \uD30C\uC77C \uACBD\uB85C\uC640 \uBCF8\uBB38\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 "\uB0B4 \uD504\uB85C\uD544\uC744 \uC774\uB825\uC11C\uB85C \uBF51\uC544\uC918"\uCC98\uB7FC \uAD6C\uC870\uD654\uB41C \uB370\uC774\uD130 \uC804\uCCB4\uB97C \uC774\uB825\uC11C\uB85C \uBC1B\uACE0 \uC2F6\uC744 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. \uD2B9\uC815 \uACF5\uACE0 \uB9DE\uCDA4 \uC774\uB825\uC11C\uB294 add_resume\uB85C \uC815\uB9AC\xB7\uC800\uC7A5\uD55C \uB4A4 export_resume\uB97C \uC4F0\uC138\uC694. \uB300\uC2DC\uBCF4\uB4DC\uC5D0\uC11C \uC9C1\uC811 \uB2E4\uC6B4\uB85C\uB4DC\uD560 \uC218\uB3C4 \uC788\uC2B5\uB2C8\uB2E4.',
80257
+ inputSchema: {
80258
+ format: external_exports.enum(["md", "html"]).optional().describe("\uAE30\uBCF8 md")
80259
+ },
80260
+ handler: (args) => {
80261
+ const profile = profileRepo.get();
80262
+ if (!profile) return fail("\uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \uD504\uB85C\uD544\uC744 \uC800\uC7A5\uD558\uC138\uC694.");
80263
+ const format = args.format ?? "md";
80264
+ const experiences = experienceRepo.list();
80265
+ const projects = projectRepo.list();
80266
+ const skills = skillRepo.list();
80267
+ const result2 = format === "html" ? profileToHtml(profile, experiences, projects, skills) : profileToMarkdown(profile, experiences, projects, skills);
80268
+ const dir = getExportsDir();
80269
+ const filePath = path7.join(dir, result2.filename);
80270
+ try {
80271
+ fs7.writeFileSync(filePath, result2.content, "utf8");
80272
+ } catch (e) {
80273
+ return fail(`\uD30C\uC77C \uC800\uC7A5 \uC2E4\uD328: ${e instanceof Error ? e.message : e}`);
80274
+ }
80275
+ return ok(`\uD504\uB85C\uD544\uC744 \uC774\uB825\uC11C(${format.toUpperCase()})\uB85C \uB0B4\uBCF4\uB0C8\uC2B5\uB2C8\uB2E4.
79676
80276
  \uC800\uC7A5 \uC704\uCE58: ${filePath}`, {
79677
80277
  path: filePath,
79678
80278
  filename: result2.filename,
@@ -79724,9 +80324,17 @@ ${res.hint}` : "");
79724
80324
  {
79725
80325
  name: "get_workflow_guide",
79726
80326
  title: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAC00\uC774\uB4DC",
79727
- description: '\uCEE4\uB9AC\uC5B4 \uC791\uC5C5(\uACF5\uACE0 \uBD84\uC11D\xB7\uC790\uC18C\uC11C\xB7\uBA74\uC811 \uC900\uBE44 \uB4F1)\uC744 \uC2DC\uC791\uD558\uAE30 \uC9C1\uC804\uC5D0 \uD638\uCD9C\uD558\uC138\uC694. \uD45C\uC900 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uB2E8\uACC4\uBCC4 \uC548\uB0B4\uC5D0 \uB354\uD574, \uADF8 \uC791\uC5C5\uC758 "\uC804\uBB38\uAC00 \uC2E4\uD589 \uC808\uCC28(EOP)"\uC640 \uC801\uC6A9\uD560 \uC804\uBB38\uAC00 \uD50C\uB808\uC774\uBD81\xB7\uC800\uC7A5 \uC804 \uAC80\uC99D\uAE30 \uC21C\uC11C\uB97C \uD55C \uBC88\uC5D0 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC548\uB0B4\uB41C \uB300\uB85C get_playbook\uC73C\uB85C \uB3C4\uBA54\uC778 \uC9C0\uC2DD\uC744, \uC800\uC7A5 \uC9C1\uC804 get_verifier\uB85C \uAC80\uC99D \uB8E8\uBE0C\uB9AD\uC744 \uBC1B\uC544 \uC801\uC6A9\uD558\uC138\uC694. workflow_id\uB97C \uC0DD\uB7B5\uD558\uBA74 \uC804\uCCB4 \uBAA9\uB85D\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4.',
80327
+ description: '\uCEE4\uB9AC\uC5B4 \uC791\uC5C5(\uACF5\uACE0 \uBD84\uC11D\xB7\uC790\uC18C\uC11C\xB7\uACBD\uB825\uAE30\uC220\uC11C\xB7\uBA74\uC811 \uC900\uBE44 \uB4F1)\uC744 \uC2DC\uC791\uD558\uAE30 \uC9C1\uC804\uC5D0 \uD638\uCD9C\uD558\uC138\uC694. \uD45C\uC900 \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC758 \uB2E8\uACC4\uBCC4 \uC548\uB0B4\uC5D0 \uB354\uD574, \uADF8 \uC791\uC5C5\uC758 "\uC804\uBB38\uAC00 \uC2E4\uD589 \uC808\uCC28(EOP)"\uC640 \uC801\uC6A9\uD560 \uC804\uBB38\uAC00 \uD50C\uB808\uC774\uBD81\xB7\uC800\uC7A5 \uC804 \uAC80\uC99D\uAE30 \uC21C\uC11C\uB97C \uD55C \uBC88\uC5D0 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC548\uB0B4\uB41C \uB300\uB85C get_playbook\uC73C\uB85C \uB3C4\uBA54\uC778 \uC9C0\uC2DD\uC744, \uC800\uC7A5 \uC9C1\uC804 get_verifier\uB85C \uAC80\uC99D \uB8E8\uBE0C\uB9AD\uC744 \uBC1B\uC544 \uC801\uC6A9\uD558\uC138\uC694. workflow_id\uB97C \uC0DD\uB7B5\uD558\uBA74 \uC804\uCCB4 \uBAA9\uB85D\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4.',
79728
80328
  inputSchema: {
79729
- workflow_id: external_exports.enum(["onboarding", "analyze_job", "write_cover_letter", "manage_application_status", "prepare_interview"]).optional()
80329
+ workflow_id: external_exports.enum([
80330
+ "onboarding",
80331
+ "analyze_job",
80332
+ "write_cover_letter",
80333
+ "write_career_description",
80334
+ "manage_application_status",
80335
+ "prepare_interview",
80336
+ "build_personal_brand"
80337
+ ]).optional()
79730
80338
  },
79731
80339
  readOnly: true,
79732
80340
  handler: (args) => {
@@ -79821,10 +80429,23 @@ ${report.disclaimer}`, report);
79821
80429
  {
79822
80430
  name: "get_writing_style_guide",
79823
80431
  title: "AI \uD2F0 \uC548 \uB098\uB294 \uAE00\uC4F0\uAE30 \uAC00\uC774\uB4DC",
79824
- description: '\uC790\uAE30\uC18C\uAC1C\uC11C\xB7\uC790\uAE30 PR\xB7\uC9C0\uC6D0 \uBA54\uC77C \uB4F1 \uC0AC\uB78C\uC774 \uC4F4 \uB4EF\uD55C \uAE00\uC744 \uC791\uC131\uD558\uAE30 \uC9C1\uC804\uC5D0 \uD638\uCD9C\uD558\uC138\uC694. "AI\uAC00 \uC4F4 \uD2F0"\uAC00 \uB098\uB294 \uD55C\uAD6D\uC5B4 \uBB38\uC7A5 \uC2B5\uAD00(\uBC88\uC5ED\uD22C, \uD074\uB9AC\uC170, \uAE30\uACC4\uC801 \uBCD1\uB82C, \uC0C1\uD22C\uC801 \uC5F0\uACB0\uC5B4, \uADE0\uC77C\uD55C \uBB38\uC7A5 \uB9AC\uB4EC \uB4F1)\uC744 \uC81C\uAC70\uD558\uB294 \uC791\uC131 \uADDC\uCE59\uACFC \uC800\uC7A5 \uC804 \uC790\uAC00 \uC810\uAC80 \uD56D\uBAA9\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC2E4\xB7\uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uB294 \uADF8\uB300\uB85C \uB450\uACE0 \uBB38\uC7A5 \uACB0\uB9CC \uB2E4\uB4EC\uB3C4\uB85D \uC548\uB0B4\uD569\uB2C8\uB2E4. write_cover_letter / analyze_job \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC5D0\uC11C \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uC4F8 \uB54C \uBC18\uB4DC\uC2DC \uD568\uAED8 \uC801\uC6A9\uD558\uC138\uC694.',
79825
- inputSchema: {},
80432
+ description: '\uC790\uAE30\uC18C\uAC1C\uC11C\xB7\uC790\uAE30 PR\xB7\uC9C0\uC6D0 \uBA54\uC77C \uB4F1 \uC0AC\uB78C\uC774 \uC4F4 \uB4EF\uD55C \uAE00\uC744 \uC791\uC131\uD558\uAE30 \uC9C1\uC804\uC5D0 \uD638\uCD9C\uD558\uC138\uC694. "AI\uAC00 \uC4F4 \uD2F0"\uAC00 \uB098\uB294 \uD55C\uAD6D\uC5B4 \uBB38\uC7A5 \uC2B5\uAD00(\uBC88\uC5ED\uD22C, \uD074\uB9AC\uC170, \uAE30\uACC4\uC801 \uBCD1\uB82C, \uC0C1\uD22C\uC801 \uC5F0\uACB0\uC5B4, \uADE0\uC77C\uD55C \uBB38\uC7A5 \uB9AC\uB4EC \uB4F1)\uC744 \uC81C\uAC70\uD558\uB294 \uC791\uC131 \uADDC\uCE59\uACFC \uC800\uC7A5 \uC804 \uC790\uAC00 \uC810\uAC80 \uD56D\uBAA9\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0AC\uC2E4\xB7\uC218\uCE58\xB7\uACE0\uC720\uBA85\uC0AC\uB294 \uADF8\uB300\uB85C \uB450\uACE0 \uBB38\uC7A5 \uACB0\uB9CC \uB2E4\uB4EC\uB3C4\uB85D \uC548\uB0B4\uD569\uB2C8\uB2E4. \uACBD\uB825\uAE30\uC220\uC11C\xB7\uC774\uB825\uC11C\xB7\uD3EC\uD2B8\uD3F4\uB9AC\uC624\uB97C \uC4F8 \uB54C\uB294 doc_type\uC744 \uD568\uAED8 \uC8FC\uBA74 \uBD88\uB9BF\xB7\uBC88\uD638 \uC131\uACFC \uAC19\uC740 \uAD6C\uC870\uB97C \uC0B0\uBB38\uC73C\uB85C \uD3C9\uD0C4\uD654\uD558\uC9C0 \uC54A\uB3C4\uB85D \uAD6C\uC870 \uBCF4\uC874 \uBCF4\uC815 \uC9C0\uCE68\uC744 \uB354\uD574 \uB3CC\uB824\uC90D\uB2C8\uB2E4. write_cover_letter / write_career_description / analyze_job \uC6CC\uD06C\uD50C\uB85C\uC6B0\uC5D0\uC11C \uAE00\uC744 \uC4F8 \uB54C \uBC18\uB4DC\uC2DC \uD568\uAED8 \uC801\uC6A9\uD558\uC138\uC694.',
80433
+ inputSchema: {
80434
+ doc_type: external_exports.enum([
80435
+ "cover_letter",
80436
+ "self_pr",
80437
+ "application_email",
80438
+ "career_description",
80439
+ "resume",
80440
+ "portfolio"
80441
+ ]).optional().describe(
80442
+ "\uC791\uC131\uD560 \uBB38\uC11C \uC720\uD615. career_description\xB7resume\xB7portfolio\uB294 \uBD88\uB9BF\xB7\uAD6C\uC870\uB97C \uBCF4\uC874\uD558\uB294 \uBCF4\uC815\uC744 \uB354\uD574 \uB3CC\uB824\uC90D\uB2C8\uB2E4. \uC0DD\uB7B5\uD558\uBA74 \uC790\uAE30\uC18C\uAC1C\uC11C \uB4F1 \uC0B0\uBB38\uD615 \uAE30\uC900."
80443
+ )
80444
+ },
79826
80445
  readOnly: true,
79827
- handler: () => ok("AI \uD2F0 \uC548 \uB098\uB294 \uAE00\uC4F0\uAE30 \uAC00\uC774\uB4DC\uB97C \uC801\uC6A9\uD574 \uC791\uC131\uD558\uC138\uC694.", { guide: HUMANIZE_WRITING_GUIDE })
80446
+ handler: (args) => ok("AI \uD2F0 \uC548 \uB098\uB294 \uAE00\uC4F0\uAE30 \uAC00\uC774\uB4DC\uB97C \uC801\uC6A9\uD574 \uC791\uC131\uD558\uC138\uC694.", {
80447
+ guide: getWritingStyleGuide(args?.doc_type)
80448
+ })
79828
80449
  },
79829
80450
  /* ----------------------------------------------------------------- update */
79830
80451
  {
@@ -79834,7 +80455,7 @@ ${report.disclaimer}`, report);
79834
80455
  inputSchema: {},
79835
80456
  readOnly: true,
79836
80457
  handler: async () => {
79837
- const u = await getUpdateStatusAsync();
80458
+ const u = await getUpdateStatusAsync(true);
79838
80459
  if (u.latest === null) return ok("\uC5C5\uB370\uC774\uD2B8 \uD655\uC778\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4(\uC624\uD504\uB77C\uC778\uC774\uAC70\uB098 \uC77C\uC2DC\uC801 \uC624\uB958). \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.", u);
79839
80460
  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}).`;
79840
80461
  return ok(
@@ -79911,7 +80532,7 @@ async function main() {
79911
80532
  }
79912
80533
  ok2(`MCP \uB3C4\uAD6C ${TOOLS.length}\uAC1C \uB4F1\uB85D\uB428`);
79913
80534
  try {
79914
- const u = await getUpdateStatusAsync();
80535
+ const u = await getUpdateStatusAsync(true);
79915
80536
  if (u.latest === null) info2(`\uBC84\uC804 v${u.current} (\uC5C5\uB370\uC774\uD2B8 \uD655\uC778 \uC0DD\uB7B5 \u2014 \uC624\uD504\uB77C\uC778\uC774\uAC70\uB098 \uC77C\uC2DC\uC801 \uC624\uB958)`);
79916
80537
  else if (u.update_available) warn2(`\uC0C8 \uBC84\uC804 v${u.latest} \uC788\uC74C (\uD604\uC7AC v${u.current}). \uC5C5\uB370\uC774\uD2B8: ${u.update_command}`);
79917
80538
  else ok2(`\uCD5C\uC2E0 \uBC84\uC804 v${u.current}`);