@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.
- package/LICENSE +21 -0
- package/README.md +322 -2
- package/agents/dossier-answerer.md +168 -0
- package/agents/dossier-proposer.md +215 -0
- package/agents/dossier-tailor.md +232 -0
- package/dist/answer/prompt.d.ts +17 -0
- package/dist/answer/prompt.js +44 -0
- package/dist/answer/prompt.js.map +1 -0
- package/dist/answer/run.d.ts +21 -0
- package/dist/answer/run.js +272 -0
- package/dist/answer/run.js.map +1 -0
- package/dist/career/import-resume.d.ts +17 -0
- package/dist/career/import-resume.js +194 -0
- package/dist/career/import-resume.js.map +1 -0
- package/dist/career/load.d.ts +10 -0
- package/dist/career/load.js +96 -0
- package/dist/career/load.js.map +1 -0
- package/dist/career/schema.d.ts +147 -0
- package/dist/career/schema.js +95 -0
- package/dist/career/schema.js.map +1 -0
- package/dist/clean/run.d.ts +1 -0
- package/dist/clean/run.js +8 -0
- package/dist/clean/run.js.map +1 -0
- package/dist/cli/commands/answer.d.ts +23 -0
- package/dist/cli/commands/answer.js +110 -0
- package/dist/cli/commands/answer.js.map +1 -0
- package/dist/cli/commands/clean.d.ts +2 -0
- package/dist/cli/commands/clean.js +11 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.js +83 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.js +80 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/paths.d.ts +7 -0
- package/dist/cli/commands/paths.js +42 -0
- package/dist/cli/commands/paths.js.map +1 -0
- package/dist/cli/commands/proposal.d.ts +30 -0
- package/dist/cli/commands/proposal.js +148 -0
- package/dist/cli/commands/proposal.js.map +1 -0
- package/dist/cli/commands/pull-private.d.ts +8 -0
- package/dist/cli/commands/pull-private.js +30 -0
- package/dist/cli/commands/pull-private.js.map +1 -0
- package/dist/cli/commands/score.d.ts +11 -0
- package/dist/cli/commands/score.js +58 -0
- package/dist/cli/commands/score.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +13 -0
- package/dist/cli/commands/sync.js +65 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/tailor.d.ts +24 -0
- package/dist/cli/commands/tailor.js +113 -0
- package/dist/cli/commands/tailor.js.map +1 -0
- package/dist/cli/commands/verify.d.ts +6 -0
- package/dist/cli/commands/verify.js +15 -0
- package/dist/cli/commands/verify.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +85 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/config.d.ts +36 -0
- package/dist/config/config.js +71 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/paths.d.ts +34 -0
- package/dist/config/paths.js +126 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/evidence/numbers.d.ts +2 -0
- package/dist/evidence/numbers.js +26 -0
- package/dist/evidence/numbers.js.map +1 -0
- package/dist/evidence/verify.d.ts +109 -0
- package/dist/evidence/verify.js +445 -0
- package/dist/evidence/verify.js.map +1 -0
- package/dist/job/input.d.ts +9 -0
- package/dist/job/input.js +141 -0
- package/dist/job/input.js.map +1 -0
- package/dist/job/page.d.ts +14 -0
- package/dist/job/page.js +426 -0
- package/dist/job/page.js.map +1 -0
- package/dist/job/types.d.ts +30 -0
- package/dist/job/types.js +2 -0
- package/dist/job/types.js.map +1 -0
- package/dist/llm/agents.d.ts +7 -0
- package/dist/llm/agents.js +46 -0
- package/dist/llm/agents.js.map +1 -0
- package/dist/llm/opencode.d.ts +19 -0
- package/dist/llm/opencode.js +117 -0
- package/dist/llm/opencode.js.map +1 -0
- package/dist/llm/providers.d.ts +63 -0
- package/dist/llm/providers.js +207 -0
- package/dist/llm/providers.js.map +1 -0
- package/dist/private/pull.d.ts +7 -0
- package/dist/private/pull.js +168 -0
- package/dist/private/pull.js.map +1 -0
- package/dist/projects/rank.d.ts +17 -0
- package/dist/projects/rank.js +100 -0
- package/dist/projects/rank.js.map +1 -0
- package/dist/projects/store.d.ts +7 -0
- package/dist/projects/store.js +31 -0
- package/dist/projects/store.js.map +1 -0
- package/dist/projects/sync-github.d.ts +11 -0
- package/dist/projects/sync-github.js +269 -0
- package/dist/projects/sync-github.js.map +1 -0
- package/dist/projects/sync-local.d.ts +8 -0
- package/dist/projects/sync-local.js +318 -0
- package/dist/projects/sync-local.js.map +1 -0
- package/dist/projects/types.d.ts +71 -0
- package/dist/projects/types.js +2 -0
- package/dist/projects/types.js.map +1 -0
- package/dist/proposal/prompt.d.ts +20 -0
- package/dist/proposal/prompt.js +64 -0
- package/dist/proposal/prompt.js.map +1 -0
- package/dist/proposal/run.d.ts +28 -0
- package/dist/proposal/run.js +386 -0
- package/dist/proposal/run.js.map +1 -0
- package/dist/resume/basics.d.ts +4 -0
- package/dist/resume/basics.js +33 -0
- package/dist/resume/basics.js.map +1 -0
- package/dist/resume/find.d.ts +12 -0
- package/dist/resume/find.js +27 -0
- package/dist/resume/find.js.map +1 -0
- package/dist/resume/format.d.ts +3 -0
- package/dist/resume/format.js +53 -0
- package/dist/resume/format.js.map +1 -0
- package/dist/resume/one-page.d.ts +149 -0
- package/dist/resume/one-page.js +164 -0
- package/dist/resume/one-page.js.map +1 -0
- package/dist/resume/prompt.d.ts +10 -0
- package/dist/resume/prompt.js +23 -0
- package/dist/resume/prompt.js.map +1 -0
- package/dist/resume/render.d.ts +8 -0
- package/dist/resume/render.js +84 -0
- package/dist/resume/render.js.map +1 -0
- package/dist/resume/run.d.ts +21 -0
- package/dist/resume/run.js +350 -0
- package/dist/resume/run.js.map +1 -0
- package/dist/resume/skills.d.ts +6 -0
- package/dist/resume/skills.js +47 -0
- package/dist/resume/skills.js.map +1 -0
- package/dist/resume/trace.d.ts +13 -0
- package/dist/resume/trace.js +82 -0
- package/dist/resume/trace.js.map +1 -0
- package/dist/resume/types.d.ts +94 -0
- package/dist/resume/types.js +2 -0
- package/dist/resume/types.js.map +1 -0
- package/dist/resume/verify.d.ts +19 -0
- package/dist/resume/verify.js +193 -0
- package/dist/resume/verify.js.map +1 -0
- package/dist/upwork/profile.d.ts +50 -0
- package/dist/upwork/profile.js +302 -0
- package/dist/upwork/profile.js.map +1 -0
- package/dist/upwork/settings.d.ts +96 -0
- package/dist/upwork/settings.js +166 -0
- package/dist/upwork/settings.js.map +1 -0
- package/dist/util/open-file.d.ts +1 -0
- package/dist/util/open-file.js +24 -0
- package/dist/util/open-file.js.map +1 -0
- package/dist/util/slug.d.ts +2 -0
- package/dist/util/slug.js +13 -0
- package/dist/util/slug.js.map +1 -0
- package/dist/verify/run.d.ts +4 -0
- package/dist/verify/run.js +91 -0
- package/dist/verify/run.js.map +1 -0
- package/package.json +67 -4
- package/templates/career.example.yml +63 -0
- package/templates/career.private.example.yml +10 -0
- package/templates/config.example.yml +16 -0
- 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,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[];
|