hunter-mate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/cache/db.d.ts +7 -0
  2. package/dist/cache/db.js +105 -0
  3. package/dist/commands/addons.d.ts +4 -0
  4. package/dist/commands/addons.js +378 -0
  5. package/dist/commands/cache.d.ts +8 -0
  6. package/dist/commands/cache.js +58 -0
  7. package/dist/commands/config.d.ts +12 -0
  8. package/dist/commands/config.js +27 -0
  9. package/dist/commands/doctor.d.ts +21 -0
  10. package/dist/commands/doctor.js +332 -0
  11. package/dist/commands/extension.d.ts +5 -0
  12. package/dist/commands/extension.js +438 -0
  13. package/dist/commands/extras.d.ts +10 -0
  14. package/dist/commands/extras.js +111 -0
  15. package/dist/commands/init.d.ts +10 -0
  16. package/dist/commands/init.js +87 -0
  17. package/dist/commands/install.d.ts +9 -0
  18. package/dist/commands/install.js +126 -0
  19. package/dist/commands/job.d.ts +9 -0
  20. package/dist/commands/job.js +114 -0
  21. package/dist/commands/login.d.ts +3 -0
  22. package/dist/commands/login.js +51 -0
  23. package/dist/commands/logout.d.ts +3 -0
  24. package/dist/commands/logout.js +16 -0
  25. package/dist/commands/native-check.d.ts +22 -0
  26. package/dist/commands/native-check.js +93 -0
  27. package/dist/commands/ops.d.ts +6 -0
  28. package/dist/commands/ops.js +330 -0
  29. package/dist/commands/record.d.ts +12 -0
  30. package/dist/commands/record.js +96 -0
  31. package/dist/commands/report.d.ts +7 -0
  32. package/dist/commands/report.js +54 -0
  33. package/dist/commands/search.d.ts +14 -0
  34. package/dist/commands/search.js +46 -0
  35. package/dist/commands/server.d.ts +23 -0
  36. package/dist/commands/server.js +232 -0
  37. package/dist/commands/status.d.ts +20 -0
  38. package/dist/commands/status.js +92 -0
  39. package/dist/commands/update.d.ts +8 -0
  40. package/dist/commands/update.js +161 -0
  41. package/dist/config.d.ts +12 -0
  42. package/dist/config.js +65 -0
  43. package/dist/i18n/index.d.ts +7 -0
  44. package/dist/i18n/index.js +24 -0
  45. package/dist/i18n/locales/en-US.json +35 -0
  46. package/dist/i18n/locales/zh-CN.json +35 -0
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.js +133 -0
  49. package/dist/keychain.d.ts +3 -0
  50. package/dist/keychain.js +117 -0
  51. package/dist/sentry.d.ts +3 -0
  52. package/dist/sentry.js +62 -0
  53. package/dist/updater.d.ts +23 -0
  54. package/dist/updater.js +161 -0
  55. package/dist/version.d.ts +16 -0
  56. package/dist/version.js +249 -0
  57. package/package.json +50 -0
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.doctorCommand = void 0;
40
+ exports.runDoctor = runDoctor;
41
+ const commander_1 = require("commander");
42
+ const axios_1 = __importDefault(require("axios"));
43
+ const config_1 = require("../config");
44
+ const init_1 = require("./init");
45
+ const server_1 = require("./server");
46
+ const install_1 = require("./install");
47
+ const extension_1 = require("./extension");
48
+ const native_check_1 = require("./native-check");
49
+ const B = {
50
+ reset: '\x1b[0m',
51
+ bold: '\x1b[1m',
52
+ green: '\x1b[32m',
53
+ yellow: '\x1b[33m',
54
+ red: '\x1b[31m',
55
+ cyan: '\x1b[36m',
56
+ magenta: '\x1b[35m',
57
+ };
58
+ /** 对应 ChromePilot doctor: 全链路健康检查 — 带 auto-heal, 无感启动 server/安装扩展 */
59
+ async function runDoctor(opts) {
60
+ const checks = [];
61
+ const hints = [];
62
+ const healed = [];
63
+ const actions = [];
64
+ const autoHeal = opts.autoHeal !== false; // default true
65
+ const interactive = opts.interactive !== false; // default true
66
+ // ── Banner (human 模式) ──
67
+ if (!opts.json) {
68
+ console.log(`\n${B.bold}${B.cyan}╭─────────────────────────────────────────────╮${B.reset}`);
69
+ console.log(`${B.bold}${B.cyan}│ HunterMate Doctor · 环境全链路自检与自愈 │${B.reset}`);
70
+ console.log(`${B.bold}${B.cyan}╰─────────────────────────────────────────────╯${B.reset}\n`);
71
+ }
72
+ // ── 1) 目录 & token ──
73
+ let initResult = null;
74
+ try {
75
+ initResult = (0, init_1.runInit)();
76
+ checks.push({ key: 'home_dir', status: 'ok', detail: initResult.dir });
77
+ }
78
+ catch (e) {
79
+ checks.push({ key: 'home_dir', status: 'fail', detail: e.message });
80
+ if (autoHeal && !opts.json) {
81
+ console.log(`${B.yellow}⚠ 基础目录缺失, hunter-mate 正在自动创建...${B.reset}`);
82
+ initResult = (0, init_1.runInit)(true);
83
+ checks.push({ key: 'home_dir_auto_init', status: 'ok', detail: '已自动创建 ~/.hunter-mate 目录结构' });
84
+ healed.push('init_dirs');
85
+ }
86
+ }
87
+ if (!initResult)
88
+ initResult = (0, init_1.runInit)();
89
+ // ── 2) 扩展安装检测 + 自动安装 ──
90
+ const fs = require('fs');
91
+ const path = require('path');
92
+ const manifestPath = path.join(initResult.extensionDir, 'manifest.json');
93
+ let extInstalled = fs.existsSync(manifestPath);
94
+ if (extInstalled) {
95
+ checks.push({ key: 'extension_installed', status: 'ok', detail: `manifest.json present @ ${initResult.extensionDir}` });
96
+ }
97
+ else {
98
+ checks.push({ key: 'extension_installed', status: 'warn', detail: `manifest.json missing @ ${initResult.extensionDir}` });
99
+ if (autoHeal) {
100
+ if (!opts.json) {
101
+ console.log(`${B.yellow}⚠ 扩展尚未安装, hunter-mate 正在自动执行 install...${B.reset}`);
102
+ }
103
+ const r = (0, install_1.runInstall)(initResult.extensionDir);
104
+ if (r.source) {
105
+ checks.push({ key: 'extension_auto_install', status: 'ok', detail: `已从 ${r.source} 复制 ${r.copied} 个文件到 ${r.target}` });
106
+ healed.push('install_extension');
107
+ extInstalled = true;
108
+ }
109
+ else {
110
+ checks.push({ key: 'extension_auto_install', status: 'warn', detail: `内置 extension dist 未构建, 无法自动安装。目标目录已准备好: ${r.target}` });
111
+ hints.push('请在 hunter-mate monorepo 执行: pnpm --filter @hunter-mate/extension build');
112
+ }
113
+ }
114
+ else {
115
+ hints.push('hunter-mate install');
116
+ }
117
+ }
118
+ // ── 2.5) 原生模块 ABI 自检(server 启动前置闸) ──
119
+ // better-sqlite3 按 node ABI 绑定;不匹配时 server 起来即崩且报错被后台 spawn 吞掉。
120
+ // 放在自动启动之前:fail 就不浪费 8s 去启动必然崩的 server。
121
+ const native = (0, native_check_1.checkNativeModules)();
122
+ for (const m of native.modules) {
123
+ if (m.status === 'skip') {
124
+ checks.push({ key: `native_${m.module}`, status: 'skip', detail: m.detail });
125
+ continue;
126
+ }
127
+ checks.push({
128
+ key: `native_${m.module}`,
129
+ status: m.status === 'ok' ? 'ok' : 'fail',
130
+ detail: m.status === 'ok' ? m.detail : `${m.detail} | 修复: ${m.hint ?? '见 TROUBLESHOOTING.md'}`,
131
+ });
132
+ }
133
+ // ── 3) Server 自动启动(原生模块 fail 时跳过) ──
134
+ const config = (0, config_1.loadConfig)();
135
+ let serverUp = false;
136
+ if (!native.ok) {
137
+ checks.push({ key: 'server', status: 'skip', detail: '原生模块检查未通过,跳过自动启动(修好 ABI 后重跑 doctor)' });
138
+ hints.push('先修复原生模块 ABI(见上方 native_* 检查项), 再重跑 hunter-mate doctor');
139
+ }
140
+ else {
141
+ try {
142
+ const r = await axios_1.default.get(`${config.serverUrl}/health`, { timeout: 3000 });
143
+ serverUp = true;
144
+ checks.push({ key: 'server', status: 'ok', detail: `${config.serverUrl} (HTTP ${r.status})` });
145
+ }
146
+ catch (e) {
147
+ checks.push({ key: 'server', status: 'warn', detail: `${config.serverUrl} unreachable (${e.code || e.message})` });
148
+ if (autoHeal) {
149
+ if (!opts.json) {
150
+ console.log(`${B.yellow}⚠ Server 未运行, hunter-mate 正在后台自动启动...${B.reset}`);
151
+ }
152
+ const r = await (0, server_1.runStart)({ foreground: false });
153
+ // 等待 server 真正就绪(最多 8s)
154
+ for (let i = 0; i < 16; i++) {
155
+ await new Promise((resolve) => setTimeout(resolve, 500));
156
+ try {
157
+ await axios_1.default.get(`${config.serverUrl}/health`, { timeout: 2000 });
158
+ serverUp = true;
159
+ break;
160
+ }
161
+ catch { /* keep trying */ }
162
+ }
163
+ if (serverUp) {
164
+ checks.push({ key: 'server_auto_start', status: 'ok', detail: `已自动启动 server (pid=${r.pid}) on ${r.url}` });
165
+ healed.push('start_server');
166
+ }
167
+ else if (!r.started && !r.pid) {
168
+ // 秒死(runStart 已捕获日志尾部与排障指引)
169
+ checks.push({ key: 'server_auto_start', status: 'fail', detail: r.msg });
170
+ hints.push('排障: TROUBLESHOOTING.md#server-启动即崩abi(常见根因: node 与 better-sqlite3 ABI 不匹配)');
171
+ }
172
+ else {
173
+ checks.push({ key: 'server_auto_start', status: 'fail', detail: `自动启动超时, server 仍不可达: ${r.msg}` });
174
+ hints.push('请手动启动(前台模式看真实报错): hunter-mate start -f');
175
+ hints.push('排障: TROUBLESHOOTING.md#server-启动即崩abi(常见根因: node 与 better-sqlite3 ABI 不匹配)');
176
+ }
177
+ }
178
+ else {
179
+ hints.push('hunter-mate start');
180
+ }
181
+ }
182
+ } // native.ok
183
+ // ── 4) 扩展 WebSocket 连通 ──
184
+ let extConnected = false;
185
+ try {
186
+ if (serverUp) {
187
+ await (0, extension_1.runExtensionCheck)(5000);
188
+ extConnected = true;
189
+ checks.push({ key: 'extension_ws', status: 'ok', detail: '扩展已连接, WebSocket 通道就绪' });
190
+ }
191
+ else {
192
+ checks.push({ key: 'extension_ws', status: 'skip', detail: 'server 未运行, 跳过扩展连通检查' });
193
+ }
194
+ }
195
+ catch (e) {
196
+ checks.push({ key: 'extension_ws', status: 'fail', detail: e.message });
197
+ hints.push('请在 Chrome 中加载 Hunter Mate 扩展(见下方引导)');
198
+ // autoHeal: 尝试打开扩展所在目录 + chrome://extensions
199
+ if (autoHeal) {
200
+ try {
201
+ const { default: open } = await Promise.resolve().then(() => __importStar(require('open')));
202
+ if (extInstalled) {
203
+ if (!opts.json) {
204
+ console.log(`${B.magenta}→ hunter-mate 正在为你打开扩展所在目录...${B.reset}`);
205
+ }
206
+ open(initResult.extensionDir).catch(() => { });
207
+ healed.push('open_ext_dir');
208
+ }
209
+ if (!opts.json) {
210
+ console.log(`${B.magenta}→ 同时打开 Chrome 扩展管理页...${B.reset}`);
211
+ }
212
+ open('chrome://extensions').catch(() => { });
213
+ healed.push('open_chrome_extensions');
214
+ }
215
+ catch { }
216
+ }
217
+ }
218
+ // ── 5) 登录态(不强制) ──
219
+ try {
220
+ const { getToken } = await Promise.resolve().then(() => __importStar(require('../keychain')));
221
+ const token = await getToken();
222
+ checks.push({
223
+ key: 'auth',
224
+ status: token ? 'ok' : 'warn',
225
+ detail: token ? `已登录 (token head=${String(token).slice(0, 6)}...)` : '未登录, 数据面 API 可能受限',
226
+ });
227
+ if (!token)
228
+ hints.push('hunter-mate login');
229
+ }
230
+ catch (e) {
231
+ checks.push({ key: 'auth', status: 'skip', detail: `跳过(keychain 读取失败): ${e.message}` });
232
+ }
233
+ // ── Summary ──
234
+ const anyFail = checks.some((c) => c.status === 'fail');
235
+ const anyWarn = checks.some((c) => c.status === 'warn');
236
+ const summary = anyFail ? 'fail' : anyWarn ? 'warn' : 'pass';
237
+ // ── human output ──
238
+ if (!opts.json) {
239
+ if (healed.length) {
240
+ console.log(`\n${B.bold}${B.green}✓ hunter-mate 自动修复完成 (${healed.length} 项): ${healed.join(', ')}${B.reset}`);
241
+ }
242
+ console.log(`\n${B.bold}检查结果:${B.reset}`);
243
+ for (const c of checks) {
244
+ const sym = c.status === 'ok' ? `${B.green}✓${B.reset}` : c.status === 'warn' ? `${B.yellow}⚠${B.reset}` : c.status === 'fail' ? `${B.red}✗${B.reset}` : `${B.cyan}–${B.reset}`;
245
+ console.log(` ${sym} [${c.status.toUpperCase()}] ${c.key}: ${c.detail}`);
246
+ }
247
+ // ── 友好中文引导(仅 human + 有问题时) ──
248
+ if (summary !== 'pass' || !extConnected) {
249
+ showFriendlyGuide(extInstalled, extConnected, serverUp, healed, initResult.extensionDir);
250
+ }
251
+ if (summary === 'pass') {
252
+ console.log(`\n${B.bold}${B.green}════════════════════════════════════════════${B.reset}`);
253
+ console.log(`${B.bold}${B.green} HunterMate 环境就绪! 可以直接使用 extension 操作了${B.reset}`);
254
+ console.log(`${B.bold}${B.green}════════════════════════════════════════════${B.reset}\n`);
255
+ }
256
+ else if (summary === 'warn') {
257
+ console.log(`\n${B.bold}${B.yellow}⚠ 环境基本就绪, 但有 ${checks.filter(c => c.status === 'warn').length} 项警告。查看上方引导。${B.reset}\n`);
258
+ }
259
+ else {
260
+ console.log(`\n${B.bold}${B.red}✗ 环境未就绪, 请按上方引导完成修复后重试。${B.reset}\n`);
261
+ }
262
+ }
263
+ return { summary, checks, hints, healed, actions };
264
+ }
265
+ /** 友好中文引导 — 当环境不完备时给用户清晰的操作步骤 */
266
+ function showFriendlyGuide(extInstalled, extConnected, serverUp, healed, extDir) {
267
+ const B = {
268
+ reset: '\x1b[0m', bold: '\x1b[1m',
269
+ green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m', magenta: '\x1b[35m',
270
+ };
271
+ console.log(`\n${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 下一步操作指引 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}\n`);
272
+ if (!serverUp) {
273
+ console.log(`${B.bold}${B.red}❌ 数据面 Server 未启动${B.reset}`);
274
+ console.log(` hunter-mate 已尝试自动启动。若持续失败请手动执行:`);
275
+ console.log(` ${B.bold}hunter-mate start -f${B.reset} (前台模式可看日志)\n`);
276
+ }
277
+ if (!extInstalled) {
278
+ console.log(`${B.bold}${B.yellow}⚠ Hunter Mate Chrome 扩展尚未安装${B.reset}`);
279
+ console.log(` 步骤: hunter-mate 已自动把扩展文件复制到:`);
280
+ console.log(` ${B.cyan}${extDir}${B.reset}`);
281
+ console.log(` ${B.bold}接下来需要你手动在 Chrome 中加载(Chrome 安全策略限制命令行自动化):${B.reset}`);
282
+ console.log(` ${B.magenta}① 在 Chrome 地址栏输入:${B.reset} chrome://extensions`);
283
+ console.log(` ${B.magenta}② 打开右上角「开发者模式」开关${B.reset}`);
284
+ console.log(` ${B.magenta}③ 点击「加载已解压的扩展程序」${B.reset}`);
285
+ console.log(` ${B.magenta}④ 选择上面的目录:${B.reset} ${B.cyan}${extDir}${B.reset}`);
286
+ console.log(` ${B.magenta}⑤ Chrome 工具栏应出现 Hunter Mate 图标${B.reset}\n`);
287
+ }
288
+ if (extInstalled && !extConnected) {
289
+ console.log(`${B.bold}${B.yellow}⚠ 扩展已安装但尚未连接到 Server${B.reset}`);
290
+ console.log(` hunter-mate 已自动帮你打开了:`);
291
+ console.log(` · 扩展所在目录: ${B.cyan}${extDir}${B.reset}`);
292
+ console.log(` · Chrome 扩展管理页: ${B.cyan}chrome://extensions${B.reset}`);
293
+ console.log(` ${B.bold}请确认以下几点:${B.reset}`);
294
+ console.log(` ${B.magenta}① 扩展已在 chrome://extensions 中「已开启」${B.reset} (灰色开关变蓝色)`);
295
+ console.log(` ${B.magenta}② 扩展详情中「允许访问的网站」设为「所有网站」或包含 LinkedIn${B.reset}`);
296
+ console.log(` ${B.magenta}③ 点击 Chrome 工具栏的 Hunter Mate 图标, 确认侧栏显示「已连接」${B.reset}`);
297
+ console.log(` ${B.magenta}④ 若仍无连接, 点击扩展详情的「重新加载」按钮刷新扩展${B.reset}\n`);
298
+ }
299
+ if (healed.length) {
300
+ console.log(`${B.bold}${B.green}✨ hunter-mate 已为你自动完成:${B.reset}`);
301
+ for (const h of healed) {
302
+ const map = {
303
+ init_dirs: '创建 ~/.hunter-mate 目录结构',
304
+ install_extension: '复制扩展文件到用户目录',
305
+ start_server: '后台启动 HunterMate Server',
306
+ open_ext_dir: '在 Finder/Explorer 中打开扩展目录',
307
+ open_chrome_extensions: '打开 chrome://extensions',
308
+ };
309
+ console.log(` ${B.green}✓${B.reset} ${map[h] || h}`);
310
+ }
311
+ console.log('');
312
+ }
313
+ console.log(`${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}\n`);
314
+ }
315
+ exports.doctorCommand = new commander_1.Command('doctor')
316
+ .description('全链路自检 + 自动修复(对应 chromepilot doctor): 自动启动 server、安装扩展、打开目录引导')
317
+ .option('--json', '仅以 JSON 输出检查结果与建议(跳过引导文案)')
318
+ .option('--open-extension-folder', '扩展未连接时自动打开扩展所在文件夹')
319
+ .option('--no-auto-heal', '禁用自动修复(仅检查并给出建议, 不自动启动/安装)')
320
+ .option('--no-interactive', '无交互模式(不打印友好引导, 仅输出结构化结果)')
321
+ .action(async (opts) => {
322
+ const r = await runDoctor({
323
+ json: opts.json,
324
+ openExtensionFolder: opts.openExtensionFolder,
325
+ autoHeal: opts.autoHeal !== false,
326
+ interactive: opts.interactive !== false,
327
+ });
328
+ if (opts.json) {
329
+ console.log(JSON.stringify(r, null, 2));
330
+ }
331
+ process.exit(r.summary === 'fail' ? 1 : 0);
332
+ });
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ /** 确保环境就绪(自动启动 server、自动安装扩展、打印引导) */
3
+ export declare function ensureEnvReady(): Promise<void>;
4
+ export declare function runExtensionCheck(timeoutMs?: number): Promise<void>;
5
+ export declare const extensionCommand: Command;