careermate 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -0
- package/LICENSE +21 -0
- package/README.md +3 -1
- package/apps/web/public/pages/documents.js +7 -2
- package/apps/web/public/pages/home.js +4 -7
- package/apps/web/public/pages/jobs.js +1 -5
- package/apps/web/public/pages/profile.js +3 -3
- package/apps/web/public/styles.css +7 -2
- package/dist/doctor.mjs +112 -90
- package/dist/install-page/analytics.js +97 -0
- package/dist/install-page/index.html +77 -56
- package/dist/install-page/og.png +0 -0
- package/dist/install-page/robots.txt +4 -0
- package/dist/install-page/sitemap.xml +21 -0
- package/dist/install-page/start.html +13 -10
- package/dist/install-page/style.css +75 -40
- package/dist/mcp.mjs +112 -90
- package/dist/migrate.mjs +95 -82
- package/dist/public/pages/documents.js +7 -2
- package/dist/public/pages/home.js +4 -7
- package/dist/public/pages/jobs.js +1 -5
- package/dist/public/pages/profile.js +3 -3
- package/dist/public/styles.css +7 -2
- package/dist/web.mjs +113 -86
- package/docs/FAQ.md +101 -0
- package/docs/career-os/README.md +76 -0
- package/docs/career-os/eop/cover-letter.md +46 -0
- package/docs/career-os/eop/fit-analysis.md +48 -0
- package/docs/career-os/eop/interview-prep.md +39 -0
- package/docs/career-os/eop/job-analysis.md +42 -0
- package/docs/career-os/eop/profile-extraction.md +37 -0
- package/docs/career-os/knowledge/ats.md +131 -0
- package/docs/career-os/knowledge/company-research.md +137 -0
- package/docs/career-os/knowledge/cover-letter.md +135 -0
- package/docs/career-os/knowledge/fit-matching.md +121 -0
- package/docs/career-os/knowledge/human-writing.md +118 -0
- package/docs/career-os/knowledge/interview-behavioral.md +132 -0
- package/docs/career-os/knowledge/interview-technical.md +126 -0
- package/docs/career-os/knowledge/linkedin-profile.md +152 -0
- package/docs/career-os/knowledge/networking-referrals.md +166 -0
- package/docs/career-os/knowledge/offer-evaluation-decision.md +121 -0
- package/docs/career-os/knowledge/onboarding-first-90-days.md +126 -0
- package/docs/career-os/knowledge/portfolio.md +121 -0
- package/docs/career-os/knowledge/recruiter-screen.md +105 -0
- package/docs/career-os/knowledge/rejection-triage-iteration.md +115 -0
- package/docs/career-os/knowledge/resume.md +123 -0
- package/docs/career-os/knowledge/salary-negotiation.md +123 -0
- package/docs/career-os/knowledge/verifiers/ats-compat.md +64 -0
- package/docs/career-os/knowledge/verifiers/consistency.md +61 -0
- package/docs/career-os/knowledge/verifiers/human-voice.md +82 -0
- package/docs/career-os/knowledge/verifiers/recency-staleness.md +72 -0
- package/docs/career-os/knowledge/verifiers/responsiveness-on-target.md +82 -0
- package/docs/career-os/knowledge/verifiers/truthfulness.md +67 -0
- package/package.json +11 -3
- package/packages/db/src/repositories.ts +18 -1
- package/packages/mcp-tools/src/tools.ts +5 -5
- package/packages/parsers/src/documents.ts +13 -1
- package/packages/shared/src/schemas.ts +115 -81
- package/scripts/build-dist.mjs +7 -1
- package/scripts/gen-og.mjs +1 -1
- package/scripts/test.ts +25 -0
- package/scripts/ui-smoke.ts +32 -4
- package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +0 -12
- package/dist/install-page/.omc/state/idle-notif-cooldown.json +0 -3
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +0 -147
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +0 -22
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +0 -44
- package/docs/ARCHITECTURE.md +0 -208
- package/docs/CHANGES_V1.md +0 -103
- package/docs/DATA_MODEL.md +0 -460
- package/docs/DECISIONS.md +0 -277
- package/docs/DEMO.md +0 -242
- package/docs/ROADMAP.md +0 -135
- package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +0 -135
- package/docs/TODO.md +0 -57
- package/docs/UX_NOTES.md +0 -247
- package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +0 -64
package/AGENTS.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# AGENTS.md — CareerMate 상시 지침 (모든 AI 에이전트 공통)
|
|
2
|
+
|
|
3
|
+
이 파일은 CareerMate를 사용하는 AI 에이전트의 **상시 지침 단일 원본**입니다. Codex CLI는 이 파일을 자동으로 읽고, **Claude(`CLAUDE.md`)와 Gemini(`GEMINI.md`)는 이 파일을 그대로 가져다 씁니다.** 따라서 공통 규칙은 항상 여기 한 곳만 고치면 됩니다. 당신(AI 에이전트)이 **사용자의 커리어를 함께 관리**하기 위한 규칙입니다.
|
|
4
|
+
|
|
5
|
+
## CareerMate란
|
|
6
|
+
|
|
7
|
+
CareerMate는 사용자 PC에만 데이터를 두는 **로컬 커리어 작업 공간**입니다. 내부에 LLM이 없는 MCP-우선 도구이며, **AI 서비스가 아니라 "커리어 서랍장"** 입니다. 분석·글쓰기 같은 사고는 모두 **당신이** 하고, CareerMate는 구조화된 커리어 데이터를 저장·제공할 뿐입니다.
|
|
8
|
+
|
|
9
|
+
> 프라임 디렉티브: **두뇌는 당신, 저장은 CareerMate.** 적합도 분석·자기소개서·면접 자료는 당신이 작성하고, 그 입력과 결과는 CareerMate 도구로 가져오고 저장합니다.
|
|
10
|
+
|
|
11
|
+
## 규칙
|
|
12
|
+
|
|
13
|
+
- **기존 데이터를 항상 먼저 활용하라.** 사용자에게 묻거나 무언가를 새로 만들기 전에, CareerMate를 MCP로 조회한다: `get_onboarding_status`(연결 직후 최우선), `get_application_context`, `list_jobs`, `get_profile`, `get_resumes`, `get_cover_letters`, `list_recent_activity`. 이미 채워진 항목은 다시 묻지 마라.
|
|
14
|
+
- **사용자가 파일을 주면 `read_document`로 읽어라.** 이력서·경력기술서·자소서·채용공고가 PDF·Word(`.docx`)·한컴(`.hwp`/`.hwpx`)·텍스트(`.txt`/`.md`) 파일로 컴퓨터에 있고 사용자가 경로로 가리키면, `read_document({ path })`로 본문 텍스트를 추출한 뒤 그 내용으로 작업하고 결과는 아래 저장 도구로 보관한다(파일 내용을 새 파일로 다시 쓰지 마라). 경로는 가능하면 절대 경로로 준다. 이미지·스캔 PDF는 텍스트 레이어가 없어 추출되지 않을 수 있는데, 그때는 이미지를 직접 볼 수 있는 클라이언트로 읽거나 사용자에게 내용을 텍스트로 붙여넣어 달라고 안내한다.
|
|
15
|
+
- **공고 분석·자소서 작성 전에는 반드시 `get_application_context`를 먼저 호출하라.** 한 번의 호출로 프로필·대표 이력서·경력·스킬·기존 자소서·대상 공고·선호 문체·강조 포인트를 모두 돌려준다. 맥락 없이 작성하지 마라.
|
|
16
|
+
- **결과는 다시 CareerMate에 저장하라.** 분석 → `save_fit_analysis`, 자소서 → `save_cover_letter_version`, 공고 → `save_job_posting`, 면접 자료 → `save_interview_prep`. 커리어 데이터는 흩어진 파일이 아니라 CareerMate 안에 둔다. 임의의 로컬 파일 생성은 최소화하라(사용자가 파일을 원하면 `export_cover_letter`로 `~/.careermate/exports`에 내보낸다).
|
|
17
|
+
- **5개 표준 워크플로우를 따르라**: onboarding, analyze_job, write_cover_letter, manage_application_status, prepare_interview. 순서가 헷갈리면 `get_workflow_guide`를 호출한다.
|
|
18
|
+
- **사람이 쓴 듯한 글**이 필요할 때(자소서·자기 PR·지원 메일)는 작성 직전 `get_writing_style_guide`를 적용한다. 사실·수치·고유명사는 그대로 보존한다.
|
|
19
|
+
- **8단계 지원 상태 게이팅을 존중하라**: `draft`(작성 중) → `planned`(지원 예정) → `applied`(지원 완료) → `document_passed`(서류 합격) → `interview`(면접 진행) → `final_passed`(최종 합격) / `rejected`(불합격) / `on_hold`(보류). 면접 준비는 **`document_passed` 이상**에서만 해금된다. 상태 변경은 `update_application_status`.
|
|
20
|
+
- **결과를 낼 때마다 대시보드로 안내하라.** 공고 저장·적합도 분석·자소서 버전·상태 변경·면접 준비 등 무언가를 저장·완료할 때마다 대시보드(`http://127.0.0.1:4319`) 주소를 알려준다. 브라우저를 직접 여는 건 **첫 온보딩 때 한 번만**(`open_dashboard`) — 이후에는 자동으로 열지 말고 링크만 보여주고, 사용자가 "열어줘"라고 하면 그때 `open_application`(단건)·`open_dashboard`(전체)로 연다.
|
|
21
|
+
- **절대 사용자 데이터를 외부로 업로드하지 마라.** 모든 데이터는 `~/.careermate`(Windows: `%USERPROFILE%\.careermate`)에만 있고, 대시보드는 `127.0.0.1`에만 바인딩된다. CareerMate는 (선택적 버전 확인 외) 네트워크로 사용자 데이터를 보내지 않는다.
|
|
22
|
+
- 기술 용어(MCP, `job_id` 등)는 사용자에게 노출하지 말고, 매 단계 무엇을 하는지 쉬운 한국어로 설명하라. 확실하지 않으면 지어내지 말고 사용자에게 확인하라.
|
|
23
|
+
|
|
24
|
+
## 아직 연결되지 않았다면
|
|
25
|
+
|
|
26
|
+
CareerMate MCP 도구가 보이지 않으면(예: `get_onboarding_status` 호출 불가) **먼저 설치·등록부터** 한다. **클라이언트별 등록 방법은 [`./INSTALL.md`](INSTALL.md)** 에 있다(Claude Code/Desktop, Codex, Gemini 등). 요지: 해당 클라이언트의 MCP 설정에 stdio 서버로 등록 → AI 클라이언트를 **완전히 재시작** → `get_onboarding_status`를 한 번 호출해 응답이 오는지 확인한다.
|
|
27
|
+
|
|
28
|
+
## 더 보기
|
|
29
|
+
|
|
30
|
+
- [`./INSTALL.md`](INSTALL.md) — 설치·등록 런북(클라이언트별 등록 방법)
|
|
31
|
+
- [`docs/START_WORKFLOW.md`](docs/START_WORKFLOW.md) — 연결 직후 사용자를 빠르게 생산적으로 만드는 단계별 런북
|
|
32
|
+
- [`docs/MCP_TOOLS.md`](docs/MCP_TOOLS.md) — MCP 도구 레퍼런스(입력·반환·호출 시점)
|
|
33
|
+
- [`docs/WORKFLOWS.md`](docs/WORKFLOWS.md) — 5개 표준 워크플로우 상세
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CareerMate
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -240,7 +240,9 @@ CareerMate/
|
|
|
240
240
|
- [`AGENTS.md`](AGENTS.md) — Codex용 영속 지침. / [`CLAUDE.md`](CLAUDE.md) — Claude Code용 영속 지침.
|
|
241
241
|
- [`docs/SUPPORTED_AI_APPS.md`](docs/SUPPORTED_AI_APPS.md) — **설치 레퍼런스 허브**: 지원 앱 매트릭스 + 설치 3방식(에이전트/npx/.mcpb) + 클라이언트별 수동 MCP 설정 + 알려진 제약. (사람용 안내는 https://careermate.life)
|
|
242
242
|
- [`docs/START_WORKFLOW.md`](docs/START_WORKFLOW.md) — 등록부터 면접 준비까지 단계별 작업 런북.
|
|
243
|
+
- [`docs/FAQ.md`](docs/FAQ.md) — **자주 묻는 질문 / 문제 해결**: "PDF가 안 읽혀요", "분석이 안 돼요", "공고 URL은 어떻게 넣어요" 등.
|
|
243
244
|
- [`docs/TODO.md`](docs/TODO.md) — 남은 작업과 v1 범위 밖 항목.
|
|
245
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — 버전별 변경 이력. / [`CONTRIBUTING.md`](CONTRIBUTING.md) · [`SECURITY.md`](SECURITY.md) · [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) — 기여·보안·행동 강령.
|
|
244
246
|
|
|
245
247
|
---
|
|
246
248
|
|
|
@@ -258,4 +260,4 @@ npm run typecheck
|
|
|
258
260
|
|
|
259
261
|
## 라이선스
|
|
260
262
|
|
|
261
|
-
MIT 라이선스 —
|
|
263
|
+
MIT 라이선스 — 전문은 [`LICENSE`](LICENSE) 파일을 참고하세요. (개발용 GitHub 저장소는 현재 비공개입니다.)
|
|
@@ -23,6 +23,7 @@ export async function render(ctx) {
|
|
|
23
23
|
root.append(el('div', { class: 'tabs' }, tabCover, tabDocs), panel);
|
|
24
24
|
|
|
25
25
|
let query = '';
|
|
26
|
+
let searchInput = null;
|
|
26
27
|
function selectTab(next) {
|
|
27
28
|
tab = next;
|
|
28
29
|
query = '';
|
|
@@ -43,9 +44,12 @@ export async function render(ctx) {
|
|
|
43
44
|
if (!hide) shown += 1;
|
|
44
45
|
}
|
|
45
46
|
const existing = panel.querySelector('.search-empty');
|
|
47
|
+
if (existing) existing.remove();
|
|
46
48
|
if (q && cards.length && shown === 0) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
panel.append(el('div', { class: 'search-empty empty' },
|
|
50
|
+
el('p', { class: 'muted', style: { margin: '0 0 12px' } }, `‘${query.trim()}’에 맞는 항목이 없어요.`),
|
|
51
|
+
Btn('필터 초기화', { sm: true, variant: 'ghost', onClick: () => { query = ''; if (searchInput) searchInput.value = ''; applyFilter(); } })));
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
async function reload() {
|
|
@@ -70,6 +74,7 @@ export async function render(ctx) {
|
|
|
70
74
|
function setActions() {
|
|
71
75
|
const search = Input({ type: 'search', placeholder: tab === 'cover' ? '자기소개서 검색' : '문서 검색', value: query, attrs: { 'aria-label': '검색' } });
|
|
72
76
|
search.classList.add('input--inline');
|
|
77
|
+
searchInput = search;
|
|
73
78
|
search.addEventListener('input', () => { query = search.value; applyFilter(); });
|
|
74
79
|
const createBtn = tab === 'cover'
|
|
75
80
|
? Btn('새 자기소개서', { icon: 'plus', variant: 'primary', onClick: () => openCoverCreate(reload) })
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// the 시작하기 card. Every empty state is ONE screen-specific sentence; never repeat
|
|
5
5
|
// the same "AI에게 보내면 저장됩니다" instruction across surfaces.
|
|
6
6
|
import {
|
|
7
|
-
el, get, icon, navigate, Card, Badge, Btn,
|
|
7
|
+
el, get, icon, navigate, Card, Badge, Btn, ListRow, CheckRow,
|
|
8
8
|
Stat, PageHead, fmtDate, fmtRelative, scoreClass, STATUS_COLOR, statusColor, mount,
|
|
9
9
|
} from '/lib.js';
|
|
10
10
|
|
|
@@ -59,7 +59,7 @@ function Greeting(name, s, firstRun) {
|
|
|
59
59
|
let focus;
|
|
60
60
|
if (firstRun) focus = '시작해 볼까요 — 먼저 기본 정보를 채워 주세요.';
|
|
61
61
|
else if (s.interview_todo.length) focus = `면접 준비가 필요한 지원 ${s.interview_todo.length}건이 있어요.`;
|
|
62
|
-
else if (s.in_progress.length) focus = `진행 중인 지원 ${s.in_progress.length}
|
|
62
|
+
else if (s.in_progress.length) focus = `진행 중인 지원 ${s.in_progress.length}건이 있어요.`;
|
|
63
63
|
else if (s.counts.jobs) focus = `저장된 공고 ${s.counts.jobs}건 · 새 적합도 분석을 받아보세요.`;
|
|
64
64
|
else focus = '오늘도 한 걸음 나아가 볼까요.';
|
|
65
65
|
return PageHead({ title: name ? `${name}님, 안녕하세요` : '환영합니다', desc: focus });
|
|
@@ -87,7 +87,7 @@ function GettingStarted(o) {
|
|
|
87
87
|
el('div', { class: 'callout__body' },
|
|
88
88
|
'공고 분석·자기소개서·면접 준비는 평소 쓰던 AI에게 말로 시키면, 결과가 이 대시보드에 쌓여요.'))),
|
|
89
89
|
el('div', { class: 'progress' }, el('div', { class: 'progress__bar', style: { width: `${o.profile_completeness}%` } })),
|
|
90
|
-
el('p', { class: 'text-secondary text-sm
|
|
90
|
+
el('p', { class: 'text-secondary text-sm mt-3 mb-2' },
|
|
91
91
|
'완성할수록 AI의 적합도 분석과 자기소개서 품질이 좋아져요.'),
|
|
92
92
|
el('div', {}, ...steps.map((it) => CheckRow({ done: it.done, label: it.label, onClick: () => navigate(it.to) }))),
|
|
93
93
|
],
|
|
@@ -201,10 +201,7 @@ function RecentJobs(jobs) {
|
|
|
201
201
|
if (!jobs.length) {
|
|
202
202
|
return Card({
|
|
203
203
|
title: '최근 공고',
|
|
204
|
-
body:
|
|
205
|
-
iconName: 'briefcase', title: '저장된 공고가 아직 없어요',
|
|
206
|
-
action: Btn('공고 추가', { icon: 'plus', variant: 'ghost', onClick: () => navigate('/jobs') }),
|
|
207
|
-
}),
|
|
204
|
+
body: el('p', { class: 'muted', style: { margin: 0 } }, '저장된 공고가 아직 없어요. 새 공고를 추가해 보세요.'),
|
|
208
205
|
});
|
|
209
206
|
}
|
|
210
207
|
const rows = jobs.map((j) => ListRow({
|
|
@@ -365,11 +365,7 @@ function FitCard(fit) {
|
|
|
365
365
|
if (!fit) {
|
|
366
366
|
return Card({
|
|
367
367
|
title: '적합도 분석',
|
|
368
|
-
body:
|
|
369
|
-
iconName: 'target',
|
|
370
|
-
title: '적합도 분석 전이에요',
|
|
371
|
-
body: '이 공고와 내 프로필을 비교한 분석 결과가 여기에 표시됩니다.',
|
|
372
|
-
}),
|
|
368
|
+
body: el('p', { class: 'muted', style: { margin: 0 } }, '아직 분석 전이에요. 이 공고와 내 프로필을 비교한 결과가 여기에 표시됩니다.'),
|
|
373
369
|
});
|
|
374
370
|
}
|
|
375
371
|
|
|
@@ -264,7 +264,7 @@ function editWriting(p, reload) {
|
|
|
264
264
|
/* ---------------------------------------------------- 4. 경력 (Experiences) */
|
|
265
265
|
|
|
266
266
|
function ExperiencesCard(items, reload) {
|
|
267
|
-
const add = Btn('추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editExperience(null, reload) });
|
|
267
|
+
const add = Btn('경력 추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editExperience(null, reload) });
|
|
268
268
|
|
|
269
269
|
if (!items.length) {
|
|
270
270
|
return Card({
|
|
@@ -368,7 +368,7 @@ function editExperience(x, reload) {
|
|
|
368
368
|
/* ----------------------------------------------------- 5. 프로젝트 (Projects) */
|
|
369
369
|
|
|
370
370
|
function ProjectsCard(items, reload) {
|
|
371
|
-
const add = Btn('추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editProject(null, reload) });
|
|
371
|
+
const add = Btn('프로젝트 추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editProject(null, reload) });
|
|
372
372
|
|
|
373
373
|
if (!items.length) {
|
|
374
374
|
return Card({
|
|
@@ -469,7 +469,7 @@ function editProject(x, reload) {
|
|
|
469
469
|
/* -------------------------------------------------------- 6. 기술 (Skills) */
|
|
470
470
|
|
|
471
471
|
function SkillsCard(items, reload) {
|
|
472
|
-
const add = Btn('추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editSkill(null, reload) });
|
|
472
|
+
const add = Btn('기술 추가', { icon: 'plus', sm: true, variant: 'ghost', onClick: () => editSkill(null, reload) });
|
|
473
473
|
|
|
474
474
|
if (!items.length) {
|
|
475
475
|
return Card({
|
|
@@ -403,7 +403,9 @@ h1,h2,h3,h4 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
|
|
|
403
403
|
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 22px 26px; max-height: 60vh; overflow-y: auto; }
|
|
404
404
|
.kv { display: grid; grid-template-columns: 132px 1fr; gap: 8px 16px; }
|
|
405
405
|
.kv dt { color: var(--text-tertiary); font-size: 13px; }
|
|
406
|
-
|
|
406
|
+
/* min-width:0 overrides a grid item's default min-width:auto so the 1fr column
|
|
407
|
+
can shrink below its content — otherwise a long path/value overflows the grid. */
|
|
408
|
+
.kv dd { margin: 0; min-width: 0; }
|
|
407
409
|
|
|
408
410
|
/* ----------------------------------------------------------------- modal */
|
|
409
411
|
.modal-root { position: fixed; inset: 0; z-index: 60; display: none; }
|
|
@@ -450,7 +452,10 @@ h1,h2,h3,h4 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
|
|
|
450
452
|
.between { justify-content: space-between; } .center { align-items: center; } .wrap { flex-wrap: wrap; }
|
|
451
453
|
.ml-auto { margin-left: auto; } .mt-2{margin-top:8px;} .mt-3{margin-top:12px;} .mt-4{margin-top:16px;} .mb-2{margin-bottom:8px;} .mb-3{margin-bottom:12px;} .mb-4{margin-bottom:16px;}
|
|
452
454
|
.tnum { font-variant-numeric: tabular-nums; }
|
|
453
|
-
|
|
455
|
+
/* min-width:0 lets a truncating element actually shrink inside a flex row;
|
|
456
|
+
without it a long unbreakable value (e.g. a data-folder path) forces the
|
|
457
|
+
flex item to its content width and overflows the viewport on narrow screens. */
|
|
458
|
+
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; min-width: 0; }
|
|
454
459
|
.divider { height: 1px; background: var(--border); margin: 16px 0; }
|
|
455
460
|
.skeleton { background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--surface-hover) 37%, var(--bg-sunken) 63%); background-size: 400% 100%; animation: shimmer 1.4s infinite; border-radius: 6px; }
|
|
456
461
|
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
|
package/dist/doctor.mjs
CHANGED
|
@@ -75561,29 +75561,42 @@ function isSafeUrl(u) {
|
|
|
75561
75561
|
return !/^[a-z][a-z0-9+.-]*:/i.test(s) || /^(https?:|mailto:)/i.test(s);
|
|
75562
75562
|
}
|
|
75563
75563
|
var UNSAFE_URL_MSG = "javascript: \uAC19\uC740 \uC704\uD5D8\uD55C \uB9C1\uD06C\uB294 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. http(s) \uB9C1\uD06C\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.";
|
|
75564
|
-
var
|
|
75565
|
-
var
|
|
75564
|
+
var MAX_URL = 2e3;
|
|
75565
|
+
var SafeUrl = external_exports.string().min(1).max(MAX_URL).refine(isSafeUrl, { message: UNSAFE_URL_MSG });
|
|
75566
|
+
var SafeUrlOptional = external_exports.string().max(MAX_URL).optional().refine((u) => u == null || u === "" || isSafeUrl(u), { message: UNSAFE_URL_MSG });
|
|
75567
|
+
var MAX_LINE = 500;
|
|
75568
|
+
var MAX_NOTE = 1e4;
|
|
75569
|
+
var MAX_BODY = 2e5;
|
|
75570
|
+
var MAX_ITEM = 2e3;
|
|
75571
|
+
var MAX_ITEMS = 500;
|
|
75572
|
+
var EMPTY_MSG = "\uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4(\uACF5\uBC31\uB9CC\uC73C\uB85C\uB294 \uC800\uC7A5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4).";
|
|
75573
|
+
var reqLine = external_exports.string().trim().min(1).max(MAX_LINE);
|
|
75574
|
+
var optLine = external_exports.string().max(MAX_LINE).optional();
|
|
75575
|
+
var optNote = external_exports.string().max(MAX_NOTE).optional();
|
|
75576
|
+
var optBody = external_exports.string().max(MAX_BODY).optional();
|
|
75577
|
+
var reqBody = external_exports.string().max(MAX_BODY).refine((s) => s.trim().length > 0, { message: EMPTY_MSG });
|
|
75578
|
+
var strList = external_exports.array(external_exports.string().max(MAX_ITEM)).max(MAX_ITEMS);
|
|
75566
75579
|
var baseRecord = {
|
|
75567
75580
|
id,
|
|
75568
75581
|
created_at: isoDateTime,
|
|
75569
75582
|
updated_at: isoDateTime
|
|
75570
75583
|
};
|
|
75571
75584
|
var LinkSchema = external_exports.object({
|
|
75572
|
-
label:
|
|
75585
|
+
label: reqLine,
|
|
75573
75586
|
url: SafeUrl
|
|
75574
75587
|
});
|
|
75575
75588
|
var ProfileInputSchema = external_exports.object({
|
|
75576
|
-
name:
|
|
75577
|
-
email:
|
|
75578
|
-
phone:
|
|
75579
|
-
location:
|
|
75580
|
-
headline: external_exports.string().optional().describe("\uD55C \uC904 \uC18C\uAC1C / \uC9C1\uBB34 \uD0C0\uC774\uD2C0"),
|
|
75581
|
-
summary: external_exports.string().optional().describe("\uC790\uAE30\uC18C\uAC1C \uC694\uC57D"),
|
|
75582
|
-
desired_roles:
|
|
75583
|
-
desired_conditions: external_exports.string().optional().describe("\uD76C\uB9DD \uADFC\uBB34 \uC870\uAC74 (\uC5F0\uBD09, \uC9C0\uC5ED, \uADFC\uBB34\uD615\uD0DC \uB4F1)"),
|
|
75584
|
-
preferred_tone: external_exports.string().optional().describe("\uC790\uAE30\uC18C\uAC1C\uC11C \uC120\uD638 \uBB38\uCCB4 (\uC608: \uB2F4\uBC31\uD558\uACE0 \uAD6C\uCCB4\uC801)"),
|
|
75585
|
-
emphasis_points:
|
|
75586
|
-
links: external_exports.array(LinkSchema).optional().describe("\uD3EC\uD2B8\uD3F4\uB9AC\uC624/\uAE43\uD5C8\uBE0C/\uB9C1\uD06C\uB4DC\uC778 \uB4F1")
|
|
75589
|
+
name: reqLine.optional(),
|
|
75590
|
+
email: optLine,
|
|
75591
|
+
phone: optLine,
|
|
75592
|
+
location: optLine,
|
|
75593
|
+
headline: external_exports.string().max(MAX_LINE).optional().describe("\uD55C \uC904 \uC18C\uAC1C / \uC9C1\uBB34 \uD0C0\uC774\uD2C0"),
|
|
75594
|
+
summary: external_exports.string().max(MAX_NOTE).optional().describe("\uC790\uAE30\uC18C\uAC1C \uC694\uC57D"),
|
|
75595
|
+
desired_roles: strList.optional().describe("\uD76C\uB9DD \uC9C1\uBB34"),
|
|
75596
|
+
desired_conditions: external_exports.string().max(MAX_NOTE).optional().describe("\uD76C\uB9DD \uADFC\uBB34 \uC870\uAC74 (\uC5F0\uBD09, \uC9C0\uC5ED, \uADFC\uBB34\uD615\uD0DC \uB4F1)"),
|
|
75597
|
+
preferred_tone: external_exports.string().max(MAX_LINE).optional().describe("\uC790\uAE30\uC18C\uAC1C\uC11C \uC120\uD638 \uBB38\uCCB4 (\uC608: \uB2F4\uBC31\uD558\uACE0 \uAD6C\uCCB4\uC801)"),
|
|
75598
|
+
emphasis_points: strList.optional().describe("\uAC15\uC870\uD558\uACE0 \uC2F6\uC740 \uD575\uC2EC \uD3EC\uC778\uD2B8"),
|
|
75599
|
+
links: external_exports.array(LinkSchema).max(MAX_ITEMS).optional().describe("\uD3EC\uD2B8\uD3F4\uB9AC\uC624/\uAE43\uD5C8\uBE0C/\uB9C1\uD06C\uB4DC\uC778 \uB4F1")
|
|
75587
75600
|
});
|
|
75588
75601
|
var ProfileRecordSchema = external_exports.object({
|
|
75589
75602
|
...baseRecord,
|
|
@@ -75600,15 +75613,15 @@ var ProfileRecordSchema = external_exports.object({
|
|
|
75600
75613
|
links: external_exports.array(LinkSchema)
|
|
75601
75614
|
});
|
|
75602
75615
|
var ExperienceInputSchema = external_exports.object({
|
|
75603
|
-
company:
|
|
75604
|
-
role:
|
|
75605
|
-
employment_type: external_exports.string().optional().describe("\uC815\uADDC\uC9C1/\uACC4\uC57D\uC9C1/\uC778\uD134/\uD504\uB9AC\uB79C\uC11C \uB4F1"),
|
|
75606
|
-
start_date: external_exports.string().optional().describe("YYYY-MM \uB610\uB294 YYYY-MM-DD"),
|
|
75607
|
-
end_date: external_exports.string().optional().describe("\uC7AC\uC9C1 \uC911\uC774\uBA74 \uBE44\uC6CC\uB450\uAE30"),
|
|
75616
|
+
company: reqLine,
|
|
75617
|
+
role: optLine,
|
|
75618
|
+
employment_type: external_exports.string().max(MAX_LINE).optional().describe("\uC815\uADDC\uC9C1/\uACC4\uC57D\uC9C1/\uC778\uD134/\uD504\uB9AC\uB79C\uC11C \uB4F1"),
|
|
75619
|
+
start_date: external_exports.string().max(MAX_LINE).optional().describe("YYYY-MM \uB610\uB294 YYYY-MM-DD"),
|
|
75620
|
+
end_date: external_exports.string().max(MAX_LINE).optional().describe("\uC7AC\uC9C1 \uC911\uC774\uBA74 \uBE44\uC6CC\uB450\uAE30"),
|
|
75608
75621
|
is_current: external_exports.boolean().optional(),
|
|
75609
|
-
description:
|
|
75610
|
-
achievements:
|
|
75611
|
-
tech:
|
|
75622
|
+
description: optBody,
|
|
75623
|
+
achievements: strList.optional().describe("\uC131\uACFC/\uC5C5\uC801 (\uC815\uB7C9 \uC9C0\uD45C \uAD8C\uC7A5)"),
|
|
75624
|
+
tech: strList.optional().describe("\uC0AC\uC6A9 \uAE30\uC220/\uB3C4\uAD6C"),
|
|
75612
75625
|
order_index: external_exports.number().optional()
|
|
75613
75626
|
});
|
|
75614
75627
|
var ExperienceRecordSchema = external_exports.object({
|
|
@@ -75625,14 +75638,14 @@ var ExperienceRecordSchema = external_exports.object({
|
|
|
75625
75638
|
order_index: external_exports.number()
|
|
75626
75639
|
});
|
|
75627
75640
|
var ProjectInputSchema = external_exports.object({
|
|
75628
|
-
name:
|
|
75629
|
-
role:
|
|
75630
|
-
description:
|
|
75631
|
-
highlights:
|
|
75632
|
-
tech:
|
|
75641
|
+
name: reqLine,
|
|
75642
|
+
role: optLine,
|
|
75643
|
+
description: optBody,
|
|
75644
|
+
highlights: strList.optional(),
|
|
75645
|
+
tech: strList.optional(),
|
|
75633
75646
|
url: SafeUrlOptional,
|
|
75634
|
-
start_date:
|
|
75635
|
-
end_date:
|
|
75647
|
+
start_date: optLine,
|
|
75648
|
+
end_date: optLine,
|
|
75636
75649
|
order_index: external_exports.number().optional()
|
|
75637
75650
|
});
|
|
75638
75651
|
var ProjectRecordSchema = external_exports.object({
|
|
@@ -75648,9 +75661,9 @@ var ProjectRecordSchema = external_exports.object({
|
|
|
75648
75661
|
order_index: external_exports.number()
|
|
75649
75662
|
});
|
|
75650
75663
|
var SkillInputSchema = external_exports.object({
|
|
75651
|
-
name:
|
|
75652
|
-
category: external_exports.string().optional().describe("\uC5B8\uC5B4/\uD504\uB808\uC784\uC6CC\uD06C/\uD234/\uC18C\uD504\uD2B8\uC2A4\uD0AC \uB4F1"),
|
|
75653
|
-
level: external_exports.string().optional().describe("\uC0C1/\uC911/\uD558 \uB610\uB294 \uC790\uC720 \uC11C\uC220"),
|
|
75664
|
+
name: reqLine,
|
|
75665
|
+
category: external_exports.string().max(MAX_LINE).optional().describe("\uC5B8\uC5B4/\uD504\uB808\uC784\uC6CC\uD06C/\uD234/\uC18C\uD504\uD2B8\uC2A4\uD0AC \uB4F1"),
|
|
75666
|
+
level: external_exports.string().max(MAX_LINE).optional().describe("\uC0C1/\uC911/\uD558 \uB610\uB294 \uC790\uC720 \uC11C\uC220"),
|
|
75654
75667
|
years: external_exports.number().optional(),
|
|
75655
75668
|
order_index: external_exports.number().optional()
|
|
75656
75669
|
});
|
|
@@ -75664,11 +75677,11 @@ var SkillRecordSchema = external_exports.object({
|
|
|
75664
75677
|
});
|
|
75665
75678
|
var DocumentInputSchema = external_exports.object({
|
|
75666
75679
|
kind: external_exports.enum(DOCUMENT_KINDS),
|
|
75667
|
-
title:
|
|
75668
|
-
content:
|
|
75680
|
+
title: reqLine,
|
|
75681
|
+
content: reqBody.describe("Markdown \uB610\uB294 \uC77C\uBC18 \uD14D\uC2A4\uD2B8 \uBCF8\uBB38"),
|
|
75669
75682
|
source: external_exports.enum(CONTENT_SOURCES).optional(),
|
|
75670
75683
|
is_primary: external_exports.boolean().optional().describe("\uB300\uD45C \uBB38\uC11C \uC5EC\uBD80"),
|
|
75671
|
-
tags:
|
|
75684
|
+
tags: strList.optional()
|
|
75672
75685
|
});
|
|
75673
75686
|
var DocumentRecordSchema = external_exports.object({
|
|
75674
75687
|
...baseRecord,
|
|
@@ -75680,19 +75693,19 @@ var DocumentRecordSchema = external_exports.object({
|
|
|
75680
75693
|
tags: external_exports.array(external_exports.string())
|
|
75681
75694
|
});
|
|
75682
75695
|
var CoverLetterInputSchema = external_exports.object({
|
|
75683
|
-
title:
|
|
75684
|
-
job_id:
|
|
75696
|
+
title: reqLine,
|
|
75697
|
+
job_id: optLine.describe("\uD2B9\uC815 \uACF5\uACE0\uC5D0 \uC5F0\uACB0\uD560 \uACBD\uC6B0"),
|
|
75685
75698
|
is_primary: external_exports.boolean().optional(),
|
|
75686
|
-
content:
|
|
75699
|
+
content: optBody.describe("\uCD08\uAE30 \uBC84\uC804 \uBCF8\uBB38 (\uC788\uC73C\uBA74 v1\uB85C \uC800\uC7A5)"),
|
|
75687
75700
|
source: external_exports.enum(CONTENT_SOURCES).optional(),
|
|
75688
|
-
note:
|
|
75701
|
+
note: optNote.describe("\uCD08\uAE30 \uBC84\uC804 \uBA54\uBAA8")
|
|
75689
75702
|
});
|
|
75690
75703
|
var CoverLetterVersionInputSchema = external_exports.object({
|
|
75691
|
-
cover_letter_id:
|
|
75692
|
-
title: external_exports.string().optional().describe("\uC0C8 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uB9CC\uB4E4 \uB54C \uC81C\uBAA9"),
|
|
75693
|
-
job_id:
|
|
75694
|
-
content:
|
|
75695
|
-
note:
|
|
75704
|
+
cover_letter_id: optLine.describe("\uAE30\uC874 \uC790\uAE30\uC18C\uAC1C\uC11C\uC5D0 \uC0C8 \uBC84\uC804 \uCD94\uAC00 \uC2DC"),
|
|
75705
|
+
title: external_exports.string().max(MAX_LINE).optional().describe("\uC0C8 \uC790\uAE30\uC18C\uAC1C\uC11C\uB97C \uB9CC\uB4E4 \uB54C \uC81C\uBAA9"),
|
|
75706
|
+
job_id: optLine,
|
|
75707
|
+
content: reqBody,
|
|
75708
|
+
note: optNote.describe("\uC774 \uBC84\uC804\uC758 \uBCC0\uACBD \uC694\uC57D (\uC608: \uC9C0\uC6D0\uB3D9\uAE30 \uBCF4\uAC15)"),
|
|
75696
75709
|
source: external_exports.enum(CONTENT_SOURCES).optional(),
|
|
75697
75710
|
set_current: external_exports.boolean().optional().describe("\uC774 \uBC84\uC804\uC744 \uD604\uC7AC \uBC84\uC804\uC73C\uB85C \uC9C0\uC815 (\uAE30\uBCF8 true)")
|
|
75698
75711
|
});
|
|
@@ -75716,16 +75729,16 @@ var CoverLetterRecordSchema = external_exports.object({
|
|
|
75716
75729
|
versions: external_exports.array(CoverLetterVersionRecordSchema).optional()
|
|
75717
75730
|
});
|
|
75718
75731
|
var JobInputSchema = external_exports.object({
|
|
75719
|
-
company:
|
|
75720
|
-
position:
|
|
75732
|
+
company: reqLine,
|
|
75733
|
+
position: reqLine.describe("\uC9C1\uBB34/\uD3EC\uC9C0\uC158\uBA85"),
|
|
75721
75734
|
url: SafeUrlOptional,
|
|
75722
|
-
location:
|
|
75723
|
-
employment_type:
|
|
75724
|
-
description:
|
|
75725
|
-
requirements:
|
|
75726
|
-
keywords:
|
|
75727
|
-
deadline: external_exports.string().optional().describe("\uB9C8\uAC10\uC77C YYYY-MM-DD"),
|
|
75728
|
-
source: external_exports.string().optional().describe("\uCD9C\uCC98 (\uC0AC\uB78C\uC778/\uC6D0\uD2F0\uB4DC/\uC9C1\uC811 \uC785\uB825 \uB4F1)")
|
|
75735
|
+
location: optLine,
|
|
75736
|
+
employment_type: optLine,
|
|
75737
|
+
description: optBody.describe("\uACF5\uACE0 \uC6D0\uBB38 \uB610\uB294 \uC815\uB9AC\uB41C \uD14D\uC2A4\uD2B8"),
|
|
75738
|
+
requirements: strList.optional().describe("\uC790\uACA9\uC694\uAC74/\uC6B0\uB300\uC0AC\uD56D \uD575\uC2EC"),
|
|
75739
|
+
keywords: strList.optional().describe("\uD575\uC2EC \uD0A4\uC6CC\uB4DC"),
|
|
75740
|
+
deadline: external_exports.string().max(MAX_LINE).optional().describe("\uB9C8\uAC10\uC77C YYYY-MM-DD"),
|
|
75741
|
+
source: external_exports.string().max(MAX_LINE).optional().describe("\uCD9C\uCC98 (\uC0AC\uB78C\uC778/\uC6D0\uD2F0\uB4DC/\uC9C1\uC811 \uC785\uB825 \uB4F1)")
|
|
75729
75742
|
});
|
|
75730
75743
|
var JobRecordSchema = external_exports.object({
|
|
75731
75744
|
...baseRecord,
|
|
@@ -75741,14 +75754,14 @@ var JobRecordSchema = external_exports.object({
|
|
|
75741
75754
|
source: external_exports.string().nullable()
|
|
75742
75755
|
});
|
|
75743
75756
|
var FitAnalysisInputSchema = external_exports.object({
|
|
75744
|
-
job_id:
|
|
75757
|
+
job_id: reqLine.describe("\uBD84\uC11D \uB300\uC0C1 \uACF5\uACE0 ID"),
|
|
75745
75758
|
score: external_exports.number().min(0).max(100).optional().describe("\uC885\uD569 \uC801\uD569\uB3C4 0~100"),
|
|
75746
|
-
summary: external_exports.string().optional().describe("\uD55C\uB450 \uBB38\uB2E8 \uC694\uC57D"),
|
|
75747
|
-
strengths:
|
|
75748
|
-
gaps:
|
|
75749
|
-
matched_keywords:
|
|
75750
|
-
missing_keywords:
|
|
75751
|
-
recommendations:
|
|
75759
|
+
summary: external_exports.string().max(MAX_NOTE).optional().describe("\uD55C\uB450 \uBB38\uB2E8 \uC694\uC57D"),
|
|
75760
|
+
strengths: strList.optional().describe("\uAC15\uC810 / \uC798 \uB9DE\uB294 \uBD80\uBD84"),
|
|
75761
|
+
gaps: strList.optional().describe("\uBD80\uC871\uD55C \uBD80\uBD84 / \uBCF4\uC644 \uD544\uC694"),
|
|
75762
|
+
matched_keywords: strList.optional(),
|
|
75763
|
+
missing_keywords: strList.optional(),
|
|
75764
|
+
recommendations: strList.optional().describe("\uC790\uAE30\uC18C\uAC1C\uC11C/\uC9C0\uC6D0 \uC804\uB7B5 \uC81C\uC548")
|
|
75752
75765
|
});
|
|
75753
75766
|
var FitAnalysisRecordSchema = external_exports.object({
|
|
75754
75767
|
...baseRecord,
|
|
@@ -75762,18 +75775,18 @@ var FitAnalysisRecordSchema = external_exports.object({
|
|
|
75762
75775
|
recommendations: external_exports.array(external_exports.string())
|
|
75763
75776
|
});
|
|
75764
75777
|
var ApplicationInputSchema = external_exports.object({
|
|
75765
|
-
job_id:
|
|
75778
|
+
job_id: reqLine,
|
|
75766
75779
|
status: external_exports.enum(APPLICATION_STATUSES).optional(),
|
|
75767
|
-
resume_id:
|
|
75768
|
-
cover_letter_id:
|
|
75769
|
-
applied_at:
|
|
75770
|
-
notes:
|
|
75780
|
+
resume_id: optLine,
|
|
75781
|
+
cover_letter_id: optLine,
|
|
75782
|
+
applied_at: optLine,
|
|
75783
|
+
notes: optNote
|
|
75771
75784
|
});
|
|
75772
75785
|
var ApplicationStatusUpdateSchema = external_exports.object({
|
|
75773
|
-
job_id:
|
|
75774
|
-
application_id:
|
|
75786
|
+
job_id: optLine,
|
|
75787
|
+
application_id: optLine,
|
|
75775
75788
|
status: external_exports.enum(APPLICATION_STATUSES),
|
|
75776
|
-
note:
|
|
75789
|
+
note: optNote.describe("\uC0C1\uD0DC \uBCC0\uACBD \uC0AC\uC720/\uBA54\uBAA8")
|
|
75777
75790
|
});
|
|
75778
75791
|
var ApplicationRecordSchema = external_exports.object({
|
|
75779
75792
|
...baseRecord,
|
|
@@ -75785,24 +75798,24 @@ var ApplicationRecordSchema = external_exports.object({
|
|
|
75785
75798
|
notes: external_exports.string().nullable()
|
|
75786
75799
|
});
|
|
75787
75800
|
var StarGuideSchema = external_exports.object({
|
|
75788
|
-
question: external_exports.string(),
|
|
75789
|
-
situation:
|
|
75790
|
-
task:
|
|
75791
|
-
action:
|
|
75792
|
-
result:
|
|
75801
|
+
question: external_exports.string().max(MAX_NOTE),
|
|
75802
|
+
situation: optNote,
|
|
75803
|
+
task: optNote,
|
|
75804
|
+
action: optNote,
|
|
75805
|
+
result: optNote
|
|
75793
75806
|
});
|
|
75794
75807
|
var InterviewQuestionSchema = external_exports.object({
|
|
75795
|
-
question: external_exports.string(),
|
|
75796
|
-
intent: external_exports.string().optional().describe("\uC9C8\uBB38 \uC758\uB3C4"),
|
|
75797
|
-
followups:
|
|
75798
|
-
answer_outline:
|
|
75808
|
+
question: external_exports.string().max(MAX_NOTE),
|
|
75809
|
+
intent: external_exports.string().max(MAX_NOTE).optional().describe("\uC9C8\uBB38 \uC758\uB3C4"),
|
|
75810
|
+
followups: strList.optional().describe("\uC608\uC0C1 \uAF2C\uB9AC \uC9C8\uBB38"),
|
|
75811
|
+
answer_outline: optBody.describe("\uB2F5\uBCC0 \uAC00\uC774\uB4DC/\uD575\uC2EC \uD3EC\uC778\uD2B8")
|
|
75799
75812
|
});
|
|
75800
75813
|
var InterviewPrepInputSchema = external_exports.object({
|
|
75801
|
-
job_id:
|
|
75802
|
-
questions: external_exports.array(InterviewQuestionSchema).optional(),
|
|
75803
|
-
star_guides: external_exports.array(StarGuideSchema).optional(),
|
|
75804
|
-
self_introduction:
|
|
75805
|
-
notes:
|
|
75814
|
+
job_id: reqLine,
|
|
75815
|
+
questions: external_exports.array(InterviewQuestionSchema).max(MAX_ITEMS).optional(),
|
|
75816
|
+
star_guides: external_exports.array(StarGuideSchema).max(MAX_ITEMS).optional(),
|
|
75817
|
+
self_introduction: optBody.describe("1\uBD84 \uC790\uAE30\uC18C\uAC1C \uCD08\uC548"),
|
|
75818
|
+
notes: optNote.describe("\uBA74\uC811 \uD6C4\uAE30/\uBA54\uBAA8")
|
|
75806
75819
|
});
|
|
75807
75820
|
var InterviewPrepRecordSchema = external_exports.object({
|
|
75808
75821
|
...baseRecord,
|
|
@@ -75856,7 +75869,7 @@ var ApplicationContextSchema = external_exports.object({
|
|
|
75856
75869
|
});
|
|
75857
75870
|
|
|
75858
75871
|
// packages/shared/src/build-info.ts
|
|
75859
|
-
var APP_VERSION = true ? "0.1.
|
|
75872
|
+
var APP_VERSION = true ? "0.1.4" : "0.0.0-dev";
|
|
75860
75873
|
var BUNDLED = true;
|
|
75861
75874
|
|
|
75862
75875
|
// packages/shared/src/index.ts
|
|
@@ -77931,9 +77944,19 @@ async function finishPdf(buf, base) {
|
|
|
77931
77944
|
});
|
|
77932
77945
|
return base("pdf", { text, bytes: buf.length, warnings: pageWarnings });
|
|
77933
77946
|
} catch (e) {
|
|
77947
|
+
const name = e && typeof e === "object" && "name" in e ? String(e.name) : "";
|
|
77948
|
+
if (name === "PasswordException") {
|
|
77949
|
+
return base("unsupported", {
|
|
77950
|
+
bytes: buf.length,
|
|
77951
|
+
warnings: [
|
|
77952
|
+
"\uC774 PDF\uB294 \uC554\uD638(\uBE44\uBC00\uBC88\uD638)\uB85C \uBCF4\uD638\uB418\uC5B4 \uC788\uC5B4 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. PDF \uBDF0\uC5B4\uC5D0\uC11C \uC554\uD638\uB97C \uD574\uC81C\uD574 \uB2E4\uC2DC \uC800\uC7A5\uD558\uAC70\uB098, \uB0B4\uC6A9\uC744 \uD14D\uC2A4\uD2B8\uB85C \uBD99\uC5EC\uB123\uC5B4 \uC8FC\uC138\uC694."
|
|
77953
|
+
],
|
|
77954
|
+
unsupported: true
|
|
77955
|
+
});
|
|
77956
|
+
}
|
|
77934
77957
|
return base("unsupported", {
|
|
77935
77958
|
bytes: buf.length,
|
|
77936
|
-
warnings: [`PDF\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errMsg(e)}). \
|
|
77959
|
+
warnings: [`PDF\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(${errMsg(e)}). \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 PDF\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uB85C \uBD99\uC5EC\uB123\uC5B4 \uC8FC\uC138\uC694.`],
|
|
77937
77960
|
unsupported: true
|
|
77938
77961
|
});
|
|
77939
77962
|
}
|
|
@@ -78487,13 +78510,12 @@ ${lines}`;
|
|
|
78487
78510
|
name: "add_resume",
|
|
78488
78511
|
title: "\uC774\uB825\uC11C/\uACBD\uB825\uAE30\uC220\uC11C \uCD94\uAC00",
|
|
78489
78512
|
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.",
|
|
78513
|
+
// Reuse the shared (length-bounded, whitespace-rejecting) Document schema so
|
|
78514
|
+
// the MCP ingestion path — the primary route for résumé text — inherits the
|
|
78515
|
+
// same caps as the web API. kind stays optional here (defaults to resume).
|
|
78490
78516
|
inputSchema: {
|
|
78491
|
-
|
|
78492
|
-
|
|
78493
|
-
kind: external_exports.enum(DOCUMENT_KINDS).optional().describe("resume(\uC774\uB825\uC11C)/career_description(\uACBD\uB825\uAE30\uC220\uC11C)/portfolio/other"),
|
|
78494
|
-
source: external_exports.enum(CONTENT_SOURCES).optional(),
|
|
78495
|
-
is_primary: external_exports.boolean().optional().describe("\uB300\uD45C \uBB38\uC11C \uC5EC\uBD80"),
|
|
78496
|
-
tags: external_exports.array(external_exports.string()).optional()
|
|
78517
|
+
...DocumentInputSchema.omit({ kind: true }).shape,
|
|
78518
|
+
kind: external_exports.enum(DOCUMENT_KINDS).optional().describe("resume(\uC774\uB825\uC11C)/career_description(\uACBD\uB825\uAE30\uC220\uC11C)/portfolio/other")
|
|
78497
78519
|
},
|
|
78498
78520
|
handler: (args) => {
|
|
78499
78521
|
const doc = addResume(args);
|