@reconcrap/boss-recommend-mcp 1.3.32 → 1.3.33
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/config/screening-config.example.json +11 -11
- package/package.json +64 -64
- package/src/boss-chat.js +769 -769
- package/src/test-adapters-runtime.js +628 -628
- package/src/test-boss-chat.js +2716 -2227
- package/vendor/boss-chat-cli/src/app.js +1435 -1268
- package/vendor/boss-chat-cli/src/browser/chat-page.js +412 -242
- package/vendor/boss-chat-cli/src/cli.js +1580 -1580
- package/vendor/boss-chat-cli/src/services/chrome-client.js +103 -103
- package/vendor/boss-chat-cli/src/services/llm.js +1146 -810
- package/vendor/boss-chat-cli/src/services/llm.test.js +326 -0
- package/vendor/boss-chat-cli/src/services/profile-store.js +168 -168
- package/vendor/boss-chat-cli/src/services/report-store.js +317 -317
- package/vendor/boss-chat-cli/src/services/resume-capture.js +469 -469
- package/vendor/boss-chat-cli/src/services/resume-network.js +727 -727
- package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +6660 -6272
- package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +429 -31
|
@@ -1,628 +1,628 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
ensureFeaturedCalibrationReady,
|
|
7
|
-
runPipelinePreflight,
|
|
8
|
-
runRecommendSearchCli,
|
|
9
|
-
runRecommendScreenCli,
|
|
10
|
-
resolveSharedLlmTransportConfig,
|
|
11
|
-
__testables as adapterTestables
|
|
12
|
-
} from "./adapters.js";
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
runProcess,
|
|
16
|
-
parseJsonOutput,
|
|
17
|
-
parseScreenProgressLine,
|
|
18
|
-
resolveRecommendScreenTimeoutMs,
|
|
19
|
-
buildRecommendScreenProcessError
|
|
20
|
-
} = adapterTestables;
|
|
21
|
-
|
|
22
|
-
async function testRunProcessHeartbeatAndOutput() {
|
|
23
|
-
const heartbeats = [];
|
|
24
|
-
const lines = [];
|
|
25
|
-
const result = await runProcess({
|
|
26
|
-
command: "node",
|
|
27
|
-
args: [
|
|
28
|
-
"-e",
|
|
29
|
-
"let i=0; const t=setInterval(()=>{console.error(`tick ${++i}`); if(i===3){clearInterval(t); console.log('{\"status\":\"COMPLETED\"}');}}, 120);"
|
|
30
|
-
],
|
|
31
|
-
timeoutMs: 5000,
|
|
32
|
-
heartbeatIntervalMs: 40,
|
|
33
|
-
onHeartbeat: (event) => {
|
|
34
|
-
heartbeats.push(event?.source || "unknown");
|
|
35
|
-
},
|
|
36
|
-
onLine: (event) => {
|
|
37
|
-
lines.push(event?.line || "");
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
assert.equal(result.code, 0);
|
|
42
|
-
assert.equal(result.error_code, undefined);
|
|
43
|
-
assert.equal(heartbeats.length >= 3, true);
|
|
44
|
-
assert.equal(lines.some((line) => line.includes("tick 1")), true);
|
|
45
|
-
assert.equal(lines.some((line) => line.includes("\"status\":\"COMPLETED\"")), true);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function testRunProcessAbortSignal() {
|
|
49
|
-
const controller = new AbortController();
|
|
50
|
-
setTimeout(() => controller.abort(), 120);
|
|
51
|
-
|
|
52
|
-
const result = await runProcess({
|
|
53
|
-
command: "node",
|
|
54
|
-
args: ["-e", "setTimeout(() => console.log('done'), 5000);"],
|
|
55
|
-
timeoutMs: 6000,
|
|
56
|
-
signal: controller.signal
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
assert.equal(result.code, -1);
|
|
60
|
-
assert.equal(result.error_code, "ABORTED");
|
|
61
|
-
assert.equal(String(result.stderr || "").includes("aborted"), true);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function testParsePausedStructuredOutput() {
|
|
65
|
-
const parsed = parseJsonOutput(`
|
|
66
|
-
[log] doing work
|
|
67
|
-
{"status":"PAUSED","result":{"processed_count":3,"output_csv":"C:/tmp/test.csv"}}
|
|
68
|
-
`);
|
|
69
|
-
assert.equal(parsed?.status, "PAUSED");
|
|
70
|
-
assert.equal(parsed?.result?.processed_count, 3);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function testParseScreenProgressLineShouldCountFavoriteFailureAsSkipped() {
|
|
74
|
-
let progress = { processed: 0, passed: 0, skipped: 0, greet_count: 0 };
|
|
75
|
-
let tracker = {};
|
|
76
|
-
const feed = (line) => {
|
|
77
|
-
const parsed = parseScreenProgressLine(line, progress, tracker);
|
|
78
|
-
if (!parsed) return;
|
|
79
|
-
progress = parsed.progress;
|
|
80
|
-
tracker = parsed.tracker;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
feed("处理第 1 位候选人: 甲");
|
|
84
|
-
feed("筛选结果: 通过");
|
|
85
|
-
feed("[关闭详情] 成功: no popup or detail signal visible");
|
|
86
|
-
feed("处理第 2 位候选人: 乙");
|
|
87
|
-
feed("筛选结果: 通过");
|
|
88
|
-
feed("候选人处理失败: FAVORITE_BUTTON_FAILED");
|
|
89
|
-
feed("[关闭详情] 成功: no popup or detail signal visible");
|
|
90
|
-
|
|
91
|
-
assert.equal(progress.processed, 2);
|
|
92
|
-
assert.equal(progress.passed, 1);
|
|
93
|
-
assert.equal(progress.skipped, 1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function testResolveScreenTimeoutDefaultsTo24Hours() {
|
|
97
|
-
const previous = process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
98
|
-
delete process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
99
|
-
try {
|
|
100
|
-
assert.equal(resolveRecommendScreenTimeoutMs(null), 24 * 60 * 60 * 1000);
|
|
101
|
-
assert.equal(resolveRecommendScreenTimeoutMs({ timeoutMs: 1234 }), 1234);
|
|
102
|
-
} finally {
|
|
103
|
-
if (previous === undefined) {
|
|
104
|
-
delete process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
105
|
-
} else {
|
|
106
|
-
process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS = previous;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides() {
|
|
112
|
-
assert.deepEqual(resolveSharedLlmTransportConfig({}), {
|
|
113
|
-
llmTimeoutMs: 60000,
|
|
114
|
-
llmMaxRetries: 3,
|
|
115
|
-
});
|
|
116
|
-
assert.deepEqual(
|
|
117
|
-
resolveSharedLlmTransportConfig({
|
|
118
|
-
llmTimeoutMs: 90000,
|
|
119
|
-
llmMaxRetries: 5,
|
|
120
|
-
}),
|
|
121
|
-
{
|
|
122
|
-
llmTimeoutMs: 90000,
|
|
123
|
-
llmMaxRetries: 5,
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function testBuildRecommendScreenProcessErrorMapsTimeout() {
|
|
129
|
-
const error = buildRecommendScreenProcessError({ code: -1, error_code: "TIMEOUT" }, 86400000);
|
|
130
|
-
assert.equal(error?.code, "TIMEOUT");
|
|
131
|
-
assert.equal(String(error?.message || "").includes("86400000"), true);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async function testResumeRequiresCheckpointFile() {
|
|
135
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
136
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-resume-"));
|
|
137
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
138
|
-
try {
|
|
139
|
-
const configPath = path.join(tempHome, "screening-config.json");
|
|
140
|
-
fs.writeFileSync(configPath, JSON.stringify({
|
|
141
|
-
baseUrl: "https://api.openai.com/v1",
|
|
142
|
-
apiKey: "sk-test-valid",
|
|
143
|
-
model: "gpt-4.1-mini"
|
|
144
|
-
}, null, 2));
|
|
145
|
-
|
|
146
|
-
const missingCheckpoint = path.join(tempHome, "missing-checkpoint.json");
|
|
147
|
-
const result = await runRecommendScreenCli({
|
|
148
|
-
workspaceRoot: process.cwd(),
|
|
149
|
-
screenParams: {
|
|
150
|
-
criteria: "有MCP经验",
|
|
151
|
-
target_count: 10,
|
|
152
|
-
post_action: "favorite",
|
|
153
|
-
max_greet_count: null
|
|
154
|
-
},
|
|
155
|
-
resume: {
|
|
156
|
-
resume: true,
|
|
157
|
-
require_checkpoint: true,
|
|
158
|
-
checkpoint_path: missingCheckpoint,
|
|
159
|
-
pause_control_path: path.join(tempHome, "run-state.json"),
|
|
160
|
-
output_csv: path.join(tempHome, "resume.csv")
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
assert.equal(result.ok, false);
|
|
165
|
-
assert.equal(result.error?.code, "RESUME_CHECKPOINT_MISSING");
|
|
166
|
-
} finally {
|
|
167
|
-
if (previousHome === undefined) {
|
|
168
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
169
|
-
} else {
|
|
170
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
171
|
-
}
|
|
172
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async function testRecommendScreenCliShouldPassSharedLlmTransportArgs() {
|
|
177
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-stub-"));
|
|
178
|
-
const screenDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
179
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-home-"));
|
|
180
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
181
|
-
fs.mkdirSync(screenDir, { recursive: true });
|
|
182
|
-
fs.writeFileSync(
|
|
183
|
-
path.join(screenDir, "boss-recommend-screen-cli.cjs"),
|
|
184
|
-
[
|
|
185
|
-
"#!/usr/bin/env node",
|
|
186
|
-
"const fs = require('node:fs');",
|
|
187
|
-
"const path = require('node:path');",
|
|
188
|
-
"const argv = process.argv.slice(2);",
|
|
189
|
-
"const parsed = {};",
|
|
190
|
-
"for (let i = 0; i < argv.length; i += 1) {",
|
|
191
|
-
" const token = argv[i];",
|
|
192
|
-
" if (!token.startsWith('--')) continue;",
|
|
193
|
-
" const next = argv[i + 1];",
|
|
194
|
-
" parsed[token.slice(2)] = next && !next.startsWith('--') ? next : true;",
|
|
195
|
-
" if (next && !next.startsWith('--')) i += 1;",
|
|
196
|
-
"}",
|
|
197
|
-
"const output = path.join(process.env.BOSS_RECOMMEND_HOME, 'screen-cli-args.json');",
|
|
198
|
-
"fs.writeFileSync(output, JSON.stringify(parsed, null, 2));",
|
|
199
|
-
"console.log(JSON.stringify({ status: 'COMPLETED', result: { processed_count: 0, output_csv: parsed.output || '' } }));",
|
|
200
|
-
].join("\n"),
|
|
201
|
-
"utf8",
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
205
|
-
fs.writeFileSync(
|
|
206
|
-
path.join(tempHome, "screening-config.json"),
|
|
207
|
-
JSON.stringify(
|
|
208
|
-
{
|
|
209
|
-
baseUrl: "https://api.openai.com/v1",
|
|
210
|
-
apiKey: "sk-valid-test",
|
|
211
|
-
model: "gpt-4.1-mini",
|
|
212
|
-
llmTimeoutMs: 75000,
|
|
213
|
-
llmMaxRetries: 6,
|
|
214
|
-
},
|
|
215
|
-
null,
|
|
216
|
-
2,
|
|
217
|
-
),
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
const result = await runRecommendScreenCli({
|
|
222
|
-
workspaceRoot,
|
|
223
|
-
screenParams: {
|
|
224
|
-
criteria: "有 MCP 经验",
|
|
225
|
-
target_count: null,
|
|
226
|
-
post_action: "none",
|
|
227
|
-
max_greet_count: null,
|
|
228
|
-
},
|
|
229
|
-
pageScope: "recommend",
|
|
230
|
-
});
|
|
231
|
-
assert.equal(result.ok, true);
|
|
232
|
-
const parsed = JSON.parse(fs.readFileSync(path.join(tempHome, "screen-cli-args.json"), "utf8"));
|
|
233
|
-
assert.equal(parsed["llm-timeout-ms"], "75000");
|
|
234
|
-
assert.equal(parsed["llm-max-retries"], "6");
|
|
235
|
-
} finally {
|
|
236
|
-
if (previousHome === undefined) {
|
|
237
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
238
|
-
} else {
|
|
239
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
240
|
-
}
|
|
241
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
242
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function testPreflightShouldCheckSharpInsteadOfPython() {
|
|
247
|
-
const preflight = runPipelinePreflight(process.cwd());
|
|
248
|
-
const keys = new Set((preflight.checks || []).map((item) => item?.key));
|
|
249
|
-
assert.equal(keys.has("npm_dep_sharp"), true);
|
|
250
|
-
assert.equal(keys.has("python_cli"), false);
|
|
251
|
-
assert.equal(keys.has("python_pillow"), false);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function testPreflightFeaturedShouldRequireFavoriteCalibration() {
|
|
255
|
-
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "featured" });
|
|
256
|
-
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
257
|
-
assert.equal(Boolean(check), true);
|
|
258
|
-
assert.equal(check.optional, false);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function testPreflightRecommendShouldKeepFavoriteCalibrationOptional() {
|
|
262
|
-
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "recommend" });
|
|
263
|
-
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
264
|
-
assert.equal(Boolean(check), true);
|
|
265
|
-
assert.equal(check.optional, true);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function testPreflightLatestShouldKeepFavoriteCalibrationOptional() {
|
|
269
|
-
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "latest" });
|
|
270
|
-
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
271
|
-
assert.equal(Boolean(check), true);
|
|
272
|
-
assert.equal(check.optional, true);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async function testEnsureFeaturedCalibrationReadyShouldAutoCalibrate() {
|
|
276
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
277
|
-
const previousCodexHome = process.env.CODEX_HOME;
|
|
278
|
-
const previousScript = process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT;
|
|
279
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-featured-cal-home-"));
|
|
280
|
-
const tempCodex = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-featured-cal-codex-"));
|
|
281
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
282
|
-
process.env.CODEX_HOME = tempCodex;
|
|
283
|
-
|
|
284
|
-
const configPath = path.join(tempHome, "screening-config.json");
|
|
285
|
-
const scriptPath = path.join(tempHome, "fake-calibrate.cjs");
|
|
286
|
-
fs.writeFileSync(configPath, JSON.stringify({
|
|
287
|
-
baseUrl: "https://api.openai.com/v1",
|
|
288
|
-
apiKey: "sk-valid",
|
|
289
|
-
model: "gpt-4.1-mini",
|
|
290
|
-
calibrationFile: "favorite-calibration.json"
|
|
291
|
-
}, null, 2));
|
|
292
|
-
fs.writeFileSync(scriptPath, [
|
|
293
|
-
"#!/usr/bin/env node",
|
|
294
|
-
"const fs = require('node:fs');",
|
|
295
|
-
"const path = require('node:path');",
|
|
296
|
-
"const args = process.argv.slice(2).reduce((acc, token, idx, arr) => {",
|
|
297
|
-
" if (token.startsWith('--')) {",
|
|
298
|
-
" const key = token.slice(2);",
|
|
299
|
-
" const next = arr[idx + 1];",
|
|
300
|
-
" acc[key] = next && !next.startsWith('--') ? next : true;",
|
|
301
|
-
" }",
|
|
302
|
-
" return acc;",
|
|
303
|
-
"}, {});",
|
|
304
|
-
"const output = path.resolve(String(args.output || 'favorite-calibration.json'));",
|
|
305
|
-
"fs.mkdirSync(path.dirname(output), { recursive: true });",
|
|
306
|
-
"fs.writeFileSync(output, JSON.stringify({ favoritePosition: { pageX: 100, pageY: 200, canvasX: 0, canvasY: 0 } }, null, 2));",
|
|
307
|
-
"console.log('calibrated');"
|
|
308
|
-
].join("\n"), "utf8");
|
|
309
|
-
process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT = scriptPath;
|
|
310
|
-
|
|
311
|
-
try {
|
|
312
|
-
const result = await ensureFeaturedCalibrationReady(process.cwd(), {
|
|
313
|
-
port: 9222,
|
|
314
|
-
timeoutMs: 5000
|
|
315
|
-
});
|
|
316
|
-
assert.equal(result.ok, true);
|
|
317
|
-
assert.equal(result.auto_started, true);
|
|
318
|
-
assert.equal(String(result.calibration_path || "").endsWith("favorite-calibration.json"), true);
|
|
319
|
-
assert.equal(fs.existsSync(result.calibration_path), true);
|
|
320
|
-
} finally {
|
|
321
|
-
if (previousHome === undefined) {
|
|
322
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
323
|
-
} else {
|
|
324
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
325
|
-
}
|
|
326
|
-
if (previousCodexHome === undefined) {
|
|
327
|
-
delete process.env.CODEX_HOME;
|
|
328
|
-
} else {
|
|
329
|
-
process.env.CODEX_HOME = previousCodexHome;
|
|
330
|
-
}
|
|
331
|
-
if (previousScript === undefined) {
|
|
332
|
-
delete process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT;
|
|
333
|
-
} else {
|
|
334
|
-
process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT = previousScript;
|
|
335
|
-
}
|
|
336
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
337
|
-
fs.rmSync(tempCodex, { recursive: true, force: true });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async function testSearchCliShouldPassPageScopeArgument() {
|
|
342
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-search-page-scope-"));
|
|
343
|
-
const cliDir = path.join(workspaceRoot, "boss-recommend-search-cli", "src");
|
|
344
|
-
fs.mkdirSync(cliDir, { recursive: true });
|
|
345
|
-
const cliPath = path.join(cliDir, "cli.js");
|
|
346
|
-
fs.writeFileSync(
|
|
347
|
-
cliPath,
|
|
348
|
-
[
|
|
349
|
-
"#!/usr/bin/env node",
|
|
350
|
-
"console.log(JSON.stringify({ status: 'COMPLETED', result: { argv: process.argv.slice(2) } }));"
|
|
351
|
-
].join("\n"),
|
|
352
|
-
"utf8"
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
try {
|
|
356
|
-
const result = await runRecommendSearchCli({
|
|
357
|
-
workspaceRoot,
|
|
358
|
-
searchParams: {
|
|
359
|
-
school_tag: ["不限"],
|
|
360
|
-
degree: ["不限"],
|
|
361
|
-
gender: "不限",
|
|
362
|
-
recent_not_view: "不限"
|
|
363
|
-
},
|
|
364
|
-
selectedJob: null,
|
|
365
|
-
pageScope: "featured"
|
|
366
|
-
});
|
|
367
|
-
assert.equal(result.ok, true);
|
|
368
|
-
const argv = result.summary?.argv || [];
|
|
369
|
-
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
370
|
-
assert.equal(pageScopeIndex >= 0, true);
|
|
371
|
-
assert.equal(argv[pageScopeIndex + 1], "featured");
|
|
372
|
-
const calibrationIndex = argv.indexOf("--calibration");
|
|
373
|
-
assert.equal(calibrationIndex >= 0, true);
|
|
374
|
-
assert.equal(String(argv[calibrationIndex + 1] || "").includes("favorite-calibration.json"), true);
|
|
375
|
-
} finally {
|
|
376
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async function testSearchCliShouldPassLatestPageScopeWithoutCalibration() {
|
|
381
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-search-page-scope-latest-"));
|
|
382
|
-
const cliDir = path.join(workspaceRoot, "boss-recommend-search-cli", "src");
|
|
383
|
-
fs.mkdirSync(cliDir, { recursive: true });
|
|
384
|
-
const cliPath = path.join(cliDir, "cli.js");
|
|
385
|
-
fs.writeFileSync(
|
|
386
|
-
cliPath,
|
|
387
|
-
[
|
|
388
|
-
"#!/usr/bin/env node",
|
|
389
|
-
"console.log(JSON.stringify({ status: 'COMPLETED', result: { argv: process.argv.slice(2) } }));"
|
|
390
|
-
].join("\n"),
|
|
391
|
-
"utf8"
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
try {
|
|
395
|
-
const result = await runRecommendSearchCli({
|
|
396
|
-
workspaceRoot,
|
|
397
|
-
searchParams: {
|
|
398
|
-
school_tag: ["不限"],
|
|
399
|
-
degree: ["不限"],
|
|
400
|
-
gender: "不限",
|
|
401
|
-
recent_not_view: "不限"
|
|
402
|
-
},
|
|
403
|
-
selectedJob: null,
|
|
404
|
-
pageScope: "latest"
|
|
405
|
-
});
|
|
406
|
-
assert.equal(result.ok, true);
|
|
407
|
-
const argv = result.summary?.argv || [];
|
|
408
|
-
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
409
|
-
assert.equal(pageScopeIndex >= 0, true);
|
|
410
|
-
assert.equal(argv[pageScopeIndex + 1], "latest");
|
|
411
|
-
assert.equal(argv.includes("--calibration"), false);
|
|
412
|
-
} finally {
|
|
413
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
async function testScreenCliShouldPassPageScopeArgument() {
|
|
418
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
419
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-home-"));
|
|
420
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-workspace-"));
|
|
421
|
-
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
422
|
-
fs.mkdirSync(cliDir, { recursive: true });
|
|
423
|
-
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
424
|
-
fs.writeFileSync(
|
|
425
|
-
cliPath,
|
|
426
|
-
[
|
|
427
|
-
"#!/usr/bin/env node",
|
|
428
|
-
"console.log(JSON.stringify({",
|
|
429
|
-
" status: 'COMPLETED',",
|
|
430
|
-
" result: {",
|
|
431
|
-
" processed_count: 0,",
|
|
432
|
-
" passed_count: 0,",
|
|
433
|
-
" skipped_count: 0,",
|
|
434
|
-
" argv: process.argv.slice(2),",
|
|
435
|
-
" resume_source: 'network',",
|
|
436
|
-
" active_tab_status: '3'",
|
|
437
|
-
" }",
|
|
438
|
-
"}));"
|
|
439
|
-
].join("\n"),
|
|
440
|
-
"utf8"
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
444
|
-
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
445
|
-
baseUrl: "https://api.openai.com/v1",
|
|
446
|
-
apiKey: "sk-valid-test",
|
|
447
|
-
model: "gpt-4.1-mini"
|
|
448
|
-
}, null, 2));
|
|
449
|
-
|
|
450
|
-
try {
|
|
451
|
-
const result = await runRecommendScreenCli({
|
|
452
|
-
workspaceRoot,
|
|
453
|
-
screenParams: {
|
|
454
|
-
criteria: "有 MCP 经验",
|
|
455
|
-
target_count: null,
|
|
456
|
-
post_action: "none",
|
|
457
|
-
max_greet_count: null
|
|
458
|
-
},
|
|
459
|
-
pageScope: "featured"
|
|
460
|
-
});
|
|
461
|
-
assert.equal(result.ok, true);
|
|
462
|
-
const argv = result.summary?.argv || [];
|
|
463
|
-
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
464
|
-
assert.equal(pageScopeIndex >= 0, true);
|
|
465
|
-
assert.equal(argv[pageScopeIndex + 1], "featured");
|
|
466
|
-
} finally {
|
|
467
|
-
if (previousHome === undefined) {
|
|
468
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
469
|
-
} else {
|
|
470
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
471
|
-
}
|
|
472
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
473
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
async function testScreenCliShouldPassLatestPageScopeArgument() {
|
|
478
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
479
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-latest-home-"));
|
|
480
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-latest-workspace-"));
|
|
481
|
-
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
482
|
-
fs.mkdirSync(cliDir, { recursive: true });
|
|
483
|
-
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
484
|
-
fs.writeFileSync(
|
|
485
|
-
cliPath,
|
|
486
|
-
[
|
|
487
|
-
"#!/usr/bin/env node",
|
|
488
|
-
"console.log(JSON.stringify({",
|
|
489
|
-
" status: 'COMPLETED',",
|
|
490
|
-
" result: {",
|
|
491
|
-
" processed_count: 0,",
|
|
492
|
-
" passed_count: 0,",
|
|
493
|
-
" skipped_count: 0,",
|
|
494
|
-
" argv: process.argv.slice(2),",
|
|
495
|
-
" resume_source: 'image_fallback',",
|
|
496
|
-
" active_tab_status: '1'",
|
|
497
|
-
" }",
|
|
498
|
-
"}));"
|
|
499
|
-
].join("\n"),
|
|
500
|
-
"utf8"
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
504
|
-
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
505
|
-
baseUrl: "https://api.openai.com/v1",
|
|
506
|
-
apiKey: "sk-valid-test",
|
|
507
|
-
model: "gpt-4.1-mini"
|
|
508
|
-
}, null, 2));
|
|
509
|
-
|
|
510
|
-
try {
|
|
511
|
-
const result = await runRecommendScreenCli({
|
|
512
|
-
workspaceRoot,
|
|
513
|
-
screenParams: {
|
|
514
|
-
criteria: "有 MCP 经验",
|
|
515
|
-
target_count: null,
|
|
516
|
-
post_action: "none",
|
|
517
|
-
max_greet_count: null
|
|
518
|
-
},
|
|
519
|
-
pageScope: "latest"
|
|
520
|
-
});
|
|
521
|
-
assert.equal(result.ok, true);
|
|
522
|
-
const argv = result.summary?.argv || [];
|
|
523
|
-
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
524
|
-
assert.equal(pageScopeIndex >= 0, true);
|
|
525
|
-
assert.equal(argv[pageScopeIndex + 1], "latest");
|
|
526
|
-
} finally {
|
|
527
|
-
if (previousHome === undefined) {
|
|
528
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
529
|
-
} else {
|
|
530
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
531
|
-
}
|
|
532
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
533
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
async function testScreenCliShouldPassInputSummaryArgument() {
|
|
538
|
-
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
539
|
-
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-input-summary-home-"));
|
|
540
|
-
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-input-summary-workspace-"));
|
|
541
|
-
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
542
|
-
fs.mkdirSync(cliDir, { recursive: true });
|
|
543
|
-
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
544
|
-
fs.writeFileSync(
|
|
545
|
-
cliPath,
|
|
546
|
-
[
|
|
547
|
-
"#!/usr/bin/env node",
|
|
548
|
-
"console.log(JSON.stringify({",
|
|
549
|
-
" status: 'COMPLETED',",
|
|
550
|
-
" result: {",
|
|
551
|
-
" processed_count: 0,",
|
|
552
|
-
" passed_count: 0,",
|
|
553
|
-
" skipped_count: 0,",
|
|
554
|
-
" argv: process.argv.slice(2),",
|
|
555
|
-
" resume_source: 'network',",
|
|
556
|
-
" active_tab_status: '0'",
|
|
557
|
-
" }",
|
|
558
|
-
"}));"
|
|
559
|
-
].join("\n"),
|
|
560
|
-
"utf8"
|
|
561
|
-
);
|
|
562
|
-
|
|
563
|
-
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
564
|
-
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
565
|
-
baseUrl: "https://api.openai.com/v1",
|
|
566
|
-
apiKey: "sk-valid-test",
|
|
567
|
-
model: "gpt-4.1-mini"
|
|
568
|
-
}, null, 2));
|
|
569
|
-
|
|
570
|
-
try {
|
|
571
|
-
const inputSummary = {
|
|
572
|
-
instruction: "测试输入摘要",
|
|
573
|
-
search_params: { school_tag: ["985"], gender: "男" },
|
|
574
|
-
screen_params: { criteria: "有 MCP 经验" }
|
|
575
|
-
};
|
|
576
|
-
const result = await runRecommendScreenCli({
|
|
577
|
-
workspaceRoot,
|
|
578
|
-
screenParams: {
|
|
579
|
-
criteria: "有 MCP 经验",
|
|
580
|
-
target_count: null,
|
|
581
|
-
post_action: "none",
|
|
582
|
-
max_greet_count: null
|
|
583
|
-
},
|
|
584
|
-
inputSummary
|
|
585
|
-
});
|
|
586
|
-
assert.equal(result.ok, true);
|
|
587
|
-
const argv = result.summary?.argv || [];
|
|
588
|
-
const summaryIndex = argv.indexOf("--input-summary-json");
|
|
589
|
-
assert.equal(summaryIndex >= 0, true);
|
|
590
|
-
const parsedSummary = JSON.parse(String(argv[summaryIndex + 1] || "{}"));
|
|
591
|
-
assert.equal(parsedSummary.instruction, "测试输入摘要");
|
|
592
|
-
assert.equal(parsedSummary.search_params?.gender, "男");
|
|
593
|
-
assert.equal(parsedSummary.screen_params?.criteria, "有 MCP 经验");
|
|
594
|
-
} finally {
|
|
595
|
-
if (previousHome === undefined) {
|
|
596
|
-
delete process.env.BOSS_RECOMMEND_HOME;
|
|
597
|
-
} else {
|
|
598
|
-
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
599
|
-
}
|
|
600
|
-
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
601
|
-
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
async function main() {
|
|
606
|
-
await testRunProcessHeartbeatAndOutput();
|
|
607
|
-
await testRunProcessAbortSignal();
|
|
608
|
-
testParsePausedStructuredOutput();
|
|
609
|
-
testParseScreenProgressLineShouldCountFavoriteFailureAsSkipped();
|
|
610
|
-
testResolveScreenTimeoutDefaultsTo24Hours();
|
|
611
|
-
testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides();
|
|
612
|
-
testBuildRecommendScreenProcessErrorMapsTimeout();
|
|
613
|
-
await testResumeRequiresCheckpointFile();
|
|
614
|
-
await testRecommendScreenCliShouldPassSharedLlmTransportArgs();
|
|
615
|
-
testPreflightShouldCheckSharpInsteadOfPython();
|
|
616
|
-
testPreflightFeaturedShouldRequireFavoriteCalibration();
|
|
617
|
-
testPreflightRecommendShouldKeepFavoriteCalibrationOptional();
|
|
618
|
-
testPreflightLatestShouldKeepFavoriteCalibrationOptional();
|
|
619
|
-
await testEnsureFeaturedCalibrationReadyShouldAutoCalibrate();
|
|
620
|
-
await testSearchCliShouldPassPageScopeArgument();
|
|
621
|
-
await testSearchCliShouldPassLatestPageScopeWithoutCalibration();
|
|
622
|
-
await testScreenCliShouldPassPageScopeArgument();
|
|
623
|
-
await testScreenCliShouldPassLatestPageScopeArgument();
|
|
624
|
-
await testScreenCliShouldPassInputSummaryArgument();
|
|
625
|
-
console.log("adapters runtime tests passed");
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
await main();
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import {
|
|
6
|
+
ensureFeaturedCalibrationReady,
|
|
7
|
+
runPipelinePreflight,
|
|
8
|
+
runRecommendSearchCli,
|
|
9
|
+
runRecommendScreenCli,
|
|
10
|
+
resolveSharedLlmTransportConfig,
|
|
11
|
+
__testables as adapterTestables
|
|
12
|
+
} from "./adapters.js";
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
runProcess,
|
|
16
|
+
parseJsonOutput,
|
|
17
|
+
parseScreenProgressLine,
|
|
18
|
+
resolveRecommendScreenTimeoutMs,
|
|
19
|
+
buildRecommendScreenProcessError
|
|
20
|
+
} = adapterTestables;
|
|
21
|
+
|
|
22
|
+
async function testRunProcessHeartbeatAndOutput() {
|
|
23
|
+
const heartbeats = [];
|
|
24
|
+
const lines = [];
|
|
25
|
+
const result = await runProcess({
|
|
26
|
+
command: "node",
|
|
27
|
+
args: [
|
|
28
|
+
"-e",
|
|
29
|
+
"let i=0; const t=setInterval(()=>{console.error(`tick ${++i}`); if(i===3){clearInterval(t); console.log('{\"status\":\"COMPLETED\"}');}}, 120);"
|
|
30
|
+
],
|
|
31
|
+
timeoutMs: 5000,
|
|
32
|
+
heartbeatIntervalMs: 40,
|
|
33
|
+
onHeartbeat: (event) => {
|
|
34
|
+
heartbeats.push(event?.source || "unknown");
|
|
35
|
+
},
|
|
36
|
+
onLine: (event) => {
|
|
37
|
+
lines.push(event?.line || "");
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
assert.equal(result.code, 0);
|
|
42
|
+
assert.equal(result.error_code, undefined);
|
|
43
|
+
assert.equal(heartbeats.length >= 3, true);
|
|
44
|
+
assert.equal(lines.some((line) => line.includes("tick 1")), true);
|
|
45
|
+
assert.equal(lines.some((line) => line.includes("\"status\":\"COMPLETED\"")), true);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function testRunProcessAbortSignal() {
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
setTimeout(() => controller.abort(), 120);
|
|
51
|
+
|
|
52
|
+
const result = await runProcess({
|
|
53
|
+
command: "node",
|
|
54
|
+
args: ["-e", "setTimeout(() => console.log('done'), 5000);"],
|
|
55
|
+
timeoutMs: 6000,
|
|
56
|
+
signal: controller.signal
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
assert.equal(result.code, -1);
|
|
60
|
+
assert.equal(result.error_code, "ABORTED");
|
|
61
|
+
assert.equal(String(result.stderr || "").includes("aborted"), true);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function testParsePausedStructuredOutput() {
|
|
65
|
+
const parsed = parseJsonOutput(`
|
|
66
|
+
[log] doing work
|
|
67
|
+
{"status":"PAUSED","result":{"processed_count":3,"output_csv":"C:/tmp/test.csv"}}
|
|
68
|
+
`);
|
|
69
|
+
assert.equal(parsed?.status, "PAUSED");
|
|
70
|
+
assert.equal(parsed?.result?.processed_count, 3);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function testParseScreenProgressLineShouldCountFavoriteFailureAsSkipped() {
|
|
74
|
+
let progress = { processed: 0, passed: 0, skipped: 0, greet_count: 0 };
|
|
75
|
+
let tracker = {};
|
|
76
|
+
const feed = (line) => {
|
|
77
|
+
const parsed = parseScreenProgressLine(line, progress, tracker);
|
|
78
|
+
if (!parsed) return;
|
|
79
|
+
progress = parsed.progress;
|
|
80
|
+
tracker = parsed.tracker;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
feed("处理第 1 位候选人: 甲");
|
|
84
|
+
feed("筛选结果: 通过");
|
|
85
|
+
feed("[关闭详情] 成功: no popup or detail signal visible");
|
|
86
|
+
feed("处理第 2 位候选人: 乙");
|
|
87
|
+
feed("筛选结果: 通过");
|
|
88
|
+
feed("候选人处理失败: FAVORITE_BUTTON_FAILED");
|
|
89
|
+
feed("[关闭详情] 成功: no popup or detail signal visible");
|
|
90
|
+
|
|
91
|
+
assert.equal(progress.processed, 2);
|
|
92
|
+
assert.equal(progress.passed, 1);
|
|
93
|
+
assert.equal(progress.skipped, 1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function testResolveScreenTimeoutDefaultsTo24Hours() {
|
|
97
|
+
const previous = process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
98
|
+
delete process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
99
|
+
try {
|
|
100
|
+
assert.equal(resolveRecommendScreenTimeoutMs(null), 24 * 60 * 60 * 1000);
|
|
101
|
+
assert.equal(resolveRecommendScreenTimeoutMs({ timeoutMs: 1234 }), 1234);
|
|
102
|
+
} finally {
|
|
103
|
+
if (previous === undefined) {
|
|
104
|
+
delete process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS;
|
|
105
|
+
} else {
|
|
106
|
+
process.env.BOSS_RECOMMEND_SCREEN_TIMEOUT_MS = previous;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides() {
|
|
112
|
+
assert.deepEqual(resolveSharedLlmTransportConfig({}), {
|
|
113
|
+
llmTimeoutMs: 60000,
|
|
114
|
+
llmMaxRetries: 3,
|
|
115
|
+
});
|
|
116
|
+
assert.deepEqual(
|
|
117
|
+
resolveSharedLlmTransportConfig({
|
|
118
|
+
llmTimeoutMs: 90000,
|
|
119
|
+
llmMaxRetries: 5,
|
|
120
|
+
}),
|
|
121
|
+
{
|
|
122
|
+
llmTimeoutMs: 90000,
|
|
123
|
+
llmMaxRetries: 5,
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function testBuildRecommendScreenProcessErrorMapsTimeout() {
|
|
129
|
+
const error = buildRecommendScreenProcessError({ code: -1, error_code: "TIMEOUT" }, 86400000);
|
|
130
|
+
assert.equal(error?.code, "TIMEOUT");
|
|
131
|
+
assert.equal(String(error?.message || "").includes("86400000"), true);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function testResumeRequiresCheckpointFile() {
|
|
135
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
136
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-resume-"));
|
|
137
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
138
|
+
try {
|
|
139
|
+
const configPath = path.join(tempHome, "screening-config.json");
|
|
140
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
141
|
+
baseUrl: "https://api.openai.com/v1",
|
|
142
|
+
apiKey: "sk-test-valid",
|
|
143
|
+
model: "gpt-4.1-mini"
|
|
144
|
+
}, null, 2));
|
|
145
|
+
|
|
146
|
+
const missingCheckpoint = path.join(tempHome, "missing-checkpoint.json");
|
|
147
|
+
const result = await runRecommendScreenCli({
|
|
148
|
+
workspaceRoot: process.cwd(),
|
|
149
|
+
screenParams: {
|
|
150
|
+
criteria: "有MCP经验",
|
|
151
|
+
target_count: 10,
|
|
152
|
+
post_action: "favorite",
|
|
153
|
+
max_greet_count: null
|
|
154
|
+
},
|
|
155
|
+
resume: {
|
|
156
|
+
resume: true,
|
|
157
|
+
require_checkpoint: true,
|
|
158
|
+
checkpoint_path: missingCheckpoint,
|
|
159
|
+
pause_control_path: path.join(tempHome, "run-state.json"),
|
|
160
|
+
output_csv: path.join(tempHome, "resume.csv")
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
assert.equal(result.ok, false);
|
|
165
|
+
assert.equal(result.error?.code, "RESUME_CHECKPOINT_MISSING");
|
|
166
|
+
} finally {
|
|
167
|
+
if (previousHome === undefined) {
|
|
168
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
169
|
+
} else {
|
|
170
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
171
|
+
}
|
|
172
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function testRecommendScreenCliShouldPassSharedLlmTransportArgs() {
|
|
177
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-stub-"));
|
|
178
|
+
const screenDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
179
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-home-"));
|
|
180
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
181
|
+
fs.mkdirSync(screenDir, { recursive: true });
|
|
182
|
+
fs.writeFileSync(
|
|
183
|
+
path.join(screenDir, "boss-recommend-screen-cli.cjs"),
|
|
184
|
+
[
|
|
185
|
+
"#!/usr/bin/env node",
|
|
186
|
+
"const fs = require('node:fs');",
|
|
187
|
+
"const path = require('node:path');",
|
|
188
|
+
"const argv = process.argv.slice(2);",
|
|
189
|
+
"const parsed = {};",
|
|
190
|
+
"for (let i = 0; i < argv.length; i += 1) {",
|
|
191
|
+
" const token = argv[i];",
|
|
192
|
+
" if (!token.startsWith('--')) continue;",
|
|
193
|
+
" const next = argv[i + 1];",
|
|
194
|
+
" parsed[token.slice(2)] = next && !next.startsWith('--') ? next : true;",
|
|
195
|
+
" if (next && !next.startsWith('--')) i += 1;",
|
|
196
|
+
"}",
|
|
197
|
+
"const output = path.join(process.env.BOSS_RECOMMEND_HOME, 'screen-cli-args.json');",
|
|
198
|
+
"fs.writeFileSync(output, JSON.stringify(parsed, null, 2));",
|
|
199
|
+
"console.log(JSON.stringify({ status: 'COMPLETED', result: { processed_count: 0, output_csv: parsed.output || '' } }));",
|
|
200
|
+
].join("\n"),
|
|
201
|
+
"utf8",
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
205
|
+
fs.writeFileSync(
|
|
206
|
+
path.join(tempHome, "screening-config.json"),
|
|
207
|
+
JSON.stringify(
|
|
208
|
+
{
|
|
209
|
+
baseUrl: "https://api.openai.com/v1",
|
|
210
|
+
apiKey: "sk-valid-test",
|
|
211
|
+
model: "gpt-4.1-mini",
|
|
212
|
+
llmTimeoutMs: 75000,
|
|
213
|
+
llmMaxRetries: 6,
|
|
214
|
+
},
|
|
215
|
+
null,
|
|
216
|
+
2,
|
|
217
|
+
),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const result = await runRecommendScreenCli({
|
|
222
|
+
workspaceRoot,
|
|
223
|
+
screenParams: {
|
|
224
|
+
criteria: "有 MCP 经验",
|
|
225
|
+
target_count: null,
|
|
226
|
+
post_action: "none",
|
|
227
|
+
max_greet_count: null,
|
|
228
|
+
},
|
|
229
|
+
pageScope: "recommend",
|
|
230
|
+
});
|
|
231
|
+
assert.equal(result.ok, true);
|
|
232
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(tempHome, "screen-cli-args.json"), "utf8"));
|
|
233
|
+
assert.equal(parsed["llm-timeout-ms"], "75000");
|
|
234
|
+
assert.equal(parsed["llm-max-retries"], "6");
|
|
235
|
+
} finally {
|
|
236
|
+
if (previousHome === undefined) {
|
|
237
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
238
|
+
} else {
|
|
239
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
240
|
+
}
|
|
241
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
242
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function testPreflightShouldCheckSharpInsteadOfPython() {
|
|
247
|
+
const preflight = runPipelinePreflight(process.cwd());
|
|
248
|
+
const keys = new Set((preflight.checks || []).map((item) => item?.key));
|
|
249
|
+
assert.equal(keys.has("npm_dep_sharp"), true);
|
|
250
|
+
assert.equal(keys.has("python_cli"), false);
|
|
251
|
+
assert.equal(keys.has("python_pillow"), false);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function testPreflightFeaturedShouldRequireFavoriteCalibration() {
|
|
255
|
+
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "featured" });
|
|
256
|
+
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
257
|
+
assert.equal(Boolean(check), true);
|
|
258
|
+
assert.equal(check.optional, false);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function testPreflightRecommendShouldKeepFavoriteCalibrationOptional() {
|
|
262
|
+
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "recommend" });
|
|
263
|
+
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
264
|
+
assert.equal(Boolean(check), true);
|
|
265
|
+
assert.equal(check.optional, true);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function testPreflightLatestShouldKeepFavoriteCalibrationOptional() {
|
|
269
|
+
const preflight = runPipelinePreflight(process.cwd(), { pageScope: "latest" });
|
|
270
|
+
const check = (preflight.checks || []).find((item) => item?.key === "favorite_calibration");
|
|
271
|
+
assert.equal(Boolean(check), true);
|
|
272
|
+
assert.equal(check.optional, true);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function testEnsureFeaturedCalibrationReadyShouldAutoCalibrate() {
|
|
276
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
277
|
+
const previousCodexHome = process.env.CODEX_HOME;
|
|
278
|
+
const previousScript = process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT;
|
|
279
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-featured-cal-home-"));
|
|
280
|
+
const tempCodex = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-featured-cal-codex-"));
|
|
281
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
282
|
+
process.env.CODEX_HOME = tempCodex;
|
|
283
|
+
|
|
284
|
+
const configPath = path.join(tempHome, "screening-config.json");
|
|
285
|
+
const scriptPath = path.join(tempHome, "fake-calibrate.cjs");
|
|
286
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
287
|
+
baseUrl: "https://api.openai.com/v1",
|
|
288
|
+
apiKey: "sk-valid",
|
|
289
|
+
model: "gpt-4.1-mini",
|
|
290
|
+
calibrationFile: "favorite-calibration.json"
|
|
291
|
+
}, null, 2));
|
|
292
|
+
fs.writeFileSync(scriptPath, [
|
|
293
|
+
"#!/usr/bin/env node",
|
|
294
|
+
"const fs = require('node:fs');",
|
|
295
|
+
"const path = require('node:path');",
|
|
296
|
+
"const args = process.argv.slice(2).reduce((acc, token, idx, arr) => {",
|
|
297
|
+
" if (token.startsWith('--')) {",
|
|
298
|
+
" const key = token.slice(2);",
|
|
299
|
+
" const next = arr[idx + 1];",
|
|
300
|
+
" acc[key] = next && !next.startsWith('--') ? next : true;",
|
|
301
|
+
" }",
|
|
302
|
+
" return acc;",
|
|
303
|
+
"}, {});",
|
|
304
|
+
"const output = path.resolve(String(args.output || 'favorite-calibration.json'));",
|
|
305
|
+
"fs.mkdirSync(path.dirname(output), { recursive: true });",
|
|
306
|
+
"fs.writeFileSync(output, JSON.stringify({ favoritePosition: { pageX: 100, pageY: 200, canvasX: 0, canvasY: 0 } }, null, 2));",
|
|
307
|
+
"console.log('calibrated');"
|
|
308
|
+
].join("\n"), "utf8");
|
|
309
|
+
process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT = scriptPath;
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
const result = await ensureFeaturedCalibrationReady(process.cwd(), {
|
|
313
|
+
port: 9222,
|
|
314
|
+
timeoutMs: 5000
|
|
315
|
+
});
|
|
316
|
+
assert.equal(result.ok, true);
|
|
317
|
+
assert.equal(result.auto_started, true);
|
|
318
|
+
assert.equal(String(result.calibration_path || "").endsWith("favorite-calibration.json"), true);
|
|
319
|
+
assert.equal(fs.existsSync(result.calibration_path), true);
|
|
320
|
+
} finally {
|
|
321
|
+
if (previousHome === undefined) {
|
|
322
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
323
|
+
} else {
|
|
324
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
325
|
+
}
|
|
326
|
+
if (previousCodexHome === undefined) {
|
|
327
|
+
delete process.env.CODEX_HOME;
|
|
328
|
+
} else {
|
|
329
|
+
process.env.CODEX_HOME = previousCodexHome;
|
|
330
|
+
}
|
|
331
|
+
if (previousScript === undefined) {
|
|
332
|
+
delete process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT;
|
|
333
|
+
} else {
|
|
334
|
+
process.env.BOSS_RECOMMEND_RECRUIT_CALIBRATION_SCRIPT = previousScript;
|
|
335
|
+
}
|
|
336
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
337
|
+
fs.rmSync(tempCodex, { recursive: true, force: true });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function testSearchCliShouldPassPageScopeArgument() {
|
|
342
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-search-page-scope-"));
|
|
343
|
+
const cliDir = path.join(workspaceRoot, "boss-recommend-search-cli", "src");
|
|
344
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
345
|
+
const cliPath = path.join(cliDir, "cli.js");
|
|
346
|
+
fs.writeFileSync(
|
|
347
|
+
cliPath,
|
|
348
|
+
[
|
|
349
|
+
"#!/usr/bin/env node",
|
|
350
|
+
"console.log(JSON.stringify({ status: 'COMPLETED', result: { argv: process.argv.slice(2) } }));"
|
|
351
|
+
].join("\n"),
|
|
352
|
+
"utf8"
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
const result = await runRecommendSearchCli({
|
|
357
|
+
workspaceRoot,
|
|
358
|
+
searchParams: {
|
|
359
|
+
school_tag: ["不限"],
|
|
360
|
+
degree: ["不限"],
|
|
361
|
+
gender: "不限",
|
|
362
|
+
recent_not_view: "不限"
|
|
363
|
+
},
|
|
364
|
+
selectedJob: null,
|
|
365
|
+
pageScope: "featured"
|
|
366
|
+
});
|
|
367
|
+
assert.equal(result.ok, true);
|
|
368
|
+
const argv = result.summary?.argv || [];
|
|
369
|
+
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
370
|
+
assert.equal(pageScopeIndex >= 0, true);
|
|
371
|
+
assert.equal(argv[pageScopeIndex + 1], "featured");
|
|
372
|
+
const calibrationIndex = argv.indexOf("--calibration");
|
|
373
|
+
assert.equal(calibrationIndex >= 0, true);
|
|
374
|
+
assert.equal(String(argv[calibrationIndex + 1] || "").includes("favorite-calibration.json"), true);
|
|
375
|
+
} finally {
|
|
376
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function testSearchCliShouldPassLatestPageScopeWithoutCalibration() {
|
|
381
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-search-page-scope-latest-"));
|
|
382
|
+
const cliDir = path.join(workspaceRoot, "boss-recommend-search-cli", "src");
|
|
383
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
384
|
+
const cliPath = path.join(cliDir, "cli.js");
|
|
385
|
+
fs.writeFileSync(
|
|
386
|
+
cliPath,
|
|
387
|
+
[
|
|
388
|
+
"#!/usr/bin/env node",
|
|
389
|
+
"console.log(JSON.stringify({ status: 'COMPLETED', result: { argv: process.argv.slice(2) } }));"
|
|
390
|
+
].join("\n"),
|
|
391
|
+
"utf8"
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
const result = await runRecommendSearchCli({
|
|
396
|
+
workspaceRoot,
|
|
397
|
+
searchParams: {
|
|
398
|
+
school_tag: ["不限"],
|
|
399
|
+
degree: ["不限"],
|
|
400
|
+
gender: "不限",
|
|
401
|
+
recent_not_view: "不限"
|
|
402
|
+
},
|
|
403
|
+
selectedJob: null,
|
|
404
|
+
pageScope: "latest"
|
|
405
|
+
});
|
|
406
|
+
assert.equal(result.ok, true);
|
|
407
|
+
const argv = result.summary?.argv || [];
|
|
408
|
+
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
409
|
+
assert.equal(pageScopeIndex >= 0, true);
|
|
410
|
+
assert.equal(argv[pageScopeIndex + 1], "latest");
|
|
411
|
+
assert.equal(argv.includes("--calibration"), false);
|
|
412
|
+
} finally {
|
|
413
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async function testScreenCliShouldPassPageScopeArgument() {
|
|
418
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
419
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-home-"));
|
|
420
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-workspace-"));
|
|
421
|
+
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
422
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
423
|
+
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
424
|
+
fs.writeFileSync(
|
|
425
|
+
cliPath,
|
|
426
|
+
[
|
|
427
|
+
"#!/usr/bin/env node",
|
|
428
|
+
"console.log(JSON.stringify({",
|
|
429
|
+
" status: 'COMPLETED',",
|
|
430
|
+
" result: {",
|
|
431
|
+
" processed_count: 0,",
|
|
432
|
+
" passed_count: 0,",
|
|
433
|
+
" skipped_count: 0,",
|
|
434
|
+
" argv: process.argv.slice(2),",
|
|
435
|
+
" resume_source: 'network',",
|
|
436
|
+
" active_tab_status: '3'",
|
|
437
|
+
" }",
|
|
438
|
+
"}));"
|
|
439
|
+
].join("\n"),
|
|
440
|
+
"utf8"
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
444
|
+
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
445
|
+
baseUrl: "https://api.openai.com/v1",
|
|
446
|
+
apiKey: "sk-valid-test",
|
|
447
|
+
model: "gpt-4.1-mini"
|
|
448
|
+
}, null, 2));
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const result = await runRecommendScreenCli({
|
|
452
|
+
workspaceRoot,
|
|
453
|
+
screenParams: {
|
|
454
|
+
criteria: "有 MCP 经验",
|
|
455
|
+
target_count: null,
|
|
456
|
+
post_action: "none",
|
|
457
|
+
max_greet_count: null
|
|
458
|
+
},
|
|
459
|
+
pageScope: "featured"
|
|
460
|
+
});
|
|
461
|
+
assert.equal(result.ok, true);
|
|
462
|
+
const argv = result.summary?.argv || [];
|
|
463
|
+
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
464
|
+
assert.equal(pageScopeIndex >= 0, true);
|
|
465
|
+
assert.equal(argv[pageScopeIndex + 1], "featured");
|
|
466
|
+
} finally {
|
|
467
|
+
if (previousHome === undefined) {
|
|
468
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
469
|
+
} else {
|
|
470
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
471
|
+
}
|
|
472
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
473
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async function testScreenCliShouldPassLatestPageScopeArgument() {
|
|
478
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
479
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-latest-home-"));
|
|
480
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-page-scope-latest-workspace-"));
|
|
481
|
+
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
482
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
483
|
+
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
484
|
+
fs.writeFileSync(
|
|
485
|
+
cliPath,
|
|
486
|
+
[
|
|
487
|
+
"#!/usr/bin/env node",
|
|
488
|
+
"console.log(JSON.stringify({",
|
|
489
|
+
" status: 'COMPLETED',",
|
|
490
|
+
" result: {",
|
|
491
|
+
" processed_count: 0,",
|
|
492
|
+
" passed_count: 0,",
|
|
493
|
+
" skipped_count: 0,",
|
|
494
|
+
" argv: process.argv.slice(2),",
|
|
495
|
+
" resume_source: 'image_fallback',",
|
|
496
|
+
" active_tab_status: '1'",
|
|
497
|
+
" }",
|
|
498
|
+
"}));"
|
|
499
|
+
].join("\n"),
|
|
500
|
+
"utf8"
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
504
|
+
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
505
|
+
baseUrl: "https://api.openai.com/v1",
|
|
506
|
+
apiKey: "sk-valid-test",
|
|
507
|
+
model: "gpt-4.1-mini"
|
|
508
|
+
}, null, 2));
|
|
509
|
+
|
|
510
|
+
try {
|
|
511
|
+
const result = await runRecommendScreenCli({
|
|
512
|
+
workspaceRoot,
|
|
513
|
+
screenParams: {
|
|
514
|
+
criteria: "有 MCP 经验",
|
|
515
|
+
target_count: null,
|
|
516
|
+
post_action: "none",
|
|
517
|
+
max_greet_count: null
|
|
518
|
+
},
|
|
519
|
+
pageScope: "latest"
|
|
520
|
+
});
|
|
521
|
+
assert.equal(result.ok, true);
|
|
522
|
+
const argv = result.summary?.argv || [];
|
|
523
|
+
const pageScopeIndex = argv.indexOf("--page-scope");
|
|
524
|
+
assert.equal(pageScopeIndex >= 0, true);
|
|
525
|
+
assert.equal(argv[pageScopeIndex + 1], "latest");
|
|
526
|
+
} finally {
|
|
527
|
+
if (previousHome === undefined) {
|
|
528
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
529
|
+
} else {
|
|
530
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
531
|
+
}
|
|
532
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
533
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async function testScreenCliShouldPassInputSummaryArgument() {
|
|
538
|
+
const previousHome = process.env.BOSS_RECOMMEND_HOME;
|
|
539
|
+
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-input-summary-home-"));
|
|
540
|
+
const workspaceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "boss-recommend-screen-input-summary-workspace-"));
|
|
541
|
+
const cliDir = path.join(workspaceRoot, "boss-recommend-screen-cli");
|
|
542
|
+
fs.mkdirSync(cliDir, { recursive: true });
|
|
543
|
+
const cliPath = path.join(cliDir, "boss-recommend-screen-cli.cjs");
|
|
544
|
+
fs.writeFileSync(
|
|
545
|
+
cliPath,
|
|
546
|
+
[
|
|
547
|
+
"#!/usr/bin/env node",
|
|
548
|
+
"console.log(JSON.stringify({",
|
|
549
|
+
" status: 'COMPLETED',",
|
|
550
|
+
" result: {",
|
|
551
|
+
" processed_count: 0,",
|
|
552
|
+
" passed_count: 0,",
|
|
553
|
+
" skipped_count: 0,",
|
|
554
|
+
" argv: process.argv.slice(2),",
|
|
555
|
+
" resume_source: 'network',",
|
|
556
|
+
" active_tab_status: '0'",
|
|
557
|
+
" }",
|
|
558
|
+
"}));"
|
|
559
|
+
].join("\n"),
|
|
560
|
+
"utf8"
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
process.env.BOSS_RECOMMEND_HOME = tempHome;
|
|
564
|
+
fs.writeFileSync(path.join(tempHome, "screening-config.json"), JSON.stringify({
|
|
565
|
+
baseUrl: "https://api.openai.com/v1",
|
|
566
|
+
apiKey: "sk-valid-test",
|
|
567
|
+
model: "gpt-4.1-mini"
|
|
568
|
+
}, null, 2));
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
const inputSummary = {
|
|
572
|
+
instruction: "测试输入摘要",
|
|
573
|
+
search_params: { school_tag: ["985"], gender: "男" },
|
|
574
|
+
screen_params: { criteria: "有 MCP 经验" }
|
|
575
|
+
};
|
|
576
|
+
const result = await runRecommendScreenCli({
|
|
577
|
+
workspaceRoot,
|
|
578
|
+
screenParams: {
|
|
579
|
+
criteria: "有 MCP 经验",
|
|
580
|
+
target_count: null,
|
|
581
|
+
post_action: "none",
|
|
582
|
+
max_greet_count: null
|
|
583
|
+
},
|
|
584
|
+
inputSummary
|
|
585
|
+
});
|
|
586
|
+
assert.equal(result.ok, true);
|
|
587
|
+
const argv = result.summary?.argv || [];
|
|
588
|
+
const summaryIndex = argv.indexOf("--input-summary-json");
|
|
589
|
+
assert.equal(summaryIndex >= 0, true);
|
|
590
|
+
const parsedSummary = JSON.parse(String(argv[summaryIndex + 1] || "{}"));
|
|
591
|
+
assert.equal(parsedSummary.instruction, "测试输入摘要");
|
|
592
|
+
assert.equal(parsedSummary.search_params?.gender, "男");
|
|
593
|
+
assert.equal(parsedSummary.screen_params?.criteria, "有 MCP 经验");
|
|
594
|
+
} finally {
|
|
595
|
+
if (previousHome === undefined) {
|
|
596
|
+
delete process.env.BOSS_RECOMMEND_HOME;
|
|
597
|
+
} else {
|
|
598
|
+
process.env.BOSS_RECOMMEND_HOME = previousHome;
|
|
599
|
+
}
|
|
600
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
601
|
+
fs.rmSync(workspaceRoot, { recursive: true, force: true });
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async function main() {
|
|
606
|
+
await testRunProcessHeartbeatAndOutput();
|
|
607
|
+
await testRunProcessAbortSignal();
|
|
608
|
+
testParsePausedStructuredOutput();
|
|
609
|
+
testParseScreenProgressLineShouldCountFavoriteFailureAsSkipped();
|
|
610
|
+
testResolveScreenTimeoutDefaultsTo24Hours();
|
|
611
|
+
testResolveSharedLlmTransportConfigShouldUseDefaultsAndOverrides();
|
|
612
|
+
testBuildRecommendScreenProcessErrorMapsTimeout();
|
|
613
|
+
await testResumeRequiresCheckpointFile();
|
|
614
|
+
await testRecommendScreenCliShouldPassSharedLlmTransportArgs();
|
|
615
|
+
testPreflightShouldCheckSharpInsteadOfPython();
|
|
616
|
+
testPreflightFeaturedShouldRequireFavoriteCalibration();
|
|
617
|
+
testPreflightRecommendShouldKeepFavoriteCalibrationOptional();
|
|
618
|
+
testPreflightLatestShouldKeepFavoriteCalibrationOptional();
|
|
619
|
+
await testEnsureFeaturedCalibrationReadyShouldAutoCalibrate();
|
|
620
|
+
await testSearchCliShouldPassPageScopeArgument();
|
|
621
|
+
await testSearchCliShouldPassLatestPageScopeWithoutCalibration();
|
|
622
|
+
await testScreenCliShouldPassPageScopeArgument();
|
|
623
|
+
await testScreenCliShouldPassLatestPageScopeArgument();
|
|
624
|
+
await testScreenCliShouldPassInputSummaryArgument();
|
|
625
|
+
console.log("adapters runtime tests passed");
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
await main();
|