hunter-mate 0.1.3 → 0.1.4
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/dist/assets/extension/background/service-worker.js +113 -24
- package/dist/assets/extension/content/index.js +239 -134
- package/dist/assets/extension/manifest.json +2 -4
- package/dist/assets/extension/sidepanel/index.js +76 -2
- package/dist/assets/server/app.module.js +4 -2
- package/dist/assets/server/app.module.js.map +1 -1
- package/dist/assets/server/build-info.json +1 -1
- package/dist/assets/server/db/sqlite.module.js +4 -0
- package/dist/assets/server/db/sqlite.module.js.map +1 -1
- package/dist/assets/server/devops/devops-sink-init.d.ts +14 -1
- package/dist/assets/server/devops/devops-sink-init.js +8 -3
- package/dist/assets/server/devops/devops-sink-init.js.map +1 -1
- package/dist/assets/server/doctor/doctor.controller.d.ts +13 -0
- package/dist/assets/server/doctor/doctor.controller.js +62 -0
- package/dist/assets/server/doctor/doctor.controller.js.map +1 -0
- package/dist/assets/server/doctor/doctor.module.d.ts +2 -0
- package/dist/assets/server/doctor/doctor.module.js +27 -0
- package/dist/assets/server/doctor/doctor.module.js.map +1 -0
- package/dist/assets/server/doctor/doctor.service.d.ts +15 -0
- package/dist/assets/server/doctor/doctor.service.js +209 -0
- package/dist/assets/server/doctor/doctor.service.js.map +1 -0
- package/dist/assets/server/doctor/doctor.types.d.ts +46 -0
- package/dist/assets/server/doctor/doctor.types.js +3 -0
- package/dist/assets/server/doctor/doctor.types.js.map +1 -0
- package/dist/assets/server/extraction/adapter.service.d.ts +18 -4
- package/dist/assets/server/extraction/adapter.service.js +129 -15
- package/dist/assets/server/extraction/adapter.service.js.map +1 -1
- package/dist/assets/server/extraction/anomaly-report.service.d.ts +12 -0
- package/dist/assets/server/extraction/anomaly-report.service.js +81 -0
- package/dist/assets/server/extraction/anomaly-report.service.js.map +1 -0
- package/dist/assets/server/extraction/entities/adapter-rule.entity.d.ts +13 -0
- package/dist/assets/server/extraction/entities/adapter-rule.entity.js +71 -0
- package/dist/assets/server/extraction/entities/adapter-rule.entity.js.map +1 -0
- package/dist/assets/server/extraction/entities/parse-log.entity.d.ts +4 -1
- package/dist/assets/server/extraction/entities/parse-log.entity.js +15 -0
- package/dist/assets/server/extraction/entities/parse-log.entity.js.map +1 -1
- package/dist/assets/server/extraction/extraction-entity.controller.d.ts +40 -2
- package/dist/assets/server/extraction/extraction-entity.controller.js +196 -13
- package/dist/assets/server/extraction/extraction-entity.controller.js.map +1 -1
- package/dist/assets/server/extraction/extraction-rule.service.js +16 -8
- package/dist/assets/server/extraction/extraction-rule.service.js.map +1 -1
- package/dist/assets/server/extraction/extraction.module.js +12 -2
- package/dist/assets/server/extraction/extraction.module.js.map +1 -1
- package/dist/assets/server/extraction/extraction.service.d.ts +17 -1
- package/dist/assets/server/extraction/extraction.service.js +125 -42
- package/dist/assets/server/extraction/extraction.service.js.map +1 -1
- package/dist/assets/server/extraction/linkedin-extractor.d.ts +1 -0
- package/dist/assets/server/extraction/linkedin-extractor.js +244 -0
- package/dist/assets/server/extraction/linkedin-extractor.js.map +1 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.d.ts +15 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.js +48 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.js.map +1 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.spec.d.ts +1 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.spec.js +60 -0
- package/dist/assets/server/extraction/rrweb-snapshot.utils.spec.js.map +1 -0
- package/dist/assets/server/extraction/script-rule.d.ts +1 -0
- package/dist/assets/server/extraction/script-rule.js +4 -0
- package/dist/assets/server/extraction/script-rule.js.map +1 -1
- package/dist/assets/server/extraction/snapshot-analysis.service.d.ts +23 -0
- package/dist/assets/server/extraction/snapshot-analysis.service.js +147 -0
- package/dist/assets/server/extraction/snapshot-analysis.service.js.map +1 -0
- package/dist/assets/server/recording/entities/recording-snapshot.entity.d.ts +16 -0
- package/dist/assets/server/recording/entities/recording-snapshot.entity.js +91 -0
- package/dist/assets/server/recording/entities/recording-snapshot.entity.js.map +1 -0
- package/dist/assets/server/recording/recording-event-bus.service.d.ts +4 -0
- package/dist/assets/server/recording/recording-event-bus.service.js +25 -0
- package/dist/assets/server/recording/recording-event-bus.service.js.map +1 -0
- package/dist/assets/server/recording/recording-snapshot.service.d.ts +13 -0
- package/dist/assets/server/recording/recording-snapshot.service.js +81 -0
- package/dist/assets/server/recording/recording-snapshot.service.js.map +1 -0
- package/dist/assets/server/recording/recording-snapshot.service.spec.d.ts +1 -0
- package/dist/assets/server/recording/recording-snapshot.service.spec.js +65 -0
- package/dist/assets/server/recording/recording-snapshot.service.spec.js.map +1 -0
- package/dist/assets/server/recording/recording.controller.d.ts +3 -1
- package/dist/assets/server/recording/recording.controller.js +7 -3
- package/dist/assets/server/recording/recording.controller.js.map +1 -1
- package/dist/assets/server/recording/recording.module.js +11 -4
- package/dist/assets/server/recording/recording.module.js.map +1 -1
- package/dist/assets/server/recording/recording.service.d.ts +5 -21
- package/dist/assets/server/recording/recording.service.js +22 -9
- package/dist/assets/server/recording/recording.service.js.map +1 -1
- package/dist/assets/server/site/entities/site-registry.entity.d.ts +2 -0
- package/dist/assets/server/site/entities/site-registry.entity.js +10 -0
- package/dist/assets/server/site/entities/site-registry.entity.js.map +1 -1
- package/dist/assets/server/site/site.controller.d.ts +2 -0
- package/dist/assets/server/site/site.controller.js +1 -1
- package/dist/assets/server/site/site.controller.js.map +1 -1
- package/dist/assets/server/site/site.service.d.ts +2 -1
- package/dist/assets/server/site/site.service.js +10 -3
- package/dist/assets/server/site/site.service.js.map +1 -1
- package/dist/auto-doctor.d.ts +8 -0
- package/dist/auto-doctor.js +34 -0
- package/dist/commands/doctor.d.ts +38 -0
- package/dist/commands/doctor.js +162 -7
- package/dist/commands/extension.js +2 -2
- package/dist/commands/extras.d.ts +1 -1
- package/dist/commands/extras.js +4 -3
- package/dist/commands/install.js +11 -8
- package/dist/index.js +7 -0
- package/package.json +3 -3
package/dist/commands/doctor.js
CHANGED
|
@@ -9,6 +9,7 @@ import { runInstall } from './install.js';
|
|
|
9
9
|
import { runExtensionCheck } from './extension.js';
|
|
10
10
|
import { checkNativeModules } from '../native-check.js';
|
|
11
11
|
import { getCliLogger } from '../logger.js';
|
|
12
|
+
import { getToken } from '../keychain.js';
|
|
12
13
|
const B = {
|
|
13
14
|
reset: '\x1b[0m',
|
|
14
15
|
bold: '\x1b[1m',
|
|
@@ -18,6 +19,32 @@ const B = {
|
|
|
18
19
|
cyan: '\x1b[36m',
|
|
19
20
|
magenta: '\x1b[35m',
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* 调用 server /doctor/run 统一入口。
|
|
24
|
+
* 失败时返回 null,调用方决定如何处理。
|
|
25
|
+
*/
|
|
26
|
+
export async function runDoctorChecks(opts) {
|
|
27
|
+
const config = loadConfig();
|
|
28
|
+
const token = await getToken().catch(() => undefined);
|
|
29
|
+
const checks = opts.checks && opts.checks.length ? opts.checks : undefined;
|
|
30
|
+
const timeout = opts.timeout ?? 60_000;
|
|
31
|
+
try {
|
|
32
|
+
const { data } = await axios.post(`${config.serverUrl}/doctor/run`, {
|
|
33
|
+
checks,
|
|
34
|
+
mode: opts.fix ? 'repair' : 'check',
|
|
35
|
+
dryRun: opts.dryRun === true,
|
|
36
|
+
}, {
|
|
37
|
+
timeout,
|
|
38
|
+
headers: token ? { Authorization: `UTOKEN ${token}` } : {},
|
|
39
|
+
});
|
|
40
|
+
return data;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
const message = e?.response?.data?.message || e.message || String(e);
|
|
44
|
+
getCliLogger().warn('doctor:checks:failed', { error: message, fix: opts.fix, checks });
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
21
48
|
/** 对应 ChromePilot doctor: 全链路健康检查 — 带 auto-heal, 无感启动 server/安装扩展 */
|
|
22
49
|
export async function runDoctor(opts) {
|
|
23
50
|
const checks = [];
|
|
@@ -25,7 +52,7 @@ export async function runDoctor(opts) {
|
|
|
25
52
|
const healed = [];
|
|
26
53
|
const actions = [];
|
|
27
54
|
const autoHeal = opts.autoHeal !== false; // default true
|
|
28
|
-
const
|
|
55
|
+
const fix = opts.fix === true;
|
|
29
56
|
// ── Banner (human 模式) ──
|
|
30
57
|
if (!opts.json) {
|
|
31
58
|
console.log(`\n${B.bold}${B.cyan}╭─────────────────────────────────────────────╮${B.reset}`);
|
|
@@ -184,7 +211,7 @@ export async function runDoctor(opts) {
|
|
|
184
211
|
if (!opts.json) {
|
|
185
212
|
console.log(`${B.magenta}→ hunter-mate 正在为你打开扩展所在目录...${B.reset}`);
|
|
186
213
|
}
|
|
187
|
-
open(initResult.extensionDir).catch(() => { });
|
|
214
|
+
open(path.dirname(initResult.extensionDir)).catch(() => { });
|
|
188
215
|
healed.push('open_ext_dir');
|
|
189
216
|
}
|
|
190
217
|
if (!opts.json) {
|
|
@@ -211,6 +238,35 @@ export async function runDoctor(opts) {
|
|
|
211
238
|
catch (e) {
|
|
212
239
|
checks.push({ key: 'auth', status: 'skip', detail: `跳过(keychain 读取失败): ${e.message}` });
|
|
213
240
|
}
|
|
241
|
+
// ── 6) 数据面 doctor checks ──
|
|
242
|
+
let data = null;
|
|
243
|
+
if (serverUp) {
|
|
244
|
+
if (!opts.json) {
|
|
245
|
+
console.log(`\n${B.bold}${B.cyan}→ 正在运行数据面检查${fix ? ' (repair 模式)' : ' (只读 check 模式)'}...${B.reset}`);
|
|
246
|
+
}
|
|
247
|
+
data = await runDoctorChecks({
|
|
248
|
+
fix,
|
|
249
|
+
checks: opts.checks,
|
|
250
|
+
json: opts.json,
|
|
251
|
+
timeout: 120_000,
|
|
252
|
+
});
|
|
253
|
+
if (data) {
|
|
254
|
+
for (const c of data.checks) {
|
|
255
|
+
const status = c.ok ? 'ok' : c.severity === 'error' ? 'fail' : 'warn';
|
|
256
|
+
checks.push({
|
|
257
|
+
key: `data_${c.id}`,
|
|
258
|
+
status,
|
|
259
|
+
detail: c.message || c.description,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
checks.push({ key: 'data_doctor', status: 'warn', detail: '无法连接 /doctor/run (server 可能尚未就绪)' });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
checks.push({ key: 'data_doctor', status: 'skip', detail: 'server 未运行,跳过数据面检查' });
|
|
269
|
+
}
|
|
214
270
|
// ── Summary ──
|
|
215
271
|
const anyFail = checks.some((c) => c.status === 'fail');
|
|
216
272
|
const anyWarn = checks.some((c) => c.status === 'warn');
|
|
@@ -247,7 +303,7 @@ export async function runDoctor(opts) {
|
|
|
247
303
|
console.log(`\n${B.bold}${B.red}✗ 环境未就绪, 请按上方引导完成修复后重试。${B.reset}\n`);
|
|
248
304
|
}
|
|
249
305
|
}
|
|
250
|
-
return { summary, checks, hints, healed, actions };
|
|
306
|
+
return { summary, checks, hints, healed, actions, data };
|
|
251
307
|
}
|
|
252
308
|
/** 友好中文引导 — 当环境不完备时给用户清晰的操作步骤 */
|
|
253
309
|
function showFriendlyGuide(extInstalled, extConnected, serverUp, healed, extDir) {
|
|
@@ -261,21 +317,24 @@ function showFriendlyGuide(extInstalled, extConnected, serverUp, healed, extDir)
|
|
|
261
317
|
console.log(` hunter-mate 已尝试自动启动。若持续失败请手动执行:`);
|
|
262
318
|
console.log(` ${B.bold}hunter-mate start -f${B.reset} (前台模式可看日志)\n`);
|
|
263
319
|
}
|
|
320
|
+
const extParentDir = path.dirname(extDir);
|
|
321
|
+
const extFolderName = path.basename(extDir);
|
|
264
322
|
if (!extInstalled) {
|
|
265
323
|
console.log(`${B.bold}${B.yellow}⚠ Hunter Mate Chrome 扩展尚未安装${B.reset}`);
|
|
266
324
|
console.log(` 步骤: hunter-mate 已自动把扩展文件复制到:`);
|
|
267
325
|
console.log(` ${B.cyan}${extDir}${B.reset}`);
|
|
326
|
+
console.log(` 并已打开扩展所在目录: ${B.cyan}${extParentDir}${B.reset}`);
|
|
268
327
|
console.log(` ${B.bold}接下来需要你手动在 Chrome 中加载(Chrome 安全策略限制命令行自动化):${B.reset}`);
|
|
269
328
|
console.log(` ${B.magenta}① 在 Chrome 地址栏输入:${B.reset} chrome://extensions`);
|
|
270
329
|
console.log(` ${B.magenta}② 打开右上角「开发者模式」开关${B.reset}`);
|
|
271
|
-
console.log(` ${B.magenta}③
|
|
272
|
-
console.log(`
|
|
273
|
-
console.log(` ${B.magenta}
|
|
330
|
+
console.log(` ${B.magenta}③ 把 ${B.bold}${extFolderName}${B.reset} 文件夹拖到 chrome://extensions 页面里${B.reset}`);
|
|
331
|
+
console.log(` (也可以点击「加载已解压的扩展程序」后选择 ${B.cyan}${extDir}${B.reset})`);
|
|
332
|
+
console.log(` ${B.magenta}④ Chrome 工具栏应出现 Hunter Mate 图标,侧栏显示「已连接」${B.reset}\n`);
|
|
274
333
|
}
|
|
275
334
|
if (extInstalled && !extConnected) {
|
|
276
335
|
console.log(`${B.bold}${B.yellow}⚠ 扩展已安装但尚未连接到 Server${B.reset}`);
|
|
277
336
|
console.log(` hunter-mate 已自动帮你打开了:`);
|
|
278
|
-
console.log(` · 扩展所在目录: ${B.cyan}${
|
|
337
|
+
console.log(` · 扩展所在目录: ${B.cyan}${extParentDir}${B.reset}`);
|
|
279
338
|
console.log(` · Chrome 扩展管理页: ${B.cyan}chrome://extensions${B.reset}`);
|
|
280
339
|
console.log(` ${B.bold}请确认以下几点:${B.reset}`);
|
|
281
340
|
console.log(` ${B.magenta}① 扩展已在 chrome://extensions 中「已开启」${B.reset} (灰色开关变蓝色)`);
|
|
@@ -304,14 +363,110 @@ export const doctorCommand = new Command('doctor')
|
|
|
304
363
|
.option('--json', '仅以 JSON 输出检查结果与建议(跳过引导文案)')
|
|
305
364
|
.option('--no-auto-heal', '禁用自动修复(仅检查并给出建议, 不自动启动/安装)')
|
|
306
365
|
.option('--no-interactive', '无交互模式(不打印友好引导, 仅输出结构化结果)')
|
|
366
|
+
.option('--fix', '执行可修复的数据检查(默认只读 check)')
|
|
367
|
+
.option('--checks <ids>', '只跑指定检查,逗号分隔(如 linkedin-dupes)', (val) => val.split(',').map((s) => s.trim()).filter(Boolean))
|
|
368
|
+
.option('--list', '列出 server 上注册的数据检查项')
|
|
307
369
|
.action(async (opts) => {
|
|
370
|
+
if (opts.list) {
|
|
371
|
+
const config = loadConfig();
|
|
372
|
+
try {
|
|
373
|
+
const { data } = await axios.get(`${config.serverUrl}/doctor/checks`, { timeout: 10_000 });
|
|
374
|
+
if (opts.json) {
|
|
375
|
+
console.log(JSON.stringify(data, null, 2));
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
console.log(`\n${B.bold}${B.cyan}已注册 Doctor 检查项:${B.reset}`);
|
|
379
|
+
for (const c of data) {
|
|
380
|
+
const fixTag = c.fixable ? `${B.green}[可修复]${B.reset}` : `${B.yellow}[只读]${B.reset}`;
|
|
381
|
+
console.log(` ${fixTag} ${B.bold}${c.id}${B.reset} (${c.severity})`);
|
|
382
|
+
console.log(` ${c.name}`);
|
|
383
|
+
console.log(` ${c.description}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
process.exit(0);
|
|
387
|
+
}
|
|
388
|
+
catch (e) {
|
|
389
|
+
const message = e?.response?.data?.message || e.message || String(e);
|
|
390
|
+
getCliLogger().error('doctor:list failed', { message });
|
|
391
|
+
if (opts.json) {
|
|
392
|
+
console.log(JSON.stringify({ error: message }, null, 2));
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
console.log(`${B.red}获取检查列表失败:${B.reset} ${message}`);
|
|
396
|
+
}
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
308
401
|
const r = await runDoctor({
|
|
309
402
|
json: opts.json,
|
|
310
403
|
autoHeal: opts.autoHeal !== false,
|
|
311
404
|
interactive: opts.interactive !== false,
|
|
405
|
+
fix: opts.fix === true,
|
|
406
|
+
checks: opts.checks,
|
|
312
407
|
});
|
|
313
408
|
if (opts.json) {
|
|
314
409
|
console.log(JSON.stringify(r, null, 2));
|
|
315
410
|
}
|
|
316
411
|
process.exit(r.summary === 'fail' ? 1 : 0);
|
|
317
412
|
});
|
|
413
|
+
export const repairLinkedInDupesCommand = new Command('repair-linkedin-dupes')
|
|
414
|
+
.description('修复 LinkedIn /in/<slug>/details/... 子页产生的重复 talent 数据')
|
|
415
|
+
.option('--dry-run', '仅预览,不真正合并/删除')
|
|
416
|
+
.option('--json', '仅输出 JSON 结果')
|
|
417
|
+
.action(async (opts) => {
|
|
418
|
+
const data = await runDoctorChecks({
|
|
419
|
+
fix: true,
|
|
420
|
+
checks: ['linkedin-dupes'],
|
|
421
|
+
dryRun: opts.dryRun === true,
|
|
422
|
+
json: opts.json,
|
|
423
|
+
timeout: 120_000,
|
|
424
|
+
});
|
|
425
|
+
if (!data) {
|
|
426
|
+
const message = '无法连接 server /doctor/run, 请确认 server 已启动';
|
|
427
|
+
getCliLogger().error('repair-linkedin-dupes failed', { message });
|
|
428
|
+
if (opts.json) {
|
|
429
|
+
console.log(JSON.stringify({ error: message }, null, 2));
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
console.log(`修复失败: ${message}`);
|
|
433
|
+
}
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
436
|
+
const c = data.checks.find((x) => x.id === 'linkedin-dupes');
|
|
437
|
+
const details = c?.details || {};
|
|
438
|
+
const compat = {
|
|
439
|
+
dryRun: data.dryRun,
|
|
440
|
+
totalCandidates: details.totalCandidates ?? 0,
|
|
441
|
+
duplicateGroups: details.duplicateGroups ?? 0,
|
|
442
|
+
repairedCount: data.repaired?.length ?? 0,
|
|
443
|
+
merged: data.repaired ?? [],
|
|
444
|
+
summary: data.summary,
|
|
445
|
+
};
|
|
446
|
+
if (opts.json) {
|
|
447
|
+
console.log(JSON.stringify({ ...compat, raw: data }, null, 2));
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
const B = {
|
|
451
|
+
reset: '\x1b[0m',
|
|
452
|
+
bold: '\x1b[1m',
|
|
453
|
+
green: '\x1b[32m',
|
|
454
|
+
yellow: '\x1b[33m',
|
|
455
|
+
cyan: '\x1b[36m',
|
|
456
|
+
};
|
|
457
|
+
console.log(`\n${B.bold}${B.cyan}LinkedIn 重复 talent 修复结果${B.reset}`);
|
|
458
|
+
console.log(` 模式: ${data.dryRun ? B.yellow + 'dry-run' + B.reset : B.green + '正式修复' + B.reset}`);
|
|
459
|
+
console.log(` LinkedIn talent 总数: ${compat.totalCandidates}`);
|
|
460
|
+
console.log(` 归一组数: ${compat.duplicateGroups}`);
|
|
461
|
+
console.log(` 需合并组数: ${compat.repairedCount}`);
|
|
462
|
+
if (compat.merged.length) {
|
|
463
|
+
console.log(`\n${B.bold}合并详情:${B.reset}`);
|
|
464
|
+
for (const m of compat.merged) {
|
|
465
|
+
console.log(` • master #${m.masterId} ← ${m.removedIds.map((id) => `#${id}`).join(', ')}`);
|
|
466
|
+
console.log(` ${m.sourceUrl}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
process.exit(0);
|
|
471
|
+
});
|
|
472
|
+
doctorCommand.addCommand(repairLinkedInDupesCommand);
|
|
@@ -151,10 +151,10 @@ export function ensureEnvReady() {
|
|
|
151
151
|
process.exit(1);
|
|
152
152
|
}
|
|
153
153
|
console.log(`${B.green}✓ 扩展已自动安装到 ${r.target}${B.reset}`);
|
|
154
|
-
//
|
|
154
|
+
// 打开扩展所在目录(父目录),方便用户把 extension 文件夹拖到 chrome://extensions
|
|
155
155
|
try {
|
|
156
156
|
const { default: open } = await import('open');
|
|
157
|
-
open(init.extensionDir).catch(() => { });
|
|
157
|
+
open(path.dirname(init.extensionDir)).catch(() => { });
|
|
158
158
|
}
|
|
159
159
|
catch { }
|
|
160
160
|
showInstallGuide(init.extensionDir);
|
|
@@ -12,7 +12,7 @@ export declare function runReload(timeoutMs?: number): Promise<{
|
|
|
12
12
|
error: string;
|
|
13
13
|
}>;
|
|
14
14
|
}>;
|
|
15
|
-
/** 对应 ChromePilot open-ext / open-extension-folder:
|
|
15
|
+
/** 对应 ChromePilot open-ext / open-extension-folder: 打开扩展所在目录(~/.hunter-mate),方便拖到 chrome://extensions */
|
|
16
16
|
export declare function runOpenExt(target?: string): Promise<string>;
|
|
17
17
|
export declare const reloadCommand: Command;
|
|
18
18
|
export declare const openExtCommand: Command;
|
package/dist/commands/extras.js
CHANGED
|
@@ -102,10 +102,11 @@ export async function runReload(timeoutMs = 5000) {
|
|
|
102
102
|
});
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
|
-
/** 对应 ChromePilot open-ext / open-extension-folder:
|
|
105
|
+
/** 对应 ChromePilot open-ext / open-extension-folder: 打开扩展所在目录(~/.hunter-mate),方便拖到 chrome://extensions */
|
|
106
106
|
export async function runOpenExt(target) {
|
|
107
107
|
const init = runInit();
|
|
108
|
-
|
|
108
|
+
// 默认打开父目录,让用户能把 extension 文件夹拖进 Chrome;--target 可覆盖
|
|
109
|
+
const dir = target ?? path.dirname(init.extensionDir);
|
|
109
110
|
if (!fs.existsSync(dir))
|
|
110
111
|
fs.mkdirSync(dir, { recursive: true });
|
|
111
112
|
try {
|
|
@@ -133,7 +134,7 @@ export const reloadCommand = new Command('reload')
|
|
|
133
134
|
});
|
|
134
135
|
export const openExtCommand = new Command('open-extension-folder')
|
|
135
136
|
.alias('open-ext')
|
|
136
|
-
.description('
|
|
137
|
+
.description('打开扩展所在目录(~/.hunter-mate),方便把 extension 文件夹拖到 chrome://extensions 加载(对应 chromepilot open-ext)')
|
|
137
138
|
.option('-t, --target <dir>', '指定自定义扩展目录')
|
|
138
139
|
.action(async (opts) => {
|
|
139
140
|
const dir = await runOpenExt(opts.target);
|
package/dist/commands/install.js
CHANGED
|
@@ -52,16 +52,19 @@ const B = {
|
|
|
52
52
|
};
|
|
53
53
|
/** 友好引导: 告诉用户如何在 Chrome 中加载 Hunter Mate 扩展 */
|
|
54
54
|
export function showInstallGuide(extDir) {
|
|
55
|
+
const parentDir = path.dirname(extDir);
|
|
56
|
+
const folderName = path.basename(extDir);
|
|
55
57
|
console.log(`\n${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━ Hunter Mate 扩展安装指引 ━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}`);
|
|
56
58
|
console.log(`\n${B.bold}扩展文件已经准备好:${B.reset}`);
|
|
57
|
-
console.log(` ${B.cyan}${extDir}${B.reset}`);
|
|
58
|
-
console.log(
|
|
59
|
+
console.log(` 扩展文件夹: ${B.cyan}${extDir}${B.reset}`);
|
|
60
|
+
console.log(` 已为你打开: ${B.cyan}${parentDir}${B.reset}`);
|
|
61
|
+
console.log(`\n${B.bold}请按以下 4 步在 Chrome 中加载(约 30 秒):${B.reset}\n`);
|
|
59
62
|
console.log(` ${B.magenta}①${B.reset} 打开 Chrome, 地址栏输入: ${B.cyan}chrome://extensions${B.reset}`);
|
|
60
63
|
console.log(` (hunter-mate 已帮你自动打开了这个页面)`);
|
|
61
64
|
console.log(` ${B.magenta}②${B.reset} 右上角打开「${B.bold}开发者模式${B.reset}」开关`);
|
|
62
|
-
console.log(` ${B.magenta}③${B.reset}
|
|
63
|
-
console.log(`
|
|
64
|
-
console.log(` ${B.magenta}
|
|
65
|
+
console.log(` ${B.magenta}③${B.reset} 把文件夹 ${B.bold}${folderName}${B.reset} 拖到 chrome://extensions 页面里`);
|
|
66
|
+
console.log(` (也可以点击「加载已解压的扩展程序」后选择 ${B.cyan}${extDir}${B.reset})`);
|
|
67
|
+
console.log(` ${B.magenta}④${B.reset} Chrome 工具栏应出现 Hunter Mate 🤝 图标,侧栏显示「已连接」\n`);
|
|
65
68
|
console.log(`${B.bold}${B.yellow}常见问题:${B.reset}`);
|
|
66
69
|
console.log(` · 没看到「加载已解压的扩展程序」? → 先开启「开发者模式」开关`);
|
|
67
70
|
console.log(` · 加载后图标灰显? → 点击图标确认侧栏显示「已连接」`);
|
|
@@ -69,7 +72,7 @@ export function showInstallGuide(extDir) {
|
|
|
69
72
|
console.log(`\n${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}\n`);
|
|
70
73
|
}
|
|
71
74
|
export const installCommand = new Command('install')
|
|
72
|
-
.description('把内置 extension dist 复制到 ~/.hunter-mate/extension(对应 chromepilot install
|
|
75
|
+
.description('把内置 extension dist 复制到 ~/.hunter-mate/extension(对应 chromepilot install)。完成后自动打开扩展所在目录(~/.hunter-mate)并给出中文引导,方便把 extension 文件夹拖到 chrome://extensions。')
|
|
73
76
|
.option('-t, --target <dir>', '目标目录,默认 ~/.hunter-mate/extension')
|
|
74
77
|
.option('--no-open', '不自动打开扩展所在目录')
|
|
75
78
|
.action(async (opts) => {
|
|
@@ -82,11 +85,11 @@ export const installCommand = new Command('install')
|
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
87
|
console.log(`${B.green}✓ hunter-mate install OK: ${r.copied} files${B.reset} → ${B.cyan}${r.target}${B.reset}`);
|
|
85
|
-
//
|
|
88
|
+
// 自动打开扩展所在目录(父目录),方便用户把 extension 文件夹拖到 chrome://extensions
|
|
86
89
|
if (opts.open !== false) {
|
|
87
90
|
try {
|
|
88
91
|
const { default: open } = await import('open');
|
|
89
|
-
open(r.target).catch(() => { });
|
|
92
|
+
open(path.dirname(r.target)).catch(() => { });
|
|
90
93
|
}
|
|
91
94
|
catch { }
|
|
92
95
|
}
|
package/dist/index.js
CHANGED
|
@@ -76,6 +76,13 @@ program
|
|
|
76
76
|
for (const line of report.performed)
|
|
77
77
|
console.log(chalk.gray(` [auto-update] ${line}`));
|
|
78
78
|
}
|
|
79
|
+
try {
|
|
80
|
+
const { runAutoDoctor } = await import('./auto-doctor.js');
|
|
81
|
+
await runAutoDoctor(report);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* auto-doctor 永不阻塞主命令 */
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
87
|
catch {
|
|
81
88
|
/* 一致性检测永不阻塞主命令 */
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hunter-mate",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "HiredChina 猎头 Agent 数据助手 CLI:人才库/客户/职位数据访问,浏览器录制解析简历,server/扩展一致性自愈",
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+github.com:hiredchina-com/hunter-mate.git"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"open": "^8.4.0",
|
|
32
32
|
"uuid": "^9.0.0",
|
|
33
33
|
"ws": "^8.21.3",
|
|
34
|
-
"@hunter-mate/shared": "0.1.
|
|
34
|
+
"@hunter-mate/shared": "0.1.3"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/better-sqlite3": "^7.6.0",
|