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.
- package/README.md +12 -10
- package/THIRD_PARTY_NOTICES.md +15 -0
- package/apps/mcp/src/index.ts +4 -5
- package/apps/web/demo/demo-shim.js +536 -0
- package/apps/web/demo/demo.css +75 -0
- package/apps/web/demo/seed.js +269 -0
- package/apps/web/public/app.js +34 -2
- package/apps/web/public/index.html +10 -2
- package/apps/web/public/lib.js +134 -22
- package/apps/web/public/pages/applications.js +2 -9
- package/apps/web/public/pages/documents.js +66 -50
- package/apps/web/public/pages/home.js +12 -11
- package/apps/web/public/pages/interview.js +9 -12
- package/apps/web/public/pages/jobs.js +39 -36
- package/apps/web/public/pages/profile.js +66 -86
- package/apps/web/public/pages/settings.js +15 -10
- package/apps/web/public/styles.css +56 -2
- package/apps/web/src/http.ts +31 -4
- package/apps/web/src/info.ts +3 -3
- package/apps/web/src/routes.ts +2 -1
- package/apps/web/src/server.ts +1 -4
- package/dist/doctor.mjs +72607 -611
- package/dist/install-page/.omc/state/agent-replay-55a58c0d-bb6e-43ea-8a05-4b6c93b80b34.jsonl +12 -0
- package/dist/install-page/.omc/state/idle-notif-cooldown.json +3 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/mission-state.json +147 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/pre-tool-advisory-throttle.json +22 -0
- package/dist/install-page/.omc/state/sessions/55a58c0d-bb6e-43ea-8a05-4b6c93b80b34/subagent-tracking-state.json +44 -0
- package/dist/install-page/index.html +31 -70
- package/dist/install-page/landing.js +54 -0
- package/dist/install-page/start.html +13 -36
- package/dist/install-page/style.css +34 -1
- package/dist/mcp.mjs +73936 -1976
- package/dist/migrate.mjs +17 -10
- package/dist/pdf.worker.min.mjs +28 -0
- package/dist/public/app.js +34 -2
- package/dist/public/index.html +10 -2
- package/dist/public/lib.js +134 -22
- package/dist/public/pages/applications.js +2 -9
- package/dist/public/pages/documents.js +66 -50
- package/dist/public/pages/home.js +12 -11
- package/dist/public/pages/interview.js +9 -12
- package/dist/public/pages/jobs.js +39 -36
- package/dist/public/pages/profile.js +66 -86
- package/dist/public/pages/settings.js +15 -10
- package/dist/public/styles.css +56 -2
- package/dist/web.mjs +39631 -244
- package/docs/ARCHITECTURE.md +5 -5
- package/docs/DECISIONS.md +1 -1
- package/docs/DEMO.md +3 -3
- package/docs/MCP_TOOLS.md +49 -9
- package/docs/ROADMAP.md +8 -7
- package/docs/START_WORKFLOW.md +13 -7
- package/docs/TODO.md +1 -1
- package/docs/WORKFLOWS.md +7 -5
- package/docs/superpowers/specs/2026-06-16-demo-dashboard-deploy-design.md +64 -0
- package/package.json +6 -2
- package/packages/db/src/paths.ts +11 -0
- package/packages/mcp-tools/src/bridge.ts +55 -32
- package/packages/mcp-tools/src/index.ts +9 -0
- package/packages/mcp-tools/src/tools.ts +193 -70
- package/packages/mcp-tools/src/update.ts +330 -0
- package/packages/parsers/src/documents.ts +521 -0
- package/packages/parsers/src/index.ts +8 -5
- package/packages/prompts/src/onboarding.ts +2 -2
- package/packages/shared/src/build-info.ts +22 -0
- package/packages/shared/src/index.ts +1 -0
- package/packages/shared/src/schemas.ts +24 -3
- package/packages/workflows/src/definitions.ts +4 -2
- package/scripts/build-demo.mjs +130 -0
- package/scripts/build-dist.mjs +20 -1
- package/scripts/doctor.ts +16 -3
package/apps/web/src/http.ts
CHANGED
|
@@ -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
|
-
|
|
111
|
-
|
|
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
|
-
|
|
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
|
}
|
package/apps/web/src/info.ts
CHANGED
|
@@ -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
|
-
//
|
|
16
|
-
|
|
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 {
|
package/apps/web/src/routes.ts
CHANGED
|
@@ -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) =>
|
|
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,
|
package/apps/web/src/server.ts
CHANGED
|
@@ -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');
|