@rwendell/dossier 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -2
  3. package/agents/dossier-answerer.md +168 -0
  4. package/agents/dossier-proposer.md +215 -0
  5. package/agents/dossier-tailor.md +232 -0
  6. package/dist/answer/prompt.d.ts +17 -0
  7. package/dist/answer/prompt.js +44 -0
  8. package/dist/answer/prompt.js.map +1 -0
  9. package/dist/answer/run.d.ts +21 -0
  10. package/dist/answer/run.js +272 -0
  11. package/dist/answer/run.js.map +1 -0
  12. package/dist/career/import-resume.d.ts +17 -0
  13. package/dist/career/import-resume.js +194 -0
  14. package/dist/career/import-resume.js.map +1 -0
  15. package/dist/career/load.d.ts +10 -0
  16. package/dist/career/load.js +96 -0
  17. package/dist/career/load.js.map +1 -0
  18. package/dist/career/schema.d.ts +147 -0
  19. package/dist/career/schema.js +95 -0
  20. package/dist/career/schema.js.map +1 -0
  21. package/dist/clean/run.d.ts +1 -0
  22. package/dist/clean/run.js +8 -0
  23. package/dist/clean/run.js.map +1 -0
  24. package/dist/cli/commands/answer.d.ts +23 -0
  25. package/dist/cli/commands/answer.js +110 -0
  26. package/dist/cli/commands/answer.js.map +1 -0
  27. package/dist/cli/commands/clean.d.ts +2 -0
  28. package/dist/cli/commands/clean.js +11 -0
  29. package/dist/cli/commands/clean.js.map +1 -0
  30. package/dist/cli/commands/doctor.d.ts +2 -0
  31. package/dist/cli/commands/doctor.js +77 -0
  32. package/dist/cli/commands/doctor.js.map +1 -0
  33. package/dist/cli/commands/init.d.ts +7 -0
  34. package/dist/cli/commands/init.js +80 -0
  35. package/dist/cli/commands/init.js.map +1 -0
  36. package/dist/cli/commands/paths.d.ts +7 -0
  37. package/dist/cli/commands/paths.js +42 -0
  38. package/dist/cli/commands/paths.js.map +1 -0
  39. package/dist/cli/commands/proposal.d.ts +30 -0
  40. package/dist/cli/commands/proposal.js +148 -0
  41. package/dist/cli/commands/proposal.js.map +1 -0
  42. package/dist/cli/commands/pull-private.d.ts +8 -0
  43. package/dist/cli/commands/pull-private.js +30 -0
  44. package/dist/cli/commands/pull-private.js.map +1 -0
  45. package/dist/cli/commands/score.d.ts +11 -0
  46. package/dist/cli/commands/score.js +58 -0
  47. package/dist/cli/commands/score.js.map +1 -0
  48. package/dist/cli/commands/sync.d.ts +13 -0
  49. package/dist/cli/commands/sync.js +65 -0
  50. package/dist/cli/commands/sync.js.map +1 -0
  51. package/dist/cli/commands/tailor.d.ts +24 -0
  52. package/dist/cli/commands/tailor.js +113 -0
  53. package/dist/cli/commands/tailor.js.map +1 -0
  54. package/dist/cli/commands/verify.d.ts +6 -0
  55. package/dist/cli/commands/verify.js +15 -0
  56. package/dist/cli/commands/verify.js.map +1 -0
  57. package/dist/cli/index.d.ts +2 -0
  58. package/dist/cli/index.js +87 -0
  59. package/dist/cli/index.js.map +1 -0
  60. package/dist/config/config.d.ts +36 -0
  61. package/dist/config/config.js +71 -0
  62. package/dist/config/config.js.map +1 -0
  63. package/dist/config/paths.d.ts +32 -0
  64. package/dist/config/paths.js +121 -0
  65. package/dist/config/paths.js.map +1 -0
  66. package/dist/evidence/numbers.d.ts +2 -0
  67. package/dist/evidence/numbers.js +26 -0
  68. package/dist/evidence/numbers.js.map +1 -0
  69. package/dist/evidence/verify.d.ts +109 -0
  70. package/dist/evidence/verify.js +445 -0
  71. package/dist/evidence/verify.js.map +1 -0
  72. package/dist/job/input.d.ts +9 -0
  73. package/dist/job/input.js +141 -0
  74. package/dist/job/input.js.map +1 -0
  75. package/dist/job/page.d.ts +14 -0
  76. package/dist/job/page.js +426 -0
  77. package/dist/job/page.js.map +1 -0
  78. package/dist/job/types.d.ts +30 -0
  79. package/dist/job/types.js +2 -0
  80. package/dist/job/types.js.map +1 -0
  81. package/dist/llm/agents.d.ts +7 -0
  82. package/dist/llm/agents.js +44 -0
  83. package/dist/llm/agents.js.map +1 -0
  84. package/dist/llm/opencode.d.ts +19 -0
  85. package/dist/llm/opencode.js +117 -0
  86. package/dist/llm/opencode.js.map +1 -0
  87. package/dist/llm/providers.d.ts +63 -0
  88. package/dist/llm/providers.js +207 -0
  89. package/dist/llm/providers.js.map +1 -0
  90. package/dist/private/pull.d.ts +7 -0
  91. package/dist/private/pull.js +168 -0
  92. package/dist/private/pull.js.map +1 -0
  93. package/dist/projects/rank.d.ts +17 -0
  94. package/dist/projects/rank.js +100 -0
  95. package/dist/projects/rank.js.map +1 -0
  96. package/dist/projects/store.d.ts +7 -0
  97. package/dist/projects/store.js +31 -0
  98. package/dist/projects/store.js.map +1 -0
  99. package/dist/projects/sync-github.d.ts +11 -0
  100. package/dist/projects/sync-github.js +269 -0
  101. package/dist/projects/sync-github.js.map +1 -0
  102. package/dist/projects/sync-local.d.ts +8 -0
  103. package/dist/projects/sync-local.js +318 -0
  104. package/dist/projects/sync-local.js.map +1 -0
  105. package/dist/projects/types.d.ts +71 -0
  106. package/dist/projects/types.js +2 -0
  107. package/dist/projects/types.js.map +1 -0
  108. package/dist/proposal/prompt.d.ts +20 -0
  109. package/dist/proposal/prompt.js +64 -0
  110. package/dist/proposal/prompt.js.map +1 -0
  111. package/dist/proposal/run.d.ts +28 -0
  112. package/dist/proposal/run.js +386 -0
  113. package/dist/proposal/run.js.map +1 -0
  114. package/dist/resume/basics.d.ts +4 -0
  115. package/dist/resume/basics.js +33 -0
  116. package/dist/resume/basics.js.map +1 -0
  117. package/dist/resume/find.d.ts +12 -0
  118. package/dist/resume/find.js +27 -0
  119. package/dist/resume/find.js.map +1 -0
  120. package/dist/resume/format.d.ts +3 -0
  121. package/dist/resume/format.js +53 -0
  122. package/dist/resume/format.js.map +1 -0
  123. package/dist/resume/one-page.d.ts +149 -0
  124. package/dist/resume/one-page.js +164 -0
  125. package/dist/resume/one-page.js.map +1 -0
  126. package/dist/resume/prompt.d.ts +10 -0
  127. package/dist/resume/prompt.js +23 -0
  128. package/dist/resume/prompt.js.map +1 -0
  129. package/dist/resume/render.d.ts +8 -0
  130. package/dist/resume/render.js +84 -0
  131. package/dist/resume/render.js.map +1 -0
  132. package/dist/resume/run.d.ts +21 -0
  133. package/dist/resume/run.js +350 -0
  134. package/dist/resume/run.js.map +1 -0
  135. package/dist/resume/skills.d.ts +6 -0
  136. package/dist/resume/skills.js +47 -0
  137. package/dist/resume/skills.js.map +1 -0
  138. package/dist/resume/trace.d.ts +13 -0
  139. package/dist/resume/trace.js +82 -0
  140. package/dist/resume/trace.js.map +1 -0
  141. package/dist/resume/types.d.ts +94 -0
  142. package/dist/resume/types.js +2 -0
  143. package/dist/resume/types.js.map +1 -0
  144. package/dist/resume/verify.d.ts +19 -0
  145. package/dist/resume/verify.js +193 -0
  146. package/dist/resume/verify.js.map +1 -0
  147. package/dist/upwork/profile.d.ts +50 -0
  148. package/dist/upwork/profile.js +302 -0
  149. package/dist/upwork/profile.js.map +1 -0
  150. package/dist/upwork/settings.d.ts +96 -0
  151. package/dist/upwork/settings.js +166 -0
  152. package/dist/upwork/settings.js.map +1 -0
  153. package/dist/util/open-file.d.ts +1 -0
  154. package/dist/util/open-file.js +24 -0
  155. package/dist/util/open-file.js.map +1 -0
  156. package/dist/util/slug.d.ts +2 -0
  157. package/dist/util/slug.js +13 -0
  158. package/dist/util/slug.js.map +1 -0
  159. package/dist/verify/run.d.ts +4 -0
  160. package/dist/verify/run.js +91 -0
  161. package/dist/verify/run.js.map +1 -0
  162. package/package.json +67 -4
  163. package/templates/career.example.yml +63 -0
  164. package/templates/career.private.example.yml +10 -0
  165. package/templates/config.example.yml +16 -0
  166. package/templates/freelance.example.yml +48 -0
@@ -0,0 +1,272 @@
1
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import clipboard from 'clipboardy';
4
+ import { loadCareer } from '../career/load.js';
5
+ import { loadConfig } from '../config/config.js';
6
+ import { displayPath, getRuntimeDir, resolveOutputDir, } from '../config/paths.js';
7
+ import { verifyAnswer, } from '../evidence/verify.js';
8
+ import { readJobInput } from '../job/input.js';
9
+ import { ensureAgents, reloadOpencode } from '../llm/agents.js';
10
+ import { LlmError, runAgent } from '../llm/providers.js';
11
+ import { hasProjectCache, loadCandidates, } from '../projects/store.js';
12
+ import { findTailoredResume } from '../resume/find.js';
13
+ import { slugify } from '../util/slug.js';
14
+ import { applyProfileToCareer, loadUpworkProfile, mapProfilePortfolio, } from '../upwork/profile.js';
15
+ import { loadFreelanceConfig } from '../upwork/settings.js';
16
+ import { buildAnswerPrompt } from './prompt.js';
17
+ export async function runAnswer(options) {
18
+ const { config } = loadConfig();
19
+ const { config: freelanceConfig } = loadFreelanceConfig();
20
+ const question = readTextInput(options.question);
21
+ if (!question) {
22
+ throw new Error('Provide a question with -q "<text>" or -q question.txt.');
23
+ }
24
+ const configuredProfileUrl = typeof freelanceConfig.profile === 'string'
25
+ ? freelanceConfig.profile
26
+ : freelanceConfig.profile?.url;
27
+ const profileUrl = options.profile ||
28
+ (!options.noProfile ? configuredProfileUrl : '') ||
29
+ '';
30
+ let profile = null;
31
+ if (profileUrl) {
32
+ try {
33
+ profile = await loadUpworkProfile(profileUrl, {
34
+ refresh: options.refresh,
35
+ log: (message) => console.log(`dossier: ${message}`),
36
+ warn: (message) => console.warn(`dossier: ${message}`),
37
+ });
38
+ }
39
+ catch (error) {
40
+ if (options.profile)
41
+ throw error;
42
+ console.warn(`dossier: could not load configured Upwork profile: ${error.message}`);
43
+ }
44
+ }
45
+ const { career } = loadCareer();
46
+ if (profile)
47
+ applyProfileToCareer(career, profile);
48
+ if (profile) {
49
+ const mapped = mapProfilePortfolio(profile, career, []);
50
+ profile.portfolio = mapped.portfolio;
51
+ profile.preferredSamples = mapped.preferredSamples;
52
+ }
53
+ const hint = readHints(options.hint);
54
+ const client = readTextInput(options.client);
55
+ const job = await readJobInput({
56
+ input: options.input,
57
+ title: options.title,
58
+ company: options.company,
59
+ url: options.url,
60
+ description: options.description,
61
+ });
62
+ if (!job.title) {
63
+ throw new Error('Could not determine a job title. Pass --title, or use a job URL/file with a title.');
64
+ }
65
+ const slug = slugify([job.company, job.title].filter(Boolean).join(' ')) ||
66
+ 'application';
67
+ const candidates = loadCandidates(career, job);
68
+ if (candidates.length === 0 && !hasProjectCache()) {
69
+ console.warn('dossier: no project metadata cached; run `dossier sync github` or `dossier sync local` to include repositories.');
70
+ }
71
+ if (profile) {
72
+ const mapped = mapProfilePortfolio(profile, career, candidates);
73
+ profile.portfolio = mapped.portfolio;
74
+ profile.preferredSamples = mapped.preferredSamples;
75
+ }
76
+ const questionSlug = options.name
77
+ ? slugify(options.name).slice(0, 70) || 'question'
78
+ : answerSlug(question);
79
+ const outDir = resolveOutputDir(config.output.dir, options.out);
80
+ mkdirSync(outDir, { recursive: true });
81
+ const base = resolve(outDir, `answer-${slug}.${questionSlug}`);
82
+ const markdownPath = `${base}.md`;
83
+ const jsonPath = `${base}.json`;
84
+ const tailored = findTailoredResume(slug, outDir);
85
+ if (tailored) {
86
+ console.log(`dossier: using tailored resume ${displayPath(tailored.resumePath)}`);
87
+ }
88
+ const prompt = buildAnswerPrompt({
89
+ career,
90
+ job,
91
+ slug,
92
+ question,
93
+ hint,
94
+ client,
95
+ profile,
96
+ candidates,
97
+ resume: tailored?.resume,
98
+ trace: tailored?.trace,
99
+ });
100
+ console.log(`dossier: ${job.company ? `${job.company} — ` : ''}${job.title}`);
101
+ console.log(`dossier: ${truncate(question, 100)}`);
102
+ if (profile) {
103
+ console.log(`dossier: profile ${profile.name || profile.url}`);
104
+ }
105
+ console.log(`dossier: output ${displayPath(markdownPath)}`);
106
+ if (options.debug) {
107
+ writeFileSync(`${base}.prompt.txt`, prompt);
108
+ }
109
+ ensureAgents();
110
+ reloadOpencode();
111
+ let generated;
112
+ try {
113
+ generated = runAgent({
114
+ prompt,
115
+ agent: 'dossier-answerer',
116
+ title: `Answer: ${slug}`,
117
+ timeout: options.timeout ?? 10 * 60 * 1000,
118
+ cwd: getRuntimeDir(),
119
+ provider: options.provider,
120
+ model: options.model,
121
+ accept: (value) => Boolean(value &&
122
+ typeof value.answer === 'string' &&
123
+ value.answer.trim()),
124
+ onAttempt: ({ phase, label, reason, index, total }) => {
125
+ if (phase !== 'failed')
126
+ return;
127
+ const next = index + 1 < total ? '; trying the next provider' : '';
128
+ console.warn(`dossier: ${label} failed: ${reason}${next}`);
129
+ },
130
+ });
131
+ }
132
+ catch (error) {
133
+ const raw = error instanceof LlmError ? error.raw : '';
134
+ if (raw || options.debug) {
135
+ writeFileSync(`${base}.opencode-output.jsonl`, raw);
136
+ }
137
+ if (!(error instanceof LlmError))
138
+ throw error;
139
+ const saved = raw
140
+ ? ` Raw output saved to ${base}.opencode-output.jsonl.`
141
+ : '';
142
+ throw new Error(`${error.message}${saved}`);
143
+ }
144
+ const output = generated.output;
145
+ if (typeof output.answer !== 'string' || !output.answer.trim()) {
146
+ throw new Error('Model response is missing a non-empty "answer" string.');
147
+ }
148
+ const providerLabel = generated.model
149
+ ? `${generated.provider.label} (${generated.model})`
150
+ : `${generated.provider.label} (default model)`;
151
+ console.log(`dossier: draft from ${providerLabel}`);
152
+ const verification = verifyAnswer({
153
+ output,
154
+ career,
155
+ candidates,
156
+ hint,
157
+ client,
158
+ profile,
159
+ });
160
+ if (verification.errors.length > 0) {
161
+ writeFileSync(`${base}.opencode-output.jsonl`, generated.raw || '');
162
+ for (const error of verification.errors) {
163
+ console.error(` error: ${error}`);
164
+ }
165
+ for (const warning of verification.warnings) {
166
+ console.error(` warning: ${warning}`);
167
+ }
168
+ throw new Error(`Answer failed verification. Raw output saved to ${base}.opencode-output.jsonl.`);
169
+ }
170
+ if (options.debug) {
171
+ writeFileSync(`${base}.prompt.txt`, prompt);
172
+ writeFileSync(`${base}.opencode-output.jsonl`, generated.raw || '');
173
+ }
174
+ const answer = output.answer.trim();
175
+ writeFileSync(markdownPath, `${answer}\n`);
176
+ writeFileSync(jsonPath, `${JSON.stringify({
177
+ job: {
178
+ company: job.company,
179
+ title: job.title,
180
+ url: job.url,
181
+ slug,
182
+ details: job.details ?? {},
183
+ },
184
+ profile: profile
185
+ ? {
186
+ url: profile.url,
187
+ name: profile.name,
188
+ title: profile.title,
189
+ location: profile.location,
190
+ rate: profile.rate,
191
+ portfolio: profile.portfolio,
192
+ fetchedAt: profile.fetchedAt,
193
+ cached: Boolean(profile.cached),
194
+ }
195
+ : null,
196
+ question,
197
+ hint: hint || null,
198
+ questionType: output.question_type ?? 'other',
199
+ answer,
200
+ claims: output.claims ?? [],
201
+ evidence: output.evidence ?? [],
202
+ gaps: output.gaps ?? [],
203
+ followUp: output.follow_up ?? [],
204
+ provider: generated.provider.label,
205
+ model: generated.model,
206
+ cost: generated.stats?.cost ?? 0,
207
+ generatedAt: new Date().toISOString(),
208
+ sources: {
209
+ profile: profile?.cachePath ?? null,
210
+ resume: tailored?.resumePath ?? null,
211
+ trace: tailored?.tracePath ?? null,
212
+ },
213
+ }, null, '\t')}\n`);
214
+ for (const warning of verification.warnings) {
215
+ console.warn(`dossier: warning: ${warning}`);
216
+ }
217
+ console.log(`dossier: verified ${verification.claimCount} claim(s), ${verification.evidenceCount} evidence id(s), ${verification.gapCount} gap(s)`);
218
+ console.log(`dossier: saved ${markdownPath}`);
219
+ if (!options.noCopy) {
220
+ try {
221
+ await clipboard.write(answer);
222
+ console.log('dossier: copied to clipboard');
223
+ }
224
+ catch {
225
+ console.warn(`dossier: could not copy to clipboard. Answer saved at ${markdownPath}.`);
226
+ }
227
+ }
228
+ console.log('');
229
+ console.log(answer);
230
+ if ((output.follow_up ?? []).length > 0) {
231
+ console.log('');
232
+ console.log('dossier: follow-up:');
233
+ for (const item of output.follow_up ?? [])
234
+ console.log(` - ${item}`);
235
+ }
236
+ if ((output.gaps ?? []).length > 0) {
237
+ console.log('');
238
+ console.log('dossier: gaps:');
239
+ for (const gap of output.gaps ?? [])
240
+ console.log(` - ${gap}`);
241
+ }
242
+ }
243
+ function answerSlug(value) {
244
+ const slug = slugify(value);
245
+ if (slug.length <= 50)
246
+ return slug || 'question';
247
+ const cut = slug.slice(0, 50);
248
+ const lastDash = cut.lastIndexOf('-');
249
+ return (lastDash > 10 ? cut.slice(0, lastDash) : cut) || 'question';
250
+ }
251
+ function readHints(values) {
252
+ if (!Array.isArray(values))
253
+ return '';
254
+ return values
255
+ .map((value) => readTextInput(value))
256
+ .filter(Boolean)
257
+ .join('\n\n');
258
+ }
259
+ function readTextInput(value) {
260
+ if (!value)
261
+ return '';
262
+ const path = resolve(process.cwd(), value);
263
+ if (existsSync(path) && statSync(path).isFile()) {
264
+ return readFileSync(path, 'utf8').trim();
265
+ }
266
+ return String(value).trim();
267
+ }
268
+ function truncate(value, length) {
269
+ const text = String(value).replace(/\s+/g, ' ').trim();
270
+ return text.length > length ? `${text.slice(0, length - 1)}…` : text;
271
+ }
272
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/answer/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type Career } from './schema.js';
2
+ export interface ImportResumeOptions {
3
+ force?: boolean;
4
+ }
5
+ export interface ImportResumeResult {
6
+ careerPath: string;
7
+ privatePath: string | null;
8
+ roles: number;
9
+ projects: number;
10
+ }
11
+ /**
12
+ * Import a JSON Resume file into the dossier career fact bank. Contact details
13
+ * go to career.private.yml; public work/project/skill data goes to career.yml.
14
+ */
15
+ export declare function importJsonResume(input: string, { force }?: ImportResumeOptions): ImportResumeResult;
16
+ export declare function buildCareer(resume: Record<string, unknown>): Career;
17
+ export declare function buildPrivateOverlay(resume: Record<string, unknown>): Record<string, unknown> | null;
@@ -0,0 +1,194 @@
1
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { stringify as stringifyYaml } from 'yaml';
4
+ import { careerFile, privateCareerFile, } from '../config/paths.js';
5
+ import { slugify } from '../util/slug.js';
6
+ import { CareerSchema } from './schema.js';
7
+ /**
8
+ * Import a JSON Resume file into the dossier career fact bank. Contact details
9
+ * go to career.private.yml; public work/project/skill data goes to career.yml.
10
+ */
11
+ export function importJsonResume(input, { force = false } = {}) {
12
+ const inputPath = resolve(process.cwd(), input);
13
+ if (!existsSync(inputPath) || !statSync(inputPath).isFile()) {
14
+ throw new Error(`JSON Resume not found: ${inputPath}. Pass a .json file, not a json-resume checkout directory.`);
15
+ }
16
+ let parsed;
17
+ try {
18
+ parsed = JSON.parse(readFileSync(inputPath, 'utf8'));
19
+ }
20
+ catch (error) {
21
+ throw new Error(`Could not parse ${inputPath}: ${error.message}`);
22
+ }
23
+ if (!isPlainObject(parsed)) {
24
+ throw new Error(`${inputPath} must contain a JSON Resume object.`);
25
+ }
26
+ const career = buildCareer(parsed);
27
+ const privateOverlay = buildPrivateOverlay(parsed);
28
+ if (existsSync(careerFile) && !force) {
29
+ throw new Error(`${careerFile} already exists. Pass --force to replace it.`);
30
+ }
31
+ if (privateOverlay && existsSync(privateCareerFile) && !force) {
32
+ throw new Error(`${privateCareerFile} already exists. Pass --force to replace it.`);
33
+ }
34
+ CareerSchema.parse(career);
35
+ writeFileSync(careerFile, `${stringifyYaml(career).trim()}\n`);
36
+ if (privateOverlay) {
37
+ writeFileSync(privateCareerFile, `${stringifyYaml(privateOverlay).trim()}\n`);
38
+ }
39
+ return {
40
+ careerPath: careerFile,
41
+ privatePath: privateOverlay ? privateCareerFile : null,
42
+ roles: career.roles.length,
43
+ projects: career.projects.length,
44
+ };
45
+ }
46
+ export function buildCareer(resume) {
47
+ const basics = isPlainObject(resume.basics) ? resume.basics : {};
48
+ const roles = arrayOfObjects(resume.work).map((work, index) => toRole(work, index));
49
+ const projects = arrayOfObjects(resume.projects).map((project, index) => toProject(project, index));
50
+ const skills = Array.isArray(resume.skills)
51
+ ? resume.skills
52
+ .map((skill) => {
53
+ if (typeof skill === 'string')
54
+ return { name: skill };
55
+ if (!isPlainObject(skill))
56
+ return null;
57
+ return compact({
58
+ name: str(skill.name),
59
+ level: str(skill.level),
60
+ keywords: stringArray(skill.keywords),
61
+ });
62
+ })
63
+ .filter(Boolean)
64
+ : [];
65
+ const publicBasics = compact({
66
+ label: str(basics.label),
67
+ url: str(basics.url),
68
+ summary: str(basics.summary),
69
+ profiles: Array.isArray(basics.profiles)
70
+ ? basics.profiles.filter(isPlainObject).map((profile) => compact({
71
+ network: str(profile.network),
72
+ username: str(profile.username),
73
+ url: str(profile.url),
74
+ }))
75
+ : undefined,
76
+ });
77
+ const career = compact({
78
+ version: 1,
79
+ basics: Object.keys(publicBasics).length > 0 ? publicBasics : undefined,
80
+ summary: str(basics.summary) || undefined,
81
+ generic: str(basics.label)
82
+ ? { title: str(basics.label) }
83
+ : undefined,
84
+ roles,
85
+ projects,
86
+ skills,
87
+ education: arrayOfObjects(resume.education).map((entry) => compact({
88
+ id: slugify(str(entry.institution)) || undefined,
89
+ institution: str(entry.institution),
90
+ url: str(entry.url),
91
+ area: str(entry.area),
92
+ studyType: str(entry.studyType),
93
+ startDate: str(entry.startDate),
94
+ endDate: str(entry.endDate),
95
+ score: str(entry.score),
96
+ })),
97
+ constraints: { doNotClaim: [] },
98
+ transferable: [],
99
+ });
100
+ return CareerSchema.parse(career);
101
+ }
102
+ function toRole(work, index) {
103
+ const company = str(work.name) || str(work.company) || `Role ${index + 1}`;
104
+ const id = slugify(company) || `role-${index + 1}`;
105
+ const achievements = stringArray(work.highlights).map((text, position) => ({
106
+ id: `${id}-${position + 1}`,
107
+ text,
108
+ strength: 3,
109
+ }));
110
+ return compact({
111
+ id,
112
+ company,
113
+ position: str(work.position) || undefined,
114
+ url: str(work.url) || undefined,
115
+ startDate: str(work.startDate) || undefined,
116
+ endDate: str(work.endDate) || undefined,
117
+ summary: str(work.summary) || undefined,
118
+ achievements,
119
+ });
120
+ }
121
+ function toProject(project, index) {
122
+ const name = str(project.name) || `Project ${index + 1}`;
123
+ const id = slugify(name) || `project-${index + 1}`;
124
+ const url = str(project.url);
125
+ const repo = url.match(/github\.com\/([^/]+\/[^/?#]+)/i)?.[1] ?? '';
126
+ const highlights = stringArray(project.highlights).map((text, position) => ({
127
+ id: `${id}-${position + 1}`,
128
+ text,
129
+ }));
130
+ return compact({
131
+ id,
132
+ name,
133
+ repo: repo || undefined,
134
+ url: url || undefined,
135
+ description: str(project.description) || undefined,
136
+ highlights,
137
+ });
138
+ }
139
+ export function buildPrivateOverlay(resume) {
140
+ if (!isPlainObject(resume.basics))
141
+ return null;
142
+ const basics = compact({
143
+ name: str(resume.basics.name) || undefined,
144
+ email: str(resume.basics.email) || undefined,
145
+ phone: str(resume.basics.phone) || undefined,
146
+ location: isPlainObject(resume.basics.location)
147
+ ? compact({
148
+ city: str(resume.basics.location.city),
149
+ region: str(resume.basics.location.region),
150
+ countryCode: str(resume.basics.location.countryCode),
151
+ postalCode: str(resume.basics.location.postalCode),
152
+ })
153
+ : undefined,
154
+ });
155
+ if (Object.keys(basics).length === 0)
156
+ return null;
157
+ return { basics };
158
+ }
159
+ function arrayOfObjects(value) {
160
+ return Array.isArray(value) ? value.filter(isPlainObject) : [];
161
+ }
162
+ function stringArray(value) {
163
+ return Array.isArray(value)
164
+ ? value.map((item) => String(item ?? '').trim()).filter(Boolean)
165
+ : [];
166
+ }
167
+ function str(value) {
168
+ return typeof value === 'string' ? value.trim() : '';
169
+ }
170
+ function compact(value) {
171
+ const result = {};
172
+ for (const [key, entry] of Object.entries(value)) {
173
+ if (entry == null || entry === '')
174
+ continue;
175
+ if (Array.isArray(entry)) {
176
+ if (entry.length === 0)
177
+ continue;
178
+ result[key] = entry;
179
+ }
180
+ else if (isPlainObject(entry)) {
181
+ if (Object.keys(entry).length === 0)
182
+ continue;
183
+ result[key] = entry;
184
+ }
185
+ else {
186
+ result[key] = entry;
187
+ }
188
+ }
189
+ return result;
190
+ }
191
+ function isPlainObject(value) {
192
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
193
+ }
194
+ //# sourceMappingURL=import-resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resume.js","sourceRoot":"","sources":["../../src/career/import-resume.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type Career } from './schema.js';
2
+ export interface LoadedCareer {
3
+ career: Career;
4
+ publicPath: string;
5
+ privatePath: string | null;
6
+ }
7
+ export declare function loadCareer({ optional }?: {
8
+ optional?: boolean;
9
+ }): LoadedCareer;
10
+ export declare function mergeValue(base: unknown, overlay: unknown): unknown;
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { parse as parseYaml } from 'yaml';
3
+ import { careerFile, privateCareerFile } from '../config/paths.js';
4
+ import { CareerSchema } from './schema.js';
5
+ export function loadCareer({ optional = false } = {}) {
6
+ if (!existsSync(careerFile)) {
7
+ if (optional) {
8
+ return {
9
+ career: CareerSchema.parse({}),
10
+ publicPath: careerFile,
11
+ privatePath: null,
12
+ };
13
+ }
14
+ throw new Error(`Missing ${careerFile}. Run \`dossier init\` or \`dossier init --from <old-repo>\` first.`);
15
+ }
16
+ const publicCareer = parseCareerFile(careerFile, 'career.yml');
17
+ const hasPrivate = existsSync(privateCareerFile);
18
+ const privateCareer = hasPrivate
19
+ ? parseCareerFile(privateCareerFile, 'career.private.yml')
20
+ : {};
21
+ return {
22
+ career: CareerSchema.parse(mergeValue(publicCareer, privateCareer)),
23
+ publicPath: careerFile,
24
+ privatePath: hasPrivate ? privateCareerFile : null,
25
+ };
26
+ }
27
+ function parseCareerFile(path, label) {
28
+ const raw = parseYaml(readFileSync(path, 'utf8')) ?? {};
29
+ if (!isPlainObject(raw)) {
30
+ throw new Error(`${label} must contain a YAML object.`);
31
+ }
32
+ return raw;
33
+ }
34
+ export function mergeValue(base, overlay) {
35
+ if (overlay === undefined)
36
+ return base;
37
+ if (base === undefined)
38
+ return overlay;
39
+ if (Array.isArray(base) && Array.isArray(overlay)) {
40
+ return mergeArray(base, overlay);
41
+ }
42
+ if (isPlainObject(base) && isPlainObject(overlay)) {
43
+ const result = { ...base };
44
+ for (const [key, value] of Object.entries(overlay)) {
45
+ result[key] = mergeValue(result[key], value);
46
+ }
47
+ return result;
48
+ }
49
+ return overlay;
50
+ }
51
+ function mergeArray(base, overlay) {
52
+ if (overlay.length === 0)
53
+ return base;
54
+ if (base.length === 0)
55
+ return overlay;
56
+ if (base.every((value) => typeof value === 'string') &&
57
+ overlay.every((value) => typeof value === 'string')) {
58
+ return [...new Set([...base, ...overlay])];
59
+ }
60
+ const key = arrayKey([...base, ...overlay]);
61
+ if (!key)
62
+ return overlay;
63
+ const result = [...base];
64
+ const positions = new Map();
65
+ result.forEach((item, index) => {
66
+ if (isPlainObject(item) && item[key] != null) {
67
+ positions.set(String(item[key]), index);
68
+ }
69
+ });
70
+ for (const item of overlay) {
71
+ const id = isPlainObject(item) ? item[key] : null;
72
+ if (id == null || !positions.has(String(id))) {
73
+ result.push(item);
74
+ if (id != null)
75
+ positions.set(String(id), result.length - 1);
76
+ continue;
77
+ }
78
+ const index = positions.get(String(id));
79
+ result[index] = mergeValue(result[index], item);
80
+ }
81
+ return result;
82
+ }
83
+ function arrayKey(items) {
84
+ const objects = items.filter(isPlainObject);
85
+ if (objects.length !== items.length || objects.length === 0)
86
+ return null;
87
+ for (const key of ['id', 'name', 'evidence', 'network', 'institution']) {
88
+ if (objects.every((item) => item[key] != null))
89
+ return key;
90
+ }
91
+ return null;
92
+ }
93
+ function isPlainObject(value) {
94
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
95
+ }
96
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/career/load.ts"],"names":[],"mappings":"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"}