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.
- package/dist/cache/db.d.ts +7 -0
- package/dist/cache/db.js +105 -0
- package/dist/commands/addons.d.ts +4 -0
- package/dist/commands/addons.js +378 -0
- package/dist/commands/cache.d.ts +8 -0
- package/dist/commands/cache.js +58 -0
- package/dist/commands/config.d.ts +12 -0
- package/dist/commands/config.js +27 -0
- package/dist/commands/doctor.d.ts +21 -0
- package/dist/commands/doctor.js +332 -0
- package/dist/commands/extension.d.ts +5 -0
- package/dist/commands/extension.js +438 -0
- package/dist/commands/extras.d.ts +10 -0
- package/dist/commands/extras.js +111 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.js +87 -0
- package/dist/commands/install.d.ts +9 -0
- package/dist/commands/install.js +126 -0
- package/dist/commands/job.d.ts +9 -0
- package/dist/commands/job.js +114 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.js +51 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/native-check.d.ts +22 -0
- package/dist/commands/native-check.js +93 -0
- package/dist/commands/ops.d.ts +6 -0
- package/dist/commands/ops.js +330 -0
- package/dist/commands/record.d.ts +12 -0
- package/dist/commands/record.js +96 -0
- package/dist/commands/report.d.ts +7 -0
- package/dist/commands/report.js +54 -0
- package/dist/commands/search.d.ts +14 -0
- package/dist/commands/search.js +46 -0
- package/dist/commands/server.d.ts +23 -0
- package/dist/commands/server.js +232 -0
- package/dist/commands/status.d.ts +20 -0
- package/dist/commands/status.js +92 -0
- package/dist/commands/update.d.ts +8 -0
- package/dist/commands/update.js +161 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +65 -0
- package/dist/i18n/index.d.ts +7 -0
- package/dist/i18n/index.js +24 -0
- package/dist/i18n/locales/en-US.json +35 -0
- package/dist/i18n/locales/zh-CN.json +35 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +133 -0
- package/dist/keychain.d.ts +3 -0
- package/dist/keychain.js +117 -0
- package/dist/sentry.d.ts +3 -0
- package/dist/sentry.js +62 -0
- package/dist/updater.d.ts +23 -0
- package/dist/updater.js +161 -0
- package/dist/version.d.ts +16 -0
- package/dist/version.js +249 -0
- package/package.json +50 -0
|
@@ -0,0 +1,126 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.installCommand = void 0;
|
|
37
|
+
exports.runInstall = runInstall;
|
|
38
|
+
exports.showInstallGuide = showInstallGuide;
|
|
39
|
+
const commander_1 = require("commander");
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const init_1 = require("./init");
|
|
43
|
+
/** 对应 ChromePilot install: 把内置 extension dist 复制到 ~/.hunter-mate/extension */
|
|
44
|
+
function resolveBuiltinExtensionDist() {
|
|
45
|
+
// 约定: monorepo 中 extension dist 与 CLI 包并列 packages/extension/dist
|
|
46
|
+
// 单包发布时则 fallback 到 CLI 包内的 bundled-extension/
|
|
47
|
+
const candidates = [
|
|
48
|
+
path.resolve(__dirname, '../../../extension/dist'), // monorepo: packages/cli/dist/commands -> packages/extension/dist
|
|
49
|
+
path.resolve(__dirname, '../../bundled-extension'), // bundled
|
|
50
|
+
];
|
|
51
|
+
for (const c of candidates)
|
|
52
|
+
if (fs.existsSync(c))
|
|
53
|
+
return c;
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function runInstall(target) {
|
|
57
|
+
const init = (0, init_1.runInit)();
|
|
58
|
+
const targetDir = target ?? init.extensionDir;
|
|
59
|
+
if (!fs.existsSync(targetDir))
|
|
60
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
61
|
+
const source = resolveBuiltinExtensionDist();
|
|
62
|
+
let copied = 0;
|
|
63
|
+
if (source) {
|
|
64
|
+
const copy = (src, dst) => {
|
|
65
|
+
const st = fs.statSync(src);
|
|
66
|
+
if (st.isDirectory()) {
|
|
67
|
+
if (!fs.existsSync(dst))
|
|
68
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
69
|
+
for (const f of fs.readdirSync(src))
|
|
70
|
+
copy(path.join(src, f), path.join(dst, f));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
fs.copyFileSync(src, dst);
|
|
74
|
+
copied++;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
copy(source, targetDir);
|
|
78
|
+
}
|
|
79
|
+
return { source, target: targetDir, copied };
|
|
80
|
+
}
|
|
81
|
+
const B = {
|
|
82
|
+
reset: '\x1b[0m', bold: '\x1b[1m',
|
|
83
|
+
green: '\x1b[32m', yellow: '\x1b[33m', red: '\x1b[31m', cyan: '\x1b[36m', magenta: '\x1b[35m',
|
|
84
|
+
};
|
|
85
|
+
/** 友好引导: 告诉用户如何在 Chrome 中加载 Hunter Mate 扩展 */
|
|
86
|
+
function showInstallGuide(extDir) {
|
|
87
|
+
console.log(`\n${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━ Hunter Mate 扩展安装指引 ━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}`);
|
|
88
|
+
console.log(`\n${B.bold}扩展文件已经准备好:${B.reset}`);
|
|
89
|
+
console.log(` ${B.cyan}${extDir}${B.reset}`);
|
|
90
|
+
console.log(`\n${B.bold}请按以下 5 步在 Chrome 中加载(约 30 秒):${B.reset}\n`);
|
|
91
|
+
console.log(` ${B.magenta}①${B.reset} 打开 Chrome, 地址栏输入: ${B.cyan}chrome://extensions${B.reset}`);
|
|
92
|
+
console.log(` (hunter-mate 已帮你自动打开了这个页面)`);
|
|
93
|
+
console.log(` ${B.magenta}②${B.reset} 右上角打开「${B.bold}开发者模式${B.reset}」开关`);
|
|
94
|
+
console.log(` ${B.magenta}③${B.reset} 点击「${B.bold}加载已解压的扩展程序${B.reset}」按钮`);
|
|
95
|
+
console.log(` ${B.magenta}④${B.reset} 在文件选择框中选择目录: ${B.cyan}${extDir}${B.reset}`);
|
|
96
|
+
console.log(` ${B.magenta}⑤${B.reset} Chrome 工具栏应出现 Hunter Mate 🤝 图标\n`);
|
|
97
|
+
console.log(`${B.bold}${B.yellow}常见问题:${B.reset}`);
|
|
98
|
+
console.log(` · 没看到「加载已解压的扩展程序」? → 先开启「开发者模式」开关`);
|
|
99
|
+
console.log(` · 加载后图标灰显? → 点击图标确认侧栏显示「已连接」`);
|
|
100
|
+
console.log(` · 扩展报权限错误? → chrome://extensions → Hunter Mate → 详情 → 允许访问所有网站`);
|
|
101
|
+
console.log(`\n${B.bold}${B.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${B.reset}\n`);
|
|
102
|
+
}
|
|
103
|
+
exports.installCommand = new commander_1.Command('install')
|
|
104
|
+
.description('把内置 extension dist 复制到 ~/.hunter-mate/extension(对应 chromepilot install)。完成后自动打开目录并给出中文引导。')
|
|
105
|
+
.option('-t, --target <dir>', '目标目录,默认 ~/.hunter-mate/extension')
|
|
106
|
+
.option('--no-open', '不自动打开扩展所在目录')
|
|
107
|
+
.action(async (opts) => {
|
|
108
|
+
const r = runInstall(opts.target);
|
|
109
|
+
if (!r.source) {
|
|
110
|
+
console.log(`${B.yellow}⚠ 未找到内置 extension dist(本仓库 packages/extension 尚未构建)。${B.reset}\n` +
|
|
111
|
+
` 请先在 hunter-mate monorepo 执行:\n` +
|
|
112
|
+
` ${B.bold}pnpm --filter @hunter-mate/extension build${B.reset}\n` +
|
|
113
|
+
` 目标目录已准备好: ${B.cyan}${r.target}${B.reset}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(`${B.green}✓ hunter-mate install OK: ${r.copied} files${B.reset} → ${B.cyan}${r.target}${B.reset}`);
|
|
117
|
+
// 自动打开目录 + 引导
|
|
118
|
+
if (opts.open !== false) {
|
|
119
|
+
try {
|
|
120
|
+
const { default: open } = await Promise.resolve().then(() => __importStar(require('open')));
|
|
121
|
+
open(r.target).catch(() => { });
|
|
122
|
+
}
|
|
123
|
+
catch { }
|
|
124
|
+
}
|
|
125
|
+
showInstallGuide(r.target);
|
|
126
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface CreateJobCaseResult {
|
|
3
|
+
id: number;
|
|
4
|
+
externalId: string;
|
|
5
|
+
status: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function runJobCreate(folderPath: string): Promise<CreateJobCaseResult>;
|
|
8
|
+
export declare function runJobList(): any[];
|
|
9
|
+
export declare const jobCommand: Command;
|
|
@@ -0,0 +1,114 @@
|
|
|
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.jobCommand = void 0;
|
|
40
|
+
exports.runJobCreate = runJobCreate;
|
|
41
|
+
exports.runJobList = runJobList;
|
|
42
|
+
const commander_1 = require("commander");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const axios_1 = __importDefault(require("axios"));
|
|
46
|
+
const uuid_1 = require("uuid");
|
|
47
|
+
const db_1 = require("../cache/db");
|
|
48
|
+
const config_1 = require("../config");
|
|
49
|
+
const keychain_1 = require("../keychain");
|
|
50
|
+
const i18n_1 = require("../i18n");
|
|
51
|
+
async function runJobCreate(folderPath) {
|
|
52
|
+
const config = (0, config_1.loadConfig)();
|
|
53
|
+
const token = await (0, keychain_1.getToken)();
|
|
54
|
+
const headers = token ? { Authorization: `UTOKEN ${token}` } : {};
|
|
55
|
+
const resolved = path.resolve(folderPath);
|
|
56
|
+
if (!fs.existsSync(resolved)) {
|
|
57
|
+
throw new Error(`Folder not found: ${resolved}`);
|
|
58
|
+
}
|
|
59
|
+
const files = fs.readdirSync(resolved).filter((f) => f.endsWith('.md') || f.endsWith('.txt') || f.endsWith('.pdf'));
|
|
60
|
+
const rawFiles = {};
|
|
61
|
+
for (const f of files) {
|
|
62
|
+
rawFiles[f] = fs.readFileSync(path.join(resolved, f), 'utf-8');
|
|
63
|
+
}
|
|
64
|
+
const rawText = Object.values(rawFiles).join('\n---\n');
|
|
65
|
+
const title = Object.keys(rawFiles)[0]?.replace(/\.[^.]+$/, '') || 'Untitled JobCase';
|
|
66
|
+
const res = await axios_1.default.post(`${config.serverUrl}/job-cases`, {
|
|
67
|
+
externalId: (0, uuid_1.v4)(),
|
|
68
|
+
title,
|
|
69
|
+
folderPath: resolved,
|
|
70
|
+
rawFiles,
|
|
71
|
+
}, { headers, proxy: false });
|
|
72
|
+
const serverCase = res.data;
|
|
73
|
+
(0, db_1.ensureCacheDir)();
|
|
74
|
+
const jobCase = {
|
|
75
|
+
id: serverCase.id,
|
|
76
|
+
externalId: serverCase.externalId,
|
|
77
|
+
parsedFrom: {
|
|
78
|
+
folderPath: resolved,
|
|
79
|
+
fileNames: files.join(','),
|
|
80
|
+
rawText,
|
|
81
|
+
},
|
|
82
|
+
requirements: {},
|
|
83
|
+
recommendedCandidates: [],
|
|
84
|
+
status: serverCase.status,
|
|
85
|
+
createdAt: Date.now(),
|
|
86
|
+
};
|
|
87
|
+
(0, db_1.saveJobCase)(jobCase);
|
|
88
|
+
return serverCase;
|
|
89
|
+
}
|
|
90
|
+
function runJobList() {
|
|
91
|
+
return (0, db_1.listJobCases)();
|
|
92
|
+
}
|
|
93
|
+
exports.jobCommand = new commander_1.Command('job')
|
|
94
|
+
.description(i18n_1.i18n.t('job.description'));
|
|
95
|
+
exports.jobCommand
|
|
96
|
+
.command('create <folder>')
|
|
97
|
+
.description(i18n_1.i18n.t('job.create'))
|
|
98
|
+
.action(async (folderPath) => {
|
|
99
|
+
try {
|
|
100
|
+
const serverCase = await runJobCreate(folderPath);
|
|
101
|
+
console.log(`Created JobCase ${serverCase.id} (${serverCase.externalId})`);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error('Failed to create JobCase:', err.response?.data?.message || err.message);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
exports.jobCommand
|
|
109
|
+
.command('list')
|
|
110
|
+
.description('List local JobCases')
|
|
111
|
+
.action(() => {
|
|
112
|
+
const cases = runJobList();
|
|
113
|
+
console.table(cases.map((c) => ({ id: c.id, folder: c.parsedFrom?.folderPath, status: c.status, createdAt: c.createdAt })));
|
|
114
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loginCommand = void 0;
|
|
7
|
+
exports.runLogin = runLogin;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const open_1 = __importDefault(require("open"));
|
|
11
|
+
const config_1 = require("../config");
|
|
12
|
+
const keychain_1 = require("../keychain");
|
|
13
|
+
const i18n_1 = require("../i18n");
|
|
14
|
+
function sleep(ms) {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
+
}
|
|
17
|
+
async function runLogin() {
|
|
18
|
+
const config = (0, config_1.loadConfig)();
|
|
19
|
+
const { data: deviceCode } = await axios_1.default.post(`${config.serverUrl}/auth/device-code`);
|
|
20
|
+
console.log(i18n_1.i18n.t('login.userCode'), deviceCode.user_code);
|
|
21
|
+
console.log(i18n_1.i18n.t('login.verifyUrl'), deviceCode.verification_uri);
|
|
22
|
+
await (0, open_1.default)(deviceCode.verification_uri);
|
|
23
|
+
const maxAttempts = Math.ceil(deviceCode.expires_in / deviceCode.interval);
|
|
24
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
25
|
+
await sleep(deviceCode.interval * 1000);
|
|
26
|
+
const { data } = await axios_1.default.post(`${config.serverUrl}/auth/token`, {
|
|
27
|
+
deviceCode: deviceCode.device_code,
|
|
28
|
+
});
|
|
29
|
+
if (data.access_token) {
|
|
30
|
+
await (0, keychain_1.saveToken)(data.access_token);
|
|
31
|
+
return data.access_token;
|
|
32
|
+
}
|
|
33
|
+
if (data.status === 'expired') {
|
|
34
|
+
throw new Error(i18n_1.i18n.t('login.expired'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw new Error(i18n_1.i18n.t('login.expired'));
|
|
38
|
+
}
|
|
39
|
+
exports.loginCommand = new commander_1.Command('login')
|
|
40
|
+
.description(i18n_1.i18n.t('login.description'))
|
|
41
|
+
.action(async () => {
|
|
42
|
+
try {
|
|
43
|
+
console.log(i18n_1.i18n.t('login.start'));
|
|
44
|
+
await runLogin();
|
|
45
|
+
console.log(i18n_1.i18n.t('login.success'));
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
console.error(i18n_1.i18n.t('login.failed'), err.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logoutCommand = void 0;
|
|
4
|
+
exports.runLogout = runLogout;
|
|
5
|
+
const commander_1 = require("commander");
|
|
6
|
+
const keychain_1 = require("../keychain");
|
|
7
|
+
const i18n_1 = require("../i18n");
|
|
8
|
+
async function runLogout() {
|
|
9
|
+
await (0, keychain_1.deleteToken)();
|
|
10
|
+
}
|
|
11
|
+
exports.logoutCommand = new commander_1.Command('logout')
|
|
12
|
+
.description(i18n_1.i18n.t('logout.description'))
|
|
13
|
+
.action(async () => {
|
|
14
|
+
await runLogout();
|
|
15
|
+
console.log(i18n_1.i18n.t('logout.success'));
|
|
16
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原生模块(node-gyp)ABI 自检 — 与 chromepilot packages/cli/src/native-check.ts 同源逻辑。
|
|
3
|
+
*
|
|
4
|
+
* 背景:better-sqlite3 等原生模块按编译时的 Node ABI 版本绑定
|
|
5
|
+
* (Node 22=127, 23=131, 24=137, 25=138, 26=147)。
|
|
6
|
+
* 换 node 版本后 server 起来即崩(dlopen 失败),且后台 spawn 会吞掉报错,
|
|
7
|
+
* 表现为"自动启动超时, server 仍不可达"。
|
|
8
|
+
*
|
|
9
|
+
* 注意:仅 require 不触发 dlopen,必须 new Database 真验证。
|
|
10
|
+
*/
|
|
11
|
+
export interface NativeModuleStatus {
|
|
12
|
+
module: string;
|
|
13
|
+
status: 'ok' | 'fail' | 'skip';
|
|
14
|
+
detail: string;
|
|
15
|
+
compiledAbi?: number;
|
|
16
|
+
currentAbi?: number;
|
|
17
|
+
hint?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function checkNativeModules(): {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
modules: NativeModuleStatus[];
|
|
22
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkNativeModules = checkNativeModules;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const module_1 = require("module");
|
|
10
|
+
const ABI_NODE_MAP = {
|
|
11
|
+
127: 'Node 22',
|
|
12
|
+
131: 'Node 23',
|
|
13
|
+
137: 'Node 24',
|
|
14
|
+
138: 'Node 25',
|
|
15
|
+
147: 'Node 26',
|
|
16
|
+
};
|
|
17
|
+
function parseAbis(message) {
|
|
18
|
+
const compiled = /compiled against a different Node\.js version using\s+NODE_MODULE_VERSION (\d+)/.exec(message);
|
|
19
|
+
const current = /requires\s+NODE_MODULE_VERSION (\d+)/.exec(message);
|
|
20
|
+
return {
|
|
21
|
+
compiled: compiled ? Number(compiled[1]) : undefined,
|
|
22
|
+
current: current ? Number(current[1]) : undefined,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** 与 commands/server.ts 同源定位:server 包根(dist 优先,src 兜底) */
|
|
26
|
+
function locateServerEntryDir() {
|
|
27
|
+
const candidates = [
|
|
28
|
+
path_1.default.resolve(__dirname, '../../../server/dist'),
|
|
29
|
+
path_1.default.resolve(__dirname, '../../../server/src'),
|
|
30
|
+
];
|
|
31
|
+
for (const dir of candidates) {
|
|
32
|
+
if (fs_1.default.existsSync(path_1.default.join(dir, 'main.js')) || fs_1.default.existsSync(path_1.default.join(dir, 'main.ts'))) {
|
|
33
|
+
return dir;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function checkNativeModules() {
|
|
39
|
+
const entryDir = locateServerEntryDir();
|
|
40
|
+
if (!entryDir) {
|
|
41
|
+
return {
|
|
42
|
+
ok: true,
|
|
43
|
+
modules: [
|
|
44
|
+
{
|
|
45
|
+
module: 'better-sqlite3',
|
|
46
|
+
status: 'skip',
|
|
47
|
+
detail: '未找到 server 入口(packages/server/dist|src),跳过原生模块检查',
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const req = (0, module_1.createRequire)(path_1.default.join(entryDir, '__probe__.js'));
|
|
53
|
+
const modules = [];
|
|
54
|
+
try {
|
|
55
|
+
// 真验证:new Database(':memory:') 才触发 dlopen
|
|
56
|
+
const Database = req('better-sqlite3');
|
|
57
|
+
const db = new Database(':memory:');
|
|
58
|
+
db.close();
|
|
59
|
+
modules.push({ module: 'better-sqlite3', status: 'ok', detail: `加载正常 (node ${process.version}, 入口 ${entryDir})` });
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
const msg = String(e?.message ?? e);
|
|
63
|
+
if (/Cannot find module/.test(msg)) {
|
|
64
|
+
modules.push({
|
|
65
|
+
module: 'better-sqlite3',
|
|
66
|
+
status: 'skip',
|
|
67
|
+
detail: `无法从 server 入口解析到依赖(未安装?),跳过。pnpm install 后再试`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const { compiled, current } = parseAbis(msg);
|
|
72
|
+
if (compiled && current) {
|
|
73
|
+
modules.push({
|
|
74
|
+
module: 'better-sqlite3',
|
|
75
|
+
status: 'fail',
|
|
76
|
+
detail: `ABI 不匹配:编译于 ${ABI_NODE_MAP[compiled] ?? 'ABI ' + compiled}(${compiled}),当前 node ${process.version} 是 ${ABI_NODE_MAP[current] ?? 'ABI ' + current}(${current})`,
|
|
77
|
+
compiledAbi: compiled,
|
|
78
|
+
currentAbi: current,
|
|
79
|
+
hint: `二选一:① 切回 ${ABI_NODE_MAP[compiled] ?? '编译时'} 的 node;② 用当前 node 重编: pnpm rebuild -r better-sqlite3(重编后重启 server)。详见 TROUBLESHOOTING.md#server-启动即崩abi`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
modules.push({
|
|
84
|
+
module: 'better-sqlite3',
|
|
85
|
+
status: 'fail',
|
|
86
|
+
detail: msg.slice(0, 200),
|
|
87
|
+
hint: '尝试重装依赖: pnpm install。详见 TROUBLESHOOTING.md',
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { ok: modules.every((m) => m.status !== 'fail'), modules };
|
|
93
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare const recordingsCommand: Command;
|
|
3
|
+
export declare const adapterCommand: Command;
|
|
4
|
+
export declare const memoryCommand: Command;
|
|
5
|
+
export declare const traceCommand: Command;
|
|
6
|
+
export declare const autofixCommand: Command;
|