@reconcrap/boss-recommend-mcp 1.3.39 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +53 -33
  2. package/package.json +61 -9
  3. package/skills/boss-recommend-pipeline/SKILL.md +4 -0
  4. package/src/chat-mcp.js +1333 -0
  5. package/src/chat-runtime-config.js +559 -0
  6. package/src/cli.js +1095 -196
  7. package/src/core/browser/index.js +378 -0
  8. package/src/core/capture/index.js +298 -0
  9. package/src/core/cv-acquisition/index.js +219 -0
  10. package/src/core/greet-quota/index.js +54 -0
  11. package/src/core/infinite-list/index.js +459 -0
  12. package/src/core/reporting/legacy-csv.js +332 -0
  13. package/src/core/run/index.js +286 -0
  14. package/src/core/screening/index.js +1166 -0
  15. package/src/core/self-heal/index.js +848 -0
  16. package/src/domains/chat/cards.js +129 -0
  17. package/src/domains/chat/constants.js +183 -0
  18. package/src/domains/chat/detail.js +1369 -0
  19. package/src/domains/chat/index.js +7 -0
  20. package/src/domains/chat/jobs.js +334 -0
  21. package/src/domains/chat/page-guard.js +88 -0
  22. package/src/domains/chat/roots.js +56 -0
  23. package/src/domains/chat/run-service.js +1101 -0
  24. package/src/domains/recommend/actions.js +457 -0
  25. package/src/domains/recommend/cards.js +228 -0
  26. package/src/domains/recommend/constants.js +141 -0
  27. package/src/domains/recommend/detail.js +341 -0
  28. package/src/domains/recommend/filters.js +581 -0
  29. package/src/domains/recommend/index.js +10 -0
  30. package/src/domains/recommend/jobs.js +232 -0
  31. package/src/domains/recommend/refresh.js +204 -0
  32. package/src/domains/recommend/roots.js +78 -0
  33. package/src/domains/recommend/run-service.js +903 -0
  34. package/src/domains/recommend/scopes.js +245 -0
  35. package/src/domains/recruit/actions.js +277 -0
  36. package/src/domains/recruit/cards.js +67 -0
  37. package/src/domains/recruit/constants.js +130 -0
  38. package/src/domains/recruit/detail.js +414 -0
  39. package/src/domains/recruit/index.js +9 -0
  40. package/src/domains/recruit/instruction-parser.js +451 -0
  41. package/src/domains/recruit/refresh.js +40 -0
  42. package/src/domains/recruit/roots.js +68 -0
  43. package/src/domains/recruit/run-service.js +580 -0
  44. package/src/domains/recruit/search.js +1149 -0
  45. package/src/index.js +578 -419
  46. package/src/recommend-mcp.js +1257 -0
  47. package/src/recruit-mcp.js +1035 -0
  48. package/src/adapters.js +0 -3079
  49. package/src/boss-chat.js +0 -1037
  50. package/src/pipeline.js +0 -2249
  51. package/src/recommend-healing-config.js +0 -131
  52. package/src/recommend-healing-rules.json +0 -261
  53. package/src/self-heal.js +0 -2237
  54. package/src/test-adapters-runtime.js +0 -628
  55. package/src/test-boss-chat.js +0 -3196
  56. package/src/test-index-async.js +0 -498
  57. package/src/test-parser.js +0 -742
  58. package/src/test-pipeline.js +0 -2703
  59. package/src/test-run-state.js +0 -152
  60. package/src/test-self-heal.js +0 -224
  61. package/vendor/boss-chat-cli/README.md +0 -134
  62. package/vendor/boss-chat-cli/package.json +0 -53
  63. package/vendor/boss-chat-cli/src/app.js +0 -1501
  64. package/vendor/boss-chat-cli/src/browser/chat-page.js +0 -3562
  65. package/vendor/boss-chat-cli/src/cli.js +0 -1713
  66. package/vendor/boss-chat-cli/src/mcp/server.js +0 -149
  67. package/vendor/boss-chat-cli/src/mcp/tool-runtime.js +0 -193
  68. package/vendor/boss-chat-cli/src/runtime/async-run-state.js +0 -260
  69. package/vendor/boss-chat-cli/src/runtime/interaction.js +0 -102
  70. package/vendor/boss-chat-cli/src/runtime/run-control.js +0 -102
  71. package/vendor/boss-chat-cli/src/services/chrome-client.js +0 -107
  72. package/vendor/boss-chat-cli/src/services/llm.js +0 -1292
  73. package/vendor/boss-chat-cli/src/services/llm.test.js +0 -326
  74. package/vendor/boss-chat-cli/src/services/profile-store.js +0 -173
  75. package/vendor/boss-chat-cli/src/services/report-store.js +0 -317
  76. package/vendor/boss-chat-cli/src/services/resume-capture.js +0 -469
  77. package/vendor/boss-chat-cli/src/services/resume-network.js +0 -727
  78. package/vendor/boss-chat-cli/src/services/state-store.js +0 -90
  79. package/vendor/boss-chat-cli/src/utils/customer-key.js +0 -82
  80. package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +0 -7072
  81. package/vendor/boss-recommend-screen-cli/scripts/capture-full-resume-canvas.cjs +0 -817
  82. package/vendor/boss-recommend-screen-cli/scripts/stitch_resume_chunks.py +0 -141
  83. package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +0 -2423
  84. package/vendor/boss-recommend-search-cli/src/cli.js +0 -1698
  85. package/vendor/boss-recommend-search-cli/src/test-job-selection.js +0 -211
@@ -1,628 +0,0 @@
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();