jobhunt-kit 0.3.0 → 0.5.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/.claude-plugin/marketplace.json +1 -1
- package/README.md +58 -11
- package/bin/agents.mjs +66 -0
- package/bin/install-options.mjs +21 -18
- package/bin/jobhunt-kit.mjs +17 -6
- package/installer-assets/gitignore.txt +1 -0
- package/installer-assets/runtime-lock.json +56 -2
- package/installer-assets/workspace-lock.json +56 -2
- package/package.json +3 -1
- package/plugins/jobhunt-kit/.claude-plugin/plugin.json +1 -1
- package/plugins/jobhunt-kit/.codex-plugin/plugin.json +1 -1
- package/plugins/jobhunt-kit/package-lock.json +56 -2
- package/plugins/jobhunt-kit/package.json +2 -1
- package/plugins/jobhunt-kit/references/cli.md +30 -2
- package/plugins/jobhunt-kit/references/harnesses.md +12 -0
- package/plugins/jobhunt-kit/references/privacy.md +24 -0
- package/plugins/jobhunt-kit/references/storage.md +11 -5
- package/plugins/jobhunt-kit/schemas/draft.schema.json +13 -0
- package/plugins/jobhunt-kit/schemas/finish.schema.json +11 -0
- package/plugins/jobhunt-kit/schemas/policy.schema.json +36 -0
- package/plugins/jobhunt-kit/schemas/profile.schema.json +80 -0
- package/plugins/jobhunt-kit/schemas/status.schema.json +12 -0
- package/plugins/jobhunt-kit/schemas/vacancy.schema.json +29 -0
- package/plugins/jobhunt-kit/scripts/commands.mjs +57 -11
- package/plugins/jobhunt-kit/scripts/extract-resume.mjs +5 -3
- package/plugins/jobhunt-kit/scripts/files.mjs +69 -0
- package/plugins/jobhunt-kit/scripts/maintenance.mjs +292 -0
- package/plugins/jobhunt-kit/scripts/profile.mjs +23 -20
- package/plugins/jobhunt-kit/scripts/resume.mjs +42 -38
- package/plugins/jobhunt-kit/scripts/setup.mjs +8 -10
- package/plugins/jobhunt-kit/scripts/tracker.mjs +188 -33
- package/plugins/jobhunt-kit/scripts/validation.mjs +30 -0
- package/plugins/jobhunt-kit/skills/job-apply/SKILL.md +4 -2
- package/plugins/jobhunt-kit/skills/job-resume/SKILL.md +3 -2
- package/plugins/jobhunt-kit/skills/job-track/SKILL.md +8 -0
- package/scripts/check-package.mjs +7 -0
- package/scripts/pack-smoke.mjs +53 -0
- package/tests/hardening.test.mjs +337 -0
- package/tests/installer.test.mjs +47 -2
- package/tests/tracker.test.mjs +3 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ npx jobhunt-kit install
|
|
|
7
7
|
Поиск работы вместе с AI-агентом: профиль кандидата, проверка резюме, подбор вакансий
|
|
8
8
|
через Hirify, сопроводительные письма и история откликов.
|
|
9
9
|
|
|
10
|
-
Нужны **Node.js 24+ и
|
|
10
|
+
Нужны **Node.js 24+ и агент с поддержкой навыков**. Установщик предложит выбрать
|
|
11
11
|
агентов и область установки: рабочая папка или глобально для пользователя.
|
|
12
12
|
При установке в рабочую папку он создаст `my-jobhunt`, установит зависимости
|
|
13
13
|
и подключит навык к выбранным агентам. Другой путь: `install ./my-folder`.
|
|
@@ -55,6 +55,11 @@ npx jobhunt-kit profile check
|
|
|
55
55
|
npx jobhunt-kit search
|
|
56
56
|
npx jobhunt-kit track
|
|
57
57
|
npx jobhunt-kit report
|
|
58
|
+
npx jobhunt-kit recover inspect
|
|
59
|
+
npx jobhunt-kit recover packet <attempt_id>
|
|
60
|
+
npx jobhunt-kit backup ../jobhunt-backup
|
|
61
|
+
npx jobhunt-kit backup-verify ../jobhunt-backup
|
|
62
|
+
npx jobhunt-kit privacy map
|
|
58
63
|
```
|
|
59
64
|
|
|
60
65
|
`resume` извлекает текст PDF, DOCX, TXT или Markdown и готовит материалы для проверки
|
|
@@ -77,28 +82,68 @@ npx jobhunt-kit report
|
|
|
77
82
|
| `reports/latest.md` | Сводный отчёт |
|
|
78
83
|
|
|
79
84
|
Папка `local/` исключена из Git. Храните личные файлы в ней; для резервной копии
|
|
80
|
-
|
|
85
|
+
используйте `backup` и затем `backup-verify`. Restore принимает только проверяемую
|
|
86
|
+
копию, требует точное подтверждение и предварительно делает сырой quarantine-снимок,
|
|
87
|
+
который сохраняется даже тогда, когда текущие JSON или SQLite уже повреждены.
|
|
88
|
+
Restore и очистка history всегда отзывают auto-разрешение и подтверждение профиля.
|
|
89
|
+
Данные на диске не зашифрованы.
|
|
90
|
+
|
|
91
|
+
`doctor` проверяет JSON Schema профиля/policy, SQLite integrity и foreign keys,
|
|
92
|
+
незавершённые поиски/отправки и журнал атомарных файловых операций. `privacy map`
|
|
93
|
+
показывает размещение PII; `privacy export`, `redact` и `purge` дают контролируемый
|
|
94
|
+
экспорт и удаление. Redact/purge требуют точных подтверждений, а purge не запускается
|
|
95
|
+
без отдельной резервной копии.
|
|
81
96
|
|
|
82
97
|
## Выбор агентов
|
|
83
98
|
|
|
84
99
|
Без интерактивных вопросов:
|
|
85
100
|
|
|
86
101
|
```sh
|
|
87
|
-
npx jobhunt-kit install --agents codex,
|
|
88
|
-
npx jobhunt-kit install --agents
|
|
89
|
-
npx jobhunt-kit install --
|
|
102
|
+
npx jobhunt-kit install --agents codex,cursor,gemini
|
|
103
|
+
npx jobhunt-kit install --agents all
|
|
104
|
+
npx jobhunt-kit install --providers opencode,pi --scope global
|
|
105
|
+
npx jobhunt-kit agents
|
|
90
106
|
```
|
|
91
107
|
|
|
92
|
-
В режиме `project`
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
В режиме `project` навык устанавливается в созданную рабочую папку,
|
|
109
|
+
в режиме `global` — в домашнюю папку пользователя.
|
|
110
|
+
|
|
111
|
+
| Агент | Значение `--agents` | Рабочая папка | Глобально (от `~`) |
|
|
112
|
+
|---|---|---|---|
|
|
113
|
+
| Codex | `codex` | `.agents/skills/` | `.agents/skills/` |
|
|
114
|
+
| Claude Code | `claude` | `.claude/skills/` | `.claude/skills/` |
|
|
115
|
+
| Cursor | `cursor` | `.cursor/skills/` | `.cursor/skills/` |
|
|
116
|
+
| Gemini CLI | `gemini` | `.gemini/skills/` | `.gemini/skills/` |
|
|
117
|
+
| GitHub Copilot | `github` | `.github/skills/` | `.copilot/skills/` |
|
|
118
|
+
| OpenCode | `opencode` | `.opencode/skills/` | `.config/opencode/skills/` |
|
|
119
|
+
| Antigravity | `antigravity` | `.agent/skills/` | `.gemini/config/skills/` |
|
|
120
|
+
| Pi | `pi` | `.pi/skills/` | `.pi/agent/skills/` |
|
|
121
|
+
| Grok Build | `grok` | `.grok/skills/` | `.grok/skills/` |
|
|
122
|
+
| Hermes Agent | `hermes` | `.hermes/skills/` | `.hermes/skills/` |
|
|
123
|
+
| DeepSeek Harness | `dsh` | `.dsh/skills/` | `.dsh/skills/` |
|
|
124
|
+
| Kiro | `kiro` | `.kiro/skills/` | `.kiro/skills/` |
|
|
125
|
+
| Qoder | `qoder` | `.qoder/skills/` | `.qoder/skills/` |
|
|
126
|
+
| Trae | `trae` | `.trae/skills/` | `.trae/skills/` |
|
|
127
|
+
| Trae CN | `trae-cn` | `.trae-cn/skills/` | `.trae-cn/skills/` |
|
|
128
|
+
| Rovo Dev | `rovo-dev` | `.rovodev/skills/` | `.rovodev/skills/` |
|
|
129
|
+
| Mistral Vibe | `vibe` | `.vibe/skills/` | `.vibe/skills/` |
|
|
130
|
+
| Veto | `veto` | — | `.veto/skills/` |
|
|
131
|
+
|
|
132
|
+
В каждом каталоге создаётся отдельная папка `jobhunt-kit` с навыком и его ресурсами.
|
|
133
|
+
`--agents all` выбирает всех агентов для указанной области; Veto доступен только
|
|
134
|
+
глобально. `--providers` — синоним `--agents`. Можно использовать имена
|
|
135
|
+
`copilot`, `claude-code`, `deepseek` и `grok-build`.
|
|
136
|
+
|
|
137
|
+
OpenCode учитывает `OPENCODE_CONFIG_DIR` и `XDG_CONFIG_HOME`; Hermes и DeepSeek —
|
|
138
|
+
`HERMES_HOME` и `DSH_HOME`. Глобальные пути должны находиться в домашней папке.
|
|
139
|
+
При установке Hermes в проект выполните `hermes skills trust` в рабочей папке.
|
|
140
|
+
В остальных агентах при необходимости включите поддержку навыков и доверие к проекту.
|
|
96
141
|
|
|
97
142
|
После установки откройте новую сессию и попросите использовать **jobhunt-kit**.
|
|
98
143
|
В Claude Code можно вызвать `/jobhunt-kit`. Отдельные команды marketplace
|
|
99
144
|
и `--plugin-dir` для этого способа не нужны.
|
|
100
145
|
|
|
101
|
-
`--yes` выбирает обнаруженных агентов (или
|
|
146
|
+
`--yes` выбирает обнаруженных агентов (или Codex и Claude Code, если ничего не обнаружено)
|
|
102
147
|
и область `project`. Обнаружение использует каталоги агентов, а не запускает их.
|
|
103
148
|
Для скриптов задавайте `--agents` и `--scope` явно.
|
|
104
149
|
|
|
@@ -112,12 +157,14 @@ Codex — `.agents/skills/jobhunt-kit`, Claude Code — `.claude/skills/jobhunt-
|
|
|
112
157
|
npm ci --ignore-scripts
|
|
113
158
|
npm test
|
|
114
159
|
npm run check
|
|
160
|
+
npm run pack:smoke
|
|
115
161
|
```
|
|
116
162
|
|
|
117
163
|
Тесты работают с вымышленными данными и не отправляют реальные отклики.
|
|
118
164
|
|
|
119
165
|
Руководства: [формат данных](plugins/jobhunt-kit/references/storage.md),
|
|
120
166
|
[проверка резюме](plugins/jobhunt-kit/references/resume-guidance.md),
|
|
121
|
-
[сопроводительные письма](plugins/jobhunt-kit/references/cover-guidance.md)
|
|
167
|
+
[сопроводительные письма](plugins/jobhunt-kit/references/cover-guidance.md),
|
|
168
|
+
[карта приватных данных](plugins/jobhunt-kit/references/privacy.md).
|
|
122
169
|
|
|
123
170
|
Автор этого шаблона никак не аффилирован с Hirify.
|
package/bin/agents.mjs
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Directory conventions checked against Impeccable's providers.rs and README.
|
|
5
|
+
export const AGENTS = [
|
|
6
|
+
{id:'codex', name:'Codex', dir:'.agents', detect:'.codex', aliases:['agents']},
|
|
7
|
+
{id:'claude', name:'Claude Code', dir:'.claude', aliases:['claude-code']},
|
|
8
|
+
{id:'cursor', name:'Cursor', dir:'.cursor'},
|
|
9
|
+
{id:'gemini', name:'Gemini CLI', dir:'.gemini'},
|
|
10
|
+
{id:'github', name:'GitHub Copilot', dir:'.github', global:'.copilot/skills', detect:'.copilot', aliases:['copilot']},
|
|
11
|
+
{id:'opencode', name:'OpenCode', dir:'.opencode', global:'.config/opencode/skills'},
|
|
12
|
+
{id:'antigravity', name:'Antigravity', dir:'.agent', global:'.gemini/config/skills', aliases:['agent']},
|
|
13
|
+
{id:'pi', name:'Pi', dir:'.pi', global:'.pi/agent/skills'},
|
|
14
|
+
{id:'grok', name:'Grok Build', dir:'.grok', aliases:['grok-build','xai']},
|
|
15
|
+
{id:'hermes', name:'Hermes Agent', dir:'.hermes'},
|
|
16
|
+
{id:'dsh', name:'DeepSeek Harness', dir:'.dsh', aliases:['deepseek','deepseek-harness']},
|
|
17
|
+
{id:'kiro', name:'Kiro', dir:'.kiro'},
|
|
18
|
+
{id:'qoder', name:'Qoder', dir:'.qoder'},
|
|
19
|
+
{id:'trae', name:'Trae', dir:'.trae'},
|
|
20
|
+
{id:'trae-cn', name:'Trae CN', dir:'.trae-cn'},
|
|
21
|
+
{id:'rovo-dev', name:'Rovo Dev', dir:'.rovodev', aliases:['rovodev']},
|
|
22
|
+
{id:'vibe', name:'Mistral Vibe', dir:'.vibe'},
|
|
23
|
+
{id:'veto', name:'Veto', dir:'.veto', globalOnly:true}
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export function parseAgents(value) {
|
|
27
|
+
const selected = value.split(',').map(x => x.trim().toLowerCase().replace(/^\./,''));
|
|
28
|
+
if (selected.length === 1 && selected[0] === 'all') return AGENTS.map(a=>a.id);
|
|
29
|
+
return [...new Set(selected.map(id => {
|
|
30
|
+
const found=AGENTS.find(a=>a.id===id || a.aliases?.includes(id));
|
|
31
|
+
if (!found) throw new Error(`Choose agents: ${AGENTS.map(a=>a.id).join(', ')} (or all)`);
|
|
32
|
+
return found.id;
|
|
33
|
+
}))];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function skillDirectory(id, {scope, home, cwd, env = process.env}) {
|
|
37
|
+
const agent=AGENTS.find(a=>a.id===id);
|
|
38
|
+
if (!agent) throw new Error(`Unknown agent: ${id}`);
|
|
39
|
+
if (scope==='project') {
|
|
40
|
+
if (agent.globalOnly) throw new Error(`${agent.name} supports --scope global only`);
|
|
41
|
+
return join(cwd,agent.dir,'skills','jobhunt-kit');
|
|
42
|
+
}
|
|
43
|
+
let folder=join(home, agent.global || join(agent.dir,'skills'));
|
|
44
|
+
if (id==='opencode') {
|
|
45
|
+
if (env.OPENCODE_CONFIG_DIR) folder=join(resolve(cwd,env.OPENCODE_CONFIG_DIR),'skills');
|
|
46
|
+
else if (env.XDG_CONFIG_HOME) folder=join(resolve(cwd,env.XDG_CONFIG_HOME),'opencode','skills');
|
|
47
|
+
}
|
|
48
|
+
const override=id==='hermes' ? env.HERMES_HOME : id==='dsh' ? env.DSH_HOME : null;
|
|
49
|
+
if (override) folder=join(resolve(cwd,override),'skills');
|
|
50
|
+
const delta=relative(resolve(home),resolve(folder));
|
|
51
|
+
if (isAbsolute(delta) || delta==='..' || delta.startsWith(`..${sep}`)) {
|
|
52
|
+
throw new Error(`${agent.name}: global configuration path must be inside the home directory: ${folder}`);
|
|
53
|
+
}
|
|
54
|
+
return join(folder,'jobhunt-kit');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function detectAgents({home,cwd,env=process.env}) {
|
|
58
|
+
return AGENTS.filter(a=>{
|
|
59
|
+
const project=a.id==='github' ? join(cwd,'.github/skills') : join(cwd,a.dir);
|
|
60
|
+
let global;
|
|
61
|
+
try { global=dirname(dirname(skillDirectory(a.id,{scope:'global',home,cwd,env}))); }
|
|
62
|
+
catch { global=null; }
|
|
63
|
+
return (!a.globalOnly && existsSync(project)) || global && existsSync(global)
|
|
64
|
+
|| a.detect && existsSync(join(home,a.detect));
|
|
65
|
+
}).map(a=>a.id);
|
|
66
|
+
}
|
package/bin/install-options.mjs
CHANGED
|
@@ -1,40 +1,38 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util';
|
|
2
2
|
import { createInterface } from 'node:readline/promises';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
4
3
|
import { homedir } from 'node:os';
|
|
5
|
-
import {
|
|
4
|
+
import { AGENTS, detectAgents, parseAgents } from './agents.mjs';
|
|
5
|
+
export { parseAgents } from './agents.mjs';
|
|
6
6
|
|
|
7
|
-
export function
|
|
8
|
-
const agents = [...new Set(value.split(',').map(x => x.trim().toLowerCase()))];
|
|
9
|
-
if (!agents.length || agents.some(x => !['codex', 'claude'].includes(x))) {
|
|
10
|
-
throw new Error('Choose agents: codex, claude or codex,claude');
|
|
11
|
-
}
|
|
12
|
-
return agents;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function installOptions(args, { input = process.stdin, output = process.stdout, home = homedir(), cwd = process.cwd(), ask } = {}) {
|
|
7
|
+
export async function installOptions(args, { input = process.stdin, output = process.stdout, home = homedir(), cwd = process.cwd(), env = process.env, ask } = {}) {
|
|
16
8
|
const {values, positionals} = parseArgs({args, allowPositionals: true, options: {
|
|
17
|
-
agents: {type:'string'}, scope: {type:'string'}, yes: {type:'boolean', short:'y'}
|
|
9
|
+
agents: {type:'string'}, providers: {type:'string'}, scope: {type:'string'}, yes: {type:'boolean', short:'y'}
|
|
18
10
|
}});
|
|
19
11
|
if (positionals.length > 1) throw new Error('Expected at most one destination folder');
|
|
20
|
-
|
|
12
|
+
if (values.agents && values.providers) throw new Error('Use either --agents or --providers');
|
|
13
|
+
const selection = values.agents ?? values.providers;
|
|
14
|
+
let agents = selection !== undefined ? parseAgents(selection) : null;
|
|
15
|
+
let allSelected = selection?.trim().toLowerCase()==='all';
|
|
21
16
|
let scope = values.scope;
|
|
22
17
|
if (scope && !['project','global'].includes(scope)) throw new Error('Scope must be project or global');
|
|
23
|
-
const detected =
|
|
18
|
+
const detected = detectAgents({home,cwd,env});
|
|
24
19
|
const defaults = detected.length ? detected : ['codex','claude'];
|
|
25
20
|
let terminal;
|
|
26
21
|
try {
|
|
27
|
-
if (!agents && !values.yes || !scope && !values.yes &&
|
|
22
|
+
if (!agents && !values.yes || !scope && !values.yes && selection === undefined) {
|
|
28
23
|
if (!ask && (!input.isTTY || !output.isTTY)) throw new Error('Non-interactive install: pass --agents codex,claude --scope project, or --yes');
|
|
29
24
|
if (!ask) {
|
|
30
25
|
terminal = createInterface({input, output});
|
|
31
26
|
ask = question => terminal.question(question);
|
|
32
27
|
terminal.on('SIGINT', () => terminal.close());
|
|
33
28
|
}
|
|
34
|
-
output.write(`\nJobhunt Kit\nDetected: ${detected.join(', ') || 'none'}\n`);
|
|
29
|
+
output.write(`\nJobhunt Kit\n${AGENTS.map(a=>`${a.id}: ${a.name}${a.globalOnly?' (global only)':''}`).join('\n')}\nDetected: ${detected.join(', ') || 'none'}\n`);
|
|
35
30
|
while (!agents) {
|
|
36
|
-
const answer = await ask(`Agents —
|
|
37
|
-
try {
|
|
31
|
+
const answer = await ask(`Agents — comma-separated names or all [${defaults.join(',')}]: `);
|
|
32
|
+
try {
|
|
33
|
+
const chosen = answer.trim() || defaults.join(',');
|
|
34
|
+
agents = parseAgents(chosen); allSelected=chosen.toLowerCase()==='all';
|
|
35
|
+
}
|
|
38
36
|
catch (e) { output.write(`${e.message}\n`); }
|
|
39
37
|
}
|
|
40
38
|
while (!scope) {
|
|
@@ -46,6 +44,11 @@ export async function installOptions(args, { input = process.stdin, output = pro
|
|
|
46
44
|
} finally { terminal?.close(); }
|
|
47
45
|
scope ||= 'project';
|
|
48
46
|
agents ||= defaults;
|
|
47
|
+
if (scope==='project') {
|
|
48
|
+
const globalOnly = agents.filter(id=>AGENTS.find(a=>a.id===id).globalOnly);
|
|
49
|
+
if (allSelected) agents=agents.filter(id=>!globalOnly.includes(id));
|
|
50
|
+
else if (globalOnly.length) throw new Error(`${globalOnly.join(', ')} requires --scope global`);
|
|
51
|
+
}
|
|
49
52
|
if (scope === 'global' && positionals.length) throw new Error('Global installation does not take a workspace folder');
|
|
50
53
|
return {destination: positionals[0] || './my-jobhunt', agents, scope};
|
|
51
54
|
}
|
package/bin/jobhunt-kit.mjs
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, writeFileSync, realpathSync } from 'node:fs';
|
|
3
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { homedir } from 'node:os';
|
|
7
7
|
import { installOptions } from './install-options.mjs';
|
|
8
|
+
import { AGENTS, skillDirectory } from './agents.mjs';
|
|
8
9
|
|
|
9
10
|
const SOURCE = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
10
11
|
const roots = ['bin', 'installer-assets', 'plugins/jobhunt-kit', 'scripts', 'tests',
|
|
11
12
|
'AGENTS.md', 'CLAUDE.md', 'README.md', 'package.json',
|
|
12
13
|
'.agents/plugins/marketplace.json', '.claude-plugin/marketplace.json'];
|
|
14
|
+
export function pathInside(parent, child, pathApi = { relative, isAbsolute, sep }) {
|
|
15
|
+
const delta = pathApi.relative(parent, child);
|
|
16
|
+
return delta === '' || (!pathApi.isAbsolute(delta) && delta !== '..' && !delta.startsWith(`..${pathApi.sep}`));
|
|
17
|
+
}
|
|
13
18
|
function collect(path) {
|
|
14
19
|
const stat = lstatSync(path);
|
|
15
20
|
if (stat.isSymbolicLink()) throw new Error(`Symlink in template: ${path}`);
|
|
@@ -26,13 +31,13 @@ function noSymlinks(path) {
|
|
|
26
31
|
current = parent;
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
|
-
export function install(destination, { source = SOURCE, installDependencies = true, agents = [], scope = 'project', home = homedir() } = {}) {
|
|
34
|
+
export function install(destination, { source = SOURCE, installDependencies = true, agents = [], scope = 'project', home = homedir(), env = process.env } = {}) {
|
|
30
35
|
if (Number(process.versions.node.split('.')[0]) < 24) throw new Error('Node.js 24 or newer is required');
|
|
31
|
-
if (!['project', 'global'].includes(scope) || agents.some(a => !
|
|
36
|
+
if (!['project', 'global'].includes(scope) || agents.some(a => !AGENTS.some(p=>p.id===a))) throw new Error('Invalid installation scope or agents');
|
|
32
37
|
if (scope === 'global' && !agents.length) throw new Error('Global installation requires at least one agent');
|
|
33
38
|
const target = resolve(scope === 'global' ? home : destination);
|
|
34
39
|
source = resolve(source);
|
|
35
|
-
if (
|
|
40
|
+
if (pathInside(source, target)) throw new Error('Choose a destination outside the installer package');
|
|
36
41
|
const files = new Map();
|
|
37
42
|
if (scope === 'project') {
|
|
38
43
|
for (const root of roots) for (const path of collect(join(source, root))) files.set(relative(source, path), path);
|
|
@@ -43,7 +48,7 @@ export function install(destination, { source = SOURCE, installDependencies = tr
|
|
|
43
48
|
}
|
|
44
49
|
const destinations = [];
|
|
45
50
|
for (const agent of [...new Set(agents)]) {
|
|
46
|
-
const native =
|
|
51
|
+
const native = relative(target,skillDirectory(agent,{scope,home:resolve(home),cwd:scope==='project'?target:process.cwd(),env}));
|
|
47
52
|
destinations.push({agent, path: join(target, native)});
|
|
48
53
|
files.set(join(native, 'SKILL.md'), join(source, 'installer-assets/native-SKILL.md'));
|
|
49
54
|
const plugin = join(source, 'plugins/jobhunt-kit');
|
|
@@ -87,8 +92,13 @@ export function install(destination, { source = SOURCE, installDependencies = tr
|
|
|
87
92
|
return { directory: target, copied: pending.length, dependencies_installed: installDependencies, scope, agents: destinations };
|
|
88
93
|
}
|
|
89
94
|
export async function main(args) {
|
|
95
|
+
if (args[0] === 'agents') {
|
|
96
|
+
if (args.length!==1) throw new Error('Usage: jobhunt-kit agents');
|
|
97
|
+
console.log(AGENTS.map(a=>`${a.id.padEnd(14)} ${a.name}${a.globalOnly?' (global only)':''}`).join('\n'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
90
100
|
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
91
|
-
console.log('Usage: jobhunt-kit <command> [arguments] [--workspace dir | --data dir]\n\ninstall [directory] Choose agents and install (default: ./my-jobhunt)\n --agents codex,
|
|
101
|
+
console.log('Usage: jobhunt-kit <command> [arguments] [--workspace dir | --data dir]\n\ninstall [directory] Choose agents and install (default: ./my-jobhunt)\n --agents codex,cursor,... Select agents (or all); --providers is an alias\n agents List supported agents\n --scope project|global Workspace skills or user-wide skills\n --yes, -y Use detected agents and project scope\ninit <directory> Alias with an explicit destination\nprofile init|show|check Initialize/view/validate local profile\nprofile save --input file Save profile and clear confirmation\nprofile confirm --note text Record explicit candidate confirmation\nresume [file] Import file, fingerprint and mechanical checks\nresume check|reviewed Inspect file / record agent review (--input file)\nsearch [plan] Prepare context for agent; no live search\nsearch start|event|record|finish Persist search operations (--input file)\napply preview|export|begin slug Review/export/reserve application\napply prepare|approve|send|finish|resolve --input file\ntrack list|show slug|status slug --input file\nhistory | runs | report Inspect history or generate Markdown report\npolicy show|set --input file Inspect/set application policy\nschedule --input file Generate scheduler prompt; does not schedule\nbackup/backup-verify <directory> Create or verify a local backup\nrestore --input file Restore after exact typed confirmation\nrecover inspect|apply|packet Inspect, resolve, or recreate an attempt packet\nprivacy map|export|redact|purge Inspect, export or remove local PII\ndoctor Check schemas, database and recovery state without network\n\nNode.js 24+ required. Default data: ./local/jobhunt-kit. Only apply send performs a live application call.');
|
|
92
102
|
return;
|
|
93
103
|
}
|
|
94
104
|
if (!['init', 'install'].includes(args[0])) {
|
|
@@ -107,6 +117,7 @@ export async function main(args) {
|
|
|
107
117
|
const result = install(options.destination, options);
|
|
108
118
|
console.log(`\nJobhunt Kit ready: ${result.directory}\nCopied files: ${result.copied}`);
|
|
109
119
|
for (const agent of result.agents) console.log(`${agent.agent}: ${agent.path}`);
|
|
120
|
+
if (result.scope==='project' && result.agents.some(a=>a.agent==='hermes')) console.log('Hermes: run hermes skills trust from this workspace before using project skills.');
|
|
110
121
|
console.log(result.scope === 'global' ? 'Open your working folder in a new agent session.' : 'Open this folder in a new agent session.');
|
|
111
122
|
console.log('Ask: use jobhunt-kit to initialize my job search profile.\nNo profile, schedule, search or application was created.');
|
|
112
123
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jobhunt-kit-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "jobhunt-kit-plugin",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.5.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"ajv": "8.20.0",
|
|
11
12
|
"hirify-cli": "0.4.5",
|
|
12
13
|
"mammoth": "1.12.2",
|
|
13
14
|
"pdf-parse": "2.4.5"
|
|
@@ -224,6 +225,22 @@
|
|
|
224
225
|
"node": ">=10.0.0"
|
|
225
226
|
}
|
|
226
227
|
},
|
|
228
|
+
"node_modules/ajv": {
|
|
229
|
+
"version": "8.20.0",
|
|
230
|
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
|
231
|
+
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
|
232
|
+
"license": "MIT",
|
|
233
|
+
"dependencies": {
|
|
234
|
+
"fast-deep-equal": "^3.1.3",
|
|
235
|
+
"fast-uri": "^3.0.1",
|
|
236
|
+
"json-schema-traverse": "^1.0.0",
|
|
237
|
+
"require-from-string": "^2.0.2"
|
|
238
|
+
},
|
|
239
|
+
"funding": {
|
|
240
|
+
"type": "github",
|
|
241
|
+
"url": "https://github.com/sponsors/epoberezkin"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
227
244
|
"node_modules/argparse": {
|
|
228
245
|
"version": "1.0.10",
|
|
229
246
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
|
@@ -280,6 +297,28 @@
|
|
|
280
297
|
"underscore": "^1.13.1"
|
|
281
298
|
}
|
|
282
299
|
},
|
|
300
|
+
"node_modules/fast-deep-equal": {
|
|
301
|
+
"version": "3.1.3",
|
|
302
|
+
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
303
|
+
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
|
304
|
+
"license": "MIT"
|
|
305
|
+
},
|
|
306
|
+
"node_modules/fast-uri": {
|
|
307
|
+
"version": "3.1.7",
|
|
308
|
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz",
|
|
309
|
+
"integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==",
|
|
310
|
+
"funding": [
|
|
311
|
+
{
|
|
312
|
+
"type": "github",
|
|
313
|
+
"url": "https://github.com/sponsors/fastify"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"type": "opencollective",
|
|
317
|
+
"url": "https://opencollective.com/fastify"
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
"license": "BSD-3-Clause"
|
|
321
|
+
},
|
|
283
322
|
"node_modules/hirify-cli": {
|
|
284
323
|
"version": "0.4.5",
|
|
285
324
|
"resolved": "https://registry.npmjs.org/hirify-cli/-/hirify-cli-0.4.5.tgz",
|
|
@@ -310,6 +349,12 @@
|
|
|
310
349
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
|
311
350
|
"license": "MIT"
|
|
312
351
|
},
|
|
352
|
+
"node_modules/json-schema-traverse": {
|
|
353
|
+
"version": "1.0.0",
|
|
354
|
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
|
355
|
+
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
|
356
|
+
"license": "MIT"
|
|
357
|
+
},
|
|
313
358
|
"node_modules/jszip": {
|
|
314
359
|
"version": "3.10.1",
|
|
315
360
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
|
@@ -440,6 +485,15 @@
|
|
|
440
485
|
"util-deprecate": "~1.0.1"
|
|
441
486
|
}
|
|
442
487
|
},
|
|
488
|
+
"node_modules/require-from-string": {
|
|
489
|
+
"version": "2.0.2",
|
|
490
|
+
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
|
491
|
+
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
|
492
|
+
"license": "MIT",
|
|
493
|
+
"engines": {
|
|
494
|
+
"node": ">=0.10.0"
|
|
495
|
+
}
|
|
496
|
+
},
|
|
443
497
|
"node_modules/safe-buffer": {
|
|
444
498
|
"version": "5.1.2",
|
|
445
499
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jobhunt-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "jobhunt-kit",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.5.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"ajv": "8.20.0",
|
|
11
12
|
"hirify-cli": "0.4.5",
|
|
12
13
|
"mammoth": "1.12.2",
|
|
13
14
|
"pdf-parse": "2.4.5"
|
|
@@ -227,6 +228,22 @@
|
|
|
227
228
|
"node": ">=10.0.0"
|
|
228
229
|
}
|
|
229
230
|
},
|
|
231
|
+
"node_modules/ajv": {
|
|
232
|
+
"version": "8.20.0",
|
|
233
|
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
|
234
|
+
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
|
235
|
+
"license": "MIT",
|
|
236
|
+
"dependencies": {
|
|
237
|
+
"fast-deep-equal": "^3.1.3",
|
|
238
|
+
"fast-uri": "^3.0.1",
|
|
239
|
+
"json-schema-traverse": "^1.0.0",
|
|
240
|
+
"require-from-string": "^2.0.2"
|
|
241
|
+
},
|
|
242
|
+
"funding": {
|
|
243
|
+
"type": "github",
|
|
244
|
+
"url": "https://github.com/sponsors/epoberezkin"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
230
247
|
"node_modules/argparse": {
|
|
231
248
|
"version": "1.0.10",
|
|
232
249
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
|
@@ -283,6 +300,28 @@
|
|
|
283
300
|
"underscore": "^1.13.1"
|
|
284
301
|
}
|
|
285
302
|
},
|
|
303
|
+
"node_modules/fast-deep-equal": {
|
|
304
|
+
"version": "3.1.3",
|
|
305
|
+
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
|
306
|
+
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
|
307
|
+
"license": "MIT"
|
|
308
|
+
},
|
|
309
|
+
"node_modules/fast-uri": {
|
|
310
|
+
"version": "3.1.7",
|
|
311
|
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz",
|
|
312
|
+
"integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==",
|
|
313
|
+
"funding": [
|
|
314
|
+
{
|
|
315
|
+
"type": "github",
|
|
316
|
+
"url": "https://github.com/sponsors/fastify"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"type": "opencollective",
|
|
320
|
+
"url": "https://opencollective.com/fastify"
|
|
321
|
+
}
|
|
322
|
+
],
|
|
323
|
+
"license": "BSD-3-Clause"
|
|
324
|
+
},
|
|
286
325
|
"node_modules/hirify-cli": {
|
|
287
326
|
"version": "0.4.5",
|
|
288
327
|
"resolved": "https://registry.npmjs.org/hirify-cli/-/hirify-cli-0.4.5.tgz",
|
|
@@ -313,6 +352,12 @@
|
|
|
313
352
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
|
314
353
|
"license": "MIT"
|
|
315
354
|
},
|
|
355
|
+
"node_modules/json-schema-traverse": {
|
|
356
|
+
"version": "1.0.0",
|
|
357
|
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
|
358
|
+
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
|
359
|
+
"license": "MIT"
|
|
360
|
+
},
|
|
316
361
|
"node_modules/jszip": {
|
|
317
362
|
"version": "3.10.1",
|
|
318
363
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
|
|
@@ -443,6 +488,15 @@
|
|
|
443
488
|
"util-deprecate": "~1.0.1"
|
|
444
489
|
}
|
|
445
490
|
},
|
|
491
|
+
"node_modules/require-from-string": {
|
|
492
|
+
"version": "2.0.2",
|
|
493
|
+
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
|
494
|
+
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
|
495
|
+
"license": "MIT",
|
|
496
|
+
"engines": {
|
|
497
|
+
"node": ">=0.10.0"
|
|
498
|
+
}
|
|
499
|
+
},
|
|
446
500
|
"node_modules/safe-buffer": {
|
|
447
501
|
"version": "5.1.2",
|
|
448
502
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jobhunt-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"bin": {
|
|
5
5
|
"jobhunt-kit": "bin/jobhunt-kit.mjs"
|
|
6
6
|
},
|
|
@@ -19,12 +19,14 @@
|
|
|
19
19
|
"hirify": "hirify",
|
|
20
20
|
"test": "node --test tests/*.test.mjs",
|
|
21
21
|
"check": "node scripts/check-package.mjs",
|
|
22
|
+
"pack:smoke": "node scripts/pack-smoke.mjs",
|
|
22
23
|
"prepublishOnly": "npm test && npm run check"
|
|
23
24
|
},
|
|
24
25
|
"engines": {
|
|
25
26
|
"node": ">=24.0.0"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
29
|
+
"ajv": "8.20.0",
|
|
28
30
|
"hirify-cli": "0.4.5",
|
|
29
31
|
"mammoth": "1.12.2",
|
|
30
32
|
"pdf-parse": "2.4.5"
|