career-compass-mcp 2.2.0 → 2.4.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.
- package/README.md +99 -12
- package/build/bin/cli.d.ts.map +1 -1
- package/build/bin/cli.js +85 -9
- package/build/bin/cli.js.map +1 -1
- package/build/src/dashboard-lite/render.d.ts +11 -11
- package/build/src/dashboard-lite/render.d.ts.map +1 -1
- package/build/src/dashboard-lite/render.js +139 -52
- package/build/src/dashboard-lite/render.js.map +1 -1
- package/build/src/dashboard-lite/server.d.ts +23 -7
- package/build/src/dashboard-lite/server.d.ts.map +1 -1
- package/build/src/dashboard-lite/server.js +106 -5
- package/build/src/dashboard-lite/server.js.map +1 -1
- package/build/src/empty-state.d.ts +16 -0
- package/build/src/empty-state.d.ts.map +1 -0
- package/build/src/empty-state.js +31 -0
- package/build/src/empty-state.js.map +1 -0
- package/build/src/pipeline-stats.d.ts +59 -0
- package/build/src/pipeline-stats.d.ts.map +1 -0
- package/build/src/pipeline-stats.js +66 -0
- package/build/src/pipeline-stats.js.map +1 -0
- package/build/src/sample-data.d.ts +49 -0
- package/build/src/sample-data.d.ts.map +1 -0
- package/build/src/sample-data.js +234 -0
- package/build/src/sample-data.js.map +1 -0
- package/build/src/schemas/career-schema.d.ts +15 -4
- package/build/src/schemas/career-schema.d.ts.map +1 -1
- package/build/src/schemas/career-schema.js +36 -2
- package/build/src/schemas/career-schema.js.map +1 -1
- package/build/src/server.d.ts +14 -1
- package/build/src/server.d.ts.map +1 -1
- package/build/src/server.js +4 -1
- package/build/src/server.js.map +1 -1
- package/build/src/storage/file-store.d.ts +25 -0
- package/build/src/storage/file-store.d.ts.map +1 -1
- package/build/src/storage/file-store.js +91 -6
- package/build/src/storage/file-store.js.map +1 -1
- package/build/src/tools/career-kb.d.ts +2 -0
- package/build/src/tools/career-kb.d.ts.map +1 -1
- package/build/src/tools/career-kb.js +155 -12
- package/build/src/tools/career-kb.js.map +1 -1
- package/build/src/tools/doctor.d.ts +115 -0
- package/build/src/tools/doctor.d.ts.map +1 -0
- package/build/src/tools/doctor.js +549 -0
- package/build/src/tools/doctor.js.map +1 -0
- package/build/src/tools/interview.d.ts.map +1 -1
- package/build/src/tools/interview.js +208 -1
- package/build/src/tools/interview.js.map +1 -1
- package/build/src/tools/opportunity.d.ts.map +1 -1
- package/build/src/tools/opportunity.js +103 -23
- package/build/src/tools/opportunity.js.map +1 -1
- package/build/src/tools/pipeline.d.ts +23 -1
- package/build/src/tools/pipeline.d.ts.map +1 -1
- package/build/src/tools/pipeline.js +111 -18
- package/build/src/tools/pipeline.js.map +1 -1
- package/build/src/tools/resume.d.ts.map +1 -1
- package/build/src/tools/resume.js +3 -2
- package/build/src/tools/resume.js.map +1 -1
- package/build/src/types/tool-args.d.ts +4 -1
- package/build/src/types/tool-args.d.ts.map +1 -1
- package/build/src/version.d.ts +9 -0
- package/build/src/version.d.ts.map +1 -1
- package/build/src/version.js +10 -1
- package/build/src/version.js.map +1 -1
- package/data/example/career/journal.yaml +4 -4
- package/data/example/pipeline/applications.yaml +66 -66
- package/package.json +5 -2
|
@@ -16,7 +16,32 @@ export declare class CorruptDataError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
export declare function isCorruptDataError(e: unknown): e is CorruptDataError;
|
|
18
18
|
export declare function withDataLock<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
19
|
+
/** Absolute path of the directory the Career KB is read from and written to.
|
|
20
|
+
* Exported so empty-state messages can name the user's real folder instead of
|
|
21
|
+
* a repo-relative path that exists nowhere on their machine. */
|
|
22
|
+
export declare function getDataDir(): string;
|
|
23
|
+
/**
|
|
24
|
+
* How many timestamped `.bak` files to keep per data file.
|
|
25
|
+
*
|
|
26
|
+
* Backups exist so a bad write is recoverable, and recovery in practice means
|
|
27
|
+
* "the version from a few writes ago" — nobody restores the 180th. Keeping
|
|
28
|
+
* every one of them turned a normal search session into 224 files and 23.7 MB
|
|
29
|
+
* of dead weight in the user's data directory, on a tool whose pitch is that
|
|
30
|
+
* the data is plain files you can read.
|
|
31
|
+
*/
|
|
32
|
+
export declare const BACKUP_RETENTION = 5;
|
|
19
33
|
export declare function loadCareerData(): Promise<CareerData | null>;
|
|
34
|
+
/** The only section names that may become a filename. */
|
|
35
|
+
export declare const CAREER_SECTIONS: readonly ["profile", "experience", "skills", "education", "projects", "testimonials"];
|
|
36
|
+
export type CareerSection = (typeof CAREER_SECTIONS)[number];
|
|
37
|
+
/**
|
|
38
|
+
* Write one section of the Career KB.
|
|
39
|
+
*
|
|
40
|
+
* `section` becomes a path segment, so it is checked against an allowlist rather
|
|
41
|
+
* than trusted. Before this was reachable from a tool it was only ever called
|
|
42
|
+
* with literals; now that a model can supply the value, `../../.ssh/id_rsa` has
|
|
43
|
+
* to be impossible rather than merely unlikely.
|
|
44
|
+
*/
|
|
20
45
|
export declare function saveCareerSection(section: string, data: unknown): Promise<void>;
|
|
21
46
|
/**
|
|
22
47
|
* Load the career journal.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../src/storage/file-store.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAkB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../src/storage/file-store.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAkB,MAAM,6BAA6B,CAAC;AAEnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBACb,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAU9C;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,gBAAgB,CAEpE;AA8BD,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAc7E;AAID;;iEAEiE;AACjE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAqCD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AA8FlC,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAiDjE;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,uFAElB,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrF;AAQD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAI3D;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAWrF;AAID,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAmBtD;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CAaZ;AAID,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAGpD"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir, rename, copyFile } from "fs/promises";
|
|
1
|
+
import { readFile, writeFile, mkdir, rename, copyFile, readdir, rm } from "fs/promises";
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { join, dirname, basename } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
7
7
|
import { CareerData, Pipeline, JournalSection } from "../schemas/career-schema.js";
|
|
8
|
+
import { freshenSampleDates, isBundledSampleDir } from "../sample-data.js";
|
|
8
9
|
// ─── Typed errors ─────────────────────────────────────────────────────────────
|
|
9
10
|
/**
|
|
10
11
|
* Thrown when a data file exists on disk but cannot be parsed or fails schema
|
|
@@ -66,11 +67,25 @@ export function withDataLock(key, fn) {
|
|
|
66
67
|
return run;
|
|
67
68
|
}
|
|
68
69
|
// ─── Path resolution ──────────────────────────────────────────────────────────
|
|
69
|
-
|
|
70
|
+
/** Absolute path of the directory the Career KB is read from and written to.
|
|
71
|
+
* Exported so empty-state messages can name the user's real folder instead of
|
|
72
|
+
* a repo-relative path that exists nowhere on their machine. */
|
|
73
|
+
export function getDataDir() {
|
|
70
74
|
return process.env.CAREER_DATA_PATH ?? join(homedir(), ".career-compass");
|
|
71
75
|
}
|
|
72
76
|
function careerDir() { return join(getDataDir(), "career"); }
|
|
73
77
|
function pipelineDir() { return join(getDataDir(), "pipeline"); }
|
|
78
|
+
/**
|
|
79
|
+
* Is the store currently pointed at the demo that ships inside this package?
|
|
80
|
+
*
|
|
81
|
+
* Only true for `data/example/` in our own install — never for a user's data
|
|
82
|
+
* dir, even one they populated by copying the sample. It gates two things: the
|
|
83
|
+
* read-time date shift that keeps the demo from curdling, and the refusal to
|
|
84
|
+
* write into a directory that belongs to the package rather than the user.
|
|
85
|
+
*/
|
|
86
|
+
function servingBundledSample() {
|
|
87
|
+
return isBundledSampleDir(getDataDir());
|
|
88
|
+
}
|
|
74
89
|
// ─── YAML helpers ─────────────────────────────────────────────────────────────
|
|
75
90
|
/**
|
|
76
91
|
* Read + parse + validate a YAML file.
|
|
@@ -91,22 +106,69 @@ async function readYaml(filePath, schema) {
|
|
|
91
106
|
throw new CorruptDataError(filePath, error);
|
|
92
107
|
}
|
|
93
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* How many timestamped `.bak` files to keep per data file.
|
|
111
|
+
*
|
|
112
|
+
* Backups exist so a bad write is recoverable, and recovery in practice means
|
|
113
|
+
* "the version from a few writes ago" — nobody restores the 180th. Keeping
|
|
114
|
+
* every one of them turned a normal search session into 224 files and 23.7 MB
|
|
115
|
+
* of dead weight in the user's data directory, on a tool whose pitch is that
|
|
116
|
+
* the data is plain files you can read.
|
|
117
|
+
*/
|
|
118
|
+
export const BACKUP_RETENTION = 5;
|
|
119
|
+
/** Matches only the backups {@link atomicWriteYaml} writes: `<file>.<ISO>.bak`. */
|
|
120
|
+
function backupPattern(base) {
|
|
121
|
+
const escaped = base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
122
|
+
return new RegExp(`^${escaped}\\.\\d{4}-\\d{2}-\\d{2}T[\\d-]+Z\\.bak$`);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Delete all but the newest {@link BACKUP_RETENTION} backups of one file.
|
|
126
|
+
*
|
|
127
|
+
* Names carry an ISO timestamp with `:` and `.` swapped for `-`, so they are
|
|
128
|
+
* fixed-width and sort lexicographically in chronological order — no stat() per
|
|
129
|
+
* candidate. Only names matching that exact shape are considered: a `.bak` a
|
|
130
|
+
* user made by hand before editing is theirs, not ours to garbage-collect.
|
|
131
|
+
*
|
|
132
|
+
* Best-effort by design. A backup we cannot delete (locked by a scanner on
|
|
133
|
+
* Windows, say) is not a reason to fail the write that already succeeded.
|
|
134
|
+
*/
|
|
135
|
+
async function pruneBackups(dir, base) {
|
|
136
|
+
try {
|
|
137
|
+
const pattern = backupPattern(base);
|
|
138
|
+
const ours = (await readdir(dir)).filter((n) => pattern.test(n)).sort();
|
|
139
|
+
const stale = ours.slice(0, Math.max(0, ours.length - BACKUP_RETENTION));
|
|
140
|
+
await Promise.all(stale.map((n) => rm(join(dir, n), { force: true }).catch(() => { })));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Housekeeping only — never surfaced to the caller.
|
|
144
|
+
}
|
|
145
|
+
}
|
|
94
146
|
/**
|
|
95
147
|
* Back up (if the target exists) then write atomically.
|
|
96
148
|
*
|
|
97
149
|
* 1. If the destination already exists, copy it to a timestamped `.bak` so a
|
|
98
|
-
* bad write is always recoverable
|
|
150
|
+
* bad write is always recoverable, then prune older backups to
|
|
151
|
+
* {@link BACKUP_RETENTION}.
|
|
99
152
|
* 2. Write to a unique temp file in the same directory, then rename it over the
|
|
100
153
|
* destination. rename() is atomic on the same filesystem, so a reader never
|
|
101
154
|
* observes a half-written file.
|
|
102
155
|
*/
|
|
103
156
|
async function atomicWriteYaml(filePath, data) {
|
|
157
|
+
// The bundled sample lives inside the installed package and is read at a
|
|
158
|
+
// shifted date (see sample-data.ts). Writing to it would bake one session's
|
|
159
|
+
// shifted dates into the demo everyone else sees, and in a global install it
|
|
160
|
+
// means editing node_modules. It is a demo, not a store.
|
|
161
|
+
if (servingBundledSample()) {
|
|
162
|
+
throw new Error(`${filePath} is inside the bundled sample data, which is a read-only demo. ` +
|
|
163
|
+
`Point CAREER_DATA_PATH at your own directory (or unset it to use ~/.career-compass) before saving.`);
|
|
164
|
+
}
|
|
104
165
|
const dir = dirname(filePath);
|
|
105
166
|
await mkdir(dir, { recursive: true });
|
|
106
167
|
if (existsSync(filePath)) {
|
|
107
168
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
108
169
|
const backupPath = join(dir, `${basename(filePath)}.${stamp}.bak`);
|
|
109
170
|
await copyFile(filePath, backupPath);
|
|
171
|
+
await pruneBackups(dir, basename(filePath));
|
|
110
172
|
}
|
|
111
173
|
const tmpPath = join(dir, `.${basename(filePath)}.${randomUUID()}.tmp`);
|
|
112
174
|
const serialized = stringifyYaml(data, { lineWidth: 120 });
|
|
@@ -178,7 +240,10 @@ export async function loadCareerData() {
|
|
|
178
240
|
}
|
|
179
241
|
}));
|
|
180
242
|
try {
|
|
181
|
-
|
|
243
|
+
const parsed = CareerData.parse(raw);
|
|
244
|
+
// Only full YYYY-MM-DD dates move, which in the KB means journal entries.
|
|
245
|
+
// Employment history is YYYY-MM and stays exactly where Alex left it.
|
|
246
|
+
return servingBundledSample() ? freshenSampleDates(parsed) : parsed;
|
|
182
247
|
}
|
|
183
248
|
catch (error) {
|
|
184
249
|
console.error("Career data validation failed:", error);
|
|
@@ -187,7 +252,22 @@ export async function loadCareerData() {
|
|
|
187
252
|
throw new CorruptDataError(profilePath, error);
|
|
188
253
|
}
|
|
189
254
|
}
|
|
255
|
+
/** The only section names that may become a filename. */
|
|
256
|
+
export const CAREER_SECTIONS = [
|
|
257
|
+
"profile", "experience", "skills", "education", "projects", "testimonials",
|
|
258
|
+
];
|
|
259
|
+
/**
|
|
260
|
+
* Write one section of the Career KB.
|
|
261
|
+
*
|
|
262
|
+
* `section` becomes a path segment, so it is checked against an allowlist rather
|
|
263
|
+
* than trusted. Before this was reachable from a tool it was only ever called
|
|
264
|
+
* with literals; now that a model can supply the value, `../../.ssh/id_rsa` has
|
|
265
|
+
* to be impossible rather than merely unlikely.
|
|
266
|
+
*/
|
|
190
267
|
export async function saveCareerSection(section, data) {
|
|
268
|
+
if (!CAREER_SECTIONS.includes(section)) {
|
|
269
|
+
throw new Error(`Unknown career section "${section}". Expected one of: ${CAREER_SECTIONS.join(", ")}.`);
|
|
270
|
+
}
|
|
191
271
|
const path = join(careerDir(), `${section}.yaml`);
|
|
192
272
|
await withDataLock(path, () => atomicWriteYaml(path, data));
|
|
193
273
|
}
|
|
@@ -205,7 +285,9 @@ function journalPath() { return join(careerDir(), "journal.yaml"); }
|
|
|
205
285
|
*/
|
|
206
286
|
export async function loadJournal() {
|
|
207
287
|
const parsed = await readYaml(journalPath(), JournalSection);
|
|
208
|
-
|
|
288
|
+
if (!parsed)
|
|
289
|
+
return [];
|
|
290
|
+
return servingBundledSample() ? freshenSampleDates(parsed) : parsed;
|
|
209
291
|
}
|
|
210
292
|
/**
|
|
211
293
|
* Append one entry to the journal and persist it (atomic write + .bak backup,
|
|
@@ -235,7 +317,10 @@ export async function loadPipeline() {
|
|
|
235
317
|
try {
|
|
236
318
|
const raw = await readFile(path, "utf-8");
|
|
237
319
|
const parsed = parseYaml(raw);
|
|
238
|
-
|
|
320
|
+
const pipeline = Pipeline.parse(parsed);
|
|
321
|
+
// The bundled demo is dated relative to today so its interviews are still
|
|
322
|
+
// upcoming and its follow-ups are not months overdue. Nothing on disk moves.
|
|
323
|
+
return servingBundledSample() ? freshenSampleDates(pipeline) : pipeline;
|
|
239
324
|
}
|
|
240
325
|
catch (error) {
|
|
241
326
|
console.error("Failed to parse pipeline:", error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../src/storage/file-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../src/storage/file-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/** The shapes as one block, for the `data` parameter description. */
|
|
3
|
+
export declare const SECTION_SHAPE_HELP: string;
|
|
2
4
|
export declare function registerCareerKBTools(server: McpServer): void;
|
|
3
5
|
//# sourceMappingURL=career-kb.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"career-kb.d.ts","sourceRoot":"","sources":["../../../src/tools/career-kb.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"career-kb.d.ts","sourceRoot":"","sources":["../../../src/tools/career-kb.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0DzE,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,QAElB,CAAC;AAEd,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2X7D"}
|
|
@@ -1,7 +1,56 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { randomUUID } from "crypto";
|
|
3
|
-
import {
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { saveCareerSection, mutatePipeline, appendJournalEntry, isCorruptDataError, getDataDir, CAREER_SECTIONS } from "../storage/file-store.js";
|
|
5
|
+
import { Profile, Experience, Skill, Education, Project, Testimonial } from "../schemas/career-schema.js";
|
|
4
6
|
import { embedUntrusted } from "../untrusted.js";
|
|
7
|
+
/** Per-section schema, so a write is validated with the same rules the loader
|
|
8
|
+
* enforces on read. Writing first and validating later would let one bad write
|
|
9
|
+
* make the entire KB unloadable. */
|
|
10
|
+
const CAREER_SECTION_SCHEMA = {
|
|
11
|
+
profile: Profile,
|
|
12
|
+
experience: z.array(Experience),
|
|
13
|
+
skills: z.array(Skill),
|
|
14
|
+
education: z.array(Education),
|
|
15
|
+
projects: z.array(Project),
|
|
16
|
+
testimonials: z.array(Testimonial),
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* What each section's `data` has to look like, in the parameter description and
|
|
20
|
+
* in the error when it doesn't.
|
|
21
|
+
*
|
|
22
|
+
* `data` is `z.unknown()` because its shape depends on `section`, so the
|
|
23
|
+
* generated input schema tells a caller nothing at all — and the first thing
|
|
24
|
+
* anyone writes for an experience entry is `achievements: ["led the migration"]`,
|
|
25
|
+
* which is a list of strings where the schema wants objects. The write is
|
|
26
|
+
* correctly refused, but a first write that fails is a first impression, and
|
|
27
|
+
* the caller had no way to know the shape before trying.
|
|
28
|
+
*
|
|
29
|
+
* Written out rather than derived from zod at runtime: a generated summary of a
|
|
30
|
+
* nested schema is either unreadable or lossy, and the guard test asserts every
|
|
31
|
+
* required field of every section appears here, so it cannot drift.
|
|
32
|
+
*/
|
|
33
|
+
const SECTION_SHAPES = {
|
|
34
|
+
profile: "one object: { name, summary, email?, phone?, location?, linkedIn?, portfolio?, " +
|
|
35
|
+
"targetRoles?: [string], targetIndustries?: [string], salaryMin?: number, salaryMax?: number }",
|
|
36
|
+
experience: "array of { role, company, startDate: 'YYYY-MM', endDate: 'YYYY-MM' | 'present', " +
|
|
37
|
+
"summary?, industry?, location?, tags?: [string], " +
|
|
38
|
+
"achievements: [{ metric, context, impact, keywords?: [string] }] } " +
|
|
39
|
+
"— achievements are OBJECTS, not strings: metric is the quantified outcome " +
|
|
40
|
+
"('cut onboarding from 6 weeks to 9 days'), context is the situation, impact is why it mattered",
|
|
41
|
+
skills: "array of { name, category ('Technical' | 'Leadership' | 'Domain' | …), " +
|
|
42
|
+
"proficiency?: 1-5, yearsUsed?: number, lastUsed?: 'YYYY' | 'current' }",
|
|
43
|
+
education: "array of { degree, institution, date: 'YYYY' | 'YYYY-MM', honors?, " +
|
|
44
|
+
"relevantCoursework?: [string], certifications?: [string] }",
|
|
45
|
+
projects: "array of { name, role, description, technologies?: [string], metrics?: [string], " +
|
|
46
|
+
"outcomes?: [string], url? }",
|
|
47
|
+
testimonials: "array of { source (name and title), relationship ('Direct Manager' | 'Peer' | …), " +
|
|
48
|
+
"quote, date?, context? }",
|
|
49
|
+
};
|
|
50
|
+
/** The shapes as one block, for the `data` parameter description. */
|
|
51
|
+
export const SECTION_SHAPE_HELP = Object.entries(SECTION_SHAPES)
|
|
52
|
+
.map(([section, shape]) => `${section}: ${shape}`)
|
|
53
|
+
.join("\n");
|
|
5
54
|
export function registerCareerKBTools(server) {
|
|
6
55
|
server.registerTool("ingest_document", {
|
|
7
56
|
title: "Ingest Career Document",
|
|
@@ -12,16 +61,23 @@ export function registerCareerKBTools(server) {
|
|
|
12
61
|
idempotentHint: true,
|
|
13
62
|
openWorldHint: false,
|
|
14
63
|
},
|
|
15
|
-
description: "Paste any career document — performance review, award email, project summary, LinkedIn recommendation — and extract structured achievements
|
|
64
|
+
description: "Paste any career document — performance review, award email, project summary, LinkedIn recommendation — and extract structured achievements for your Career KB. " +
|
|
65
|
+
"Extraction only: it reads what you paste and returns YAML for review. Writing that YAML to disk is a separate, explicit step with save_career_section.",
|
|
16
66
|
inputSchema: {
|
|
17
67
|
content: z.string().describe("Full document text to ingest"),
|
|
18
68
|
documentType: z.enum(["performance_review", "award", "project_summary", "recommendation", "email", "self_review", "other"]).describe("Type of document"),
|
|
19
69
|
associatedRole: z.string().optional().describe("Job role this document relates to"),
|
|
20
70
|
associatedCompany: z.string().optional().describe("Company this document relates to"),
|
|
21
71
|
datePeriod: z.string().optional().describe("Time period this covers, e.g. '2023 Q1' or '2022-2023'"),
|
|
22
|
-
autoSave: z.boolean().default(false).describe("If true, the output names the exact Career KB file each extracted item belongs in, so you can review before anything is written. This tool only extracts — it never writes."),
|
|
23
72
|
},
|
|
24
|
-
},
|
|
73
|
+
},
|
|
74
|
+
// There used to be an `autoSave` flag here. This tool is readOnlyHint:true
|
|
75
|
+
// and has no write path, so the flag never saved anything — it only chose
|
|
76
|
+
// which closing paragraph to print, one of which told the caller to set it
|
|
77
|
+
// "to let Claude do it automatically." Removing it is the honest fix; a
|
|
78
|
+
// caller that still sends it is ignored rather than failed, and the output
|
|
79
|
+
// now names the one tool that actually writes the Career KB.
|
|
80
|
+
async ({ content, documentType, associatedRole, associatedCompany, datePeriod }) => {
|
|
25
81
|
return {
|
|
26
82
|
content: [{
|
|
27
83
|
type: "text",
|
|
@@ -78,11 +134,14 @@ skills:
|
|
|
78
134
|
### 4. Keywords Extracted
|
|
79
135
|
Top 10 ATS-friendly keywords from this document.
|
|
80
136
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
**Nothing has been written.** This tool only extracts.
|
|
140
|
+
|
|
141
|
+
**To save:** show the user the YAML above, then call \`save_career_section\` with the
|
|
142
|
+
section it belongs in (\`experience\`, \`skills\`, \`testimonials\`, …). That tool replaces the
|
|
143
|
+
whole section, so send the existing entries plus the new ones — read the section first if
|
|
144
|
+
you don't already have it. The previous version is kept as a timestamped \`.bak\`.`,
|
|
86
145
|
}],
|
|
87
146
|
};
|
|
88
147
|
});
|
|
@@ -95,9 +154,16 @@ ${autoSave ? `
|
|
|
95
154
|
idempotentHint: false,
|
|
96
155
|
openWorldHint: false,
|
|
97
156
|
},
|
|
98
|
-
|
|
157
|
+
// The annotations have always been honest — destructiveHint is true — but
|
|
158
|
+
// the sentence a user reads in the confirmation dialog described a
|
|
159
|
+
// drafting tool. Passing applicationId also writes the pipeline, and the
|
|
160
|
+
// description is where that has to be said.
|
|
161
|
+
description: "Craft a graceful rejection response that keeps the door open, maintains relationships, and " +
|
|
162
|
+
"positions you for future opportunities. If you pass applicationId, this also sets that " +
|
|
163
|
+
"application's status to `rejected` in your pipeline — it does not only write a draft.",
|
|
99
164
|
inputSchema: {
|
|
100
|
-
applicationId: z.string().optional().describe("Pipeline application ID"
|
|
165
|
+
applicationId: z.string().optional().describe("Pipeline application ID. Supplying it fills in the company and role from the pipeline AND " +
|
|
166
|
+
"marks that application `rejected`. Leave it out to draft a reply and change nothing."),
|
|
101
167
|
company: z.string().optional().describe("Company that sent the rejection. Filled in automatically when applicationId is given."),
|
|
102
168
|
role: z.string().optional().describe("Role you were rejected for. Filled in automatically when applicationId is given."),
|
|
103
169
|
rejectionContent: z.string().describe("The rejection email or message content"),
|
|
@@ -106,6 +172,11 @@ ${autoSave ? `
|
|
|
106
172
|
hadGoodRapport: z.boolean().default(false).describe("Did you have positive interactions during the process?"),
|
|
107
173
|
},
|
|
108
174
|
}, async ({ applicationId, company, role, rejectionContent, responseGoal, contactName, hadGoodRapport }) => {
|
|
175
|
+
// Track whether the status was ACTUALLY changed. Reporting the update on
|
|
176
|
+
// `applicationId` being present meant a bad id produced "status has been
|
|
177
|
+
// automatically updated to 'rejected'" while nothing was written — the
|
|
178
|
+
// tool claiming a state change it never made.
|
|
179
|
+
let statusUpdated = false;
|
|
109
180
|
if (applicationId) {
|
|
110
181
|
// Same critical section as pipeline_update: this is a read-modify-write
|
|
111
182
|
// on the shared pipeline file, so it must not straddle the lock.
|
|
@@ -119,6 +190,7 @@ ${autoSave ? `
|
|
|
119
190
|
// Auto-update status to rejected
|
|
120
191
|
app.status = "rejected";
|
|
121
192
|
app.dateUpdated = new Date().toISOString();
|
|
193
|
+
statusUpdated = true;
|
|
122
194
|
});
|
|
123
195
|
}
|
|
124
196
|
return {
|
|
@@ -159,7 +231,13 @@ ${responseGoal === "express_continued_interest" ? "Mention the company is still
|
|
|
159
231
|
2. **Alternative version** (different angle)
|
|
160
232
|
3. **LinkedIn connection note** (if you haven't connected yet — 300 chars)
|
|
161
233
|
|
|
162
|
-
${
|
|
234
|
+
${statusUpdated
|
|
235
|
+
? `
|
|
236
|
+
**Note:** ${applicationId} is now marked 'rejected' in your pipeline.`
|
|
237
|
+
: applicationId
|
|
238
|
+
? `
|
|
239
|
+
**Note:** No application matching \`${applicationId}\` is in your pipeline, so nothing was changed. The draft above still stands.`
|
|
240
|
+
: ""}`,
|
|
163
241
|
}],
|
|
164
242
|
};
|
|
165
243
|
});
|
|
@@ -251,5 +329,70 @@ ${applicationId ? `\n**Note:** Application ${applicationId} status has been auto
|
|
|
251
329
|
}],
|
|
252
330
|
};
|
|
253
331
|
});
|
|
332
|
+
server.registerTool("save_career_section", {
|
|
333
|
+
title: "Save Career KB Section",
|
|
334
|
+
// Overwrites one section file wholesale — a destructive update, so a host
|
|
335
|
+
// always confirms. The previous contents are kept as a timestamped .bak.
|
|
336
|
+
annotations: {
|
|
337
|
+
readOnlyHint: false,
|
|
338
|
+
destructiveHint: true,
|
|
339
|
+
idempotentHint: true,
|
|
340
|
+
openWorldHint: false,
|
|
341
|
+
},
|
|
342
|
+
description: "Write one section of the Career KB to disk. This is how the Career KB gets populated — " +
|
|
343
|
+
"ingest_document and the resume tools only read and extract. Replaces the whole section, " +
|
|
344
|
+
"so send the complete list you want stored, not just new entries. The previous version is " +
|
|
345
|
+
"kept as a timestamped .bak next to it.",
|
|
346
|
+
inputSchema: {
|
|
347
|
+
section: z.enum(CAREER_SECTIONS).describe("Which part of the Career KB to write. 'profile' is a single object; every other section is a list."),
|
|
348
|
+
data: z.unknown().describe("The complete contents for this section — an object for 'profile', an array for every " +
|
|
349
|
+
"other section. Shapes (? marks optional):\n\n" +
|
|
350
|
+
SECTION_SHAPE_HELP),
|
|
351
|
+
},
|
|
352
|
+
}, async ({ section, data }) => {
|
|
353
|
+
// Validate against the same schema the loader enforces, BEFORE touching
|
|
354
|
+
// disk. Writing first and validating on read would let one bad write make
|
|
355
|
+
// the whole KB unloadable — loadCareerData fails closed on a corrupt
|
|
356
|
+
// section, so an invalid profile.yaml takes every KB-backed tool down.
|
|
357
|
+
const schema = CAREER_SECTION_SCHEMA[section];
|
|
358
|
+
const parsed = schema.safeParse(data);
|
|
359
|
+
if (!parsed.success) {
|
|
360
|
+
const issues = parsed.error.issues
|
|
361
|
+
.slice(0, 6)
|
|
362
|
+
.map((i) => ` • ${i.path.join(".") || "(root)"}: ${i.message}`)
|
|
363
|
+
.join("\n");
|
|
364
|
+
return {
|
|
365
|
+
isError: true,
|
|
366
|
+
content: [{
|
|
367
|
+
type: "text",
|
|
368
|
+
text: `❌ That doesn't match the shape of \`${section}\`, so nothing was written ` +
|
|
369
|
+
`(your existing ${section}.yaml is untouched).\n\n${issues}` +
|
|
370
|
+
(parsed.error.issues.length > 6 ? `\n …and ${parsed.error.issues.length - 6} more` : "") +
|
|
371
|
+
// The issue list says which field is wrong; it does not say what
|
|
372
|
+
// right looks like. Repeating the shape here is what makes the
|
|
373
|
+
// retry a correction rather than a guess.
|
|
374
|
+
`\n\nExpected \`${section}\`: ${SECTION_SHAPES[section]}`,
|
|
375
|
+
}],
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
await saveCareerSection(section, parsed.data);
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
return {
|
|
383
|
+
isError: true,
|
|
384
|
+
content: [{ type: "text", text: `❌ Could not write ${section}: ${error.message}` }],
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
const count = Array.isArray(parsed.data) ? parsed.data.length : 1;
|
|
388
|
+
return {
|
|
389
|
+
content: [{
|
|
390
|
+
type: "text",
|
|
391
|
+
text: `✅ Saved **${section}** (${count} ${count === 1 ? "entry" : "entries"}) to ` +
|
|
392
|
+
`\`${join(getDataDir(), "career", `${section}.yaml`)}\`.\n\n` +
|
|
393
|
+
`It's plain YAML — open it, edit it, or delete it any time. Nothing left your machine.`,
|
|
394
|
+
}],
|
|
395
|
+
};
|
|
396
|
+
});
|
|
254
397
|
}
|
|
255
398
|
//# sourceMappingURL=career-kb.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"career-kb.js","sourceRoot":"","sources":["../../../src/tools/career-kb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,
|
|
1
|
+
{"version":3,"file":"career-kb.js","sourceRoot":"","sources":["../../../src/tools/career-kb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAkB,iBAAiB,EAAgB,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChL,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE1G,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;qCAEqC;AACrC,MAAM,qBAAqB,GAAG;IAC5B,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;IAC7B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAC1B,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC;CAC1B,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,MAAM,cAAc,GAAuD;IACzE,OAAO,EACL,iFAAiF;QACjF,+FAA+F;IACjG,UAAU,EACR,kFAAkF;QAClF,mDAAmD;QACnD,qEAAqE;QACrE,4EAA4E;QAC5E,gGAAgG;IAClG,MAAM,EACJ,yEAAyE;QACzE,wEAAwE;IAC1E,SAAS,EACP,qEAAqE;QACrE,4DAA4D;IAC9D,QAAQ,EACN,mFAAmF;QACnF,6BAA6B;IAC/B,YAAY,EACV,oFAAoF;QACpF,0BAA0B;CAC7B,CAAC;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;KAC7D,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,KAAK,KAAK,EAAE,CAAC;KACjD,IAAI,CAAC,IAAI,CAAC,CAAC;AAEd,MAAM,UAAU,qBAAqB,CAAC,MAAiB;IAErD,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,wBAAwB;QAC/B,kGAAkG;QAClG,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;QACD,WAAW,EACT,kKAAkK;YAClK,wJAAwJ;QAC1J,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;YAC5D,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,oBAAoB,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YACxJ,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YACnF,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;YACrF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;SACrG;KACF;IACD,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,2EAA2E;IAC3E,6DAA6D;IAC7D,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,UAAU,EAAE,EAAE,EAAE;QACjF,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;;;YAGJ,YAAY;EACtB,cAAc,CAAC,CAAC,CAAC,aAAa,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE;EACnD,iBAAiB,CAAC,CAAC,CAAC,gBAAgB,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;EAC5D,UAAU,CAAC,CAAC,CAAC,eAAe,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;;;EAG7C,cAAc,CAAC,mBAAmB,EAAE,OAAO,CAAC;;;;;;;;;;;;;;mBAc3B,YAAY,MAAM,iBAAiB,IAAI,iBAAiB,MAAM,UAAU,IAAI,gBAAgB;;WAEpG,cAAc,IAAI,SAAS;cACxB,iBAAiB,IAAI,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mFAkCuC;iBAC1E,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,6BAA6B,EAC7B;QACE,KAAK,EAAE,6BAA6B;QACpC,qIAAqI;QACrI,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,KAAK;SACrB;QACD,0EAA0E;QAC1E,mEAAmE;QACnE,yEAAyE;QACzE,4CAA4C;QAC5C,WAAW,EACT,6FAA6F;YAC7F,yFAAyF;YACzF,uFAAuF;QACzF,WAAW,EAAE;YACX,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAC3C,4FAA4F;gBAC1F,sFAAsF,CACzF;YACD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;YAChI,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kFAAkF,CAAC;YACxH,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YAC/E,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,gLAAgL,CAAC;YACrU,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC5E,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,wDAAwD,CAAC;SAC9G;KACF,EACD,KAAK,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,EAAE;QACtG,yEAAyE;QACzE,yEAAyE;QACzE,uEAAuE;QACvE,8CAA8C;QAC9C,IAAI,aAAa,GAAG,KAAK,CAAC;QAC1B,IAAI,aAAa,EAAE,CAAC;YAClB,wEAAwE;YACxE,iEAAiE;YACjE,MAAM,cAAc,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAChC,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,CAAC;gBACpE,qEAAqE;gBACrE,IAAI,CAAC,GAAG;oBAAE,OAAO;gBACjB,OAAO,GAAG,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC;gBACjC,IAAI,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC;gBACxB,iCAAiC;gBACjC,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC;gBACxB,GAAG,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBAC3C,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;;;eAGD,OAAO,IAAI,SAAS;YACvB,IAAI,IAAI,SAAS;EAC3B,WAAW,CAAC,CAAC,CAAC,aAAa,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;YACnC,YAAY;qBACH,cAAc,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,SAAS;;;EAGnF,cAAc,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;;;;;8CAKT,YAAY;;;;;;;EAOxD,cAAc,CAAC,CAAC,CAAC,gEAAgE,CAAC,CAAC,CAAC,EAAE;;cAE1E,YAAY;EACxB,YAAY,KAAK,gBAAgB,CAAC,CAAC,CAAC,qGAAqG,CAAC,CAAC,CAAC,EAAE;EAC9I,YAAY,KAAK,kBAAkB,CAAC,CAAC,CAAC,iGAAiG,CAAC,CAAC,CAAC,EAAE;EAC5I,YAAY,KAAK,oBAAoB,CAAC,CAAC,CAAC,8FAA8F,CAAC,CAAC,CAAC,EAAE;EAC3I,YAAY,KAAK,4BAA4B,CAAC,CAAC,CAAC,uGAAuG,CAAC,CAAC,CAAC,EAAE;;;;;;;EAO5J,aAAa;wBACb,CAAC,CAAC;YACQ,aAAa,6CAA6C;wBACpE,CAAC,CAAC,aAAa;4BACb,CAAC,CAAC;sCACgC,aAAa,+EAA+E;4BAC9H,CAAC,CAAC,EAAE,EAAE;iBACD,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,wBAAwB;QAC/B,uGAAuG;QACvG,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,KAAK;SACrB;QACD,WAAW,EACT,oSAAoS;QACtS,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;gBACX,YAAY;gBACZ,mBAAmB;gBACnB,kBAAkB;gBAClB,mBAAmB;gBACnB,gBAAgB;gBAChB,KAAK;gBACL,MAAM;aACP,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;YACnF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACnE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACxF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6GAA6G,CAAC;YACtJ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;YAC7E,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,2DAA2D,CAAC;YAC9G,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;YACrI,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC;gBACb,qBAAqB;gBACrB,mBAAmB;gBACnB,gBAAgB;gBAChB,WAAW;gBACX,iBAAiB;gBACjB,QAAQ;aACT,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;SACrE;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE;QAC5F,MAAM,KAAK,GAAiB;YAC1B,EAAE,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5B,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC9B,IAAI;YACJ,OAAO;YACP,MAAM;YACN,aAAa;YACb,OAAO;YACP,IAAI;YACJ,OAAO;YACP,SAAS;YACT,MAAM;SACP,CAAC;QAEF,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC5C,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EACF,4EAA4E;gCAC5E,mDAAmD;gCACnD,8FAA8F;gCAC9F,yDAAyD,OAAO,EAAE;yBACrE,CAAC;iBACH,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG;YACX,OAAO,IAAI,KAAK,OAAO,IAAI;YAC3B,IAAI;YACJ,aAAa,IAAI,KAAK,aAAa,IAAI;YACvC,SAAS,IAAI,cAAc,SAAS,EAAE;SACvC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE9B,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,yCAAyC,IAAI,UAAU;wBACvD,KAAK,OAAO,IAAI;wBAChB,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC/B,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC3B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBACnF,cAAc,KAAK,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,sBAAsB;wBAChF,+FAA+F;iBAClG,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,wBAAwB;QAC/B,0EAA0E;QAC1E,yEAAyE;QACzE,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;QACD,WAAW,EACT,yFAAyF;YACzF,0FAA0F;YAC1F,2FAA2F;YAC3F,wCAAwC;QAC1C,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,QAAQ,CACvC,oGAAoG,CACrG;YACD,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CACxB,uFAAuF;gBACrF,+CAA+C;gBAC/C,kBAAkB,CACrB;SACF;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1B,wEAAwE;QACxE,0EAA0E;QAC1E,qEAAqE;QACrE,uEAAuE;QACvE,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;iBAC/B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;iBAC/D,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EACF,uCAAuC,OAAO,6BAA6B;4BAC3E,kBAAkB,OAAO,2BAA2B,MAAM,EAAE;4BAC5D,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;4BACzF,iEAAiE;4BACjE,+DAA+D;4BAC/D,0CAA0C;4BAC1C,kBAAkB,OAAO,OAAO,cAAc,CAAC,OAAO,CAAC,EAAE;qBAC5D,CAAC;aACH,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,OAAO,KAAM,KAAe,CAAC,OAAO,EAAE,EAAE,CAAC;aAC/F,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,aAAa,OAAO,OAAO,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO;wBAC5E,KAAK,IAAI,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,GAAG,OAAO,OAAO,CAAC,SAAS;wBAC7D,uFAAuF;iBAC1F,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|