@reconcrap/boss-recruit-mcp 1.0.7 → 1.0.9

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/README.md CHANGED
@@ -84,7 +84,20 @@ $CODEX_HOME/boss-recruit-mcp/screening-config.json
84
84
  2. 填写以下字段:
85
85
 
86
86
  - `baseUrl` / `apiKey` / `model` 必填
87
+ - OpenAI 推荐:
88
+ - `baseUrl`: `https://api.openai.com/v1`
89
+ - `apiKey`: OpenAI API Key
90
+ - `model`: 例如 `gpt-4.1-mini`
91
+ - 也支持通过环境变量注入:
92
+ - `OPENAI_API_KEY`(可替代配置文件中的 `apiKey`)
93
+ - `OPENAI_BASE_URL`(可替代配置文件中的 `baseUrl`)
94
+ - `OPENAI_MODEL`(可替代配置文件中的 `model`)
95
+ - `OPENAI_ORG_ID` / `OPENAI_PROJECT_ID`(可选)
96
+ - 配置文件可选字段:
97
+ - `openaiOrganization`
98
+ - `openaiProject`
87
99
  - `debugPort` 可选,默认 `9222`
100
+ - 端口优先级:`--port > BOSS_RECRUIT_CHROME_PORT > screening-config.json.debugPort > 9222`
88
101
  - `calibrationFile` 可选;不填时默认使用 `$CODEX_HOME/boss-recruit-mcp/favorite-calibration.json`
89
102
  - `outputDir` 可选;不填时默认输出到用户桌面
90
103
  - 学校标签支持 `统招本科` / `双一流院校` / `985` / `211` / `qs100` / `qs500`;如果输入 `qs50`、`qs200`、`qs500` 等其他 `QS数字`,会按 `<=100 -> qs100`、`>100 -> qs500` 归一
@@ -111,6 +124,12 @@ boss-recruit-mcp run --instruction "在 Boss 上找做过推荐系统的人,
111
124
  boss-recruit-mcp run --instruction "在 Boss 上找做过推荐系统的人" --confirmation-json "{\"keyword_confirmed\":true,\"keyword_value\":\"推荐系统\",\"search_params_confirmed\":true}" --overrides-json "{\"city\":\"杭州\",\"degree\":\"本科\",\"schools\":[\"985\",\"211\",\"qs100\"],\"filter_recent_viewed\":true,\"target_count\":10}"
112
125
  ```
113
126
 
127
+ PowerShell 下更推荐用文件方式,避免引号转义导致 `INVALID_CLI_INPUT`:
128
+
129
+ ```bash
130
+ boss-recruit-mcp run --instruction-file request.txt --confirmation-file confirmation.json --overrides-file overrides.json
131
+ ```
132
+
114
133
  如果命令行中放长文本不方便,改用文件:
115
134
 
116
135
  ```bash
@@ -122,23 +141,28 @@ boss-recruit-mcp run --instruction-file request.txt --confirmation-file confirma
122
141
 
123
142
  ## Chrome 与校准
124
143
 
125
- 先确认你要使用的 Chrome 远程调试端口。推荐 `9222`,但如果你已经有一个正在运行的远程调试 Chrome,也可以继续使用那个端口。确认端口后,再执行下面的命令。
144
+ 先确认你要使用的 Chrome 远程调试端口。推荐 `9222`,但如果你已经有一个正在运行的远程调试 Chrome,也可以继续使用那个端口。
126
145
 
127
- 推荐先启动调试 Chrome:
146
+ 建议先固化一次端口(后续命令自动沿用):
128
147
 
129
148
  ```bash
130
- boss-recruit-mcp launch-chrome --port <port>
149
+ boss-recruit-mcp set-port --port <port>
131
150
  ```
132
151
 
133
- `launch-chrome` 会自动为该端口创建独立的 Chrome profile 目录,避免复用已有 Chrome 实例导致调试端口未生效。
134
- 命令还会检查新打开的 Boss 页面是否仍停留在 `search` 页面;如果跳转到了登录页或其他页面,说明需要用户先手动登录 Boss。
152
+ 确认端口后,再执行下面的命令。
135
153
 
136
- 然后执行校准:
154
+ 执行校准(会自动尝试打开 Boss 搜索页):
137
155
 
138
156
  ```bash
139
157
  boss-recruit-mcp calibrate --port <port>
140
158
  ```
141
159
 
160
+ 如果你想自定义监听窗口(默认 60 秒):
161
+
162
+ ```bash
163
+ boss-recruit-mcp calibrate --port <port> --timeout-ms 60000
164
+ ```
165
+
142
166
  如果你的 `screening-config.json` 里配置了自定义 `calibrationFile` 路径,而该路径当前不存在,直接把校准结果输出到那个路径:
143
167
 
144
168
  ```bash
@@ -164,6 +188,8 @@ $CODEX_HOME/boss-recruit-mcp/favorite-calibration.json
164
188
  也可以用下面的命令检查依赖、配置和校准文件:
165
189
 
166
190
  ```bash
191
+ boss-recruit-mcp doctor
192
+ # 或显式指定
167
193
  boss-recruit-mcp doctor --port <port>
168
194
  ```
169
195
 
@@ -200,6 +226,34 @@ boss-recruit-mcp doctor --port <port>
200
226
  - 若当前运行环境不允许启动子进程,会返回更明确的权限错误码而不是笼统失败
201
227
  - 配置文件查找顺序:`BOSS_RECRUIT_SCREEN_CONFIG` > 工作区 `boss-recruit-mcp/config/screening-config.json` > 用户目录 `$CODEX_HOME/boss-recruit-mcp/screening-config.json` > 包内示例配置
202
228
 
229
+ ## 终版测试方案
230
+
231
+ 回归脚本位置:`scripts/regression.ps1`
232
+
233
+ 1. 快速回归(不依赖 Boss 页面,验证 CLI 输入与状态机基础逻辑):
234
+
235
+ ```bash
236
+ npm run test:regression:win
237
+ ```
238
+
239
+ 2. 全链路回归(依赖 Chrome 调试端口 + 已登录 Boss):
240
+
241
+ ```bash
242
+ powershell -ExecutionPolicy Bypass -File scripts/regression.ps1 -Mode full -Port 9222
243
+ ```
244
+
245
+ 3. 负向回归(错误端口,确保不会误返回 `COMPLETED`):
246
+
247
+ ```bash
248
+ powershell -ExecutionPolicy Bypass -File scripts/regression.ps1 -Mode negative
249
+ ```
250
+
251
+ 判定标准:
252
+
253
+ - 不应出现 `INVALID_CLI_INPUT`
254
+ - 正常场景允许 `COMPLETED` 或可诊断的 `FAILED`
255
+ - 错误端口场景必须是 `FAILED`,且不是参数解析类错误
256
+
203
257
  ## 发布
204
258
 
205
259
  ```bash
@@ -1,5 +1,7 @@
1
1
  {
2
- "baseUrl": "https://your-llm-endpoint.example.com/v1",
3
- "apiKey": "replace-with-your-api-key",
4
- "model": "replace-with-your-model-name"
2
+ "baseUrl": "https://api.openai.com/v1",
3
+ "apiKey": "replace-with-openai-api-key",
4
+ "model": "gpt-4.1-mini",
5
+ "openaiOrganization": "optional-org-id",
6
+ "openaiProject": "optional-project-id"
5
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reconcrap/boss-recruit-mcp",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Unified MCP pipeline for boss-search-cli and boss-screen-cli",
5
5
  "keywords": [
6
6
  "boss",
@@ -18,7 +18,8 @@
18
18
  "start": "node src/index.js",
19
19
  "cli": "node src/cli.js",
20
20
  "install:local": "node src/cli.js install",
21
- "test:parser": "node src/test-parser.js"
21
+ "test:parser": "node src/test-parser.js",
22
+ "test:regression:win": "powershell -ExecutionPolicy Bypass -File scripts/regression.ps1 -Mode quick"
22
23
  },
23
24
  "files": [
24
25
  "bin",
@@ -33,8 +33,14 @@ boss-recruit-mcp mcp-config --client all
33
33
  - 默认优先走 MCP;如果当前 agent 无法再添加 MCP,也可以改用 `boss-recruit-mcp run` 作为 CLI fallback。
34
34
  - 正式开始前,必须先做一轮参数确认,分开展示已识别参数、待确认参数、缺失参数。
35
35
  - 参数确认尽量复用统一模板:`已识别参数` / `待确认或待修正` / `缺失参数` / `默认值提醒` / `请用户回复`。
36
+ - 在正式执行前,必须单独让用户确认筛选 `criteria`(尤其学历/学校/论文等硬性条件)无误,不能只确认关键词和搜索参数。
36
37
  - 端口未确认时,必须先询问用户是否使用推荐的 `9222`,或提供一个已有的其他远程调试端口,不能直接默认 `9222`。
37
- - 新打开 Chrome 实例后,要检查页面是否仍停留在 Boss search;如果跳转到其他页面,必须提示用户先手动登录 Boss,再继续。
38
+ - 用户确认端口后,先执行 `boss-recruit-mcp set-port --port <port>`,让后续 `doctor / launch-chrome / calibrate / run` 自动复用同一端口。
39
+ - 任何需要打开 Chrome 的动作前,先检查调试端口是否已有可用实例;端口可连时必须复用,不要再新开一个 9222 实例。
40
+ - 若页面未停留在 Boss search(例如跳到登录页或首页),必须提示用户先手动登录 Boss,再继续。
38
41
  - 如果识别结果里出现明显脏值或可疑字段,例如“杭州筛选做过”,必须要求用户改成标准值后再继续。
42
+ - 学历/学校硬性条件不能在 criteria 清洗时被剔除;即使已提取到搜索参数,criteria 仍需保留原始约束语义(例如“本科学历必须是985”)。
39
43
  - 如果缺少 `favorite-calibration.json`,必须指导用户在当前环境重新校准,不能搜索或复制历史遗留校准文件来顶替。
44
+ - 校准提示使用两阶段:先问“是否准备好开始校准”,不要问“是否已完成校准”;用户确认后应直接启动 `boss-recruit-mcp calibrate --port <port>`。
45
+ - 校准里的“打开详情 -> 收藏 -> 取消收藏 -> 关闭详情”属于动作说明,不要要求用户先手动完成这些步骤后再回复“可以校准”。
40
46
  - 若缺失参数仍未补齐,只能在用户明确确认接受默认值和质量风险后继续,不能静默按默认执行。
@@ -27,16 +27,18 @@
27
27
  - 建议使用 `9222`
28
28
  - 但也允许用户明确提供一个已在使用的其他远程调试端口
29
29
  3. 在用户确认端口前,不要直接假设 `9222` 并执行任何依赖端口的命令。
30
- 4. 端口确认后,再检查依赖与配置:
31
- - `boss-recruit-mcp doctor --port <port>`
32
- 5. 若 Chrome 未以远程调试模式启动,优先帮助用户启动:
33
- - `boss-recruit-mcp launch-chrome --port <port>`
34
- - 打开页面:`https://www.zhipin.com/web/chat/search`
35
- 6. 启动新的 Chrome debugging 实例后,必须检查页面是否仍停留在 `https://www.zhipin.com/web/chat/search`:
30
+ 4. 用户确认端口后,先执行一次端口固化,确保后续动作自动沿用同一端口:
31
+ - `boss-recruit-mcp set-port --port <port>`
32
+ 5. 再检查依赖与端口状态:
33
+ - `boss-recruit-mcp doctor`(或显式 `boss-recruit-mcp doctor --port <port>`)
34
+ 6. 任何“准备打开 Chrome”的动作前,必须先判断该端口是否已有可用实例:
35
+ - 若调试端口可连,禁止再新开 Chrome;直接复用现有实例,并确保页面在 `https://www.zhipin.com/web/chat/search`
36
+ - 仅当调试端口不可连时,才执行 `boss-recruit-mcp launch-chrome --port <port>`
37
+ 7. 若执行 `launch-chrome` 后页面没有停留在 `https://www.zhipin.com/web/chat/search`:
36
38
  - 若仍在 search 页面,可继续;
37
39
  - 若跳转到登录页、首页或其他 Boss 页面,视为“需要重新登录”;
38
40
  - 必须明确提示用户手动登录 Boss,并等待用户回复“已登录/可以继续”后,才能继续后续动作。
39
- 7. 只有在以上条件满足后,才继续调用流水线。
41
+ 8. 只有在以上条件满足后,才继续调用流水线。
40
42
 
41
43
  ## Calibration Requirement
42
44
 
@@ -48,15 +50,18 @@
48
50
  - 必须明确告诉用户“当前期望的校准文件路径”;
49
51
  - 应指导用户用 `boss-recruit-mcp calibrate --port <port> --output <expected-path>` 直接生成到该路径;
50
52
  - 不要静默改写配置,也不要把别处的文件复制过去。
51
- - 提示语必须包含这几步:
52
- - 打开 Boss 直聘
53
- - 去到搜索页面
54
- - 随便打开一位人选的详情页
55
- - 点击收藏按钮
56
- - 再次点击取消该人选的收藏
53
+ - 校准动作说明用于“让用户了解流程”,不要求用户先手动点击页面:
54
+ - 打开 Boss 直聘搜索页面
55
+ - 打开任意一位人选详情页
56
+ - 执行一次收藏,再取消收藏
57
57
  - 关闭详情页
58
+ - 校准对话必须是“两阶段”:
59
+ - 第一阶段:先完整说明校准步骤,然后只问“是否准备好开始校准”;
60
+ - 第二阶段:用户确认“准备好了”后,直接启动校准命令,并明确说明“你不需要先手动完成页面点击,我会立即启动校准流程”。
61
+ - 不要把“请确认你已完成校准”当作启动校准的前置问题;启动前应确认“准备开始”,不是“已经完成”。
62
+ - 不要要求用户先完成页面操作再回复“可以校准/已完成校准”;应在用户确认“准备开始”后立即执行校准。
58
63
  - 然后执行:
59
- - `boss-recruit-mcp calibrate --port <port>`
64
+ - `boss-recruit-mcp calibrate --port <port>`(默认监听 60 秒)
60
65
  - 默认校准文件路径:
61
66
  - `$CODEX_HOME/boss-recruit-mcp/favorite-calibration.json`
62
67
 
@@ -69,6 +74,7 @@
69
74
  - `keyword_confirmed` (boolean): 是否确认关键词
70
75
  - `keyword_value` (string): 用户确认或改写后的关键词
71
76
  - `search_params_confirmed` (boolean): 用户是否已明确确认当前参数集
77
+ - `criteria_confirmed` (boolean): 用户是否已明确确认筛选 criteria(尤其硬性约束)
72
78
  - `use_default_for_missing` (boolean): 用户是否明确同意对缺失参数使用默认值
73
79
  - `overrides` (object, optional)
74
80
  - `city` (string)
@@ -142,9 +148,13 @@
142
148
  - 明确给出校准步骤与命令;
143
149
  - 明确指出期望生成到哪个路径;
144
150
  - 不要在本机搜索并复用其他 `favorite-calibration.json`。
145
- 4. 若 `launch-chrome` 后发现页面没有停留在 search,而是跳到了登录页、首页或其他页面:
151
+ - 校准引导必须先问“是否准备好开始校准”;用户确认准备好后,再执行:
152
+ - `boss-recruit-mcp calibrate --port <port>`
153
+ - 不要要求用户先手动完成“收藏/取消收藏”等页面动作,再触发 `calibrate`。
154
+ - 除非调试端口不可连,否则不要额外先执行 `launch-chrome`。
155
+ 4. 若校准流程中发现页面没有停留在 search,或跳到了登录页、首页或其他页面:
146
156
  - 明确告诉用户“当前需要手动登录 Boss”;
147
- - 明确要求用户在新打开的 Chrome 窗口中完成登录;
157
+ - 明确要求用户在当前可见的 Chrome 窗口中完成登录;
148
158
  - 等用户回复“已登录,可以继续”后,再继续下一步;
149
159
  - 不要在用户未确认登录完成前直接执行搜索、校准或流水线。
150
160
  5. 只有当以上条件满足时,才首次进入流水线解析:
@@ -171,6 +181,7 @@
171
181
  8. 若返回 `NEED_CONFIRMATION`:
172
182
  - 询问用户是否确认 `proposed_keyword`;
173
183
  - 同时也要让用户确认其他已提取参数里是否有误;
184
+ - 必须单独确认筛选 `criteria` 是否准确(尤其学历/学校/论文等硬性条件不能丢失);
174
185
  - 若 `required_confirmations` 或 `pending_questions` 里包含 `filter_recent_viewed`,必须明确补问:是否需要过滤近 14 天查看过的人选;
175
186
  - 若确认,带 `confirmation.keyword_confirmed=true` 和 `keyword_value` 再次调用;
176
187
  - 若用户修改关键词,传用户给的新词作为 `keyword_value` 再次调用;
@@ -180,6 +191,7 @@
180
191
  - 必须得到用户明确确认“可以按默认值继续”后,才能继续执行。
181
192
  10. 只有在以下条件都满足后,才允许正式开始:
182
193
  - 用户已经确认已提取参数无误;
194
+ - 用户已经明确确认 `criteria` 无误;
183
195
  - 缺失参数已补齐,或用户已明确接受默认值;
184
196
  - `NEED_CONFIRMATION` 分支中的关键词也已确认。
185
197
  11. 若返回 `COMPLETED`:
@@ -200,6 +212,7 @@
200
212
  - 优先鼓励用户一次性给全这些字段:城市、学历、学校标签、目标人数、核心方向关键词。
201
213
  - 当用户提到“做过 AI infra / 推荐系统 / 搜索 / 广告 / 多模态”等经历,但没有显式写“关键词”,默认允许流水线先自动抽取,再走确认分支。
202
214
  - 当用户附带筛选要求(如“必须发表过 CCF-A 区论文”“有开源项目”“带过团队”),这些要求应该保留在 `criteria` 中,不应被误当作搜索过滤条件。
215
+ - 当用户明确给出“学历/学校”硬性条件(如“本科学历必须是985”),即使这些信息已被提取到搜索参数,`criteria` 里也必须保留原始约束,不可剔除。
203
216
  - 若参数提取结果出现明显噪声、截断、短语串接、非标准枚举值,优先视为“识别不可靠”,要求用户确认,不要为了推进流程直接采用。
204
217
  - 若用户输入 `qs50`、`qs200`、`qs500` 等任意 `QS数字` 学校标签,统一按 `<=100 -> qs100`、`>100 -> qs500` 处理;不要把原始 `QS200` 再传到底层搜索命令。
205
218
  - 若用户没有明确提到“是否过滤近 14 天查看过的人选”,必须在参数确认阶段主动补问,不能静默默认开启或关闭。
@@ -267,6 +280,7 @@
267
280
  - 如果工具已经返回 `diagnostics.checks`,优先基于这些检查项生成排障建议。
268
281
  - 如果工具返回 `output_csv`,在摘要里给出路径,避免重复解释内部流程。
269
282
  - 如果端口还没确认,必须先问用户“是否使用推荐的 `9222`,还是你已经有别的远程调试端口”,不能直接把 `9222` 当成已确认值。
283
+ - 用户确认端口后,先执行一次 `boss-recruit-mcp set-port --port <port>`,让后续 `doctor / launch-chrome / calibrate / run` 自动复用同一端口。
270
284
  - 如果需要打开 Chrome,优先帮用户执行而不是只给命令。
271
285
  - 如果新打开的 Chrome 页面跳离了 search 页面,必须判断为“需要登录”,提示用户手动登录后再继续。
272
286
 
@@ -279,12 +293,13 @@
279
293
  期望行为:
280
294
 
281
295
  1. 先询问用户是否使用推荐的 Chrome 调试端口 `9222`,或提供一个已有的其他端口。
282
- 2. 用户确认端口后,启动对应端口的调试 Chrome 并打开 Boss 搜索页面。
283
- 3. 先检查校准文件是否存在;若不存在,提醒用户按步骤完成校准。
284
- 4. 环境就绪后再首次调用流水线。
285
- 5. 若 keyword 被自动提取为 `AI infra`,先让用户确认。
286
- 6. 确认后再次调用。
287
- 7. 成功则返回通过人数与 CSV 路径;失败则按错误类型给出下一步。
296
+ 2. 用户确认端口后,先执行 `boss-recruit-mcp set-port --port <port>` 固化端口。
297
+ 3. 启动对应端口的调试 Chrome 并打开 Boss 搜索页面。
298
+ 4. 先检查校准文件是否存在;若不存在,提醒用户按步骤完成校准。
299
+ 5. 环境就绪后再首次调用流水线。
300
+ 6. 若 keyword 被自动提取为 `AI infra`,先让用户确认。
301
+ 7. 确认后再次调用。
302
+ 8. 成功则返回通过人数与 CSV 路径;失败则按错误类型给出下一步。
288
303
 
289
304
  ## Response Style
290
305
 
package/src/adapters.js CHANGED
@@ -49,6 +49,11 @@ function pathExists(targetPath) {
49
49
  }
50
50
  }
51
51
 
52
+ function parsePositiveInteger(raw) {
53
+ const value = Number.parseInt(String(raw || ""), 10);
54
+ return Number.isFinite(value) && value > 0 ? value : null;
55
+ }
56
+
52
57
  function resolveSearchCliDir(workspaceRoot) {
53
58
  const localDir = path.join(workspaceRoot, "boss-search-cli");
54
59
  if (pathExists(localDir)) {
@@ -190,35 +195,43 @@ function loadScreenConfig(configPath) {
190
195
  }
191
196
  }
192
197
 
193
- function resolveDebugPort(config) {
194
- const fromEnv = Number.parseInt(process.env.BOSS_RECRUIT_CHROME_PORT || "", 10);
195
- if (Number.isFinite(fromEnv) && fromEnv > 0) return fromEnv;
196
- const fromConfig = Number.parseInt(String(config?.debugPort || ""), 10);
197
- if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
198
- return 9222;
198
+ function readScreenConfigJson(configPath) {
199
+ if (!pathExists(configPath)) return null;
200
+ try {
201
+ const raw = fs.readFileSync(configPath, "utf8");
202
+ const parsed = JSON.parse(raw);
203
+ return parsed && typeof parsed === "object" ? parsed : null;
204
+ } catch {
205
+ return null;
206
+ }
207
+ }
208
+
209
+ function resolveDebugPortFromConfigPath(configPath) {
210
+ const parsed = readScreenConfigJson(configPath);
211
+ const fromConfig = parsePositiveInteger(parsed?.debugPort);
212
+ if (fromConfig) return fromConfig;
213
+ return null;
199
214
  }
200
215
 
201
216
  function resolveWorkspaceDebugPort(workspaceRoot) {
217
+ const fromEnv = parsePositiveInteger(process.env.BOSS_RECRUIT_CHROME_PORT);
218
+ if (fromEnv) return fromEnv;
219
+
202
220
  const configPath = resolveScreenConfigPath(workspaceRoot);
203
- if (pathExists(configPath)) {
204
- const loaded = loadScreenConfig(configPath);
205
- if (loaded.ok) {
206
- return resolveDebugPort(loaded.config);
207
- }
208
- }
209
- return resolveDebugPort(null);
221
+ const fromConfig = resolveDebugPortFromConfigPath(configPath);
222
+ if (fromConfig) return fromConfig;
223
+
224
+ return 9222;
210
225
  }
211
226
 
212
227
  export function runPipelinePreflight(workspaceRoot) {
213
228
  const searchDir = resolveSearchCliDir(workspaceRoot);
214
229
  const screenDir = resolveScreenCliDir(workspaceRoot);
215
230
  const screenConfigPath = resolveScreenConfigPath(workspaceRoot);
216
- const loaded = pathExists(screenConfigPath) ? loadScreenConfig(screenConfigPath) : null;
217
- const debugPort = loaded?.ok ? resolveDebugPort(loaded.config) : resolveDebugPort(null);
218
- const calibrationPath = loaded?.ok
219
- ? (loaded.config.calibrationFile
220
- ? path.resolve(path.dirname(screenConfigPath), loaded.config.calibrationFile)
221
- : getUserCalibrationPath())
231
+ const rawConfig = readScreenConfigJson(screenConfigPath);
232
+ const debugPort = resolveWorkspaceDebugPort(workspaceRoot);
233
+ const calibrationPath = rawConfig?.calibrationFile
234
+ ? path.resolve(path.dirname(screenConfigPath), rawConfig.calibrationFile)
222
235
  : getUserCalibrationPath();
223
236
  const checks = [
224
237
  {
@@ -354,7 +367,7 @@ export async function runScreenCli({ workspaceRoot, screenParams }) {
354
367
  const calibration = loaded.config.calibrationFile
355
368
  ? path.resolve(configBaseDir, loaded.config.calibrationFile)
356
369
  : getUserCalibrationPath();
357
- const debugPort = resolveDebugPort(loaded.config);
370
+ const debugPort = resolveWorkspaceDebugPort(workspaceRoot);
358
371
 
359
372
  const outputName = `筛选结果_${Date.now()}.csv`;
360
373
  let outputPath = outputName;