career-compass-mcp 2.0.0 → 2.2.0

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 (55) hide show
  1. package/README.md +391 -340
  2. package/build/bin/cli.d.ts +5 -5
  3. package/build/bin/cli.d.ts.map +1 -1
  4. package/build/bin/cli.js +55 -49
  5. package/build/bin/cli.js.map +1 -1
  6. package/build/src/dashboard-lite/render.d.ts +21 -0
  7. package/build/src/dashboard-lite/render.d.ts.map +1 -0
  8. package/build/src/dashboard-lite/render.js +216 -0
  9. package/build/src/dashboard-lite/render.js.map +1 -0
  10. package/build/src/dashboard-lite/server.d.ts +14 -0
  11. package/build/src/dashboard-lite/server.d.ts.map +1 -0
  12. package/build/src/dashboard-lite/server.js +50 -0
  13. package/build/src/dashboard-lite/server.js.map +1 -0
  14. package/build/src/schemas/career-schema.d.ts +108 -0
  15. package/build/src/schemas/career-schema.d.ts.map +1 -1
  16. package/build/src/schemas/career-schema.js +43 -0
  17. package/build/src/schemas/career-schema.js.map +1 -1
  18. package/build/src/server.d.ts.map +1 -1
  19. package/build/src/server.js +4 -1
  20. package/build/src/server.js.map +1 -1
  21. package/build/src/storage/file-store.d.ts +43 -0
  22. package/build/src/storage/file-store.d.ts.map +1 -1
  23. package/build/src/storage/file-store.js +133 -4
  24. package/build/src/storage/file-store.js.map +1 -1
  25. package/build/src/tools/career-kb.d.ts.map +1 -1
  26. package/build/src/tools/career-kb.js +120 -13
  27. package/build/src/tools/career-kb.js.map +1 -1
  28. package/build/src/tools/interview.d.ts.map +1 -1
  29. package/build/src/tools/interview.js +21 -4
  30. package/build/src/tools/interview.js.map +1 -1
  31. package/build/src/tools/opportunity.d.ts.map +1 -1
  32. package/build/src/tools/opportunity.js +19 -2
  33. package/build/src/tools/opportunity.js.map +1 -1
  34. package/build/src/tools/pipeline.d.ts.map +1 -1
  35. package/build/src/tools/pipeline.js +105 -47
  36. package/build/src/tools/pipeline.js.map +1 -1
  37. package/build/src/tools/resume.d.ts.map +1 -1
  38. package/build/src/tools/resume.js +28 -4
  39. package/build/src/tools/resume.js.map +1 -1
  40. package/build/src/tools/signal-digest.d.ts +15 -0
  41. package/build/src/tools/signal-digest.d.ts.map +1 -0
  42. package/build/src/tools/signal-digest.js +45 -0
  43. package/build/src/tools/signal-digest.js.map +1 -0
  44. package/build/src/untrusted.d.ts +63 -0
  45. package/build/src/untrusted.d.ts.map +1 -0
  46. package/build/src/untrusted.js +83 -0
  47. package/build/src/untrusted.js.map +1 -0
  48. package/build/src/version.d.ts +23 -0
  49. package/build/src/version.d.ts.map +1 -0
  50. package/build/src/version.js +66 -0
  51. package/build/src/version.js.map +1 -0
  52. package/data/example/career/education.yaml +20 -0
  53. package/data/example/career/journal.yaml +56 -0
  54. package/data/example/career/projects.yaml +47 -0
  55. package/package.json +3 -13
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Read the package version from package.json relative to the CLI directory.
4
- * Factored out so it can be unit-tested directly (the previous inline code had
5
- * a `pkgVersion = pkgVersion` self-assign that always left the version as
6
- * "unknown"). Returns "unknown" only when package.json is missing/unreadable.
3
+ * Re-exported from src/version.ts so the CLI and the MCP server resolve the
4
+ * version through exactly one code path. Kept as a named export here because
5
+ * cli-version.test.ts exercises it directly.
7
6
  */
8
- export declare function readPkgVersion(cliDir: string): string;
7
+ import { readPkgVersion } from "../src/version.js";
8
+ export { readPkgVersion };
9
9
  //# sourceMappingURL=cli.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAaA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrD"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAaA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,CAAC"}
package/build/bin/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
- import { existsSync, mkdirSync, readFileSync } from "fs";
4
+ import { existsSync, mkdirSync } from "fs";
5
5
  import { createServer as createNetServer } from "net";
6
6
  import { spawn } from "child_process";
7
7
  import { fileURLToPath } from "url";
@@ -9,20 +9,12 @@ const args = process.argv.slice(2);
9
9
  // ─── Version ─────────────────────────────────────────────────────────────────
10
10
  const __cliDir = fileURLToPath(new URL(".", import.meta.url));
11
11
  /**
12
- * Read the package version from package.json relative to the CLI directory.
13
- * Factored out so it can be unit-tested directly (the previous inline code had
14
- * a `pkgVersion = pkgVersion` self-assign that always left the version as
15
- * "unknown"). Returns "unknown" only when package.json is missing/unreadable.
12
+ * Re-exported from src/version.ts so the CLI and the MCP server resolve the
13
+ * version through exactly one code path. Kept as a named export here because
14
+ * cli-version.test.ts exercises it directly.
16
15
  */
17
- export function readPkgVersion(cliDir) {
18
- try {
19
- const pkgJson = JSON.parse(readFileSync(join(cliDir, "..", "..", "package.json"), "utf-8"));
20
- return typeof pkgJson.version === "string" ? pkgJson.version : "unknown";
21
- }
22
- catch {
23
- return "unknown"; // package.json not found — version will show as "unknown"
24
- }
25
- }
16
+ import { readPkgVersion } from "../src/version.js";
17
+ export { readPkgVersion };
26
18
  const pkgVersion = readPkgVersion(__cliDir);
27
19
  if (args.includes("--version") || args.includes("-v")) {
28
20
  console.log(`career-compass-mcp v${pkgVersion}`);
@@ -35,13 +27,15 @@ career-compass-mcp v${pkgVersion}
35
27
 
36
28
  Usage:
37
29
  career-compass-mcp Run MCP server (stdio)
38
- career-compass-mcp dashboard Open web dashboard
30
+ career-compass-mcp dashboard Open web dashboard (full if built, else lite)
31
+ career-compass-mcp dashboard --lite Force the zero-build lite dashboard
39
32
  career-compass-mcp dashboard --port 3000 Specify port (default: 3141)
40
33
  career-compass-mcp dashboard --no-open Start without opening browser
41
34
 
42
35
  Options:
43
36
  -h, --help Show this help message
44
37
  -v, --version Show version number
38
+ --lite Use the built-in zero-build dashboard (no Next.js build needed)
45
39
  --port <number> Dashboard port (default: 3141)
46
40
  --no-open Don't auto-open browser
47
41
  `);
@@ -65,6 +59,7 @@ else {
65
59
  requestedPort = portValue;
66
60
  }
67
61
  const noOpen = args.includes("--no-open");
62
+ const forceLite = args.includes("--lite");
68
63
  // Resolve data path
69
64
  const dataPath = process.env.CAREER_DATA_PATH ?? join(homedir(), ".career-compass");
70
65
  if (!existsSync(dataPath)) {
@@ -76,42 +71,53 @@ else {
76
71
  // Resolve standalone server path
77
72
  // __cliDir is build/bin/ at runtime; go up two levels to repo root
78
73
  const standalonePath = join(__cliDir, "..", "..", "dashboard", ".next", "standalone", "dashboard", "server.js");
79
- if (!existsSync(standalonePath)) {
80
- console.error([
81
- "The dashboard isn't available in this install.",
82
- "It currently ships in the source build, not the npm package (a packaged dashboard is coming in a follow-up release).",
83
- "",
84
- "To run it from source:",
85
- " git clone https://github.com/benskamps/career-compass-mcp",
86
- " cd career-compass-mcp && npm install && npm run build",
87
- " CAREER_DATA_PATH=data/example npm run dashboard",
88
- "",
89
- "The MCP server (all 11 tools) works in this install — just point Claude at it.",
90
- ].join("\n"));
91
- process.exit(1);
74
+ // Decide which dashboard to serve:
75
+ // --lite always uses the built-in zero-build dashboard.
76
+ // Otherwise prefer the full Next.js dashboard when it has been built.
77
+ // If the full build is absent (e.g. the npm install), fall back to lite
78
+ // instead of erroring — the dashboard now always works.
79
+ const useLite = forceLite || !existsSync(standalonePath);
80
+ if (useLite) {
81
+ process.env.CAREER_DATA_PATH = dataPath; // loadPipeline() reads this
82
+ const { startLiteDashboard } = await import("../src/dashboard-lite/server.js");
83
+ if (!forceLite) {
84
+ console.error("Full dashboard isn't built in this install — starting the built-in lite dashboard.");
85
+ console.error("(Run `npm run build` from source for the full Next.js dashboard with kanban drag, analytics, and Career KB views.)");
86
+ }
87
+ const server = await startLiteDashboard(port);
88
+ console.error(`Lite dashboard running at http://localhost:${port}`);
89
+ if (!noOpen)
90
+ openBrowser(`http://localhost:${port}`);
91
+ const shutdownLite = () => { server.close(); process.exit(0); };
92
+ process.on("SIGINT", shutdownLite);
93
+ process.on("SIGTERM", shutdownLite);
94
+ // Keep the process alive on the listening server.
95
+ await new Promise(() => { });
92
96
  }
93
- // Start Next.js standalone server
94
- const child = spawn("node", [standalonePath], {
95
- env: {
96
- ...process.env,
97
- PORT: String(port),
98
- HOSTNAME: "localhost",
99
- CAREER_DATA_PATH: dataPath,
100
- },
101
- stdio: ["pipe", "pipe", "inherit"],
102
- });
103
- child.stdout?.on("data", (data) => {
104
- const output = data.toString();
105
- if (output.includes("Ready") || output.includes("started")) {
106
- console.error(`Dashboard running at http://localhost:${port}`);
107
- if (!noOpen) {
108
- openBrowser(`http://localhost:${port}`);
97
+ else {
98
+ // Start Next.js standalone server
99
+ const child = spawn("node", [standalonePath], {
100
+ env: {
101
+ ...process.env,
102
+ PORT: String(port),
103
+ HOSTNAME: "localhost",
104
+ CAREER_DATA_PATH: dataPath,
105
+ },
106
+ stdio: ["pipe", "pipe", "inherit"],
107
+ });
108
+ child.stdout?.on("data", (data) => {
109
+ const output = data.toString();
110
+ if (output.includes("Ready") || output.includes("started")) {
111
+ console.error(`Dashboard running at http://localhost:${port}`);
112
+ if (!noOpen) {
113
+ openBrowser(`http://localhost:${port}`);
114
+ }
109
115
  }
110
- }
111
- });
112
- const shutdown = () => { child.kill("SIGTERM"); process.exit(0); };
113
- process.on("SIGINT", shutdown);
114
- process.on("SIGTERM", shutdown);
116
+ });
117
+ const shutdown = () => { child.kill("SIGTERM"); process.exit(0); };
118
+ process.on("SIGINT", shutdown);
119
+ process.on("SIGTERM", shutdown);
120
+ }
115
121
  }
116
122
  function findPort(preferred) {
117
123
  return new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Pipeline, Application } from "../schemas/career-schema.js";
2
+ interface NextAction {
3
+ app: Application;
4
+ label: string;
5
+ urgency: "overdue" | "soon" | "info";
6
+ }
7
+ /** Derive next actions from follow-up dates, upcoming interviews, and expiring offers. */
8
+ export declare function deriveNextActions(apps: Application[], today?: Date): NextAction[];
9
+ export interface PipelineStats {
10
+ total: number;
11
+ active: number;
12
+ inConversation: number;
13
+ offers: number;
14
+ responseRate: number;
15
+ ghostRate: number;
16
+ }
17
+ export declare function computeStats(apps: Application[]): PipelineStats;
18
+ /** Render the full self-contained HTML document. */
19
+ export declare function renderLiteDashboard(pipeline: Pipeline): string;
20
+ export {};
21
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/dashboard-lite/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAqB,MAAM,6BAA6B,CAAC;AAmC5F,UAAU,UAAU;IAAG,GAAG,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;CAAE;AAE/F,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,KAAK,OAAa,GAAG,UAAU,EAAE,CAwBvF;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IACtE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;CACzC;AACD,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,aAAa,CAa/D;AAkBD,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAuI9D"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Zero-build "lite" dashboard.
3
+ *
4
+ * Renders the pipeline into a single self-contained HTML document — all CSS and
5
+ * JS inlined, no external assets, no build step. This is what ships in the npm
6
+ * package so `career-compass-mcp dashboard` works without the Next.js standalone
7
+ * (which is source-build only). The lite server (server.ts) re-reads the YAML on
8
+ * every request and calls this, so the page is always live, never prerendered.
9
+ *
10
+ * Design note: in a plain browser there is no Claude chat bridge, so the
11
+ * "Ask Claude" affordances copy a ready-to-paste prompt to the clipboard rather
12
+ * than dispatching it. In Cowork, the artifact variant wires the same prompts to
13
+ * sendPrompt() instead.
14
+ */
15
+ const STAGE_ORDER = [
16
+ "discovered", "applied", "screening", "interviewing",
17
+ "offer", "negotiating", "accepted", "rejected", "withdrawn", "ghosted",
18
+ ];
19
+ const ACTIVE = [
20
+ "discovered", "applied", "screening", "interviewing", "offer", "negotiating",
21
+ ];
22
+ const STAGE_COLOR = {
23
+ discovered: "#64748b", applied: "#0ea5e9", screening: "#8b5cf6",
24
+ interviewing: "#f59e0b", offer: "#10b981", negotiating: "#14b8a6",
25
+ accepted: "#059669", rejected: "#ef4444", withdrawn: "#9ca3af", ghosted: "#a1a1aa",
26
+ };
27
+ function esc(s) {
28
+ return String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]));
29
+ }
30
+ /** Derive next actions from follow-up dates, upcoming interviews, and expiring offers. */
31
+ export function deriveNextActions(apps, today = new Date()) {
32
+ const out = [];
33
+ const t0 = today.getTime();
34
+ const days = (iso) => (iso ? Math.round((new Date(iso).getTime() - t0) / 86400000) : NaN);
35
+ for (const app of apps) {
36
+ if (["accepted", "rejected", "withdrawn", "ghosted"].includes(app.status))
37
+ continue;
38
+ const fu = days(app.followUpDue);
39
+ if (!Number.isNaN(fu)) {
40
+ if (fu < 0)
41
+ out.push({ app, label: `Follow-up overdue by ${Math.abs(fu)}d — ${app.company}`, urgency: "overdue" });
42
+ else if (fu <= 2)
43
+ out.push({ app, label: `Follow-up due ${fu === 0 ? "today" : `in ${fu}d`} — ${app.company}`, urgency: "soon" });
44
+ }
45
+ const nextInterview = (app.interviewRounds ?? [])
46
+ .map((r) => days(r.date)).filter((d) => !Number.isNaN(d) && d >= 0).sort((a, b) => a - b)[0];
47
+ if (nextInterview != null && nextInterview <= 7) {
48
+ out.push({ app, label: `Interview ${nextInterview === 0 ? "today" : `in ${nextInterview}d`} — ${app.company}`, urgency: nextInterview <= 2 ? "soon" : "info" });
49
+ }
50
+ if (app.offer?.expiresDate) {
51
+ const exp = days(app.offer.expiresDate);
52
+ if (!Number.isNaN(exp) && exp >= 0 && exp <= 14)
53
+ out.push({ app, label: `Offer expires ${exp === 0 ? "today" : `in ${exp}d`} — ${app.company}`, urgency: exp <= 4 ? "overdue" : "soon" });
54
+ }
55
+ }
56
+ const rank = { overdue: 0, soon: 1, info: 2 };
57
+ return out.sort((a, b) => rank[a.urgency] - rank[b.urgency]);
58
+ }
59
+ export function computeStats(apps) {
60
+ const total = apps.length;
61
+ const active = apps.filter((a) => ACTIVE.includes(a.status)).length;
62
+ const inConversation = apps.filter((a) => ["screening", "interviewing"].includes(a.status)).length;
63
+ const offers = apps.filter((a) => ["offer", "negotiating", "accepted"].includes(a.status)).length;
64
+ const applied = apps.filter((a) => a.status !== "discovered").length;
65
+ const responded = apps.filter((a) => !["discovered", "applied", "ghosted"].includes(a.status)).length;
66
+ const ghosted = apps.filter((a) => a.status === "ghosted").length;
67
+ return {
68
+ total, active, inConversation, offers,
69
+ responseRate: applied ? Math.round((responded / applied) * 100) : 0,
70
+ ghostRate: applied ? Math.round((ghosted / applied) * 100) : 0,
71
+ };
72
+ }
73
+ function kpi(n, label, foot = "") {
74
+ return `<div class="kpi"><div class="n">${esc(n)}</div><div class="l">${esc(label)}</div>${foot ? `<div class="foot">${esc(foot)}</div>` : ""}</div>`;
75
+ }
76
+ function jobCard(a) {
77
+ const color = STAGE_COLOR[a.status];
78
+ const pr = a.priority ? `<span class="pill p-${esc(a.priority)}">${esc(a.priority)}</span>` : "";
79
+ const exc = a.excitement != null ? `<span class="exc">🔥 ${esc(a.excitement)}/10</span>` : "";
80
+ const prompt = `Give me a full status on my ${a.company} application (${a.role}) — where it stands, what's next, and anything I'm at risk of dropping.`;
81
+ return `<div class="jc" style="--stage:${color}" data-prompt="${esc(prompt)}">
82
+ <div class="co">${esc(a.company)}</div>
83
+ <div class="ro">${esc(a.role)}</div>
84
+ <div class="meta">${pr}${exc}</div>
85
+ </div>`;
86
+ }
87
+ /** Render the full self-contained HTML document. */
88
+ export function renderLiteDashboard(pipeline) {
89
+ const apps = [...(pipeline.applications ?? [])].sort((a, b) => (b.dateUpdated ?? "").localeCompare(a.dateUpdated ?? ""));
90
+ const s = computeStats(apps);
91
+ const actions = deriveNextActions(apps);
92
+ const lastUpdated = pipeline.lastUpdated ? new Date(pipeline.lastUpdated).toLocaleString() : "—";
93
+ const kpis = [
94
+ kpi(s.total, "Total applications"),
95
+ kpi(s.active, "Active", "in play right now"),
96
+ kpi(s.inConversation, "In conversation", "screening + interviewing"),
97
+ kpi(s.offers, "Offers", s.offers > 0 ? "🎉 decision time" : ""),
98
+ kpi(`${s.responseRate}%`, "Response rate"),
99
+ kpi(`${s.ghostRate}%`, "Ghost rate"),
100
+ ].join("");
101
+ const presentStages = STAGE_ORDER.filter((st) => apps.some((a) => a.status === st) || ACTIVE.includes(st));
102
+ const board = presentStages.map((st) => {
103
+ const items = apps.filter((a) => a.status === st);
104
+ return `<div class="col">
105
+ <div class="h"><span class="sw" style="background:${STAGE_COLOR[st]}"></span> ${st} <span class="count">${items.length}</span></div>
106
+ <div class="stack">${items.map(jobCard).join("") || '<div class="none">—</div>'}</div>
107
+ </div>`;
108
+ }).join("");
109
+ const actionsHtml = actions.length
110
+ ? actions.map((x) => `<div class="action ${x.urgency}"><span class="dot"></span><div class="t"><b>${esc(x.label)}</b><span>${esc(x.app.role)}</span></div></div>`).join("")
111
+ : `<div class="none-lg">✅ Nothing overdue. Follow-ups, upcoming interviews, and expiring offers surface here.</div>`;
112
+ const emptyState = `<div class="panel"><div class="state">
113
+ <h3>Your pipeline is empty — let's fix that</h3>
114
+ <div>Career Compass builds everything off your pipeline. Add your first opportunity and this dashboard lights up.</div>
115
+ <div class="btns">
116
+ <button class="btn primary" data-prompt="I found a job posting I want to track. Here it is: [paste posting]. Add it to my pipeline and give me a fit analysis.">Copy: track a job posting</button>
117
+ <button class="btn" data-prompt="Add an application to my pipeline — I'll give you the company and role.">Copy: add manually</button>
118
+ </div>
119
+ </div></div>`;
120
+ const chartData = JSON.stringify(ACTIVE.filter((st) => apps.some((a) => a.status === st))
121
+ .map((st) => ({ label: st[0].toUpperCase() + st.slice(1), value: apps.filter((a) => a.status === st).length, color: STAGE_COLOR[st] })));
122
+ return `<!doctype html>
123
+ <html lang="en"><head>
124
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
125
+ <title>Career Compass — Pipeline</title>
126
+ <style>
127
+ :root{color-scheme:light;--bg:#f7f8fa;--card:#fff;--ink:#14161c;--muted:#6b7280;--line:#e6e8ee;--accent:#4f46e5;--accent-soft:#eef0fe;--shadow:0 1px 2px rgba(20,22,28,.06),0 4px 14px rgba(20,22,28,.05)}
128
+ *{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased}
129
+ .wrap{max-width:1180px;margin:0 auto;padding:20px 20px 64px}
130
+ header.top{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:18px}
131
+ h1{font-size:20px;margin:0 0 2px;letter-spacing:-.01em}.sub{color:var(--muted);font-size:12.5px}
132
+ .chip{display:inline-flex;align-items:center;gap:6px;background:var(--accent-soft);color:var(--accent);border-radius:999px;padding:4px 10px;font-size:12px;font-weight:600}
133
+ .kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:20px}
134
+ .kpi{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
135
+ .kpi .n{font-size:26px;font-weight:700;letter-spacing:-.02em}.kpi .l{color:var(--muted);font-size:12px;margin-top:2px}.kpi .foot{font-size:11.5px;margin-top:6px;color:var(--muted)}
136
+ .grid2{display:grid;grid-template-columns:1.55fr 1fr;gap:16px;align-items:start}@media(max-width:900px){.grid2{grid-template-columns:1fr}}
137
+ .panel{background:var(--card);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow)}
138
+ .panel h2{font-size:13px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin:0;padding:14px 16px;border-bottom:1px solid var(--line)}
139
+ .panel .body{padding:14px 16px}.chart-box{position:relative;height:230px;display:flex;align-items:flex-end;gap:10px}
140
+ .bar-row{display:flex;flex-direction:column;gap:9px;width:100%}
141
+ .bar{display:flex;align-items:center;gap:10px}.bar .lab{width:96px;font-size:12px;color:var(--muted);text-align:right;flex:0 0 auto}
142
+ .bar .track{flex:1;background:#f0f1f5;border-radius:6px;height:22px;overflow:hidden}.bar .fill{height:100%;border-radius:6px}
143
+ .bar .val{font-size:12px;font-weight:600;width:22px}
144
+ .action{display:flex;gap:10px;padding:11px 0;border-bottom:1px dashed var(--line)}.action:last-child{border-bottom:0}
145
+ .action .dot{width:8px;height:8px;border-radius:50%;margin-top:6px;flex:0 0 auto;background:var(--accent)}
146
+ .action.overdue .dot{background:#ef4444}.action.soon .dot{background:#f59e0b}
147
+ .action .t{flex:1}.action .t b{display:block;font-size:13.5px}.action .t span{color:var(--muted);font-size:12px}
148
+ .board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(220px,1fr);gap:12px;overflow-x:auto;padding-bottom:8px}
149
+ .col{background:#fbfbfd;border:1px solid var(--line);border-radius:12px;min-height:80px}
150
+ .col .h{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--line);font-weight:600;font-size:12.5px;text-transform:capitalize}
151
+ .col .h .sw{width:9px;height:9px;border-radius:50%}.col .h .count{margin-left:auto;background:#eef0f4;color:var(--muted);border-radius:999px;font-size:11px;padding:1px 8px}
152
+ .col .stack{padding:10px;display:flex;flex-direction:column;gap:9px}.none{color:var(--muted);font-size:11.5px;padding:4px 2px}.none-lg{color:var(--muted);font-size:13px}
153
+ .jc{background:var(--card);border:1px solid var(--line);border-left:3px solid var(--stage,#ccc);border-radius:10px;padding:10px 11px;cursor:pointer;transition:.12s}
154
+ .jc:hover{box-shadow:var(--shadow);transform:translateY(-1px)}.jc .co{font-weight:650;font-size:13px}.jc .ro{color:var(--muted);font-size:12px;margin-top:1px}
155
+ .jc .meta{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;align-items:center}
156
+ .pill{font-size:10.5px;padding:2px 7px;border-radius:999px;font-weight:600}.p-high{background:#fee2e2;color:#b91c1c}.p-medium{background:#fef3c7;color:#92400e}.p-low{background:#e5e7eb;color:#4b5563}
157
+ .exc{font-size:11px;color:var(--muted);margin-left:auto}
158
+ .btn{border:1px solid var(--line);background:var(--card);color:var(--ink);border-radius:9px;padding:7px 12px;font-size:12.5px;font-weight:600;cursor:pointer;transition:.12s}
159
+ .btn:hover{border-color:var(--accent);color:var(--accent)}.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}.btn.primary:hover{background:#4338ca}
160
+ .toolbar{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 14px}
161
+ .state{text-align:center;padding:48px 20px;color:var(--muted)}.state h3{color:var(--ink);font-size:16px;margin:0 0 6px}.state .btns{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:16px}
162
+ .foot-note{color:var(--muted);font-size:11.5px;margin-top:22px;text-align:center}
163
+ #toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%) translateY(20px);background:var(--ink);color:#fff;padding:10px 16px;border-radius:10px;font-size:13px;opacity:0;transition:.2s;pointer-events:none}
164
+ #toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
165
+ .hidden{display:none!important}
166
+ </style></head>
167
+ <body><div class="wrap">
168
+ <header class="top">
169
+ <div><h1>🧭 Career Compass — Pipeline</h1>
170
+ <div class="sub">Live view of your job search · re-read from disk on every load · last write ${esc(lastUpdated)}</div></div>
171
+ <div class="chip">● local</div>
172
+ </header>
173
+ <div class="toolbar">
174
+ <button class="btn primary" data-prompt="What should I focus on in my job search today? Look at my pipeline and give me the 3 highest-leverage moves.">🎯 Copy: what should I do today?</button>
175
+ <button class="btn" data-prompt="Review my whole pipeline and flag anything stale, single-threaded, or at risk of going cold.">🔍 Copy: health check</button>
176
+ </div>
177
+ <div class="kpis">${kpis}</div>
178
+ ${apps.length === 0 ? emptyState : `
179
+ <div class="grid2">
180
+ <div class="panel">
181
+ <h2>Pipeline by stage</h2>
182
+ <div class="body"><div class="board">${board}</div></div>
183
+ </div>
184
+ <div style="display:flex;flex-direction:column;gap:16px">
185
+ <div class="panel"><h2>Next actions</h2><div class="body">${actionsHtml}</div></div>
186
+ <div class="panel"><h2>Stage distribution</h2><div class="body"><div id="chart" class="chart-box"></div></div></div>
187
+ </div>
188
+ </div>`}
189
+ <div class="foot-note">Data stays local (<code>~/.career-compass</code>). Click any card to copy a prompt for Claude — that's where the work happens. Refresh the page to re-read from disk.</div>
190
+ </div>
191
+ <div id="toast"></div>
192
+ <script>
193
+ const CHART=${chartData};
194
+ (function(){
195
+ const box=document.getElementById("chart");
196
+ if(box&&CHART.length){
197
+ const max=Math.max(...CHART.map(d=>d.value),1);
198
+ box.innerHTML='<div class="bar-row">'+CHART.map(d=>
199
+ '<div class="bar"><span class="lab">'+d.label+'</span><span class="track"><span class="fill" style="width:'+(d.value/max*100)+'%;background:'+d.color+'"></span></span><span class="val">'+d.value+'</span></div>'
200
+ ).join("")+'</div>';
201
+ } else if(box){ box.innerHTML='<div class="none-lg">No active applications yet.</div>'; }
202
+ const toast=document.getElementById("toast"); let tmr;
203
+ function flash(m){ toast.textContent=m; toast.classList.add("show"); clearTimeout(tmr); tmr=setTimeout(()=>toast.classList.remove("show"),1900); }
204
+ document.querySelectorAll("[data-prompt]").forEach(el=>{
205
+ el.addEventListener("click",()=>{
206
+ const p=el.getAttribute("data-prompt");
207
+ if(navigator.clipboard&&navigator.clipboard.writeText){
208
+ navigator.clipboard.writeText(p).then(()=>flash("Prompt copied — paste it to Claude 🧭")).catch(()=>flash(p));
209
+ } else { flash("Copy this: "+p); }
210
+ });
211
+ });
212
+ })();
213
+ </script>
214
+ </body></html>`;
215
+ }
216
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/dashboard-lite/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type Server } from "http";
2
+ /**
3
+ * Zero-build "lite" dashboard server.
4
+ *
5
+ * A dependency-free Node HTTP server that, on every request, re-reads the
6
+ * pipeline YAML from disk and renders it via renderLiteDashboard(). Nothing is
7
+ * cached or prerendered — refreshing the page always reflects the current state
8
+ * of ~/.career-compass, mirroring the force-dynamic guarantee of the Next.js
9
+ * dashboard. Ships in the npm package (pure JS, no framework, no build).
10
+ */
11
+ export declare function createLiteDashboardServer(): Server;
12
+ /** Start the lite dashboard on `port`, resolving once it's listening. */
13
+ export declare function startLiteDashboard(port: number, hostname?: string): Promise<Server>;
14
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/dashboard-lite/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAIjD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CA2BlD;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxF"}
@@ -0,0 +1,50 @@
1
+ import { createServer } from "http";
2
+ import { loadPipeline, isCorruptDataError } from "../storage/file-store.js";
3
+ import { renderLiteDashboard } from "./render.js";
4
+ /**
5
+ * Zero-build "lite" dashboard server.
6
+ *
7
+ * A dependency-free Node HTTP server that, on every request, re-reads the
8
+ * pipeline YAML from disk and renders it via renderLiteDashboard(). Nothing is
9
+ * cached or prerendered — refreshing the page always reflects the current state
10
+ * of ~/.career-compass, mirroring the force-dynamic guarantee of the Next.js
11
+ * dashboard. Ships in the npm package (pure JS, no framework, no build).
12
+ */
13
+ export function createLiteDashboardServer() {
14
+ return createServer(async (req, res) => {
15
+ // Only serve the dashboard at "/"; everything else 404s (favicon, etc.).
16
+ const path = (req.url ?? "/").split("?")[0];
17
+ if (path !== "/" && path !== "/index.html") {
18
+ res.writeHead(404, { "content-type": "text/plain" });
19
+ res.end("Not found");
20
+ return;
21
+ }
22
+ try {
23
+ const pipeline = await loadPipeline();
24
+ const html = renderLiteDashboard(pipeline);
25
+ res.writeHead(200, {
26
+ "content-type": "text/html; charset=utf-8",
27
+ // Never cache: the whole point is a live read of local data.
28
+ "cache-control": "no-store, must-revalidate",
29
+ });
30
+ res.end(html);
31
+ }
32
+ catch (err) {
33
+ const corrupt = isCorruptDataError(err);
34
+ const msg = corrupt
35
+ ? `Your pipeline file exists but couldn't be parsed. Fix it or restore a .bak backup, then refresh.\n\n${err.message}`
36
+ : `Failed to render dashboard: ${err?.message ?? String(err)}`;
37
+ res.writeHead(corrupt ? 422 : 500, { "content-type": "text/plain; charset=utf-8" });
38
+ res.end(msg);
39
+ }
40
+ });
41
+ }
42
+ /** Start the lite dashboard on `port`, resolving once it's listening. */
43
+ export function startLiteDashboard(port, hostname = "localhost") {
44
+ const server = createLiteDashboardServer();
45
+ return new Promise((resolve, reject) => {
46
+ server.once("error", reject);
47
+ server.listen(port, hostname, () => resolve(server));
48
+ });
49
+ }
50
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/dashboard-lite/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,MAAM,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACrC,yEAAyE;QACzE,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAC3C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,0BAA0B;gBAC1C,6DAA6D;gBAC7D,eAAe,EAAE,2BAA2B;aAC7C,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,GAAG,GAAG,OAAO;gBACjB,CAAC,CAAC,uGAAwG,GAAa,CAAC,OAAO,EAAE;gBACjI,CAAC,CAAC,+BAAgC,GAAa,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAAQ,GAAG,WAAW;IACrE,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAC;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC"}