hunter-mate 0.1.6 → 0.1.8
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/dist/assets/extension/background/service-worker.js +911 -159
- package/dist/assets/extension/build-info.json +1 -0
- package/dist/assets/extension/content/index.js +22 -4
- package/dist/assets/extension/manifest.json +5 -4
- package/dist/assets/extension/offscreen/offscreen.html +8 -0
- package/dist/assets/extension/offscreen/offscreen.js +149 -0
- package/dist/assets/extension/package.json +12 -4
- package/dist/assets/extension/sidepanel/index.css +2 -0
- package/dist/assets/extension/sidepanel/index.html +7 -394
- package/dist/assets/extension/sidepanel/index.js +53 -923
- package/dist/assets/server/app.module.js +12 -1
- package/dist/assets/server/app.module.js.map +1 -1
- package/dist/assets/server/auth/auth.controller.d.ts +7 -0
- package/dist/assets/server/auth/auth.controller.js +20 -0
- package/dist/assets/server/auth/auth.controller.js.map +1 -1
- package/dist/assets/server/auth/auth.middleware.js +9 -1
- package/dist/assets/server/auth/auth.middleware.js.map +1 -1
- package/dist/assets/server/auth/auth.service.d.ts +11 -0
- package/dist/assets/server/auth/auth.service.js +58 -1
- package/dist/assets/server/auth/auth.service.js.map +1 -1
- package/dist/assets/server/build-info.json +1 -1
- package/dist/assets/server/customer/customer.controller.d.ts +18 -0
- package/dist/assets/server/customer/customer.controller.js +81 -0
- package/dist/assets/server/customer/customer.controller.js.map +1 -0
- package/dist/assets/server/customer/customer.entity.d.ts +17 -0
- package/dist/assets/server/customer/customer.entity.js +82 -0
- package/dist/assets/server/customer/customer.entity.js.map +1 -0
- package/dist/assets/server/customer/customer.module.d.ts +2 -0
- package/dist/assets/server/customer/customer.module.js +28 -0
- package/dist/assets/server/customer/customer.module.js.map +1 -0
- package/dist/assets/server/customer/customer.service.d.ts +36 -0
- package/dist/assets/server/customer/customer.service.js +200 -0
- package/dist/assets/server/customer/customer.service.js.map +1 -0
- package/dist/assets/server/db/schema-validator.service.d.ts +2 -0
- package/dist/assets/server/db/schema-validator.service.js +32 -1
- package/dist/assets/server/db/schema-validator.service.js.map +1 -1
- package/dist/assets/server/db/sqlite.module.d.ts +1 -0
- package/dist/assets/server/db/sqlite.module.js +12 -2
- package/dist/assets/server/db/sqlite.module.js.map +1 -1
- package/dist/assets/server/devops/devops-sink-init.d.ts +1 -14
- package/dist/assets/server/devops/devops-sink-init.js +3 -8
- package/dist/assets/server/devops/devops-sink-init.js.map +1 -1
- package/dist/assets/server/extension/extension-control.controller.d.ts +15 -0
- package/dist/assets/server/extension/extension-control.controller.js +42 -2
- package/dist/assets/server/extension/extension-control.controller.js.map +1 -1
- package/dist/assets/server/extension/extension-control.service.d.ts +14 -1
- package/dist/assets/server/extension/extension-control.service.js +65 -2
- package/dist/assets/server/extension/extension-control.service.js.map +1 -1
- package/dist/assets/server/extraction/adapter.service.d.ts +3 -0
- package/dist/assets/server/extraction/adapter.service.js +127 -6
- package/dist/assets/server/extraction/adapter.service.js.map +1 -1
- package/dist/assets/server/extraction/anomaly-report.service.js +1 -1
- package/dist/assets/server/extraction/anomaly-report.service.js.map +1 -1
- package/dist/assets/server/extraction/entities/adapter-rule.entity.d.ts +2 -0
- package/dist/assets/server/extraction/entities/adapter-rule.entity.js +10 -0
- package/dist/assets/server/extraction/entities/adapter-rule.entity.js.map +1 -1
- package/dist/assets/server/extraction/extraction-entity.controller.d.ts +21 -3
- package/dist/assets/server/extraction/extraction-entity.controller.js +44 -9
- package/dist/assets/server/extraction/extraction-entity.controller.js.map +1 -1
- package/dist/assets/server/extraction/extraction.module.js +13 -3
- package/dist/assets/server/extraction/extraction.module.js.map +1 -1
- package/dist/assets/server/extraction/extraction.service.d.ts +4 -1
- package/dist/assets/server/extraction/extraction.service.js +59 -4
- package/dist/assets/server/extraction/extraction.service.js.map +1 -1
- package/dist/assets/server/extraction/harness-overlay.service.d.ts +41 -0
- package/dist/assets/server/extraction/harness-overlay.service.js +319 -0
- package/dist/assets/server/extraction/harness-overlay.service.js.map +1 -0
- package/dist/assets/server/extraction/liepin-extractor.d.ts +1 -0
- package/dist/assets/server/extraction/liepin-extractor.js +172 -0
- package/dist/assets/server/extraction/liepin-extractor.js.map +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/governance/action-audit.entity.d.ts +12 -0
- package/dist/assets/server/governance/action-audit.entity.js +66 -0
- package/dist/assets/server/governance/action-audit.entity.js.map +1 -0
- package/dist/assets/server/governance/governance.controller.d.ts +14 -0
- package/dist/assets/server/governance/governance.controller.js +77 -0
- package/dist/assets/server/governance/governance.controller.js.map +1 -0
- package/dist/assets/server/governance/governance.ingester.d.ts +20 -0
- package/dist/assets/server/governance/governance.ingester.js +114 -0
- package/dist/assets/server/governance/governance.ingester.js.map +1 -0
- package/dist/assets/server/governance/governance.module.d.ts +2 -0
- package/dist/assets/server/governance/governance.module.js +26 -0
- package/dist/assets/server/governance/governance.module.js.map +1 -0
- package/dist/assets/server/governance/governance.service.d.ts +114 -0
- package/dist/assets/server/governance/governance.service.js +356 -0
- package/dist/assets/server/governance/governance.service.js.map +1 -0
- package/dist/assets/server/jobcase/jobcase.controller.d.ts +1 -0
- package/dist/assets/server/jobcase/jobcase.entity.d.ts +1 -0
- package/dist/assets/server/jobcase/jobcase.entity.js +6 -0
- package/dist/assets/server/jobcase/jobcase.entity.js.map +1 -1
- package/dist/assets/server/jobcase/jobcase.service.d.ts +2 -0
- package/dist/assets/server/jobcase/jobcase.service.js +2 -1
- package/dist/assets/server/jobcase/jobcase.service.js.map +1 -1
- package/dist/assets/server/main.js +1 -0
- package/dist/assets/server/main.js.map +1 -1
- package/dist/assets/server/package.json +5 -4
- package/dist/assets/server/preference/preference.controller.d.ts +14 -0
- package/dist/assets/server/preference/preference.controller.js +66 -0
- package/dist/assets/server/preference/preference.controller.js.map +1 -0
- package/dist/assets/server/preference/preference.entity.d.ts +13 -0
- package/dist/assets/server/preference/preference.entity.js +77 -0
- package/dist/assets/server/preference/preference.entity.js.map +1 -0
- package/dist/assets/server/preference/preference.module.d.ts +2 -0
- package/dist/assets/server/preference/preference.module.js +26 -0
- package/dist/assets/server/preference/preference.module.js.map +1 -0
- package/dist/assets/server/preference/preference.service.d.ts +33 -0
- package/dist/assets/server/preference/preference.service.js +122 -0
- package/dist/assets/server/preference/preference.service.js.map +1 -0
- package/dist/assets/server/recording/recording-event-queue.service.d.ts +26 -0
- package/dist/assets/server/recording/recording-event-queue.service.js +115 -0
- package/dist/assets/server/recording/recording-event-queue.service.js.map +1 -0
- package/dist/assets/server/recording/recording-retention.service.d.ts +38 -0
- package/dist/assets/server/recording/recording-retention.service.js +174 -0
- package/dist/assets/server/recording/recording-retention.service.js.map +1 -0
- package/dist/assets/server/recording/recording-snapshot.service.d.ts +1 -0
- package/dist/assets/server/recording/recording-snapshot.service.js +4 -0
- package/dist/assets/server/recording/recording-snapshot.service.js.map +1 -1
- package/dist/assets/server/recording/recording.controller.d.ts +21 -1
- package/dist/assets/server/recording/recording.controller.js +37 -2
- package/dist/assets/server/recording/recording.controller.js.map +1 -1
- package/dist/assets/server/recording/recording.gateway.js +11 -0
- package/dist/assets/server/recording/recording.gateway.js.map +1 -1
- package/dist/assets/server/recording/recording.module.js +16 -2
- package/dist/assets/server/recording/recording.module.js.map +1 -1
- package/dist/assets/server/recording/recording.service.d.ts +10 -1
- package/dist/assets/server/recording/recording.service.js +31 -6
- package/dist/assets/server/recording/recording.service.js.map +1 -1
- package/dist/assets/server/remark/remark.controller.d.ts +1 -1
- package/dist/assets/server/remark/remark.controller.js +1 -10
- package/dist/assets/server/remark/remark.controller.js.map +1 -1
- package/dist/assets/server/remark/remark.entity.d.ts +1 -1
- package/dist/assets/server/remark/remark.entity.js.map +1 -1
- package/dist/assets/server/site/entities/site-registry.entity.d.ts +1 -1
- package/dist/assets/server/site/entities/site-registry.entity.js +1 -1
- package/dist/assets/server/site/entities/site-registry.entity.js.map +1 -1
- package/dist/assets/server/site/site.controller.d.ts +1 -1
- package/dist/assets/server/site/site.service.d.ts +5 -1
- package/dist/assets/server/site/site.service.js +13 -0
- package/dist/assets/server/site/site.service.js.map +1 -1
- package/dist/assets/server/system/system.controller.d.ts +1 -0
- package/dist/assets/server/system/system.controller.js +1 -1
- package/dist/assets/server/system/system.controller.js.map +1 -1
- package/dist/assets/server/system/system.service.d.ts +1 -0
- package/dist/assets/server/system/system.service.js +3 -2
- package/dist/assets/server/system/system.service.js.map +1 -1
- package/dist/cache/db.js +6 -6
- package/dist/commands/addons.js +2 -1
- package/dist/commands/cache.js +3 -4
- package/dist/commands/case.d.ts +67 -0
- package/dist/commands/case.js +101 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.js +8 -1
- package/dist/commands/customer.d.ts +25 -0
- package/dist/commands/customer.js +137 -0
- package/dist/commands/doctor.js +119 -13
- package/dist/commands/extension.js +26 -32
- package/dist/commands/extras.d.ts +22 -3
- package/dist/commands/extras.js +116 -7
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +3 -4
- package/dist/commands/issue-env.d.ts +23 -0
- package/dist/commands/issue-env.js +101 -0
- package/dist/commands/job.d.ts +6 -2
- package/dist/commands/job.js +75 -20
- package/dist/commands/login.d.ts +19 -0
- package/dist/commands/login.js +85 -13
- package/dist/commands/migrate.d.ts +32 -0
- package/dist/commands/migrate.js +116 -0
- package/dist/commands/note.d.ts +3 -0
- package/dist/commands/note.js +75 -0
- package/dist/commands/ops.js +82 -15
- package/dist/commands/preference.d.ts +6 -0
- package/dist/commands/preference.js +80 -0
- package/dist/commands/record.js +2 -4
- package/dist/commands/report.js +2 -4
- package/dist/commands/search.js +9 -2
- package/dist/commands/server.d.ts +9 -2
- package/dist/commands/server.js +118 -19
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +16 -6
- package/dist/commands/update.js +8 -9
- package/dist/config.d.ts +21 -0
- package/dist/config.js +27 -0
- package/dist/i18n/locales/en-US.json +19 -1
- package/dist/i18n/locales/zh-CN.json +19 -1
- package/dist/index.js +52 -2
- package/dist/keychain.d.ts +16 -1
- package/dist/keychain.js +43 -16
- package/dist/logger.js +2 -2
- package/dist/updater.d.ts +1 -1
- package/dist/updater.js +24 -7
- package/dist/utils/command-error.d.ts +11 -0
- package/dist/utils/command-error.js +47 -0
- package/dist/utils/link.d.ts +18 -0
- package/dist/utils/link.js +83 -0
- package/dist/utils/proxy-detect.d.ts +20 -0
- package/dist/utils/proxy-detect.js +96 -0
- package/dist/utils/script-path.d.ts +5 -0
- package/dist/utils/script-path.js +27 -0
- package/dist/version.js +34 -9
- package/dist/watchdog.d.ts +23 -1
- package/dist/watchdog.js +97 -6
- package/dist/web/dist/404.html +1 -0
- package/dist/web/dist/_next/static/WdJr3NhHjlu5xN0qOap1k/_buildManifest.js +1 -0
- package/dist/web/dist/_next/static/WdJr3NhHjlu5xN0qOap1k/_ssgManifest.js +1 -0
- package/dist/web/dist/_next/static/chunks/166.f30be223f694f8ee.js +1 -0
- package/dist/web/dist/_next/static/chunks/1e6d5a0c.0488932e17ecdf24.js +15 -0
- package/dist/web/dist/_next/static/chunks/539-5d0e8c5c238c56f8.js +1 -0
- package/dist/web/dist/_next/static/chunks/589-d632233641f35681.js +1 -0
- package/dist/web/dist/_next/static/chunks/671.3b8e9cc96b25b6ea.js +1 -0
- package/dist/web/dist/_next/static/chunks/935-99f57b7d4151d9e7.js +5 -0
- package/dist/web/dist/_next/static/chunks/a7067448-96dd4b8457c447e8.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/_not-found/page-fdf1a13a7656886a.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/auth/verify/page-8e5cff53d6f7d8e1.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/companies/page-e38a69e1929d0953.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/entity/page-250f8a9b6d91ab19.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/jobs/page-6a281776fec065f6.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/layout-83e623e973c1693f.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/logs/page-d478031d49f7ba00.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/matching/jobs/[id]/talents/page-f57f4b7529823601.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/matching/portraits/[id]/jobs/page-614d1e62d7b9d215.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/page-e3392de08ae81fba.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/parselog/page-58d3acece95b4089.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/recordings/page-e2e2e3c3a64083fb.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/snapshots/[id]/agent-prompt/page-fd3b7d7373b8f8b7.js +1 -0
- package/dist/web/dist/_next/static/chunks/app/talents/page-30748338da20d7e0.js +1 -0
- package/dist/web/dist/_next/static/chunks/framework-b3a558b17a070965.js +1 -0
- package/dist/web/dist/_next/static/chunks/main-5a4e0cd75dd7f04b.js +1 -0
- package/dist/web/dist/_next/static/chunks/main-app-80b038a312917d90.js +1 -0
- package/dist/web/dist/_next/static/chunks/pages/_app-da7d628f49271ece.js +4 -0
- package/dist/web/dist/_next/static/chunks/pages/_error-17756f67e0a11350.js +1 -0
- package/dist/web/dist/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/web/dist/_next/static/chunks/webpack-1784baecc6fdcf0b.js +1 -0
- package/dist/web/dist/_next/static/css/db881c5b3072b88a.css +3 -0
- package/dist/web/dist/_next/static/css/f60d210841fab76b.css +1 -0
- package/dist/web/dist/auth/verify.html +1 -0
- package/dist/web/dist/auth/verify.txt +8 -0
- package/dist/web/dist/companies.html +1 -0
- package/dist/web/dist/companies.txt +7 -0
- package/dist/web/dist/entity.html +1 -0
- package/dist/web/dist/entity.txt +8 -0
- package/dist/web/dist/index.html +1 -0
- package/dist/web/dist/index.txt +8 -0
- package/dist/web/dist/jobs.html +1 -0
- package/dist/web/dist/jobs.txt +7 -0
- package/dist/web/dist/logs.html +1 -0
- package/dist/web/dist/logs.txt +8 -0
- package/dist/web/dist/matching/jobs/placeholder/talents.html +1 -0
- package/dist/web/dist/matching/jobs/placeholder/talents.txt +8 -0
- package/dist/web/dist/matching/portraits/placeholder/jobs.html +1 -0
- package/dist/web/dist/matching/portraits/placeholder/jobs.txt +8 -0
- package/dist/web/dist/parselog.html +1 -0
- package/dist/web/dist/parselog.txt +8 -0
- package/dist/web/dist/recordings.html +1 -0
- package/dist/web/dist/recordings.txt +8 -0
- package/dist/web/dist/snapshots/placeholder/agent-prompt.html +1 -0
- package/dist/web/dist/snapshots/placeholder/agent-prompt.txt +8 -0
- package/dist/web/dist/talents.html +1 -0
- package/dist/web/dist/talents.txt +7 -0
- package/package.json +26 -6
package/dist/commands/doctor.js
CHANGED
|
@@ -9,7 +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
|
+
import { getToken, getTokenInfo } from '../keychain.js';
|
|
13
13
|
const B = {
|
|
14
14
|
reset: '\x1b[0m',
|
|
15
15
|
bold: '\x1b[1m',
|
|
@@ -67,6 +67,27 @@ export async function runDoctor(opts) {
|
|
|
67
67
|
status: nodeVersionFriendly ? 'ok' : 'warn',
|
|
68
68
|
detail: `Node ${process.versions.node}${nodeVersionFriendly ? '' : ' (hunter-mate 预构建包对 Node 20/22/24 支持最好,Windows 无编译器时建议切到 Node 22 LTS)'}`,
|
|
69
69
|
});
|
|
70
|
+
// ── 0.5) 死代理检测(Windows 现场:npm registry 查询失败 / prebuild 下载失败
|
|
71
|
+
// 回退 7 分钟源码编译的根因是 shell 残留指向死端口的代理变量) ──
|
|
72
|
+
try {
|
|
73
|
+
const { findDeadProxies, buildUnsetHint } = await import('../utils/proxy-detect.js');
|
|
74
|
+
const dead = await findDeadProxies(800);
|
|
75
|
+
if (dead.length) {
|
|
76
|
+
checks.push({ key: 'proxy_env', status: 'warn', detail: buildUnsetHint(dead) });
|
|
77
|
+
hints.push('清除死代理环境变量后重试(见 proxy_env 检查项的各 shell 指令)');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const proxyEnv = (await import('../utils/proxy-detect.js')).collectProxyEnv();
|
|
81
|
+
checks.push({
|
|
82
|
+
key: 'proxy_env',
|
|
83
|
+
status: 'ok',
|
|
84
|
+
detail: proxyEnv.length
|
|
85
|
+
? `代理变量已设置且端口存活: ${proxyEnv.map((p) => `${p.varName}=${p.value}`).join(', ')}`
|
|
86
|
+
: '未设置代理环境变量(直连)',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch { /* 检测失败不阻断 doctor */ }
|
|
70
91
|
// ── 1) 目录 & token ──
|
|
71
92
|
let initResult = null;
|
|
72
93
|
try {
|
|
@@ -160,9 +181,17 @@ export async function runDoctor(opts) {
|
|
|
160
181
|
}
|
|
161
182
|
else {
|
|
162
183
|
try {
|
|
163
|
-
const r = await axios.get(`${config.serverUrl}/health`, { timeout: 3000 });
|
|
184
|
+
const r = await axios.get(`${config.serverUrl}/health`, { timeout: 3000, proxy: false });
|
|
164
185
|
serverUp = true;
|
|
165
|
-
|
|
186
|
+
const hv = r.data || {};
|
|
187
|
+
checks.push({
|
|
188
|
+
key: 'server',
|
|
189
|
+
status: 'ok',
|
|
190
|
+
detail: `${config.serverUrl} (HTTP ${r.status}` +
|
|
191
|
+
(hv.version ? `, server v${hv.version}` : '') +
|
|
192
|
+
(hv.buildTime ? `, built ${hv.buildTime}` : '') +
|
|
193
|
+
')',
|
|
194
|
+
});
|
|
166
195
|
}
|
|
167
196
|
catch (e) {
|
|
168
197
|
checks.push({ key: 'server', status: 'warn', detail: `${config.serverUrl} unreachable (${e.code || e.message})` });
|
|
@@ -227,7 +256,28 @@ export async function runDoctor(opts) {
|
|
|
227
256
|
if (serverUp) {
|
|
228
257
|
await runExtensionCheck(5000);
|
|
229
258
|
extConnected = true;
|
|
230
|
-
|
|
259
|
+
// 证据化输出:列出已连接扩展实例(id/版本/连接时间)。
|
|
260
|
+
// 现场教训:doctor 报"已连"与任务执行时"未连"曾互相矛盾,
|
|
261
|
+
// 把时间戳摆出来用户才能判断报告是否过期(12:03 连过 ≠ 16:32 还连着)。
|
|
262
|
+
let detail = '扩展已连接, WebSocket 通道就绪';
|
|
263
|
+
try {
|
|
264
|
+
const r = await axios.get(`${config.serverUrl}/extensions`, { timeout: 3000, proxy: false });
|
|
265
|
+
const clients = (Array.isArray(r.data) ? r.data : []);
|
|
266
|
+
if (clients.length) {
|
|
267
|
+
const brief = clients
|
|
268
|
+
.map((c) => {
|
|
269
|
+
const at = c.connectedAt ? new Date(c.connectedAt).toLocaleString() : '?';
|
|
270
|
+
return `${c.extensionId ?? 'unknown'}@${c.version ?? '?'} (connectedAt ${at})`;
|
|
271
|
+
})
|
|
272
|
+
.join(', ');
|
|
273
|
+
detail = `扩展已连接 (${clients.length} 实例): ${brief}`;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
detail = '扩展已连接,但 /extensions 注册表为空(竞态,建议重跑 doctor 确认)';
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch { /* 证据获取失败不阻断结论 */ }
|
|
280
|
+
checks.push({ key: 'extension_ws', status: 'ok', detail });
|
|
231
281
|
}
|
|
232
282
|
else {
|
|
233
283
|
checks.push({ key: 'extension_ws', status: 'skip', detail: 'server 未运行, 跳过扩展连通检查' });
|
|
@@ -256,19 +306,75 @@ export async function runDoctor(opts) {
|
|
|
256
306
|
catch { }
|
|
257
307
|
}
|
|
258
308
|
}
|
|
259
|
-
// ── 5) 登录态(
|
|
309
|
+
// ── 5) 登录态(token 存在性 + 真实探测, fix #8) ──
|
|
310
|
+
// doctor/* 路由本身豁免认证,查 token 存在性会假阳性;
|
|
311
|
+
// 带 token 调受保护端点(/job-cases)才能确认登录真的有效。
|
|
260
312
|
let loggedIn = false;
|
|
261
313
|
try {
|
|
262
|
-
const { getToken } = await import('../keychain.js');
|
|
263
314
|
const token = await getToken();
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (!token)
|
|
315
|
+
if (!token) {
|
|
316
|
+
checks.push({
|
|
317
|
+
key: 'auth',
|
|
318
|
+
status: 'warn',
|
|
319
|
+
detail: '未登录, 数据面 API 可能受限',
|
|
320
|
+
});
|
|
271
321
|
hints.push('hunter-mate login');
|
|
322
|
+
}
|
|
323
|
+
else if (!serverUp) {
|
|
324
|
+
const issuer = (await getTokenInfo())?.issuer ?? 'unknown';
|
|
325
|
+
// hmh#43: SaaS 签发的 token 存在性 ok 但 server 起来后必 401,不能笼统报"已登录"
|
|
326
|
+
if (issuer === 'saas') {
|
|
327
|
+
checks.push({
|
|
328
|
+
key: 'auth',
|
|
329
|
+
status: 'warn',
|
|
330
|
+
detail: 'token 由 SaaS 签发(server 未运行,仅验证存在性);server 启动后数据面会 401,请重新登录',
|
|
331
|
+
});
|
|
332
|
+
hints.push('启动 server 后重新登录: hunter-mate login');
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
loggedIn = true;
|
|
336
|
+
checks.push({
|
|
337
|
+
key: 'auth',
|
|
338
|
+
status: 'ok',
|
|
339
|
+
detail: '已登录 (server 未运行, 仅验证 token 存在性)',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
try {
|
|
345
|
+
const r = await axios.get(`${config.serverUrl}/job-cases`, {
|
|
346
|
+
timeout: 5000,
|
|
347
|
+
proxy: false,
|
|
348
|
+
headers: { Authorization: `UTOKEN ${token}` },
|
|
349
|
+
});
|
|
350
|
+
loggedIn = true;
|
|
351
|
+
checks.push({ key: 'auth', status: 'ok', detail: `已登录且 token 有效 (HTTP ${r.status})` });
|
|
352
|
+
}
|
|
353
|
+
catch (e) {
|
|
354
|
+
const status = e?.response?.status;
|
|
355
|
+
if (status === 401 || status === 403) {
|
|
356
|
+
// 真实 fail: server 明确拒绝了这个 token
|
|
357
|
+
const issuer = (await getTokenInfo())?.issuer ?? 'unknown';
|
|
358
|
+
if (issuer === 'saas') {
|
|
359
|
+
// hmh#43: 定向诊断,不再笼统报"登录已过期"
|
|
360
|
+
checks.push({
|
|
361
|
+
key: 'auth',
|
|
362
|
+
status: 'fail',
|
|
363
|
+
detail: `token 由 SaaS 签发,被本地 server 拒绝 (HTTP ${status});登录时本地 server 未运行`,
|
|
364
|
+
});
|
|
365
|
+
hints.push('保持 server 运行后重新登录: hunter-mate login');
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
checks.push({ key: 'auth', status: 'fail', detail: `token 已被 server 拒绝 (HTTP ${status}), 登录已过期或无权访问` });
|
|
369
|
+
hints.push('重新登录: hunter-mate login');
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// 网络/其他原因: 标 warn,不误报 fail
|
|
374
|
+
checks.push({ key: 'auth', status: 'warn', detail: `token 存在但探测失败(网络或服务异常): ${e.message}` });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
272
378
|
}
|
|
273
379
|
catch (e) {
|
|
274
380
|
checks.push({ key: 'auth', status: 'skip', detail: `跳过(keychain 读取失败): ${e.message}` });
|
|
@@ -6,7 +6,7 @@ import * as path from 'path';
|
|
|
6
6
|
import { loadConfig } from '../config.js';
|
|
7
7
|
import { i18n } from '../i18n/index.js';
|
|
8
8
|
import { showInstallGuide, runInstall } from './install.js';
|
|
9
|
-
import {
|
|
9
|
+
import { printCommandError } from '../utils/command-error.js';
|
|
10
10
|
const B = {
|
|
11
11
|
reset: '\x1b[0m', bold: '\x1b[1m',
|
|
12
12
|
green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m', magenta: '\x1b[35m',
|
|
@@ -21,13 +21,15 @@ function http(baseUrl) {
|
|
|
21
21
|
headers: { 'Content-Type': 'application/json' },
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
-
/** 带鉴权的 client(server /extensions* 端点要求 UTOKEN,与 job/record/search 等模块一致)。
|
|
25
|
-
|
|
24
|
+
/** 带鉴权的 client(server /extensions* 端点要求 UTOKEN,与 job/record/search 等模块一致)。
|
|
25
|
+
* D4(R3 定案):timeoutMs 可传 —— axios 层默认 60s,server 侧 timeoutMs(-t)更大时
|
|
26
|
+
* HTTP 层先弃,linkedin search 等多页编排(分钟级)走 CLI 必死;+15s 缓冲覆盖 server 处理+回传。 */
|
|
27
|
+
async function httpAuth(baseUrl, timeoutMs) {
|
|
26
28
|
const { getToken } = await import('../keychain.js');
|
|
27
29
|
const token = await getToken();
|
|
28
30
|
return axios.create({
|
|
29
31
|
baseURL: baseUrl,
|
|
30
|
-
timeout: 60_000,
|
|
32
|
+
timeout: timeoutMs ?? 60_000,
|
|
31
33
|
headers: {
|
|
32
34
|
'Content-Type': 'application/json',
|
|
33
35
|
...(token ? { Authorization: `UTOKEN ${token}` } : {}),
|
|
@@ -37,9 +39,8 @@ async function httpAuth(baseUrl) {
|
|
|
37
39
|
function requireServerUrl() {
|
|
38
40
|
const config = loadConfig();
|
|
39
41
|
if (!config.serverUrl) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
42
|
+
// 同步上下文:手工构造的 Error 无 response.status,不会触发 issuer 诊断分支
|
|
43
|
+
void printCommandError('extension:no-server-url', new Error('请先 hunter-mate config 设置 serverUrl'));
|
|
43
44
|
process.exit(1);
|
|
44
45
|
}
|
|
45
46
|
return config.serverUrl;
|
|
@@ -128,9 +129,7 @@ export function ensureEnvReady() {
|
|
|
128
129
|
catch { /* ignore */ }
|
|
129
130
|
}
|
|
130
131
|
if (!serverUp) {
|
|
131
|
-
|
|
132
|
-
hint: '请手动执行 hunter-mate start -f',
|
|
133
|
-
});
|
|
132
|
+
await printCommandError('extension:server-start-failed', new Error('请手动执行 hunter-mate start -f'));
|
|
134
133
|
process.exit(1);
|
|
135
134
|
}
|
|
136
135
|
// 2) 检查扩展是否安装
|
|
@@ -145,9 +144,7 @@ export function ensureEnvReady() {
|
|
|
145
144
|
const r = runInstall(init.extensionDir);
|
|
146
145
|
if (!r.source) {
|
|
147
146
|
// 内置 dist 不存在, 无法自动安装
|
|
148
|
-
|
|
149
|
-
hint: '请在 hunter-mate monorepo 执行 pnpm --filter @hunter-mate/extension build,或手动 hunter-mate install',
|
|
150
|
-
});
|
|
147
|
+
await printCommandError('extension:auto-install-failed', new Error('内置 extension dist 不存在,请在 hunter-mate monorepo 执行 pnpm --filter @hunter-mate/extension build,或手动 hunter-mate install'));
|
|
151
148
|
process.exit(1);
|
|
152
149
|
}
|
|
153
150
|
console.log(`${B.green}✓ 扩展已自动安装到 ${r.target}${B.reset}`);
|
|
@@ -189,9 +186,7 @@ export function ensureEnvReady() {
|
|
|
189
186
|
}
|
|
190
187
|
catch {
|
|
191
188
|
// /extensions 端点不可达
|
|
192
|
-
|
|
193
|
-
hint: 'Server 可能未正确启动, 请执行 hunter-mate start -f',
|
|
194
|
-
});
|
|
189
|
+
await printCommandError('extension:check-failed', new Error('Server 可能未正确启动, 请执行 hunter-mate start -f'));
|
|
195
190
|
process.exit(1);
|
|
196
191
|
}
|
|
197
192
|
})();
|
|
@@ -230,7 +225,6 @@ export async function runExtensionCheck(timeoutMs = 5000) {
|
|
|
230
225
|
}
|
|
231
226
|
registered = true;
|
|
232
227
|
ws.close();
|
|
233
|
-
globalThis.__extensionCount = count;
|
|
234
228
|
resolve();
|
|
235
229
|
})
|
|
236
230
|
.catch((err) => {
|
|
@@ -256,8 +250,8 @@ async function withEnvCheck(fn) {
|
|
|
256
250
|
await fn();
|
|
257
251
|
}
|
|
258
252
|
catch (err) {
|
|
253
|
+
await printCommandError('extension:exec-failed', err);
|
|
259
254
|
const msg = err.response?.data?.message ?? err.response?.data?.error ?? err.message;
|
|
260
|
-
getCliLogger().error('extension:exec-failed', { error: msg });
|
|
261
255
|
if (msg.includes('no Hunter Mate Chrome extension registered') || msg.includes('no Hunter Mate')) {
|
|
262
256
|
const init = await import('./init.js').then((m) => m.runInit());
|
|
263
257
|
showInstallGuide(init.extensionDir);
|
|
@@ -284,13 +278,11 @@ async function cmdControl(command, argsJson, opts) {
|
|
|
284
278
|
params = JSON.parse(argsJson);
|
|
285
279
|
}
|
|
286
280
|
catch {
|
|
287
|
-
|
|
288
|
-
hint: 'args 必须是合法 JSON 字符串',
|
|
289
|
-
});
|
|
281
|
+
console.error('✗ extension:invalid-control-args: args 必须是合法 JSON 字符串');
|
|
290
282
|
process.exit(1);
|
|
291
283
|
}
|
|
292
284
|
}
|
|
293
|
-
const r = await (await httpAuth(serverUrl)).post('/extensions/control', {
|
|
285
|
+
const r = await (await httpAuth(serverUrl, opts.timeout ? Number(opts.timeout) + 15_000 : undefined)).post('/extensions/control', {
|
|
294
286
|
command,
|
|
295
287
|
params,
|
|
296
288
|
timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
|
|
@@ -303,7 +295,7 @@ async function cmdControl(command, argsJson, opts) {
|
|
|
303
295
|
async function cmdGoto(url, opts) {
|
|
304
296
|
return withEnvCheck(async () => {
|
|
305
297
|
const serverUrl = requireServerUrl();
|
|
306
|
-
const r = await (await httpAuth(serverUrl)).post('/extensions/goto', {
|
|
298
|
+
const r = await (await httpAuth(serverUrl, opts.timeout ? Number(opts.timeout) + 15_000 : undefined)).post('/extensions/goto', {
|
|
307
299
|
url,
|
|
308
300
|
waitUntil: opts.waitUntil,
|
|
309
301
|
timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
|
|
@@ -316,10 +308,11 @@ async function cmdGoto(url, opts) {
|
|
|
316
308
|
async function cmdEval(expression, opts) {
|
|
317
309
|
return withEnvCheck(async () => {
|
|
318
310
|
const serverUrl = requireServerUrl();
|
|
319
|
-
const r = await (await httpAuth(serverUrl)).post('/extensions/eval', {
|
|
311
|
+
const r = await (await httpAuth(serverUrl, opts.timeout ? Number(opts.timeout) + 15_000 : undefined)).post('/extensions/eval', {
|
|
320
312
|
expression,
|
|
321
313
|
timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
|
|
322
314
|
extensionId: opts.extensionId,
|
|
315
|
+
sessionId: opts.sessionId ?? opts.taskId,
|
|
323
316
|
});
|
|
324
317
|
printResult(r.data, opts.format);
|
|
325
318
|
});
|
|
@@ -327,7 +320,7 @@ async function cmdEval(expression, opts) {
|
|
|
327
320
|
async function cmdScreenshot(opts) {
|
|
328
321
|
return withEnvCheck(async () => {
|
|
329
322
|
const serverUrl = requireServerUrl();
|
|
330
|
-
const r = await (await httpAuth(serverUrl)).post('/extensions/screenshot', {
|
|
323
|
+
const r = await (await httpAuth(serverUrl, opts.timeout ? Number(opts.timeout) + 15_000 : undefined)).post('/extensions/screenshot', {
|
|
331
324
|
fullPage: opts.full ? true : undefined,
|
|
332
325
|
selector: opts.selector,
|
|
333
326
|
format: opts.imageFormat ?? 'png',
|
|
@@ -355,9 +348,7 @@ async function cmdRun(site, command, opts) {
|
|
|
355
348
|
params = JSON.parse(opts.args);
|
|
356
349
|
}
|
|
357
350
|
catch {
|
|
358
|
-
|
|
359
|
-
hint: 'args 必须是合法 JSON 字符串',
|
|
360
|
-
});
|
|
351
|
+
console.error('✗ extension:invalid-run-args: args 必须是合法 JSON 字符串');
|
|
361
352
|
process.exit(1);
|
|
362
353
|
}
|
|
363
354
|
}
|
|
@@ -366,7 +357,7 @@ async function cmdRun(site, command, opts) {
|
|
|
366
357
|
timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
|
|
367
358
|
extensionId: opts.extensionId,
|
|
368
359
|
};
|
|
369
|
-
const r = await (await httpAuth(serverUrl)).post(endpoint, payload);
|
|
360
|
+
const r = await (await httpAuth(serverUrl, opts.timeout ? Number(opts.timeout) + 15_000 : undefined)).post(endpoint, payload);
|
|
370
361
|
printResult(r.data, opts.format);
|
|
371
362
|
});
|
|
372
363
|
}
|
|
@@ -387,11 +378,14 @@ extensionCommand
|
|
|
387
378
|
.action(async () => {
|
|
388
379
|
try {
|
|
389
380
|
await ensureEnvReady();
|
|
390
|
-
|
|
381
|
+
// fix #31: 用 /extensions 真实查询的计数, 不再读 globalThis.__extensionCount(可能是 stale 0)
|
|
382
|
+
const serverUrl = requireServerUrl();
|
|
383
|
+
const r = await (await httpAuth(serverUrl)).get('/extensions', { timeout: 5000 });
|
|
384
|
+
const count = Array.isArray(r.data) ? r.data.length : 0;
|
|
391
385
|
console.log(`\n${B.green}✓ Hunter Mate 扩展已连接 (${count} 个浏览器实例)${B.reset}\n`);
|
|
392
386
|
}
|
|
393
387
|
catch (err) {
|
|
394
|
-
|
|
388
|
+
await printCommandError('extension:check-error', err);
|
|
395
389
|
process.exit(1);
|
|
396
390
|
}
|
|
397
391
|
});
|
|
@@ -419,6 +413,6 @@ common(extensionCommand
|
|
|
419
413
|
.action(async (opts) => cmdScreenshot(opts));
|
|
420
414
|
common(extensionCommand
|
|
421
415
|
.command('run <site> <command>')
|
|
422
|
-
.description('站点适配器命令 (对应 chromepilot run): linkedin search|extract|invite 或 resume extract'))
|
|
416
|
+
.description('站点适配器命令 (对应 chromepilot run): linkedin search|extract|invite、liepin search|extract 或 resume extract'))
|
|
423
417
|
.option('--args <json>', '命令参数 JSON 字符串')
|
|
424
418
|
.action(async (site, command, opts) => cmdRun(site, command, opts));
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* FID-092:扫描扩展目录最新 mtime,等待其静止——reload 广播前确认 dist 已写完。
|
|
4
|
+
* 背景:R5 实机 reload 后 3 秒 dist 仍在写入,Chrome 重读读到写了一半的
|
|
5
|
+
* service-worker.js → SW eval 崩溃 → 无 alarm 监听/无 offscreen/零重连,
|
|
6
|
+
* 所有自愈路径全部失效,只能人工点。Windows 兼容:纯 node fs,无 shell。
|
|
7
|
+
*/
|
|
8
|
+
export declare function waitForExtensionDirQuiet(dir: string, opts?: {
|
|
9
|
+
quietMs?: number;
|
|
10
|
+
maxWaitMs?: number;
|
|
11
|
+
pollMs?: number;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
quiet: boolean;
|
|
14
|
+
waitedMs: number;
|
|
15
|
+
newestMtimeMs: number;
|
|
16
|
+
}>;
|
|
17
|
+
/** FID-092:轮询 server 已连接扩展数(>=1 即判定 reload 后已回连)。 */
|
|
18
|
+
export declare function extensionConnectedCount(serverUrl: string, timeoutMs?: number): Promise<number>;
|
|
19
|
+
/**
|
|
20
|
+
* 通知所有已连接扩展 reload(自愈主链路),FID-092 三段式:
|
|
21
|
+
* 1) dist 静止确认(防 reload 读到写一半的扩展文件)
|
|
22
|
+
* 2) 广播(broadcastReload):优先 HTTP POST /system/broadcast-extension;
|
|
23
|
+
* 旧 server 无该端点时退回直连 WS /ws 广播
|
|
24
|
+
* 3) 健康校验 + 自动重试(广播后 12s 内未回连 → 再广播,最多 3 次)
|
|
6
25
|
*/
|
|
7
26
|
export declare function runReload(timeoutMs?: number): Promise<{
|
|
8
27
|
broadcast: number;
|
package/dist/commands/extras.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
3
|
import * as readline from 'readline';
|
|
4
|
-
import { loadConfig } from '../config.js';
|
|
4
|
+
import { loadConfig, resolveDataDir } from '../config.js';
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
@@ -10,12 +10,114 @@ import { runStop, tryReadPid } from './server.js';
|
|
|
10
10
|
import { i18n } from '../i18n/index.js';
|
|
11
11
|
import { getCliLogger } from '../logger.js';
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* FID-092:扫描扩展目录最新 mtime,等待其静止——reload 广播前确认 dist 已写完。
|
|
14
|
+
* 背景:R5 实机 reload 后 3 秒 dist 仍在写入,Chrome 重读读到写了一半的
|
|
15
|
+
* service-worker.js → SW eval 崩溃 → 无 alarm 监听/无 offscreen/零重连,
|
|
16
|
+
* 所有自愈路径全部失效,只能人工点。Windows 兼容:纯 node fs,无 shell。
|
|
17
|
+
*/
|
|
18
|
+
export async function waitForExtensionDirQuiet(dir, opts = {}) {
|
|
19
|
+
const quietMs = opts.quietMs ?? 2500;
|
|
20
|
+
const maxWaitMs = opts.maxWaitMs ?? 15000;
|
|
21
|
+
const pollMs = opts.pollMs ?? 400;
|
|
22
|
+
const start = Date.now();
|
|
23
|
+
const newestMtime = (d) => {
|
|
24
|
+
let latest = 0;
|
|
25
|
+
let entries;
|
|
26
|
+
try {
|
|
27
|
+
entries = fs.readdirSync(d, { withFileTypes: true });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return latest; // 目录不可读(未安装/权限)时不阻塞 reload
|
|
31
|
+
}
|
|
32
|
+
for (const e of entries) {
|
|
33
|
+
const full = path.join(d, e.name);
|
|
34
|
+
try {
|
|
35
|
+
if (e.isDirectory()) {
|
|
36
|
+
latest = Math.max(latest, newestMtime(full));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
latest = Math.max(latest, fs.statSync(full).mtimeMs);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* 单个文件竞态删除,跳过 */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return latest;
|
|
47
|
+
};
|
|
48
|
+
let newest = newestMtime(dir);
|
|
49
|
+
while (newest > 0 && Date.now() - newest < quietMs && Date.now() - start < maxWaitMs) {
|
|
50
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
51
|
+
newest = newestMtime(dir);
|
|
52
|
+
}
|
|
53
|
+
return { quiet: newest === 0 || Date.now() - newest >= quietMs, waitedMs: Date.now() - start, newestMtimeMs: newest };
|
|
54
|
+
}
|
|
55
|
+
/** FID-092:轮询 server 已连接扩展数(>=1 即判定 reload 后已回连)。 */
|
|
56
|
+
export async function extensionConnectedCount(serverUrl, timeoutMs = 3000) {
|
|
57
|
+
try {
|
|
58
|
+
const r = await axios.get(`${serverUrl}/extensions`, { timeout: timeoutMs, proxy: false });
|
|
59
|
+
return Array.isArray(r.data) ? r.data.length : 0;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return -1; // server 不可达
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 通知所有已连接扩展 reload(自愈主链路),FID-092 三段式:
|
|
67
|
+
* 1) dist 静止确认(防 reload 读到写一半的扩展文件)
|
|
68
|
+
* 2) 广播(broadcastReload):优先 HTTP POST /system/broadcast-extension;
|
|
69
|
+
* 旧 server 无该端点时退回直连 WS /ws 广播
|
|
70
|
+
* 3) 健康校验 + 自动重试(广播后 12s 内未回连 → 再广播,最多 3 次)
|
|
16
71
|
*/
|
|
17
72
|
export async function runReload(timeoutMs = 5000) {
|
|
18
73
|
const config = loadConfig();
|
|
74
|
+
// FID-092 步骤 1:dist 静止确认(软链/目录均可,扫描真实路径)
|
|
75
|
+
let extDir;
|
|
76
|
+
try {
|
|
77
|
+
extDir = fs.realpathSync(path.join(resolveDataDir(), 'extension'));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
extDir = path.join(resolveDataDir(), 'extension');
|
|
81
|
+
}
|
|
82
|
+
const q = await waitForExtensionDirQuiet(extDir);
|
|
83
|
+
const quietNote = q.waitedMs > 500 ? `(等待 dist 写入静止 ${q.waitedMs}ms) ` : '';
|
|
84
|
+
// FID-092 步骤 2+3:广播 → 校验回连 → 失败重试
|
|
85
|
+
const VERIFY_WINDOW_MS = 12000;
|
|
86
|
+
const MAX_ATTEMPTS = 3;
|
|
87
|
+
let last = await broadcastReload(config, timeoutMs);
|
|
88
|
+
if (last.broadcast <= 0) {
|
|
89
|
+
return { ...last, msg: `${quietNote}${last.msg}` };
|
|
90
|
+
}
|
|
91
|
+
const start = Date.now();
|
|
92
|
+
while (Date.now() - start < VERIFY_WINDOW_MS) {
|
|
93
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
94
|
+
const n = await extensionConnectedCount(config.serverUrl);
|
|
95
|
+
if (n > 0) {
|
|
96
|
+
return { ...last, msg: `${quietNote}${last.msg};已校验扩展回连(connected=${n})。` };
|
|
97
|
+
}
|
|
98
|
+
if (n === -1)
|
|
99
|
+
break; // server 挂了,重试无意义
|
|
100
|
+
}
|
|
101
|
+
// 未回连:重试广播(第一次读到的可能是写了一半的文件,重读即恢复)
|
|
102
|
+
for (let attempt = 2; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
103
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
104
|
+
last = await broadcastReload(config, timeoutMs);
|
|
105
|
+
if (last.broadcast <= 0)
|
|
106
|
+
break;
|
|
107
|
+
const deadline = Date.now() + VERIFY_WINDOW_MS;
|
|
108
|
+
while (Date.now() < deadline) {
|
|
109
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
110
|
+
if ((await extensionConnectedCount(config.serverUrl)) > 0) {
|
|
111
|
+
return { ...last, msg: `${quietNote}第 ${attempt} 次广播后已校验扩展回连。` };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...last,
|
|
117
|
+
msg: `${quietNote}${MAX_ATTEMPTS} 次广播后扩展仍未回连(server /extensions=0)——扩展可能处于错误态,请到 chrome://extensions 查看 HunterMate「错误」并点「重新加载」。`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function broadcastReload(config, timeoutMs = 5000) {
|
|
19
121
|
// ---------- 1) HTTP 优先(POST /system/broadcast-extension) ----------
|
|
20
122
|
try {
|
|
21
123
|
const res = await axios.post(`${config.serverUrl}/system/broadcast-extension`, { payload: { type: 'reload' } }, { timeout: timeoutMs, proxy: false });
|
|
@@ -29,6 +131,13 @@ export async function runReload(timeoutMs = 5000) {
|
|
|
29
131
|
msg: `reload 广播已通过 HTTP 通道发送给 ${broadcast} 个扩展实例:200ms 后每个实例会自动调 chrome.runtime.reload(),Chrome 将重新读取磁盘上的扩展文件。`,
|
|
30
132
|
};
|
|
31
133
|
}
|
|
134
|
+
// FID-086 deferred reload: server 已挂起意图,扩展重连(≤30s)自动下发——断连态不失败、不静默
|
|
135
|
+
if (body.queued) {
|
|
136
|
+
return {
|
|
137
|
+
broadcast: 0,
|
|
138
|
+
msg: '扩展当前未连接,重载请求已挂起:扩展重连(通常 ≤30 秒,chrome.alarms 唤醒)后将自动重新加载。无需手动干预。',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
32
141
|
if (errors.length) {
|
|
33
142
|
return {
|
|
34
143
|
broadcast: 0,
|
|
@@ -128,7 +237,7 @@ export const reloadCommand = new Command('reload')
|
|
|
128
237
|
console.log(r.msg);
|
|
129
238
|
}
|
|
130
239
|
catch (e) {
|
|
131
|
-
|
|
240
|
+
console.error(`✗ extras:reload-failed: ${e.message}`);
|
|
132
241
|
process.exit(1);
|
|
133
242
|
}
|
|
134
243
|
});
|
|
@@ -143,7 +252,7 @@ export const openExtCommand = new Command('open-extension-folder')
|
|
|
143
252
|
// ---------------------------------------------------------------------------
|
|
144
253
|
// purge — 彻底清理本地 hunter-mate 数据
|
|
145
254
|
// ---------------------------------------------------------------------------
|
|
146
|
-
const HM_ROOT =
|
|
255
|
+
const HM_ROOT = resolveDataDir;
|
|
147
256
|
/** 交互式二次确认 */
|
|
148
257
|
function confirmPrompt(question) {
|
|
149
258
|
return new Promise((resolve) => {
|
|
@@ -241,7 +350,7 @@ export async function runPurge(opts) {
|
|
|
241
350
|
// 3) 停止 server(先于目录删除,避免 server 还在写日志导致删不干净)
|
|
242
351
|
let serverStopResult = null;
|
|
243
352
|
if (livePid || exists && fs.existsSync(path.join(root, 'server.pid'))) {
|
|
244
|
-
serverStopResult = runStop();
|
|
353
|
+
serverStopResult = await runStop();
|
|
245
354
|
}
|
|
246
355
|
// 4) 删除目录
|
|
247
356
|
let removedFiles = info.files;
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
/** 对应 ChromePilot init:
|
|
2
|
+
/** 对应 ChromePilot init: 创建数据目录、SQLite、初始 token(目录位置随 dataDir 配置,FID-071) */
|
|
3
3
|
export declare function runInit(force?: boolean): {
|
|
4
4
|
dir: string;
|
|
5
5
|
extensionDir: string;
|
package/dist/commands/init.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
-
import { ensureConfigDir, loadConfig, saveConfig } from '../config.js';
|
|
4
|
+
import { ensureConfigDir, loadConfig, saveConfig, resolveDataDir } from '../config.js';
|
|
5
5
|
import { getCliLogger } from '../logger.js';
|
|
6
|
-
/** 对应 ChromePilot init:
|
|
6
|
+
/** 对应 ChromePilot init: 创建数据目录、SQLite、初始 token(目录位置随 dataDir 配置,FID-071) */
|
|
7
7
|
export function runInit(force = false) {
|
|
8
|
-
const
|
|
9
|
-
const ROOT = path.join(HOME, '.hunter-mate');
|
|
8
|
+
const ROOT = resolveDataDir();
|
|
10
9
|
const EXT_DIR = path.join(ROOT, 'extension');
|
|
11
10
|
const DB_FILE = path.join(ROOT, 'hunter-mate.db');
|
|
12
11
|
const SESSIONS_DIR = path.join(ROOT, 'sessions');
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface IssueEnvGitInfo {
|
|
3
|
+
repoRoot: string;
|
|
4
|
+
head: string | null;
|
|
5
|
+
branch: string | null;
|
|
6
|
+
/** 最近一次提交(短 hash + 时间 + subject),与 issue 模板「代码 HEAD」行对应 */
|
|
7
|
+
lastCommit: string | null;
|
|
8
|
+
/** 有未提交改动 = dist 可能滞后于 HEAD,提 issue 必须注明 */
|
|
9
|
+
dirty: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface IssueEnvResult {
|
|
12
|
+
cliVersion: string;
|
|
13
|
+
/** dev = CLI 位于 git 工作区(软链/shim 到源码仓);package = 发布包安装 */
|
|
14
|
+
installType: 'dev' | 'package';
|
|
15
|
+
git: IssueEnvGitInfo | null;
|
|
16
|
+
/** server 未运行时为 null */
|
|
17
|
+
serverBuildTime: string | null;
|
|
18
|
+
os: string;
|
|
19
|
+
node: string;
|
|
20
|
+
dataDir: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function runIssueEnv(): Promise<IssueEnvResult>;
|
|
23
|
+
export declare const issueEnvCommand: Command;
|