careermate 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +12 -10
  2. package/THIRD_PARTY_NOTICES.md +15 -0
  3. package/apps/mcp/src/index.ts +4 -5
  4. package/apps/web/demo/demo-shim.js +536 -0
  5. package/apps/web/demo/demo.css +75 -0
  6. package/apps/web/demo/seed.js +269 -0
  7. package/apps/web/public/app.js +34 -2
  8. package/apps/web/public/index.html +10 -2
  9. package/apps/web/public/lib.js +134 -22
  10. package/apps/web/public/pages/applications.js +2 -9
  11. package/apps/web/public/pages/documents.js +66 -50
  12. package/apps/web/public/pages/home.js +12 -11
  13. package/apps/web/public/pages/interview.js +9 -12
  14. package/apps/web/public/pages/jobs.js +39 -36
  15. package/apps/web/public/pages/profile.js +66 -86
  16. package/apps/web/public/pages/settings.js +15 -10
  17. package/apps/web/public/styles.css +56 -2
  18. package/apps/web/src/http.ts +31 -4
  19. package/apps/web/src/info.ts +3 -3
  20. package/apps/web/src/routes.ts +2 -1
  21. package/apps/web/src/server.ts +1 -4
  22. package/dist/doctor.mjs +72607 -611
  23. package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +12 -0
  24. package/dist/install-page/.omc/state/idle-notif-cooldown.json +3 -0
  25. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +147 -0
  26. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +22 -0
  27. package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +44 -0
  28. package/dist/install-page/index.html +31 -70
  29. package/dist/install-page/landing.js +54 -0
  30. package/dist/install-page/start.html +13 -36
  31. package/dist/install-page/style.css +34 -1
  32. package/dist/mcp.mjs +73936 -1976
  33. package/dist/migrate.mjs +17 -10
  34. package/dist/pdf.worker.min.mjs +28 -0
  35. package/dist/public/app.js +34 -2
  36. package/dist/public/index.html +10 -2
  37. package/dist/public/lib.js +134 -22
  38. package/dist/public/pages/applications.js +2 -9
  39. package/dist/public/pages/documents.js +66 -50
  40. package/dist/public/pages/home.js +12 -11
  41. package/dist/public/pages/interview.js +9 -12
  42. package/dist/public/pages/jobs.js +39 -36
  43. package/dist/public/pages/profile.js +66 -86
  44. package/dist/public/pages/settings.js +15 -10
  45. package/dist/public/styles.css +56 -2
  46. package/dist/web.mjs +39631 -244
  47. package/docs/ARCHITECTURE.md +5 -5
  48. package/docs/DECISIONS.md +1 -1
  49. package/docs/DEMO.md +3 -3
  50. package/docs/MCP_TOOLS.md +49 -9
  51. package/docs/ROADMAP.md +8 -7
  52. package/docs/START_WORKFLOW.md +13 -7
  53. package/docs/TODO.md +1 -1
  54. package/docs/WORKFLOWS.md +7 -5
  55. package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +64 -0
  56. package/package.json +6 -2
  57. package/packages/db/src/paths.ts +11 -0
  58. package/packages/mcp-tools/src/bridge.ts +55 -32
  59. package/packages/mcp-tools/src/index.ts +9 -0
  60. package/packages/mcp-tools/src/tools.ts +193 -70
  61. package/packages/mcp-tools/src/update.ts +330 -0
  62. package/packages/parsers/src/documents.ts +521 -0
  63. package/packages/parsers/src/index.ts +8 -5
  64. package/packages/prompts/src/onboarding.ts +2 -2
  65. package/packages/shared/src/build-info.ts +22 -0
  66. package/packages/shared/src/index.ts +1 -0
  67. package/packages/shared/src/schemas.ts +24 -3
  68. package/packages/workflows/src/definitions.ts +4 -2
  69. package/scripts/build-demo.mjs +130 -0
  70. package/scripts/build-dist.mjs +20 -1
  71. package/scripts/doctor.ts +16 -3
@@ -107,8 +107,13 @@ export async function readJsonBody<T>(req: IncomingMessage, schema?: ZodType<T>)
107
107
  return schema.parse(parsed);
108
108
  } catch (e) {
109
109
  if (e instanceof ZodError) {
110
- const msg = e.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join(', ');
111
- throw new HttpError(400, `입력값 검증 실패 — ${msg}`, 'validation');
110
+ // Messages already written as full Korean guidance are shown as-is (the zod
111
+ // path like "links.0.url" is developer jargon). Generic/English messages keep
112
+ // a field hint so the user knows which input to fix.
113
+ const msg = e.issues
114
+ .map((i) => (/[가-힣]/.test(i.message) ? i.message : `${i.path.join('.') || '입력값'}: ${i.message}`))
115
+ .join('\n');
116
+ throw new HttpError(400, msg, 'validation');
112
117
  }
113
118
  throw e;
114
119
  }
@@ -170,11 +175,33 @@ export function serveStatic(
170
175
  const mime = MIME[ext] ?? 'application/octet-stream';
171
176
  let payload: Buffer | string = fs.readFileSync(resolved);
172
177
  if (transform && (ext === '.html')) payload = transform(payload.toString('utf8'));
173
- res.writeHead(200, {
178
+ const headers: Record<string, string> = {
174
179
  'Content-Type': mime,
175
180
  'X-Content-Type-Options': 'nosniff',
176
181
  'Cache-Control': ext === '.html' ? 'no-store' : 'no-cache',
177
- });
182
+ };
183
+ if (ext === '.html') {
184
+ // Content-Security-Policy: with no inline scripts and only same-origin
185
+ // assets, any XSS that slips past escaping can't load external code or
186
+ // exfiltrate (connect-src 'self'). Dashboard pages (served with the token
187
+ // transform) hold the CSRF token and render user-controlled career data, so
188
+ // they get a strict no-inline-script policy. The install page (no transform)
189
+ // is static marketing with inline bootstrap scripts (theme/carousel), so it
190
+ // permits inline script but keeps every other hardening directive.
191
+ const scriptSrc = transform ? "script-src 'self'" : "script-src 'self' 'unsafe-inline'";
192
+ headers['Content-Security-Policy'] = [
193
+ "default-src 'none'",
194
+ scriptSrc,
195
+ "style-src 'self' 'unsafe-inline'", // inline style="" attrs + JS-set element styles
196
+ "img-src 'self' data:", // data: favicon + local screenshots/icons
197
+ "font-src 'self'",
198
+ "connect-src 'self'",
199
+ "base-uri 'none'",
200
+ "form-action 'none'",
201
+ "frame-ancestors 'none'", // clickjacking guard
202
+ ].join('; ');
203
+ }
204
+ res.writeHead(200, headers);
178
205
  res.end(payload);
179
206
  return true;
180
207
  }
@@ -10,11 +10,11 @@ import {
10
10
  getBackupsDir,
11
11
  getEntityCounts,
12
12
  } from '@careermate/db';
13
+ import { APP_VERSION } from '@careermate/shared';
13
14
 
14
15
  export const APP_NAME = 'CareerMate';
15
- // 번들 빌드(esbuild)에서 package.json 버전으로 치환된다. tsx 개발 실행에서는 정의되지 않아 typeof로 안전 분기.
16
- declare const __APP_VERSION__: string | undefined;
17
- export const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.0.0-dev';
16
+ // 버전은 @careermate/shared 단일 출처에서. (번들에서 package.json 버전으로 치환)
17
+ export { APP_VERSION };
18
18
 
19
19
  let _port = 0;
20
20
  export function setServerPort(port: number): void {
@@ -22,6 +22,7 @@ import {
22
22
  APPLICATION_STATUS_LABELS,
23
23
  DOCUMENT_KIND_LABELS,
24
24
  APPLICATION_BOARD_ORDER,
25
+ INTERVIEW_UNLOCK_STATUSES,
25
26
  type DocumentKind,
26
27
  type JobInput,
27
28
  } from '@careermate/shared';
@@ -263,7 +264,7 @@ export function registerApiRoutes(router: Router): void {
263
264
  const preps = interviewRepo.list().map((p) => ({ ...p, job: jobRepo.get(p.job_id) }));
264
265
  const eligible = applicationRepo
265
266
  .list()
266
- .filter((a) => ['document_passed', 'interview', 'final_passed'].includes(a.status))
267
+ .filter((a) => INTERVIEW_UNLOCK_STATUSES.includes(a.status))
267
268
  .map((a) => ({
268
269
  job: jobRepo.get(a.job_id),
269
270
  status: a.status,
@@ -6,15 +6,12 @@ import http from 'node:http';
6
6
  import path from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
8
  import { getDb, writeRuntimeInfo, clearRuntimeInfo } from '@careermate/db';
9
+ import { BUNDLED } from '@careermate/shared';
9
10
  import { checkRequest, injectToken } from './security.ts';
10
11
  import { Router, sendJson, sendDownload, serveStatic, HttpError } from './http.ts';
11
12
  import { registerApiRoutes, isDownload } from './routes.ts';
12
13
  import { setServerPort } from './info.ts';
13
14
 
14
- // 번들 빌드(esbuild)에서 true로 치환된다. tsx 개발 실행에서는 정의되지 않아 typeof로 안전 분기.
15
- declare const __BUNDLED__: boolean | undefined;
16
- const BUNDLED = typeof __BUNDLED__ !== 'undefined' && __BUNDLED__;
17
-
18
15
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
16
  // dev(tsx): apps/web/src 기준 상대경로 · prod(dist/web.mjs): dist 기준.
20
17
  const WEB_ROOT = BUNDLED ? path.resolve(__dirname, 'public') : path.resolve(__dirname, '..', 'public');