@rwendell/dossier 0.0.0-stage → 0.1.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 (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -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 +83 -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 +85 -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 +34 -0
  64. package/dist/config/paths.js +126 -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 +46 -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,117 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ const MAX_BUFFER = 100 * 1024 * 1024;
3
+ export function runOpencode({ prompt, agent, model, title, timeout, cwd, }) {
4
+ const args = ['run', '--agent', agent, '--format', 'json'];
5
+ if (title)
6
+ args.push('--title', title);
7
+ if (model)
8
+ args.push('--model', model);
9
+ args.push(prompt);
10
+ return spawnSync('opencode', args, {
11
+ cwd,
12
+ encoding: 'utf8',
13
+ maxBuffer: MAX_BUFFER,
14
+ timeout,
15
+ });
16
+ }
17
+ export function parseOpencodeStats(stdout) {
18
+ let stats = null;
19
+ for (const line of stdout.split('\n')) {
20
+ if (!line.trim())
21
+ continue;
22
+ try {
23
+ const event = JSON.parse(line);
24
+ if (event.type !== 'step_finish' || !event.part)
25
+ continue;
26
+ stats ??= { cost: 0, input: 0, output: 0, reasoning: 0 };
27
+ stats.cost += Number(event.part.cost) || 0;
28
+ stats.input += Number(event.part.tokens?.input) || 0;
29
+ stats.output += Number(event.part.tokens?.output) || 0;
30
+ stats.reasoning += Number(event.part.tokens?.reasoning) || 0;
31
+ }
32
+ catch {
33
+ // Ignore non-JSON log lines.
34
+ }
35
+ }
36
+ return stats;
37
+ }
38
+ export function parseOpencodeOutput(stdout) {
39
+ const texts = [];
40
+ for (const line of stdout.split('\n')) {
41
+ if (!line.trim())
42
+ continue;
43
+ try {
44
+ const event = JSON.parse(line);
45
+ if (event.type === 'text' && event.part?.text) {
46
+ texts.push(event.part.text);
47
+ }
48
+ }
49
+ catch {
50
+ // Ignore non-JSON log lines.
51
+ }
52
+ }
53
+ const candidates = [...texts.reverse(), stdout];
54
+ for (const text of candidates) {
55
+ const parsed = extractJson(text);
56
+ if (parsed)
57
+ return parsed;
58
+ }
59
+ return null;
60
+ }
61
+ export function extractJson(text) {
62
+ const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
63
+ if (fenced) {
64
+ try {
65
+ const parsed = JSON.parse(fenced[1]);
66
+ if (isPlainObject(parsed))
67
+ return parsed;
68
+ }
69
+ catch {
70
+ // Fall through to brace scanning.
71
+ }
72
+ }
73
+ for (let start = 0; start < text.length; start += 1) {
74
+ if (text[start] !== '{')
75
+ continue;
76
+ let depth = 0;
77
+ let inString = false;
78
+ let escaped = false;
79
+ for (let end = start; end < text.length; end += 1) {
80
+ const char = text[end];
81
+ if (inString) {
82
+ if (escaped)
83
+ escaped = false;
84
+ else if (char === '\\')
85
+ escaped = true;
86
+ else if (char === '"')
87
+ inString = false;
88
+ continue;
89
+ }
90
+ if (char === '"') {
91
+ inString = true;
92
+ continue;
93
+ }
94
+ if (char === '{')
95
+ depth += 1;
96
+ else if (char === '}') {
97
+ depth -= 1;
98
+ if (depth === 0) {
99
+ try {
100
+ const parsed = JSON.parse(text.slice(start, end + 1));
101
+ if (isPlainObject(parsed))
102
+ return parsed;
103
+ }
104
+ catch {
105
+ // Keep scanning.
106
+ }
107
+ break;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+ function isPlainObject(value) {
115
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
116
+ }
117
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/llm/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type OpencodeStats } from './opencode.js';
2
+ export declare const DEFAULT_OPENCODE_MODEL = "opencode/deepseek-v4.1-flash-free#high";
3
+ export declare const DEFAULT_GO_MODEL = "opencode-go/deepseek-v4.1-flash#high";
4
+ export declare const DEFAULT_OPENROUTER_MODEL = "openrouter/deepseek/deepseek-v4.1-flash-1017#high";
5
+ export declare const DEFAULT_OPENROUTER_FALLBACK_MODEL = "openrouter/anthropic/claude-haiku-5.5#low";
6
+ export declare const DEFAULT_OPENROUTER_TIMEOUT_MS = 120000;
7
+ export type ProviderName = 'auto' | 'opencode' | 'go' | 'openrouter';
8
+ export interface ProviderTarget {
9
+ name: Exclude<ProviderName, 'auto'>;
10
+ label: string;
11
+ model: string | null;
12
+ timeout?: number;
13
+ }
14
+ export interface LlmAttempt {
15
+ index: number;
16
+ total: number;
17
+ target: ProviderTarget;
18
+ label: string;
19
+ timeout: number;
20
+ reason?: string;
21
+ status?: number | null;
22
+ stderr?: string;
23
+ raw?: string;
24
+ stats?: OpencodeStats | null;
25
+ }
26
+ export interface RunAgentResult {
27
+ output: Record<string, unknown>;
28
+ provider: ProviderTarget;
29
+ model: string | null;
30
+ raw: string;
31
+ stats: OpencodeStats | null;
32
+ attempts: LlmAttempt[];
33
+ }
34
+ export interface RunAgentOptions {
35
+ prompt: string;
36
+ agent: string;
37
+ title?: string;
38
+ timeout?: number;
39
+ cwd: string;
40
+ provider?: string;
41
+ model?: string;
42
+ accept?: (value: Record<string, unknown>) => boolean;
43
+ onAttempt?: (event: {
44
+ phase: 'start' | 'failed' | 'succeeded';
45
+ index: number;
46
+ total: number;
47
+ target: ProviderTarget;
48
+ label: string;
49
+ timeout: number;
50
+ reason?: string;
51
+ stats?: OpencodeStats | null;
52
+ }) => void;
53
+ }
54
+ export declare class LlmError extends Error {
55
+ attempts: LlmAttempt[];
56
+ raw: string;
57
+ constructor(attempts: LlmAttempt[], raw: string);
58
+ }
59
+ export declare function resolveProviderChain({ provider, model, }?: {
60
+ provider?: string;
61
+ model?: string;
62
+ }): ProviderTarget[];
63
+ export declare function runAgent({ prompt, agent, title, timeout, cwd, provider, model, accept, onAttempt, }: RunAgentOptions): RunAgentResult;
@@ -0,0 +1,207 @@
1
+ import { parseOpencodeOutput, parseOpencodeStats, runOpencode, } from './opencode.js';
2
+ export const DEFAULT_OPENCODE_MODEL = 'opencode/deepseek-v4.1-flash-free#high';
3
+ export const DEFAULT_GO_MODEL = 'opencode-go/deepseek-v4.1-flash#high';
4
+ export const DEFAULT_OPENROUTER_MODEL = 'openrouter/deepseek/deepseek-v4.1-flash-1017#high';
5
+ export const DEFAULT_OPENROUTER_FALLBACK_MODEL = 'openrouter/anthropic/claude-haiku-5.5#low';
6
+ export const DEFAULT_OPENROUTER_TIMEOUT_MS = 120_000;
7
+ const PROVIDER_LABELS = {
8
+ opencode: 'OpenCode',
9
+ go: 'OpenCode Go',
10
+ openrouter: 'OpenRouter',
11
+ };
12
+ const PROVIDER_ALIASES = new Map([
13
+ ['auto', 'auto'],
14
+ ['opencode', 'opencode'],
15
+ ['default', 'opencode'],
16
+ ['free', 'opencode'],
17
+ ['go', 'go'],
18
+ ['opencode-go', 'go'],
19
+ ['openrouter', 'openrouter'],
20
+ ['or', 'openrouter'],
21
+ ]);
22
+ export class LlmError extends Error {
23
+ attempts;
24
+ raw;
25
+ constructor(attempts, raw) {
26
+ super(formatFailure(attempts));
27
+ this.name = 'LlmError';
28
+ this.attempts = attempts;
29
+ this.raw = raw;
30
+ }
31
+ }
32
+ export function resolveProviderChain({ provider, model, } = {}) {
33
+ const requested = normalizeProvider(provider ||
34
+ process.env.DOSSIER_LLM_PROVIDER ||
35
+ process.env.RESUME_LLM_PROVIDER ||
36
+ 'auto');
37
+ if (requested === 'auto') {
38
+ if (model)
39
+ return [createTarget('opencode', model)];
40
+ return [
41
+ ...openRouterChain(),
42
+ createTarget('go', process.env.OPENCODE_GO_MODEL
43
+ ? normalizeModelForProvider('go', process.env.OPENCODE_GO_MODEL)
44
+ : DEFAULT_GO_MODEL),
45
+ createTarget('opencode', process.env.OPENCODE_MODEL || DEFAULT_OPENCODE_MODEL),
46
+ ];
47
+ }
48
+ if (requested === 'openrouter' && !model) {
49
+ return openRouterChain();
50
+ }
51
+ const targetModel = model
52
+ ? normalizeModelForProvider(requested, model)
53
+ : defaultModelForProvider(requested);
54
+ return [createTarget(requested, targetModel)];
55
+ }
56
+ function openRouterChain() {
57
+ const primaryModel = process.env.OPENROUTER_MODEL
58
+ ? normalizeModelForProvider('openrouter', process.env.OPENROUTER_MODEL)
59
+ : DEFAULT_OPENROUTER_MODEL;
60
+ const fallbackModel = process.env.OPENROUTER_FALLBACK_MODEL
61
+ ? normalizeModelForProvider('openrouter', process.env.OPENROUTER_FALLBACK_MODEL)
62
+ : DEFAULT_OPENROUTER_FALLBACK_MODEL;
63
+ const primary = createTarget('openrouter', primaryModel, {
64
+ timeout: DEFAULT_OPENROUTER_TIMEOUT_MS,
65
+ });
66
+ const fallback = createTarget('openrouter', fallbackModel);
67
+ return primary.model === fallback.model ? [primary] : [primary, fallback];
68
+ }
69
+ export function runAgent({ prompt, agent, title, timeout = 10 * 60 * 1000, cwd, provider, model, accept, onAttempt, }) {
70
+ const chain = resolveProviderChain({ provider, model });
71
+ const attempts = [];
72
+ let lastRaw = '';
73
+ for (const [index, target] of chain.entries()) {
74
+ const targetTimeout = target.timeout ?? timeout;
75
+ const label = target.model
76
+ ? `${target.label} (${target.model})`
77
+ : `${target.label} (default model)`;
78
+ const context = {
79
+ index,
80
+ total: chain.length,
81
+ target,
82
+ label,
83
+ timeout: targetTimeout,
84
+ };
85
+ onAttempt?.({ ...context, phase: 'start' });
86
+ const result = runOpencode({
87
+ prompt,
88
+ agent,
89
+ model: target.model,
90
+ title,
91
+ timeout: targetTimeout,
92
+ cwd,
93
+ });
94
+ const raw = typeof result.stdout === 'string' ? result.stdout : '';
95
+ if (raw)
96
+ lastRaw = raw;
97
+ const stderr = typeof result.stderr === 'string' ? result.stderr : '';
98
+ if (result.error) {
99
+ const timedOut = result.error.code === 'ETIMEDOUT' ||
100
+ /timed out|ETIMEDOUT/i.test(result.error.message ?? '');
101
+ const reason = timedOut
102
+ ? `timed out after ${Math.round(targetTimeout / 1000)}s`
103
+ : truncate(result.error.message, 1200);
104
+ attempts.push({ ...context, reason, status: result.status, stderr });
105
+ onAttempt?.({ ...context, phase: 'failed', reason });
106
+ continue;
107
+ }
108
+ if (result.status !== 0) {
109
+ const detail = truncate(stderr.trim(), 1200);
110
+ const reason = `exited with status ${result.status}${detail ? `: ${detail}` : ''}`;
111
+ attempts.push({
112
+ ...context,
113
+ reason,
114
+ status: result.status,
115
+ stderr,
116
+ raw,
117
+ });
118
+ onAttempt?.({ ...context, phase: 'failed', reason });
119
+ continue;
120
+ }
121
+ const output = parseOpencodeOutput(raw);
122
+ if (!output) {
123
+ const reason = 'did not return a JSON object';
124
+ attempts.push({ ...context, reason, status: 0, stderr, raw });
125
+ onAttempt?.({ ...context, phase: 'failed', reason });
126
+ continue;
127
+ }
128
+ if (accept && !accept(output)) {
129
+ const reason = 'returned JSON that does not match the expected shape';
130
+ attempts.push({ ...context, reason, status: 0, stderr, raw });
131
+ onAttempt?.({ ...context, phase: 'failed', reason });
132
+ continue;
133
+ }
134
+ const stats = parseOpencodeStats(raw);
135
+ onAttempt?.({ ...context, phase: 'succeeded', stats });
136
+ return {
137
+ output,
138
+ provider: target,
139
+ model: target.model,
140
+ raw,
141
+ stats,
142
+ attempts,
143
+ };
144
+ }
145
+ throw new LlmError(attempts, lastRaw);
146
+ }
147
+ function normalizeProvider(value) {
148
+ const key = String(value ?? '').trim().toLowerCase();
149
+ const provider = PROVIDER_ALIASES.get(key);
150
+ if (!provider) {
151
+ throw new Error(`Unknown provider "${value}". Use auto, opencode, go, or openrouter.`);
152
+ }
153
+ return provider;
154
+ }
155
+ function defaultModelForProvider(provider) {
156
+ if (provider === 'opencode') {
157
+ return process.env.OPENCODE_MODEL || DEFAULT_OPENCODE_MODEL;
158
+ }
159
+ if (provider === 'go') {
160
+ return process.env.OPENCODE_GO_MODEL
161
+ ? normalizeModelForProvider('go', process.env.OPENCODE_GO_MODEL)
162
+ : DEFAULT_GO_MODEL;
163
+ }
164
+ return process.env.OPENROUTER_MODEL
165
+ ? normalizeModelForProvider('openrouter', process.env.OPENROUTER_MODEL)
166
+ : DEFAULT_OPENROUTER_MODEL;
167
+ }
168
+ function normalizeModelForProvider(provider, model) {
169
+ const value = String(model).trim();
170
+ if (provider === 'go' && !value.includes('/')) {
171
+ return `opencode-go/${value}`;
172
+ }
173
+ if (provider === 'openrouter' && !value.startsWith('openrouter/')) {
174
+ return `openrouter/${value}`;
175
+ }
176
+ return value;
177
+ }
178
+ function createTarget(name, model, { timeout } = {}) {
179
+ const inferred = model.startsWith('opencode-go/')
180
+ ? 'go'
181
+ : model.startsWith('openrouter/')
182
+ ? 'openrouter'
183
+ : name;
184
+ return {
185
+ name,
186
+ label: PROVIDER_LABELS[inferred],
187
+ model: model || null,
188
+ timeout,
189
+ };
190
+ }
191
+ function formatFailure(attempts) {
192
+ const lines = [
193
+ attempts.length === 1
194
+ ? 'Model request failed.'
195
+ : 'All model providers failed.',
196
+ ];
197
+ attempts.forEach((attempt, index) => {
198
+ lines.push(` ${index + 1}. ${attempt.label}: ${attempt.reason}`);
199
+ });
200
+ lines.push('Pass --provider opencode|go|openrouter to force one, or set DOSSIER_LLM_PROVIDER.');
201
+ return lines.join('\n');
202
+ }
203
+ function truncate(value, length) {
204
+ const text = String(value ?? '').replace(/\s+/g, ' ').trim();
205
+ return text.length > length ? `${text.slice(0, length - 1)}…` : text;
206
+ }
207
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/llm/providers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface PullPrivateOptions {
2
+ gist?: string;
3
+ file?: string;
4
+ allowPublic?: boolean;
5
+ }
6
+ export declare function pullPrivate(options?: PullPrivateOptions): void;
7
+ export declare function parseGistId(value: string): string;
@@ -0,0 +1,168 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { parse as parseYaml } from 'yaml';
5
+ import { loadCareer } from '../career/load.js';
6
+ import { getCacheDir, privateCareerFile } from '../config/paths.js';
7
+ export function pullPrivate(options = {}) {
8
+ const fileName = options.file || 'career.private.yml';
9
+ const outputPath = privateCareerFile;
10
+ const gist = resolveGist({
11
+ requested: options.gist,
12
+ fileName,
13
+ allowPublic: Boolean(options.allowPublic),
14
+ });
15
+ let content;
16
+ try {
17
+ content = execFileSync('gh', ['gist', 'view', gist.id, '--filename', fileName, '--raw'], { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
18
+ }
19
+ catch (error) {
20
+ throw new Error(formatGhError(`Could not read ${fileName} from gist ${gist.id}`, error));
21
+ }
22
+ content = `${content
23
+ .replace(/^\uFEFF/, '')
24
+ .replace(/\r\n/g, '\n')
25
+ .trimEnd()}\n`;
26
+ const parsed = parseYaml(content);
27
+ if (!isPlainObject(parsed)) {
28
+ throw new Error(`${fileName} is not a YAML object.`);
29
+ }
30
+ const basics = parsed.basics;
31
+ if (!isPlainObject(basics)) {
32
+ throw new Error(`${fileName} does not contain a basics object.`);
33
+ }
34
+ if (!['name', 'email', 'phone', 'location'].some((key) => basics[key] != null)) {
35
+ throw new Error(`${fileName} does not look like the private PII overlay.`);
36
+ }
37
+ const existing = existsSync(outputPath)
38
+ ? readFileSync(outputPath, 'utf8')
39
+ : null;
40
+ if (existing === content) {
41
+ console.log(`dossier: pull-private already up to date (${gist.public ? 'public' : 'secret'} gist)`);
42
+ reportMerge();
43
+ return;
44
+ }
45
+ if (existing) {
46
+ const backupDir = join(getCacheDir(), 'pull-private');
47
+ mkdirSync(backupDir, { recursive: true });
48
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
49
+ const backupPath = join(backupDir, `career.private-${stamp}.yml`);
50
+ writeFileSync(backupPath, existing);
51
+ console.log(`dossier: backed up the previous file to ${backupPath}`);
52
+ }
53
+ mkdirSync(dirname(outputPath), { recursive: true });
54
+ writeFileSync(outputPath, content);
55
+ console.log(`dossier: wrote ${outputPath} (${gist.public ? 'public' : 'secret'} gist)`);
56
+ reportMerge();
57
+ }
58
+ export function parseGistId(value) {
59
+ const text = String(value ?? '').trim();
60
+ const urlMatch = text.match(/gist\.github\.com\/(?:[^/]+\/)?([a-f0-9]+)/i);
61
+ if (urlMatch)
62
+ return urlMatch[1];
63
+ if (/^[a-f0-9]+$/i.test(text))
64
+ return text;
65
+ throw new Error(`Invalid gist id or URL: ${text || '(empty)'}`);
66
+ }
67
+ function resolveGist({ requested, fileName, allowPublic, }) {
68
+ if (requested) {
69
+ return loadGist(parseGistId(requested), fileName, allowPublic);
70
+ }
71
+ const envId = process.env.CAREER_PRIVATE_GIST_ID;
72
+ if (envId) {
73
+ return loadGist(parseGistId(envId), fileName, allowPublic);
74
+ }
75
+ const gists = listGists();
76
+ const matches = gists.filter((item) => item.files?.[fileName]);
77
+ const secretMatches = allowPublic
78
+ ? matches
79
+ : matches.filter((item) => item.public === false);
80
+ if (secretMatches.length === 0) {
81
+ if (matches.length > 0) {
82
+ throw new Error(`Only public gist(s) contain ${fileName}. Refusing to pull PII from a public gist; pass --allow-public only if you accept that risk.`);
83
+ }
84
+ throw new Error(`No gist containing ${fileName} was found. Pass --gist <id|url>, set CAREER_PRIVATE_GIST_ID, or create one with "gh gist create ${privateCareerFile}".`);
85
+ }
86
+ secretMatches.sort((a, b) => Date.parse(b.updated_at ?? '') - Date.parse(a.updated_at ?? ''));
87
+ if (secretMatches.length > 1) {
88
+ throw new Error(`Multiple secret gists contain ${fileName}. Run "gh gist list" or pass --gist to choose one.`);
89
+ }
90
+ return loadGist(secretMatches[0].id, fileName, allowPublic);
91
+ }
92
+ function loadGist(id, fileName, allowPublic) {
93
+ const gist = fetchGist(id);
94
+ if (gist.public && !allowPublic) {
95
+ throw new Error(`Gist ${id} is public. Refusing to pull PII from a public gist; pass --allow-public only if you accept that risk.`);
96
+ }
97
+ if (!gist.files?.[fileName]) {
98
+ const available = Object.keys(gist.files ?? {});
99
+ throw new Error(`Gist ${id} does not contain ${fileName}. Available file(s): ${available.join(', ') || '(none)'}.`);
100
+ }
101
+ return { id, public: gist.public === true };
102
+ }
103
+ function listGists() {
104
+ let raw;
105
+ try {
106
+ raw = execFileSync('gh', ['api', 'gists?per_page=100', '--paginate'], {
107
+ encoding: 'utf8',
108
+ maxBuffer: 20 * 1024 * 1024,
109
+ });
110
+ }
111
+ catch (error) {
112
+ throw new Error(formatGhError('Could not list gists', error));
113
+ }
114
+ let data;
115
+ try {
116
+ data = JSON.parse(raw);
117
+ }
118
+ catch (error) {
119
+ throw new Error(`Could not parse the gist list: ${error.message}`);
120
+ }
121
+ if (!Array.isArray(data)) {
122
+ throw new Error('GitHub returned an unexpected gist list.');
123
+ }
124
+ return data;
125
+ }
126
+ function fetchGist(id) {
127
+ let raw;
128
+ try {
129
+ raw = execFileSync('gh', ['api', `gists/${id}`], {
130
+ encoding: 'utf8',
131
+ maxBuffer: 10 * 1024 * 1024,
132
+ });
133
+ }
134
+ catch (error) {
135
+ throw new Error(formatGhError(`Could not read gist ${id}`, error));
136
+ }
137
+ try {
138
+ const gist = JSON.parse(raw);
139
+ if (!gist?.id)
140
+ throw new Error('missing id');
141
+ return gist;
142
+ }
143
+ catch (error) {
144
+ throw new Error(`Could not parse gist ${id}: ${error.message}`);
145
+ }
146
+ }
147
+ function formatGhError(prefix, error) {
148
+ const err = error;
149
+ if (err?.code === 'ENOENT') {
150
+ return `${prefix}: the gh CLI was not found. Install GitHub CLI and run "gh auth login".`;
151
+ }
152
+ const stderr = err?.stderr ? String(err.stderr).trim() : '';
153
+ return `${prefix}: ${stderr || err?.message || String(error)}`;
154
+ }
155
+ function reportMerge() {
156
+ try {
157
+ const { career } = loadCareer();
158
+ const achievements = career.roles.reduce((sum, role) => sum + role.achievements.length, 0);
159
+ console.log(`dossier: merged ${career.roles.length} role(s), ${achievements} achievement(s)`);
160
+ }
161
+ catch (error) {
162
+ throw new Error(`Pulled the file, but the merged career failed to load: ${error.message}`);
163
+ }
164
+ }
165
+ function isPlainObject(value) {
166
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
167
+ }
168
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/private/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Career } from '../career/schema.js';
2
+ import type { Job } from '../job/types.js';
3
+ import type { GitHubData, LocalProjectsData, ProjectCandidate } from './types.js';
4
+ export interface ScoredProject {
5
+ repo: GitHubData['repos'][number] | LocalProjectsData['projects'][number];
6
+ matched: string[];
7
+ baseScore: number;
8
+ pinned: boolean;
9
+ score: number;
10
+ }
11
+ export interface RankProjectsResult {
12
+ tokens: string[];
13
+ scored: ScoredProject[];
14
+ selected: ProjectCandidate[];
15
+ }
16
+ export declare function rankProjects(github: GitHubData | null, local: LocalProjectsData | null, career: Career, job: Job, limit?: number): RankProjectsResult;
17
+ export declare function selectProjects(github: GitHubData | null, local: LocalProjectsData | null, career: Career, job: Job, limit?: number): ProjectCandidate[];