@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.
- package/LICENSE +21 -0
- package/README.md +323 -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 +77 -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 +87 -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 +32 -0
- package/dist/config/paths.js +121 -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 +44 -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,96 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const DEFAULT_BANNED_PHRASES: string[];
|
|
3
|
+
export declare const RateSchema: z.ZodObject<{
|
|
4
|
+
type: z.ZodDefault<z.ZodEnum<{
|
|
5
|
+
fixed: "fixed";
|
|
6
|
+
hourly: "hourly";
|
|
7
|
+
}>>;
|
|
8
|
+
amount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
9
|
+
currency: z.ZodDefault<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export declare const FreelanceConfigSchema: z.ZodObject<{
|
|
12
|
+
profile: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
13
|
+
url: z.ZodDefault<z.ZodString>;
|
|
14
|
+
}, z.core.$loose>]>>;
|
|
15
|
+
rate: z.ZodDefault<z.ZodObject<{
|
|
16
|
+
type: z.ZodDefault<z.ZodEnum<{
|
|
17
|
+
fixed: "fixed";
|
|
18
|
+
hourly: "hourly";
|
|
19
|
+
}>>;
|
|
20
|
+
amount: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
21
|
+
currency: z.ZodDefault<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
minHourlyRate: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
24
|
+
availability: z.ZodDefault<z.ZodString>;
|
|
25
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
26
|
+
timeline: z.ZodDefault<z.ZodString>;
|
|
27
|
+
proposal: z.ZodDefault<z.ZodObject<{
|
|
28
|
+
targetWords: z.ZodDefault<z.ZodNumber>;
|
|
29
|
+
minWords: z.ZodDefault<z.ZodNumber>;
|
|
30
|
+
maxWords: z.ZodDefault<z.ZodNumber>;
|
|
31
|
+
maxChars: z.ZodDefault<z.ZodNumber>;
|
|
32
|
+
includeRate: z.ZodDefault<z.ZodBoolean>;
|
|
33
|
+
includeAvailability: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
}, z.core.$strip>>;
|
|
35
|
+
preferredSamples: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
36
|
+
bannedPhrases: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
37
|
+
}, z.core.$loose>;
|
|
38
|
+
export type FreelanceConfig = z.infer<typeof FreelanceConfigSchema>;
|
|
39
|
+
export type ConfiguredRate = z.infer<typeof RateSchema>;
|
|
40
|
+
export interface EffectiveRate {
|
|
41
|
+
type: 'hourly' | 'fixed';
|
|
42
|
+
amount: number;
|
|
43
|
+
currency: string;
|
|
44
|
+
}
|
|
45
|
+
export interface LoadedFreelanceConfig {
|
|
46
|
+
config: FreelanceConfig;
|
|
47
|
+
path: string | null;
|
|
48
|
+
}
|
|
49
|
+
export declare function loadFreelanceConfig(): LoadedFreelanceConfig;
|
|
50
|
+
export interface ProfileDefaults {
|
|
51
|
+
rate?: EffectiveRate | null;
|
|
52
|
+
hoursPerWeek?: string;
|
|
53
|
+
preferredSamples?: string[];
|
|
54
|
+
}
|
|
55
|
+
export interface ProposalOptions {
|
|
56
|
+
rate?: string | number;
|
|
57
|
+
rateType?: string;
|
|
58
|
+
noRate?: boolean;
|
|
59
|
+
availability?: string;
|
|
60
|
+
timeline?: string;
|
|
61
|
+
profile?: string;
|
|
62
|
+
noProfile?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface ProposalSettings {
|
|
65
|
+
targetWords: number;
|
|
66
|
+
minWords: number;
|
|
67
|
+
maxWords: number;
|
|
68
|
+
maxChars: number;
|
|
69
|
+
includeRate: boolean;
|
|
70
|
+
includeAvailability: boolean;
|
|
71
|
+
rate: EffectiveRate | null;
|
|
72
|
+
availability: string;
|
|
73
|
+
timeline: string;
|
|
74
|
+
timezone: string;
|
|
75
|
+
profileUrl: string;
|
|
76
|
+
minHourlyRate: number | null;
|
|
77
|
+
preferredSamples: string[];
|
|
78
|
+
bannedPhrases: string[];
|
|
79
|
+
currency: string;
|
|
80
|
+
}
|
|
81
|
+
export declare function buildProposalSettings(config: FreelanceConfig, opts?: ProposalOptions, profile?: ProfileDefaults | null): ProposalSettings;
|
|
82
|
+
export declare function extractRequiredOpening(body: string): string;
|
|
83
|
+
export declare function parseBudget(value: unknown): {
|
|
84
|
+
min: number;
|
|
85
|
+
max: number;
|
|
86
|
+
raw: string;
|
|
87
|
+
} | null;
|
|
88
|
+
export declare function formatRate(rate: {
|
|
89
|
+
type: 'hourly' | 'fixed';
|
|
90
|
+
amount: number;
|
|
91
|
+
currency?: string;
|
|
92
|
+
} | null | undefined): string;
|
|
93
|
+
export declare function describeBudget(details: {
|
|
94
|
+
budget?: string;
|
|
95
|
+
budgetType?: string;
|
|
96
|
+
}): string;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { parse as parseYaml } from 'yaml';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { freelanceFile, legacyProposalFile, legacyUpworkFile, } from '../config/paths.js';
|
|
5
|
+
export const DEFAULT_BANNED_PHRASES = [
|
|
6
|
+
'I hope this message finds you well',
|
|
7
|
+
'Dear Hiring Manager',
|
|
8
|
+
'I am excited to apply',
|
|
9
|
+
'I am the perfect fit',
|
|
10
|
+
'I would be a great fit',
|
|
11
|
+
'As an AI language model',
|
|
12
|
+
];
|
|
13
|
+
export const RateSchema = z.object({
|
|
14
|
+
type: z.enum(['hourly', 'fixed']).default('hourly'),
|
|
15
|
+
amount: z.number().positive().nullable().default(null),
|
|
16
|
+
currency: z.string().default('USD'),
|
|
17
|
+
});
|
|
18
|
+
export const FreelanceConfigSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
profile: z
|
|
21
|
+
.union([
|
|
22
|
+
z.string(),
|
|
23
|
+
z.object({ url: z.string().default('') }).passthrough(),
|
|
24
|
+
])
|
|
25
|
+
.optional(),
|
|
26
|
+
rate: RateSchema.default({
|
|
27
|
+
type: 'hourly',
|
|
28
|
+
amount: null,
|
|
29
|
+
currency: 'USD',
|
|
30
|
+
}),
|
|
31
|
+
minHourlyRate: z.number().positive().nullable().default(null),
|
|
32
|
+
availability: z.string().default(''),
|
|
33
|
+
timezone: z.string().default(''),
|
|
34
|
+
timeline: z.string().default(''),
|
|
35
|
+
proposal: z
|
|
36
|
+
.object({
|
|
37
|
+
targetWords: z.number().positive().default(180),
|
|
38
|
+
minWords: z.number().positive().default(120),
|
|
39
|
+
maxWords: z.number().positive().default(260),
|
|
40
|
+
maxChars: z.number().positive().default(5000),
|
|
41
|
+
includeRate: z.boolean().default(false),
|
|
42
|
+
includeAvailability: z.boolean().default(true),
|
|
43
|
+
})
|
|
44
|
+
.default({
|
|
45
|
+
targetWords: 180,
|
|
46
|
+
minWords: 120,
|
|
47
|
+
maxWords: 260,
|
|
48
|
+
maxChars: 5000,
|
|
49
|
+
includeRate: false,
|
|
50
|
+
includeAvailability: true,
|
|
51
|
+
}),
|
|
52
|
+
preferredSamples: z.array(z.string()).default([]),
|
|
53
|
+
bannedPhrases: z.array(z.string()).default([]),
|
|
54
|
+
})
|
|
55
|
+
.passthrough();
|
|
56
|
+
export function loadFreelanceConfig() {
|
|
57
|
+
const path = existsSync(freelanceFile)
|
|
58
|
+
? freelanceFile
|
|
59
|
+
: existsSync(legacyProposalFile)
|
|
60
|
+
? legacyProposalFile
|
|
61
|
+
: existsSync(legacyUpworkFile)
|
|
62
|
+
? legacyUpworkFile
|
|
63
|
+
: null;
|
|
64
|
+
if (!path) {
|
|
65
|
+
return { config: FreelanceConfigSchema.parse({}), path: null };
|
|
66
|
+
}
|
|
67
|
+
const raw = parseYaml(readFileSync(path, 'utf8')) ?? {};
|
|
68
|
+
return { config: FreelanceConfigSchema.parse(raw), path };
|
|
69
|
+
}
|
|
70
|
+
export function buildProposalSettings(config, opts = {}, profile) {
|
|
71
|
+
const cliRate = numberOrNull(opts.rate);
|
|
72
|
+
const configRate = numberOrNull(config.rate.amount);
|
|
73
|
+
const profileRate = numberOrNull(profile?.rate?.amount);
|
|
74
|
+
const hourlyRate = cliRate ?? configRate ?? profileRate;
|
|
75
|
+
const rateType = String(opts.rateType || config.rate.type || profile?.rate?.type || 'hourly').toLowerCase();
|
|
76
|
+
const currency = String(config.rate.currency || profile?.rate?.currency || 'USD');
|
|
77
|
+
const configuredProfileUrl = typeof config.profile === 'string'
|
|
78
|
+
? config.profile
|
|
79
|
+
: config.profile?.url;
|
|
80
|
+
const profileUrl = cleanText(opts.profile) ||
|
|
81
|
+
(!opts.noProfile ? cleanText(configuredProfileUrl) : '');
|
|
82
|
+
const yamlPreferred = config.preferredSamples;
|
|
83
|
+
const preferredSamples = yamlPreferred.length > 0
|
|
84
|
+
? yamlPreferred
|
|
85
|
+
: (profile?.preferredSamples ?? []);
|
|
86
|
+
return {
|
|
87
|
+
targetWords: config.proposal.targetWords,
|
|
88
|
+
minWords: config.proposal.minWords,
|
|
89
|
+
maxWords: config.proposal.maxWords,
|
|
90
|
+
maxChars: config.proposal.maxChars,
|
|
91
|
+
includeRate: opts.noRate
|
|
92
|
+
? false
|
|
93
|
+
: Boolean(opts.rate) || config.proposal.includeRate,
|
|
94
|
+
includeAvailability: config.proposal.includeAvailability !== false,
|
|
95
|
+
rate: hourlyRate == null
|
|
96
|
+
? null
|
|
97
|
+
: {
|
|
98
|
+
type: rateType === 'fixed' ? 'fixed' : 'hourly',
|
|
99
|
+
amount: hourlyRate,
|
|
100
|
+
currency,
|
|
101
|
+
},
|
|
102
|
+
availability: cleanText(opts.availability) ||
|
|
103
|
+
cleanText(config.availability) ||
|
|
104
|
+
cleanText(profile?.hoursPerWeek),
|
|
105
|
+
timeline: cleanText(opts.timeline) || cleanText(config.timeline),
|
|
106
|
+
timezone: cleanText(config.timezone),
|
|
107
|
+
profileUrl,
|
|
108
|
+
minHourlyRate: config.minHourlyRate,
|
|
109
|
+
preferredSamples,
|
|
110
|
+
bannedPhrases: [
|
|
111
|
+
...new Set([...DEFAULT_BANNED_PHRASES, ...config.bannedPhrases]),
|
|
112
|
+
],
|
|
113
|
+
currency,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export function extractRequiredOpening(body) {
|
|
117
|
+
const text = String(body ?? '');
|
|
118
|
+
const match = text.match(/(?:start|begin)\s+(?:(?:your|the)\s+proposal\s+with|with\s+(?:the\s+word|the\s+phrase))\s*(?:the\s+word|the\s+phrase)?\s*["“'‘]?([^"”'’.\n]+)/i);
|
|
119
|
+
if (!match)
|
|
120
|
+
return '';
|
|
121
|
+
return match[1]
|
|
122
|
+
.trim()
|
|
123
|
+
.replace(/^["“'‘]+|["”'’]+$/g, '')
|
|
124
|
+
.replace(/\s+(?:and|then)\b.*$/i, '')
|
|
125
|
+
.replace(/[.,;:]+$/, '')
|
|
126
|
+
.trim();
|
|
127
|
+
}
|
|
128
|
+
export function parseBudget(value) {
|
|
129
|
+
const text = String(value ?? '').replace(/,/g, '');
|
|
130
|
+
const amounts = [...text.matchAll(/\$?\s*(\d+(?:\.\d+)?)/g)].map((match) => Number(match[1]));
|
|
131
|
+
if (amounts.length === 0)
|
|
132
|
+
return null;
|
|
133
|
+
return {
|
|
134
|
+
min: Math.min(...amounts),
|
|
135
|
+
max: Math.max(...amounts),
|
|
136
|
+
raw: String(value),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function formatRate(rate) {
|
|
140
|
+
if (!rate || rate.amount == null)
|
|
141
|
+
return '';
|
|
142
|
+
const symbol = rate.currency === 'EUR' ? '€' : rate.currency === 'GBP' ? '£' : '$';
|
|
143
|
+
const amount = Number(rate.amount).toLocaleString('en-US', {
|
|
144
|
+
maximumFractionDigits: 2,
|
|
145
|
+
});
|
|
146
|
+
return rate.type === 'fixed'
|
|
147
|
+
? `${symbol}${amount} fixed`
|
|
148
|
+
: `${symbol}${amount}/hr`;
|
|
149
|
+
}
|
|
150
|
+
export function describeBudget(details) {
|
|
151
|
+
if (!details.budget)
|
|
152
|
+
return '';
|
|
153
|
+
return details.budgetType === 'fixed'
|
|
154
|
+
? `${details.budget} fixed`
|
|
155
|
+
: `${details.budget}/hr`;
|
|
156
|
+
}
|
|
157
|
+
function numberOrNull(value) {
|
|
158
|
+
if (value == null || value === '')
|
|
159
|
+
return null;
|
|
160
|
+
const number = Number(value);
|
|
161
|
+
return Number.isFinite(number) && number > 0 ? number : null;
|
|
162
|
+
}
|
|
163
|
+
function cleanText(value) {
|
|
164
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/upwork/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function openFile(path: string): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
export function openFile(path) {
|
|
3
|
+
const candidates = process.platform === 'darwin'
|
|
4
|
+
? [['open', [path]]]
|
|
5
|
+
: process.platform === 'win32'
|
|
6
|
+
? [['cmd', ['/c', 'start', '', path]]]
|
|
7
|
+
: [
|
|
8
|
+
['xdg-open', [path]],
|
|
9
|
+
['gio', ['open', path]],
|
|
10
|
+
['kde-open', [path]],
|
|
11
|
+
['gnome-open', [path]],
|
|
12
|
+
['wslview', [path]],
|
|
13
|
+
];
|
|
14
|
+
for (const [command, args] of candidates) {
|
|
15
|
+
const result = spawnSync(command, args, {
|
|
16
|
+
stdio: 'ignore',
|
|
17
|
+
timeout: 5000,
|
|
18
|
+
});
|
|
19
|
+
if (!result.error && result.status === 0)
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=open-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-file.js","sourceRoot":"","sources":["../../src/util/open-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,UAAU,GACd,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC3B,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;YACtC,CAAC,CAAC;gBACE,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACvB,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC;aACpB,CAAC;IAEV,KAAK,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;YACtC,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function slugify(value) {
|
|
2
|
+
return String(value ?? '')
|
|
3
|
+
.toLowerCase()
|
|
4
|
+
.normalize('NFKD')
|
|
5
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
6
|
+
.replace(/^-+|-+$/g, '')
|
|
7
|
+
.slice(0, 70);
|
|
8
|
+
}
|
|
9
|
+
export function truncate(value, length) {
|
|
10
|
+
const text = String(value ?? '').replace(/\s+/g, ' ').trim();
|
|
11
|
+
return text.length > length ? `${text.slice(0, length - 1)}…` : text;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=slug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/util/slug.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,WAAW,EAAE;SACb,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,MAAc;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7D,OAAO,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { loadCareer } from '../career/load.js';
|
|
4
|
+
import { loadConfig } from '../config/config.js';
|
|
5
|
+
import { resolveOutputDir } from '../config/paths.js';
|
|
6
|
+
import { getPdfPageCount } from '../resume/render.js';
|
|
7
|
+
import { verifyTailoredResume } from '../resume/verify.js';
|
|
8
|
+
import { slugify } from '../util/slug.js';
|
|
9
|
+
export async function runVerify(options) {
|
|
10
|
+
const { config } = loadConfig();
|
|
11
|
+
const resolved = resolveResumeFiles(options.input, resolveOutputDir(config.output.dir, undefined));
|
|
12
|
+
const resume = JSON.parse(readFileSync(resolved.resumePath, 'utf8'));
|
|
13
|
+
const trace = JSON.parse(readFileSync(resolved.tracePath, 'utf8'));
|
|
14
|
+
const { career } = loadCareer();
|
|
15
|
+
const verification = await verifyTailoredResume({
|
|
16
|
+
resume,
|
|
17
|
+
trace,
|
|
18
|
+
career,
|
|
19
|
+
});
|
|
20
|
+
for (const warning of verification.warnings) {
|
|
21
|
+
console.warn(`dossier: warning: ${warning}`);
|
|
22
|
+
}
|
|
23
|
+
if (resolved.pdfPath && existsSync(resolved.pdfPath)) {
|
|
24
|
+
const pages = await getPdfPageCount(resolved.pdfPath);
|
|
25
|
+
if (pages !== 1) {
|
|
26
|
+
verification.errors.push(`PDF is ${pages} pages, expected 1`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.log('dossier: PDF is 1 page');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const error of verification.errors) {
|
|
33
|
+
console.error(`dossier: error: ${error}`);
|
|
34
|
+
}
|
|
35
|
+
console.log(`dossier: ${verification.errors.length} error(s), ${verification.warnings.length} warning(s), ${verification.gaps.length} gap(s)`);
|
|
36
|
+
if (verification.gaps.length > 0) {
|
|
37
|
+
console.log('dossier: gaps:');
|
|
38
|
+
for (const gap of verification.gaps)
|
|
39
|
+
console.log(` - ${gap}`);
|
|
40
|
+
}
|
|
41
|
+
if (verification.errors.length > 0) {
|
|
42
|
+
throw new Error('Resume verification failed.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function resolveResumeFiles(input, outputDir) {
|
|
46
|
+
const direct = resolve(process.cwd(), input);
|
|
47
|
+
if (existsSync(direct)) {
|
|
48
|
+
if (direct.toLowerCase().endsWith('.pdf')) {
|
|
49
|
+
return {
|
|
50
|
+
resumePath: direct.replace(/\.pdf$/i, '.json'),
|
|
51
|
+
tracePath: direct.replace(/\.pdf$/i, '.trace.json'),
|
|
52
|
+
pdfPath: direct,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (direct.toLowerCase().endsWith('.json')) {
|
|
56
|
+
const tracePath = direct.endsWith('.trace.json')
|
|
57
|
+
? direct
|
|
58
|
+
: direct.replace(/\.json$/i, '.trace.json');
|
|
59
|
+
const resumePath = direct.endsWith('.trace.json')
|
|
60
|
+
? direct.replace(/\.trace\.json$/i, '.json')
|
|
61
|
+
: direct;
|
|
62
|
+
return {
|
|
63
|
+
resumePath,
|
|
64
|
+
tracePath,
|
|
65
|
+
pdfPath: resumePath.replace(/\.json$/i, '.pdf'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
resumePath: join(direct, 'resume.json'),
|
|
70
|
+
tracePath: join(direct, 'trace.json'),
|
|
71
|
+
pdfPath: join(direct, 'resume.pdf'),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const slug = slugify(input.replace(/\.(json|pdf)$/i, ''));
|
|
75
|
+
const candidates = [
|
|
76
|
+
resolve(process.cwd(), `resume-${slug}.json`),
|
|
77
|
+
resolve(outputDir, `resume-${slug}.json`),
|
|
78
|
+
resolve(process.cwd(), input.endsWith('.json') ? input : `${input}.json`),
|
|
79
|
+
];
|
|
80
|
+
for (const resumePath of candidates) {
|
|
81
|
+
if (!existsSync(resumePath))
|
|
82
|
+
continue;
|
|
83
|
+
return {
|
|
84
|
+
resumePath,
|
|
85
|
+
tracePath: resumePath.replace(/\.json$/i, '.trace.json'),
|
|
86
|
+
pdfPath: resumePath.replace(/\.json$/i, '.pdf'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Resume not found: ${input}. Pass a .json/.pdf path or a resume slug.`);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/verify/run.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,69 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rwendell/dossier",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Grounded resume, application answer, and Upwork proposal generation from a local career dossier.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dossier": "dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"agents",
|
|
12
|
+
"templates",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"dev": "tsx src/cli/index.ts",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
24
|
+
"prepack": "aube run build",
|
|
25
|
+
"prepublishOnly": "aube run typecheck && aube run test"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"resume",
|
|
29
|
+
"json-resume",
|
|
30
|
+
"upwork",
|
|
31
|
+
"proposal",
|
|
32
|
+
"freelance",
|
|
33
|
+
"opencode"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/rwendell/dossier.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/rwendell/dossier#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/rwendell/dossier/issues"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@jsonresume/schema": "1.7.0",
|
|
49
|
+
"cheerio": "^1.2.0",
|
|
50
|
+
"clipboardy": "^5.3.2",
|
|
51
|
+
"env-paths": "^4.0.0",
|
|
52
|
+
"html-to-text": "^10.0.1",
|
|
53
|
+
"jsonresume-theme-straightforward": "0.5.0",
|
|
54
|
+
"pdf-lib": "1.17.1",
|
|
55
|
+
"puppeteer": "^24.43.1",
|
|
56
|
+
"resumed": "6.1.0",
|
|
57
|
+
"yaml": "^2.9.1",
|
|
58
|
+
"yargs": "^18.2.0",
|
|
59
|
+
"zod": "^4.6.7"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/html-to-text": "^9.0.4",
|
|
63
|
+
"@types/node": "^26.6.6",
|
|
64
|
+
"@types/yargs": "^17.0.35",
|
|
65
|
+
"tsx": "^4.23.15",
|
|
66
|
+
"typescript": "^7.0.2",
|
|
67
|
+
"vitest": "^5.1.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Dossier career fact bank.
|
|
2
|
+
# Keep public, non-PII facts here. Put name/contact/location in
|
|
3
|
+
# career.private.yml.
|
|
4
|
+
|
|
5
|
+
version: 1
|
|
6
|
+
basics:
|
|
7
|
+
profiles:
|
|
8
|
+
- network: GitHub
|
|
9
|
+
username: your-handle
|
|
10
|
+
url: https://github.com/your-handle
|
|
11
|
+
|
|
12
|
+
summary: >-
|
|
13
|
+
One or two sentences describing the kind of work you do and the value you
|
|
14
|
+
bring. The proposal agent will use this as framing, not as evidence.
|
|
15
|
+
|
|
16
|
+
generic:
|
|
17
|
+
title: Software Engineer
|
|
18
|
+
publishAs: software-engineer
|
|
19
|
+
description: >-
|
|
20
|
+
Build a general-purpose resume from the strongest evidence in this fact
|
|
21
|
+
bank. Prefer quantified outcomes and recent, relevant work.
|
|
22
|
+
|
|
23
|
+
roles:
|
|
24
|
+
- id: example-company
|
|
25
|
+
company: Example Company
|
|
26
|
+
position: Software Engineer
|
|
27
|
+
startDate: 2022-01
|
|
28
|
+
endDate: 2025-01
|
|
29
|
+
summary: Built and maintained customer-facing systems.
|
|
30
|
+
achievements:
|
|
31
|
+
- id: example-delivery
|
|
32
|
+
text: Led delivery of a production feature from requirements through deployment and support.
|
|
33
|
+
skills: [delivery, api-design, testing]
|
|
34
|
+
strength: 5
|
|
35
|
+
|
|
36
|
+
projects:
|
|
37
|
+
- id: example-project
|
|
38
|
+
name: Example Project
|
|
39
|
+
repo: your-handle/example-project
|
|
40
|
+
url: https://github.com/your-handle/example-project
|
|
41
|
+
description: A short description of the project.
|
|
42
|
+
highlights:
|
|
43
|
+
- id: example-project-highlight
|
|
44
|
+
text: Built a multi-user application with authentication and real-time data.
|
|
45
|
+
skills: [typescript, full-stack]
|
|
46
|
+
|
|
47
|
+
education:
|
|
48
|
+
- id: example-school
|
|
49
|
+
institution: Example University
|
|
50
|
+
area: Computer Science
|
|
51
|
+
studyType: Bachelor of Science
|
|
52
|
+
startDate: 2014
|
|
53
|
+
endDate: 2018
|
|
54
|
+
|
|
55
|
+
skills:
|
|
56
|
+
- name: TypeScript
|
|
57
|
+
- name: SQL
|
|
58
|
+
|
|
59
|
+
constraints:
|
|
60
|
+
doNotClaim:
|
|
61
|
+
- People management unless explicitly listed
|
|
62
|
+
|
|
63
|
+
transferable: []
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Dossier machine configuration.
|
|
2
|
+
output:
|
|
3
|
+
# Empty means the current working directory.
|
|
4
|
+
dir: ""
|
|
5
|
+
# Open the generated PDF when tailoring finishes.
|
|
6
|
+
open: true
|
|
7
|
+
|
|
8
|
+
cache:
|
|
9
|
+
# auto | dev | release
|
|
10
|
+
mode: "auto"
|
|
11
|
+
# Optional explicit cache directory; overrides mode.
|
|
12
|
+
dir: ""
|
|
13
|
+
|
|
14
|
+
theme: "jsonresume-theme-straightforward"
|
|
15
|
+
provider: "auto"
|
|
16
|
+
editor: ""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Dossier freelance proposal defaults.
|
|
2
|
+
#
|
|
3
|
+
# Copy this file to ~/.local/share/dossier/freelance.yml and edit it. CLI flags
|
|
4
|
+
# override these values.
|
|
5
|
+
|
|
6
|
+
# Public Upwork profile. When set, public values fill name, title, location,
|
|
7
|
+
# rate, skills, and portfolio; hours per week is used when present. Values below
|
|
8
|
+
# and CLI flags override.
|
|
9
|
+
profile:
|
|
10
|
+
url: "" # e.g. https://www.upwork.com/freelancers/~01fbe3cf033cea5004
|
|
11
|
+
|
|
12
|
+
# Your standard rate. Used in proposals only when includeRate is true, and for
|
|
13
|
+
# the bid/no-bid warning against a job's stated budget. Leave amount null to
|
|
14
|
+
# use the public profile rate.
|
|
15
|
+
rate:
|
|
16
|
+
type: hourly # hourly | fixed
|
|
17
|
+
amount: null # e.g. 85
|
|
18
|
+
currency: USD
|
|
19
|
+
|
|
20
|
+
# Warn when an hourly job's maximum budget is below this. Leave null to disable.
|
|
21
|
+
minHourlyRate: null
|
|
22
|
+
|
|
23
|
+
# Logistics included when includeAvailability is true.
|
|
24
|
+
availability: "" # e.g. "20-30 hrs/week; UK overlap until 6pm GMT"
|
|
25
|
+
timezone: "" # e.g. "US Eastern"
|
|
26
|
+
timeline: "" # e.g. "2 weeks"; --timeline overrides
|
|
27
|
+
|
|
28
|
+
proposal:
|
|
29
|
+
targetWords: 180
|
|
30
|
+
minWords: 120
|
|
31
|
+
maxWords: 260
|
|
32
|
+
maxChars: 5000
|
|
33
|
+
includeRate: false
|
|
34
|
+
includeAvailability: true
|
|
35
|
+
|
|
36
|
+
# Soft hint: evidence ids or project names to prefer when relevant. The agent
|
|
37
|
+
# still chooses the final `samples` based on the job; this list does not filter
|
|
38
|
+
# or rank candidates.
|
|
39
|
+
preferredSamples: []
|
|
40
|
+
|
|
41
|
+
# The verifier warns when a proposal contains these generic phrases. The
|
|
42
|
+
# built-in defaults are always included.
|
|
43
|
+
bannedPhrases:
|
|
44
|
+
- "I hope this message finds you well"
|
|
45
|
+
- "Dear Hiring Manager"
|
|
46
|
+
- "I am excited to apply"
|
|
47
|
+
- "I am the perfect fit"
|
|
48
|
+
- "I would be a great fit"
|