careermate 0.1.0 → 0.1.1

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 (93) hide show
  1. package/README.md +10 -7
  2. package/apps/mcp/src/index.ts +3 -1
  3. package/apps/web/DESIGN_GUIDE.md +2 -2
  4. package/apps/web/public/icon-180.png +0 -0
  5. package/apps/web/public/index.html +4 -1
  6. package/apps/web/public/lib.js +1 -1
  7. package/apps/web/public/pages/applications.js +17 -1
  8. package/apps/web/public/pages/settings.js +6 -4
  9. package/apps/web/public/styles.css +49 -36
  10. package/apps/web/src/info.ts +9 -22
  11. package/apps/web/src/routes.ts +17 -13
  12. package/apps/web/src/server.ts +33 -25
  13. package/apps/web/src/settings.ts +35 -17
  14. package/bin/careermate.mjs +8 -5
  15. package/dist/{mcpb-stage/dist/web.mjs → doctor.mjs} +1122 -1450
  16. package/dist/install-page/favicon.svg +1 -0
  17. package/dist/install-page/icon-180.png +0 -0
  18. package/dist/install-page/icon-512.png +0 -0
  19. package/dist/install-page/index.html +309 -167
  20. package/dist/install-page/llms-install.txt +202 -0
  21. package/dist/install-page/og.png +0 -0
  22. package/dist/install-page/shots/applications-dark.png +0 -0
  23. package/dist/install-page/shots/applications-light.png +0 -0
  24. package/dist/install-page/shots/documents-dark.png +0 -0
  25. package/dist/install-page/shots/documents-light.png +0 -0
  26. package/dist/install-page/shots/home-dark.png +0 -0
  27. package/dist/install-page/shots/home-light.png +0 -0
  28. package/dist/install-page/shots/interview-dark.png +0 -0
  29. package/dist/install-page/shots/interview-light.png +0 -0
  30. package/dist/install-page/shots/jobs-dark.png +0 -0
  31. package/dist/install-page/shots/jobs-light.png +0 -0
  32. package/dist/install-page/shots/settings-dark.png +0 -0
  33. package/dist/install-page/shots/settings-light.png +0 -0
  34. package/dist/install-page/start.html +346 -0
  35. package/dist/install-page/style.css +94 -3
  36. package/dist/mcp.mjs +326 -68
  37. package/dist/migrate.mjs +4715 -0
  38. package/dist/public/icon-180.png +0 -0
  39. package/dist/public/index.html +4 -1
  40. package/dist/public/lib.js +1 -1
  41. package/dist/public/pages/applications.js +17 -1
  42. package/dist/public/pages/settings.js +6 -4
  43. package/dist/public/styles.css +49 -36
  44. package/dist/web.mjs +323 -129
  45. package/docs/DEMO.md +3 -3
  46. package/docs/MCP_TOOLS.md +21 -2
  47. package/docs/ROADMAP.md +3 -3
  48. package/docs/RUNTIME_DISTRIBUTION_RESEARCH.md +135 -0
  49. package/docs/START_WORKFLOW.md +6 -0
  50. package/docs/SUPPORTED_AI_APPS.md +85 -33
  51. package/docs/WORKFLOWS.md +1 -1
  52. package/package.json +3 -2
  53. package/packages/core/src/services.ts +42 -1
  54. package/packages/db/src/connection.ts +30 -0
  55. package/packages/db/src/index.ts +1 -0
  56. package/packages/db/src/repositories.ts +109 -63
  57. package/packages/db/src/schema.ts +118 -0
  58. package/packages/exporters/src/html.ts +9 -12
  59. package/packages/mcp-tools/src/tools.ts +81 -0
  60. package/packages/shared/src/enums.ts +39 -0
  61. package/scripts/build-dist.mjs +27 -8
  62. package/scripts/build-mcpb.mjs +60 -4
  63. package/scripts/gen-og.mjs +86 -0
  64. package/scripts/init.ts +32 -3
  65. package/scripts/seed.ts +5 -5
  66. package/scripts/shots-seed.ts +192 -0
  67. package/scripts/shots.ts +89 -0
  68. package/tsconfig.json +3 -1
  69. package/dist/careermate.mcpb +0 -0
  70. package/dist/mcp-smoke.err +0 -3
  71. package/dist/mcpb-stage/README.md +0 -219
  72. package/dist/mcpb-stage/dist/install-page/index.html +0 -434
  73. package/dist/mcpb-stage/dist/install-page/style.css +0 -407
  74. package/dist/mcpb-stage/dist/install-page/vercel.json +0 -20
  75. package/dist/mcpb-stage/dist/mcp.mjs +0 -23704
  76. package/dist/mcpb-stage/dist/public/app.js +0 -118
  77. package/dist/mcpb-stage/dist/public/index.html +0 -41
  78. package/dist/mcpb-stage/dist/public/lib.js +0 -282
  79. package/dist/mcpb-stage/dist/public/pages/applications.js +0 -98
  80. package/dist/mcpb-stage/dist/public/pages/documents.js +0 -446
  81. package/dist/mcpb-stage/dist/public/pages/home.js +0 -263
  82. package/dist/mcpb-stage/dist/public/pages/interview.js +0 -230
  83. package/dist/mcpb-stage/dist/public/pages/jobs.js +0 -494
  84. package/dist/mcpb-stage/dist/public/pages/profile.js +0 -576
  85. package/dist/mcpb-stage/dist/public/pages/settings.js +0 -233
  86. package/dist/mcpb-stage/dist/public/styles.css +0 -420
  87. package/dist/mcpb-stage/manifest.json +0 -40
  88. package/docs/INSTALL.md +0 -148
  89. package/docs/INSTALL_AND_USAGE.md +0 -99
  90. package/install-page/index.html +0 -474
  91. package/install-page/style.css +0 -391
  92. package/install-page/vercel.json +0 -20
  93. /package/dist/{mcpb-stage/dist/public → install-page}/fonts/PretendardVariable.woff2 +0 -0
@@ -0,0 +1,202 @@
1
+ # CareerMate 설치 지시문 (AI 에이전트용) · 공개본
2
+
3
+ 이 파일은 https://careermate.life/llms-install.txt 에서 AI 에이전트가 직접 읽도록 호스팅된
4
+ 설치 런북입니다. 사용자가 "이 URL을 읽고 CareerMate를 설치해줘"라고 하면, 당신(AI)이 아래
5
+ 순서를 그대로 따르세요. **빈 폴더에서 시작해도 됩니다 — 소스를 미리 받아둘 필요가 없습니다.**
6
+ (이 문서는 npm 패키지 `careermate`를 가리키므로 항상 최신입니다.)
7
+
8
+ CareerMate란: **MCP 우선 로컬 커리어 워크스페이스**입니다. 내부에 LLM이 없습니다 — 분석·글쓰기
9
+ 같은 "생각"은 당신(사용자의 AI)이 하고, CareerMate는 커리어 데이터를 이 컴퓨터에만 구조화해
10
+ 저장·조회합니다. "당신의 AI가 두뇌, CareerMate는 커리어 서랍장."
11
+
12
+ ────────────────────────────────────────────────────────
13
+ 0. 대원칙 (반드시 지킬 것)
14
+ ────────────────────────────────────────────────────────
15
+ - 동의 먼저: 파일을 만들거나 서버를 켜거나 **시스템에 무언가 설치(예: Node)하기 전에**, 무엇을
16
+ 왜 하는지 한국어로 설명하고 사용자 동의를 받습니다.
17
+ - 설명 먼저, 실행 나중: 각 명령 전에 한 줄로 알립니다.
18
+ - 로컬 전용: 모든 데이터는 `~/.careermate`에만 저장됩니다. 어떤 단계에서도 외부로 업로드하지
19
+ 않습니다.
20
+ - 개인 파일(이력서·자소서 등)은 설치 단계에서 읽지 않습니다. 사용자가 그 단계를 요청할 때만.
21
+ - 실패하면 멈추지 말고 7번 "문제 해결"을 안내합니다.
22
+
23
+ ────────────────────────────────────────────────────────
24
+ 1. 사전 점검 — Node.js (런타임, 유일한 전제)
25
+ ────────────────────────────────────────────────────────
26
+ CareerMate MCP 서버는 Node 프로그램입니다. 먼저 확인하세요:
27
+
28
+ node --version
29
+
30
+ - **v22.5.0 이상**이면 통과 (CareerMate는 Node 내장 `node:sqlite`를 써서 컴파일·네이티브
31
+ 빌드가 필요 없습니다).
32
+ - 명령이 없거나 버전이 낮으면 → **사용자 동의를 받은 뒤** 설치:
33
+ · Windows(PowerShell): winget install OpenJS.NodeJS.LTS
34
+ · macOS: brew install node
35
+ · 그 외 / 위가 안 되면: https://nodejs.org 에서 LTS 설치
36
+ 설치 후 **터미널을 새로 열어** `node --version`을 다시 확인합니다.
37
+ - 사용자가 **Claude Desktop만** 쓰고 터미널을 원치 않으면 → 여기서 멈추고 `.mcpb` 설치로
38
+ 안내하세요: https://careermate.life 에서 `careermate.mcpb`를 받아, Claude Desktop의
39
+ **Settings → Extensions → Advanced settings → Install extension…** 에서 그 파일을 선택해 추가
40
+ (Windows에서 더블클릭·드래그는 파일 연결이 안 잡혀 무반응일 수 있으니 반드시 이 메뉴 경로를 쓰세요).
41
+ Claude Desktop은 Node를 내장하므로 터미널이 필요 없지만, **내장 Node 버전에 따라 설치가 막히거나
42
+ 불안정할 수 있습니다** — 잘 안 되면 아래 3·4번(npm 설치)로 안내하세요.
43
+
44
+ ────────────────────────────────────────────────────────
45
+ 2. 동의 받기 (여기서 멈추고 확인)
46
+ ────────────────────────────────────────────────────────
47
+ 아래를 그대로 보여주고 동의를 받은 뒤에만 진행합니다.
48
+ "설치하면 CareerMate는 다음을 합니다. 진행할까요?"
49
+ [ ] 데이터 폴더 `~/.careermate` 생성
50
+ [ ] 로컬 SQLite DB `careermate.sqlite` 생성
51
+ [ ] 로컬 대시보드 `http://127.0.0.1:4319` 실행(요청 시) — 외부 접근 불가(127.0.0.1 전용)
52
+ [ ] 모든 데이터를 이 컴퓨터에만 저장 (외부 업로드 없음)
53
+
54
+ ────────────────────────────────────────────────────────
55
+ 3. 설치 — npm으로 `~/.careermate/app`에 (clone·zip 불필요)
56
+ ────────────────────────────────────────────────────────
57
+ 글로벌 설치(`-g`)나 npx 즉석 실행 대신, **한곳에 설치하고 절대경로로 참조**합니다. 가장
58
+ 안정적입니다(글로벌 PATH 문제 없음, 매 실행 재해석 없음, 데이터와 같은 곳에 보관).
59
+
60
+ # macOS / Linux / Git Bash:
61
+ npm install --prefix "$HOME/.careermate/app" careermate
62
+
63
+ # Windows PowerShell:
64
+ npm install --prefix "$env:USERPROFILE\.careermate\app" careermate
65
+
66
+ 설치 후 실행 진입점(이하 <BIN>)은 **이 절대경로**입니다:
67
+ · macOS/Linux: $HOME/.careermate/app/node_modules/careermate/bin/careermate.mjs
68
+ · Windows: %USERPROFILE%\.careermate\app\node_modules\careermate\bin\careermate.mjs
69
+
70
+ <BIN>은 항상 **그 사용자의 실제 절대경로로 치환**해 사용하세요. `~`나 `$HOME`은 설정 파일
71
+ 안에서 확장되지 않습니다. (`node <BIN> mcp`가 MCP 서버를 띄우는 명령이며, `--experimental-sqlite`
72
+ 플래그는 <BIN>이 알아서 붙입니다.)
73
+
74
+ ▸ 대안(권장 — GUI 앱·샌드박스 친화): **작업 폴더 안에 전부 설치.**
75
+ 사용자가 Claude "Code" 탭이나 Codex 앱처럼 **작업 폴더(cwd)를 잡고** 쓰는 경우, 설치물과 데이터를
76
+ 그 폴더 안에 두면 (1) 폴더만 백업·이동하면 데이터가 따라오고 (2) Codex의 workspace-write 샌드박스가
77
+ cwd 하위 쓰기를 허용해 설치 단계 권한 마찰이 줄어듭니다. <WS>를 그 작업 폴더의 절대경로라 할 때:
78
+ npm install --prefix "<WS>/.cm/app" careermate
79
+ 그러면 <BIN> = <WS>/.cm/app/node_modules/careermate/bin/careermate.mjs 이고, 데이터는 아래처럼
80
+ MCP 등록의 env로 작업 폴더 안에 고정합니다(기본값 ~/.careermate 대신):
81
+ CAREERMATE_DATA_DIR = <WS>/.cm/data
82
+ 주의: 데이터 폴더 이름을 `.git`/`.codex`/`.agents`로 두지 마세요(앱이 읽기 전용으로 보호).
83
+
84
+ ────────────────────────────────────────────────────────
85
+ 4. 연결 — 사용 중인 AI 앱의 MCP 설정에 등록
86
+ ────────────────────────────────────────────────────────
87
+ 사용자가 쓰는 앱에 맞춰, 서버 명령을 `node <BIN> mcp`로 등록합니다.
88
+
89
+ ▸ Claude Code (또는 Claude Desktop의 "Code" 탭):
90
+ 지금 작업 중인(또는 열) **그 폴더에** `.mcp.json` 파일을 만들고 아래 내용을 넣으세요.
91
+ (이 폴더가 곧 Claude Code 프로젝트입니다. 빈 폴더여도 됩니다.)
92
+
93
+ {
94
+ "mcpServers": {
95
+ "careermate": {
96
+ "type": "stdio",
97
+ "command": "node",
98
+ "args": ["<BIN>", "mcp"]
99
+ }
100
+ }
101
+ }
102
+
103
+ · Windows 경로는 JSON에서 백슬래시를 `\\`로 이스케이프하거나 `/`로 쓰세요.
104
+ · 작업 폴더 안에 데이터를 두려면(위 3번 대안) `args` 옆에 env를 추가:
105
+ "env": { "CAREERMATE_DATA_DIR": "<WS>/.cm/data" }
106
+ · 또는 명령으로: claude mcp add --scope project --transport stdio careermate -- node <BIN> mcp
107
+
108
+ ▸ Codex: `~/.codex/config.toml`에 아래 테이블을 추가(있으면 교체):
109
+
110
+ [mcp_servers.careermate]
111
+ command = "node"
112
+ args = ["<BIN>", "mcp"]
113
+ # 작업 폴더 안에 데이터를 두려면(위 3번 대안):
114
+ # env = { CAREERMATE_DATA_DIR = "<WS>/.cm/data" }
115
+
116
+ · 또는 명령으로: codex mcp add careermate -- node <BIN> mcp
117
+ · ⚠️ Codex 주의(2026-06): 데스크톱 앱은 시작 시 `~/.codex/config.toml`을 재작성해 등록이 사라질 수
118
+ 있고(openai/codex#24718), 프로젝트 `.codex/config.toml`은 무시합니다(#13025). 이 재작성은 '승인'으로
119
+ 못 풀립니다 → **전역 config + 가능하면 Codex CLI**를 쓰세요(데스크톱보다 안정적). 또한 기본
120
+ workspace-write 샌드박스는 네트워크가 꺼져 있어 설치 단계 `npm install`에 네트워크 1회 허용(또는
121
+ `[sandbox_workspace_write] network_access = true`)이 필요합니다 — 이건 사용자가 승인하면 풀립니다.
122
+ (MCP 서버 자체는 샌드박스 밖에서 돌아, 일단 연결되면 데이터 읽기/쓰기는 막히지 않습니다. 대시보드
123
+ 127.0.0.1는 선택 기능이며 샌드박스에서 셸로 띄울 땐 로컬 포트 허용이 필요할 수 있습니다.)
124
+
125
+ ▸ Cursor: `~/.cursor/mcp.json`에 위 Claude Code와 같은 `mcpServers` 블록을 추가.
126
+
127
+ ▸ Gemini CLI / Antigravity: Gemini CLI는 `~/.gemini/settings.json`의 `mcpServers`에 같은 블록을 추가
128
+ (`type` 키는 없어도 됨). 단 **2026-06-18부터 소비자용 Gemini CLI는 Antigravity로 전환**됩니다 —
129
+ Antigravity는 `~/.gemini/(config|antigravity|antigravity-cli)/mcp_config.json` 중 **이미 있는 파일**의
130
+ `mcpServers`에 추가하세요(스키마 동일). `node <BIN> init`은 Gemini를 자동 등록하고 Antigravity는
131
+ 후보 파일이 있을 때만 등록합니다.
132
+
133
+ ▸ Claude Desktop(앱 본체, "Code" 탭이 아닌 채팅): `.mcpb` 원클릭이 가장 쉽습니다(1번 끝의
134
+ 안내). 굳이 수동이면 `claude_desktop_config.json`의 `mcpServers`에 같은 블록을 추가.
135
+
136
+ 단축: `node <BIN> init`을 실행하면 **감지된 Codex·Cursor·Claude Desktop·Gemini 전역 설정**을 올바른
137
+ 절대경로로 자동 등록하고 `~/.careermate`도 만듭니다(Antigravity는 후보 설정 파일이 이미 있을 때만).
138
+ 단 **Claude Code의 프로젝트 `.mcp.json`은 위처럼 작업 폴더에 직접** 만드세요(전역 설정이 아니므로
139
+ init이 대신 못 둡니다).
140
+
141
+ ────────────────────────────────────────────────────────
142
+ 5. 마무리 — 재시작 · 승인 · 검증
143
+ ────────────────────────────────────────────────────────
144
+ 1) 연결한 AI 앱을 **완전히 종료했다 다시** 켭니다.
145
+ 2) Claude Code/Code 탭이면 프로젝트 `.mcp.json`에 대해 **1회 승인**을 물을 때 허용합니다.
146
+ 3) 사용자가 AI에게: "**get_onboarding_status 호출해서 연결됐는지 확인해줘**". 응답이 오면 성공.
147
+ (Codex는 `/mcp`로 careermate 등록 여부도 확인 가능.)
148
+ 4) 대시보드(선택): node <BIN> start → http://127.0.0.1:4319 (종료: Ctrl+C)
149
+
150
+ ────────────────────────────────────────────────────────
151
+ 6. 데이터 위치 / 환경변수
152
+ ────────────────────────────────────────────────────────
153
+ - 데이터: `~/.careermate` (Windows: `%USERPROFILE%\.careermate`). 안에 careermate.sqlite,
154
+ exports/, backups/, uploads/, server.json.
155
+ - `CAREERMATE_DATA_DIR` — 데이터 폴더 위치 변경.
156
+ - `CAREERMATE_PORT` — 대시보드 포트 고정(기본 4319, 사용 중이면 자동으로 다음 포트).
157
+ - `CAREERMATE_NO_OPEN=1` — 대시보드 시작 시 브라우저 자동 열기 비활성화(값이 정확히 `1`일 때만).
158
+
159
+ ────────────────────────────────────────────────────────
160
+ 7. 문제 해결
161
+ ────────────────────────────────────────────────────────
162
+ - 연결이 안 보이면: ① <BIN> 절대경로가 맞는지 ② `node --version`이 22.5+인지 ③ 설치(npm install)가
163
+ 끝났는지 ④ 설정 파일 경로·이름이 맞는지 확인한 뒤 **AI 앱을 완전히 재시작**.
164
+ - 다시 설치(업데이트): npm install --prefix "<설치 prefix>" careermate@latest 후 AI 앱 재시작.
165
+ - DB는 MCP 서버가 켜질 때 자동으로 생성·마이그레이트하므로 보통 따로 손댈 일이 없습니다.
166
+ - 데이터를 완전히 비우려면 `~/.careermate/backups/`로 먼저 백업한 뒤
167
+ `~/.careermate/careermate.sqlite`를 지우고 AI 앱을 재시작하면 새로 만들어집니다(되돌릴 수 없으니 백업 먼저).
168
+
169
+ ────────────────────────────────────────────────────────
170
+ 8. 설치 완료 카드 — 사용자에게 보여주고 마무리
171
+ ────────────────────────────────────────────────────────
172
+ 연결 검증(5번)까지 끝났으면, 사용자에게 아래 "완료 카드"를 쉬운 한국어로 보여주세요(도구
173
+ 이름은 노출하지 말 것). 다음에 뭘 하면 되는지 한눈에 알게 하는 게 목적입니다. **지금 네가
174
+ 돌고 있는 앱에 맞는 항목만 골라** 안내하세요(공통 '붙여넣기'는 항상 포함).
175
+
176
+ ✅ 설치 끝! 이제 이렇게 시작하세요
177
+
178
+ 1) (아직이면) 이 앱을 완전히 껐다 다시 켜세요. 처음 한 번 뜨는 승인 창은 '허용'을 누르세요.
179
+
180
+ 2) 이력서를 저에게 주세요 — 편한 방법 아무거나:
181
+ · [공통·제일 쉬움] 이력서 '내용'을 복사해서 대화창에 그대로 붙여넣기. 파일이 어디 있든 상관없어요.
182
+ · [Claude 채팅(.mcpb)] 채팅창에 이력서 파일을 직접 첨부.
183
+ · [폴더 기반 — Claude Code 탭 / Codex / Antigravity 등] 작업 폴더에 파일을 두고
184
+ "이력서.pdf 읽어서 등록해줘"처럼 파일명·경로로 알려주기.
185
+ · ⚠️ 스캔본(이미지) PDF나 보안 걸린 파일은 못 읽을 수 있어요 → 그때는 내용을 텍스트로 붙여넣어 주세요.
186
+ 그리고 "내 이력서로 처음 세팅 해줘" 한마디면 제가 프로필·이력서로 정리해 저장합니다.
187
+
188
+ 3) 대시보드에서 눈으로 확인: http://127.0.0.1:4319
189
+ (안 열려 있으면 "대시보드 열어줘"라고 하세요. 포트가 바뀌면 실제 주소를 알려드릴게요.)
190
+
191
+ * 데이터는 전부 이 컴퓨터(~/.careermate)에만 저장돼요. 어디로도 올라가지 않습니다.
192
+
193
+ 헷갈려 할 때 한 줄 안내:
194
+ - "이력서 주기·세팅해줘" 같은 말은 전부 '저와의 대화창'에 자연어로 하면 됩니다(명령어가 아니에요).
195
+ - 설치 때 친 명령어(npm·node…)는 '터미널'에서 돈 것이고, 보통 제가 대신 실행했습니다.
196
+ · Claude Code 탭 / Codex = 터미널 안에서 저와 대화(한 창). · Claude 채팅 앱 = 터미널 없이 채팅창만.
197
+
198
+ 그 다음부터는 평소 흐름입니다(공고 저장 → 적합도 분석 → 자소서 작성 → 지원 상태 관리 → 면접 준비).
199
+ **무언가를 저장·완료할 때마다 대시보드 주소(위)를 알려주세요.** 단 브라우저를 자동으로 새로 여는 건
200
+ **첫 온보딩 때 한 번만** — 이후엔 링크만 보여주고, 사용자가 "열어줘"라고 하면 그때 엽니다. 자소서 등
201
+ "사람이 쓴 듯한 글"을 쓰기 직전에는 `get_writing_style_guide`를, 분석·작성 직전에는
202
+ `get_application_context`를 먼저 호출하세요.
Binary file
@@ -0,0 +1,346 @@
1
+ <!DOCTYPE html>
2
+ <html lang="ko" data-theme="dark">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <script>
7
+ (function () {
8
+ try {
9
+ var t = window.localStorage.getItem('cf-theme');
10
+ document.documentElement.setAttribute('data-theme', t === 'light' || t === 'dark' ? t : 'dark');
11
+ } catch (e) { document.documentElement.setAttribute('data-theme', 'dark'); }
12
+ })();
13
+ </script>
14
+ <title>처음이세요? — CareerMate 시작하기</title>
15
+ <meta name="description" content="터미널이 뭔지 몰라도 괜찮아요. 쓰는 AI와 컴퓨터만 고르면, 당신에게 맞는 설치 길 하나를 처음부터 알려드립니다." />
16
+ <meta name="robots" content="index,follow" />
17
+ <link rel="icon" href="favicon.svg" type="image/svg+xml" />
18
+ <meta name="theme-color" content="#faf8f4" media="(prefers-color-scheme: light)" />
19
+ <meta name="theme-color" content="#14130f" media="(prefers-color-scheme: dark)" />
20
+ <link rel="preload" href="fonts/PretendardVariable.woff2" as="font" type="font/woff2" crossorigin />
21
+ <link rel="stylesheet" href="style.css" />
22
+ <style>
23
+ /* 선택형 위저드 — start.html 전용. style.css 토큰 재사용. */
24
+ .wizard { max-width: 760px; margin: 0 auto; }
25
+ .q { margin: 0 0 1.6rem; }
26
+ .q__label { font-weight: 650; margin: 0 0 .7rem; font-size: 1.02rem; }
27
+ .q__label .num { color: var(--accent); margin-right: .4rem; }
28
+ .choices { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
29
+ .choice { position: relative; display: block; cursor: pointer; border: 1.5px solid var(--border-strong);
30
+ border-radius: var(--radius); background: var(--surface); padding: .85rem 1rem; transition: border-color .12s, background .12s; }
31
+ .choice:hover { background: var(--surface-hover); }
32
+ .choice input { position: absolute; opacity: 0; pointer-events: none; }
33
+ .choice.is-sel { border-color: var(--accent); background: var(--accent-soft); }
34
+ .choice__t { font-weight: 600; display: block; }
35
+ .choice__s { color: var(--text-tertiary); font-size: .85rem; display: block; margin-top: .15rem; }
36
+ .result { display: none; margin-top: 2rem; padding-top: 1.6rem; border-top: 1px solid var(--border); }
37
+ .result.show { display: block; }
38
+ .path { display: none; }
39
+ .path.show { display: block; }
40
+ .os-win, .os-mac { display: none; }
41
+ .result[data-os="win"] .os-win { display: revert; }
42
+ .result[data-os="mac"] .os-mac { display: revert; }
43
+ li.step.os-win, li.step.os-mac { display: none; }
44
+ .result[data-os="win"] li.step.os-win { display: flex; }
45
+ .result[data-os="mac"] li.step.os-mac { display: flex; }
46
+ .path__tag { display: inline-block; font-size: .78rem; font-weight: 650; color: var(--accent);
47
+ background: var(--accent-soft); border: 1px solid var(--accent-border); border-radius: 999px; padding: .15rem .6rem; margin-bottom: .5rem; }
48
+ .filenote { margin-top: .9rem; font-size: .9rem; color: var(--text-secondary);
49
+ background: var(--bg-subtle); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .7rem .9rem; }
50
+ .subcard { border: 1px solid var(--border); border-radius: var(--radius); padding: 1.1rem 1.2rem; margin: 1rem 0; background: var(--bg-elev); }
51
+ .hint { color: var(--text-tertiary); font-size: .9rem; }
52
+ </style>
53
+ </head>
54
+ <body>
55
+ <nav class="nav">
56
+ <a class="nav__brand" href="index.html#top">
57
+ <span class="nav__logo" aria-hidden="true">C</span>
58
+ <span class="nav__name">CareerMate</span>
59
+ </a>
60
+ <div class="nav__links">
61
+ <a href="index.html#how">동작 방식</a>
62
+ <a href="index.html#install">설치 전체</a>
63
+ </div>
64
+ <div class="nav__actions">
65
+ <button class="theme-toggle" id="theme-toggle" type="button" aria-label="다크 모드 전환" title="다크 모드 전환">
66
+ <svg class="i-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
67
+ <svg class="i-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
68
+ </button>
69
+ </div>
70
+ </nav>
71
+
72
+ <main id="top">
73
+ <header class="hero">
74
+ <span class="pill-badge"><span class="pill-badge__dot" aria-hidden="true"></span> 처음이세요?</span>
75
+ <h1 class="hero__title">터미널이 뭔지 몰라도<br /><span class="accent">괜찮아요</span></h1>
76
+ <p class="hero__lede">
77
+ <strong>쓰는 AI</strong>와 <strong>컴퓨터</strong>만 고르면,<br />
78
+ 당신에게 맞는 설치 길 <strong>하나</strong>를 처음부터 알려드립니다.
79
+ </p>
80
+ </header>
81
+
82
+ <section class="section" style="padding-top:0">
83
+ <div class="wizard">
84
+ <!-- Q1 -->
85
+ <div class="q">
86
+ <p class="q__label"><span class="num">1</span>어떤 AI를 쓰고 있나요?</p>
87
+ <div class="choices" id="q-sub" role="radiogroup" aria-label="쓰는 AI">
88
+ <label class="choice"><input type="radio" name="sub" value="claude" />
89
+ <span class="choice__t">Claude 유료</span><span class="choice__s">Pro·Max 구독</span></label>
90
+ <label class="choice"><input type="radio" name="sub" value="chatgpt" />
91
+ <span class="choice__t">ChatGPT 유료</span><span class="choice__s">Plus 이상 구독</span></label>
92
+ <label class="choice"><input type="radio" name="sub" value="free" />
93
+ <span class="choice__t">무료 / 잘 모름</span><span class="choice__s">유료 구독 없음</span></label>
94
+ </div>
95
+ </div>
96
+ <!-- Q2 -->
97
+ <div class="q">
98
+ <p class="q__label"><span class="num">2</span>컴퓨터는요?</p>
99
+ <div class="choices" id="q-os" role="radiogroup" aria-label="운영체제" style="grid-template-columns:repeat(auto-fit,minmax(140px,1fr))">
100
+ <label class="choice"><input type="radio" name="os" value="win" />
101
+ <span class="choice__t">Windows</span></label>
102
+ <label class="choice"><input type="radio" name="os" value="mac" />
103
+ <span class="choice__t">Mac</span></label>
104
+ </div>
105
+ </div>
106
+
107
+ <p class="hint" id="prompt-pick">위 두 가지를 고르면 아래에 당신에게 맞는 길이 나타납니다.</p>
108
+
109
+ <!-- ============ 결과 ============ -->
110
+ <div class="result" id="result" aria-live="polite">
111
+
112
+ <!-- ===== Claude 유료 → Code 탭 ===== -->
113
+ <div class="path" data-sub="claude">
114
+ <span class="path__tag">당신에겐 — Claude "Code" 탭</span>
115
+ <h2>Claude 데스크톱 앱의 <span class="accent">Code 탭</span>으로</h2>
116
+ <p>이미 Claude를 구독 중이라 추가 비용 없이 가장 매끄럽습니다.<br />앱 안에서 끝나 별도 터미널이 필요 없습니다.</p>
117
+ <ol class="steps">
118
+ <li class="step"><div class="step__no">1</div><div class="step__body">
119
+ <h3>Claude 데스크톱 설치 → 로그인</h3>
120
+ <p><a href="https://claude.ai/download" rel="noopener" target="_blank">claude.ai/download</a>에서 받아 설치하고 본인 계정으로 로그인하세요.</p>
121
+ </div></li>
122
+ <li class="step os-win"><div class="step__no">2</div><div class="step__body">
123
+ <h3>(Windows) Git 설치</h3>
124
+ <p>Code 탭을 처음 열면 앱이 <strong>"Git is required"</strong>라고 안내합니다.<br /><a href="https://git-scm.com/download/win" rel="noopener" target="_blank">git-scm.com/download/win</a>에서 설치하고 앱을 다시 켜면 됩니다. (Mac은 필요 없습니다.)</p>
125
+ </div></li>
126
+ <li class="step"><div class="step__no">3</div><div class="step__body">
127
+ <h3>Code 탭에서 빈 폴더 선택</h3>
128
+ <p>상단의 <strong>Code</strong> 탭을 누르고, 새 폴더 하나(예: 문서/CareerMate)를 작업 폴더로 고르세요.<br />이 폴더가 CareerMate 작업실이 됩니다.</p>
129
+ </div></li>
130
+ <li class="step"><div class="step__no">4</div><div class="step__body">
131
+ <h3>이 문장 한 번 붙여넣기</h3>
132
+ <div class="code"><button class="copy-btn" type="button" data-copy-target="p-claude">복사</button>
133
+ <pre id="p-claude">https://careermate.life/llms-install.txt 를 읽고, 그 안내대로 CareerMate를 이 폴더에 설치하고 연결해줘. 데이터도 이 폴더의 .cm/data 안에 저장하고, Node 설치처럼 시스템에 바꿀 게 있으면 실행 전에 먼저 알려줘. 설치가 끝나면 앱 재시작 방법과 이력서를 주는 법, 대시보드 주소(http://127.0.0.1:4319)도 알려줘.</pre></div>
134
+ <p class="step__tip"><strong>Node가 없어도 됩니다.</strong> 필요하면 Claude가 먼저 확인하고 설치까지 도와줍니다.<br />직접 받으려면 아래 <strong>'필요한 프로그램 받기'</strong>의 Node.js를 보세요. 설치 중 뜨는 허용 창은 눌러 주세요.</p>
135
+ </div></li>
136
+ <li class="step"><div class="step__no">5</div><div class="step__body">
137
+ <h3>앱 재시작 → 확인</h3>
138
+ <p>Claude 앱을 완전히 껐다 켜고(처음 한 번 MCP 승인을 허용), <strong>"커리어메이트 연결됐는지 확인해줘"</strong>라고 말하면 됩니다.</p>
139
+ </div></li>
140
+ </ol>
141
+ <div class="filenote">📎 <strong>이력서 넣는 법:</strong> 가장 쉬운 방법은 <strong>이력서 내용을 대화창에 붙여넣기</strong>입니다. 또는 작업 폴더에 파일을 넣고 <em>"이력서.pdf 읽어서 등록해줘"</em>라고 하거나 채팅에 직접 첨부하세요. (스캔본·보안 PDF는 안 읽힐 수 있습니다 → 그땐 텍스트로 붙여넣으세요.)</div>
142
+ <p class="hint" style="margin-top:.8rem">터미널이 부담되면 → <a href="index.html#install">파일 하나로 설치(.mcpb)</a>하는 방법도 있습니다(Claude 무료 기능).</p>
143
+ </div>
144
+
145
+ <!-- ===== ChatGPT 유료 → Codex CLI ===== -->
146
+ <div class="path" data-sub="chatgpt">
147
+ <span class="path__tag">당신에겐 — Codex CLI</span>
148
+ <h2>ChatGPT 구독으로 <span class="accent">Codex</span>에서</h2>
149
+ <p>ChatGPT는 <strong>Codex를 터미널(CLI)에서</strong> 씁니다 — 명령을 몇 줄 입력합니다.<br />Codex <strong>데스크톱 앱은 등록이 사라질 수 있어</strong> 권장하지 않습니다. 터미널이 부담되면 <a href="#" data-goto-free>터미널 없이 가능한 무료 길</a>도 있습니다.</p>
150
+ <ol class="steps">
151
+ <li class="step"><div class="step__no">1</div><div class="step__body">
152
+ <h3>Node.js 설치</h3>
153
+ <p class="os-win">Windows: PowerShell에 붙여넣기 →</p>
154
+ <div class="code os-win"><button class="copy-btn" type="button" data-copy-target="p-node-win">복사</button><pre id="p-node-win">winget install OpenJS.NodeJS.LTS</pre></div>
155
+ <p class="os-mac">Mac: 터미널에 붙여넣기(Homebrew 없으면 nodejs.org에서 LTS 설치) →</p>
156
+ <div class="code os-mac"><button class="copy-btn" type="button" data-copy-target="p-node-mac">복사</button><pre id="p-node-mac">brew install node</pre></div>
157
+ <p class="step__tip">명령이 어려우면 <a href="https://nodejs.org/" rel="noopener" target="_blank">nodejs.org</a>에서 <strong>설치 파일을 받아 더블클릭</strong>(계속 '다음')해도 됩니다.<br />설치 후 터미널을 새로 열고 <code>node --version</code>이 v22.5 이상인지 확인하세요. <strong>터미널 여는 법은 아래 도움말</strong>을 참고하세요.</p>
158
+ </div></li>
159
+ <li class="step"><div class="step__no">2</div><div class="step__body">
160
+ <h3>Codex CLI 설치 → ChatGPT 로그인</h3>
161
+ <div class="code"><button class="copy-btn" type="button" data-copy-target="p-codex-install">복사</button><pre id="p-codex-install">npm install -g @openai/codex</pre></div>
162
+ <p class="step__tip">설치 후 <code>codex</code>를 실행하면 ChatGPT 로그인 창이 열립니다(본인 구독 계정).</p>
163
+ </div></li>
164
+ <li class="step"><div class="step__no">3</div><div class="step__body">
165
+ <h3>빈 폴더에서 codex 실행 → 이 문장</h3>
166
+ <div class="code"><button class="copy-btn" type="button" data-copy-target="p-codex">복사</button>
167
+ <pre id="p-codex">https://careermate.life/llms-install.txt 를 읽고, 그 안내대로 CareerMate를 이 폴더에 설치하고 연결해줘. 데이터도 이 폴더의 .cm/data 안에 저장하고, Node 설치처럼 시스템에 바꿀 게 있으면 실행 전에 먼저 알려줘. 설치가 끝나면 앱 재시작 방법과 이력서를 주는 법, 대시보드 주소(http://127.0.0.1:4319)도 알려줘.</pre></div>
168
+ <p class="step__tip">설치 중 <strong>네트워크 허용</strong>을 물으면 한 번 허용하세요(npm 다운로드 때문).</p>
169
+ </div></li>
170
+ <li class="step"><div class="step__no">4</div><div class="step__body">
171
+ <h3>확인</h3>
172
+ <p>Codex 안에서 <code>/mcp</code>를 입력해 <code>careermate</code>가 보이면 연결된 것입니다.</p>
173
+ </div></li>
174
+ </ol>
175
+ <div class="filenote">📎 <strong>이력서 넣는 법:</strong> 첨부 기능이 없으니, 작업 폴더에 파일을 넣고 <em>"./이력서.pdf 읽어서 등록해줘"</em>라고 하세요. PDF가 안 읽히면 내용을 <strong>텍스트로 붙여넣으세요.</strong></div>
176
+ </div>
177
+
178
+ <!-- ===== 무료/없음 → .mcpb 1순위, Antigravity 2순위 ===== -->
179
+ <div class="path" data-sub="free">
180
+ <span class="path__tag">당신에겐 — 무료로 시작</span>
181
+ <h2>유료 구독 없이 <span class="accent">무료로</span></h2>
182
+ <p>유료 구독이 없어도 됩니다. 터미널이 필요 없는, 가장 쉬운 길부터 안내합니다.</p>
183
+
184
+ <div class="subcard">
185
+ <strong>① 1순위 — Claude 데스크톱 + 파일 설치(터미널 없이)</strong>
186
+ <p class="hint" style="margin:.3rem 0 .8rem">Claude 무료 계정이면 됩니다. 터미널·Node 없이 파일 하나로 끝납니다.</p>
187
+ <ol class="steps">
188
+ <li class="step"><div class="step__no">1</div><div class="step__body">
189
+ <h3>Claude 데스크톱 설치 → 로그인(무료 OK)</h3>
190
+ <p><a href="https://claude.ai/download" rel="noopener" target="_blank">claude.ai/download</a>에서 받아 설치하고 로그인하세요.</p>
191
+ </div></li>
192
+ <li class="step"><div class="step__no">2</div><div class="step__body">
193
+ <h3>설치 파일 받기</h3>
194
+ <p><a class="btn btn--ghost" href="careermate.mcpb" download="careermate.mcpb">careermate.mcpb 다운로드 (약 2&nbsp;MB)</a></p>
195
+ </div></li>
196
+ <li class="step"><div class="step__no">3</div><div class="step__body">
197
+ <h3>설정에서 추가</h3>
198
+ <p>Claude 데스크톱 → <strong>Settings → Extensions → Advanced settings → Install extension…</strong> 에서 받은 파일을 고르세요. <span class="hint">(Windows에서 더블클릭·드래그는 반응이 없을 수 있으니 이 메뉴를 쓰세요.)</span></p>
199
+ </div></li>
200
+ <li class="step"><div class="step__no">4</div><div class="step__body">
201
+ <h3>재시작 → 확인</h3>
202
+ <p>앱을 껐다 켜고 <strong>"커리어메이트 연결됐는지 확인해줘"</strong>라고 말하세요. 도구가 보이면 됩니다.</p>
203
+ </div></li>
204
+ </ol>
205
+ <div class="filenote">📎 <strong>이력서 넣는 법:</strong> Claude 채팅창에 파일을 <strong>직접 첨부</strong>하면 됩니다(가장 쉬움).</div>
206
+ <p class="hint" style="margin-top:.7rem">⚠️ 만약 <strong>도구가 안 뜨면</strong>(Claude 내장 Node 버전 문제일 수 있음) → 아래 ②를 쓰세요.</p>
207
+ </div>
208
+
209
+ <div class="subcard">
210
+ <strong>② 안 되거나 더 안정적으로 — Antigravity(무료)</strong>
211
+ <p class="hint" style="margin:.3rem 0 .8rem">Google Antigravity는 <strong>개인 Gmail로 무료</strong>(신용카드 불필요). 앱을 쓰지만 더 안정적입니다.</p>
212
+ <ol class="steps">
213
+ <li class="step"><div class="step__no">1</div><div class="step__body">
214
+ <h3>Antigravity 설치 → Gmail 로그인</h3>
215
+ <p><a href="https://antigravity.google/download" rel="noopener" target="_blank">antigravity.google/download</a>에서 받아 설치하고 개인 Gmail로 로그인(무료 플랜).</p>
216
+ </div></li>
217
+ <li class="step"><div class="step__no">2</div><div class="step__body">
218
+ <h3>빈 폴더 열고 → 이 문장</h3>
219
+ <div class="code"><button class="copy-btn" type="button" data-copy-target="p-anti">복사</button>
220
+ <pre id="p-anti">https://careermate.life/llms-install.txt 를 읽고, 그 안내대로 CareerMate를 이 폴더에 설치하고 연결해줘. 데이터도 이 폴더의 .cm/data 안에 저장하고, Node 설치처럼 시스템에 바꿀 게 있으면 실행 전에 먼저 알려줘. 설치가 끝나면 앱 재시작 방법과 이력서를 주는 법, 대시보드 주소(http://127.0.0.1:4319)도 알려줘.</pre></div>
221
+ </div></li>
222
+ <li class="step"><div class="step__no">3</div><div class="step__body">
223
+ <h3>확인</h3>
224
+ <p>연결 상태를 확인하고(보통 <code>/mcp</code> 또는 "연결됐는지 확인해줘") 끝.</p>
225
+ </div></li>
226
+ </ol>
227
+ <div class="filenote">📎 <strong>이력서 넣는 법:</strong> 작업 폴더에 파일을 넣고 파일명으로 지시. 안 읽히면 텍스트로 붙여넣기.</div>
228
+ <p class="hint" style="margin-top:.7rem">참고: 예전 <strong>Gemini CLI는 2026-06-18부터 무료 종료</strong>되어 Antigravity로 옮겨졌습니다.</p>
229
+ </div>
230
+ </div>
231
+
232
+ </div><!-- /result -->
233
+
234
+ <!-- ===== 초보자 도움말 (항상 펼쳐볼 수 있음) ===== -->
235
+ <div class="help" style="margin-top:2.4rem">
236
+ <p class="q__label" style="margin-bottom:.6rem">도움이 더 필요하면</p>
237
+
238
+ <details class="acc">
239
+ <summary>터미널(명령창)이 처음이세요? — 여는 법 <span class="acc__hint">Codex 등 CLI를 쓸 때</span></summary>
240
+ <div class="acc__body">
241
+ <p><strong>터미널</strong>은 명령을 한 줄씩 입력해 실행하는 창입니다. 이렇게 엽니다:</p>
242
+ <ul>
243
+ <li><strong>Windows</strong> — 시작 버튼 → <code>PowerShell</code> 검색 → <strong>Windows PowerShell</strong> 실행. 붙여넣기는 <strong>마우스 우클릭</strong> 또는 <kbd>Ctrl</kbd>+<kbd>V</kbd>, 실행은 <kbd>Enter</kbd>.</li>
244
+ <li><strong>Mac</strong> — <kbd>⌘</kbd>+<kbd>Space</kbd>(스포트라이트) → <code>Terminal</code> 입력 → 실행. 붙여넣기는 <kbd>⌘</kbd>+<kbd>V</kbd>, 실행은 <kbd>Return</kbd>.</li>
245
+ </ul>
246
+ <p class="hint">순서는 항상 같아요: 명령의 <strong>[복사]</strong> 버튼 → 터미널에 <strong>붙여넣기</strong> → <strong>Enter</strong>.</p>
247
+ </div>
248
+ </details>
249
+
250
+ <details class="acc">
251
+ <summary>필요한 프로그램 받기 (링크 모음) <span class="acc__hint">Node · 앱 · 설치 파일</span></summary>
252
+ <div class="acc__body">
253
+ <ul>
254
+ <li><strong>Node.js (LTS)</strong> — <a href="https://nodejs.org/" rel="noopener" target="_blank">nodejs.org</a> · 설치 파일을 받아 더블클릭(계속 '다음'). 터미널·CLI 경로에 필요.</li>
255
+ <li><strong>Claude 데스크톱</strong> — <a href="https://claude.ai/download" rel="noopener" target="_blank">claude.ai/download</a> · Code 탭 / .mcpb에 사용.</li>
256
+ <li><strong>Git for Windows</strong> — <a href="https://git-scm.com/download/win" rel="noopener" target="_blank">git-scm.com/download/win</a> · <em>Windows에서 Claude Code 탭을 쓸 때만</em>(Mac은 불필요).</li>
257
+ <li><strong>Antigravity</strong>(Google·무료) — <a href="https://antigravity.google/download" rel="noopener" target="_blank">antigravity.google/download</a> · 개인 Gmail 로그인, 카드 불필요.</li>
258
+ <li><strong>CareerMate 설치 파일(.mcpb)</strong> — <a href="careermate.mcpb" download="careermate.mcpb">careermate.mcpb</a> · Claude 데스크톱 "채팅" 앱용(약 2&nbsp;MB).</li>
259
+ </ul>
260
+ <p class="hint">받은 뒤 무엇을 하는지는 위에서 고른 "내게 맞는 길"의 단계를 따르면 됩니다.</p>
261
+ </div>
262
+ </details>
263
+ </div>
264
+
265
+ <p class="hint" style="margin-top:2rem">막히거나 다른 방법이 궁금하면 → <a href="index.html#install">설치 방법 전체 보기</a></p>
266
+ </div>
267
+ </section>
268
+ </main>
269
+
270
+ <footer class="foot">
271
+ <div class="foot__brand"><span class="nav__logo" aria-hidden="true">C</span> CareerMate</div>
272
+ <p>로컬에서 동작하는 MCP 기반 커리어 관리 도구. 모든 데이터는 이 컴퓨터에만 저장됩니다.</p>
273
+ <div class="foot__links"><a href="index.html#top">홈</a><a href="index.html#install">설치 전체</a></div>
274
+ </footer>
275
+
276
+ <div class="sr-only" role="status" aria-live="polite" id="copy-status"></div>
277
+
278
+ <script>
279
+ (function () {
280
+ 'use strict';
281
+ var status = document.getElementById('copy-status');
282
+ // --- clipboard ---
283
+ function legacyCopy(text) {
284
+ var ta = document.createElement('textarea');
285
+ ta.value = text; ta.setAttribute('readonly', ''); ta.style.position = 'absolute'; ta.style.left = '-9999px';
286
+ document.body.appendChild(ta); ta.select();
287
+ var ok = false; try { ok = document.execCommand('copy'); } catch (e) { ok = false; }
288
+ document.body.removeChild(ta); return ok;
289
+ }
290
+ function copyText(text, onok) {
291
+ if (navigator.clipboard && navigator.clipboard.writeText) {
292
+ navigator.clipboard.writeText(text).then(onok, function () { if (legacyCopy(text)) onok(); });
293
+ } else if (legacyCopy(text)) { onok(); }
294
+ }
295
+ document.querySelectorAll('.copy-btn').forEach(function (btn) {
296
+ btn.addEventListener('click', function () {
297
+ var src = document.getElementById(btn.getAttribute('data-copy-target'));
298
+ if (!src) return;
299
+ copyText(src.textContent || '', function () {
300
+ var o = btn.textContent; btn.textContent = '복사됨'; btn.classList.add('copied');
301
+ if (status) status.textContent = '클립보드에 복사되었습니다.';
302
+ window.setTimeout(function () { btn.textContent = o; btn.classList.remove('copied'); }, 1600);
303
+ });
304
+ });
305
+ });
306
+
307
+ // --- theme toggle ---
308
+ var root = document.documentElement, toggle = document.getElementById('theme-toggle');
309
+ function isDark() { var t = root.getAttribute('data-theme'); if (t === 'dark') return true; if (t === 'light') return false; return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; }
310
+ if (toggle) toggle.addEventListener('click', function () { var n = isDark() ? 'light' : 'dark'; root.setAttribute('data-theme', n); try { window.localStorage.setItem('cf-theme', n); } catch (e) {} });
311
+
312
+ // --- wizard ---
313
+ var result = document.getElementById('result');
314
+ var pickHint = document.getElementById('prompt-pick');
315
+ var sub = null, os = null;
316
+ function markSel(groupId) {
317
+ document.querySelectorAll('#' + groupId + ' .choice').forEach(function (c) {
318
+ c.classList.toggle('is-sel', !!c.querySelector('input').checked);
319
+ });
320
+ }
321
+ function render() {
322
+ if (!sub || !os) return;
323
+ if (pickHint) pickHint.style.display = 'none';
324
+ result.setAttribute('data-os', os);
325
+ result.querySelectorAll('.path').forEach(function (p) { p.classList.toggle('show', p.getAttribute('data-sub') === sub); });
326
+ result.classList.add('show');
327
+ }
328
+ document.querySelectorAll('input[name="sub"]').forEach(function (r) {
329
+ r.addEventListener('change', function () { sub = r.value; markSel('q-sub'); render(); });
330
+ });
331
+ document.querySelectorAll('input[name="os"]').forEach(function (r) {
332
+ r.addEventListener('change', function () { os = r.value; markSel('q-os'); render(); });
333
+ });
334
+ // "무료 길로" 점프(ChatGPT 경로에서)
335
+ document.querySelectorAll('[data-goto-free]').forEach(function (a) {
336
+ a.addEventListener('click', function (e) {
337
+ e.preventDefault();
338
+ var freeRadio = document.querySelector('input[name="sub"][value="free"]');
339
+ if (freeRadio) { freeRadio.checked = true; sub = 'free'; markSel('q-sub'); render(); }
340
+ result.scrollIntoView({ behavior: 'smooth', block: 'start' });
341
+ });
342
+ });
343
+ })();
344
+ </script>
345
+ </body>
346
+ </html>