@reconcrap/boss-recommend-mcp 1.3.39 → 2.0.1

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 (88) hide show
  1. package/README.md +86 -33
  2. package/package.json +62 -9
  3. package/skills/boss-chat/SKILL.md +5 -4
  4. package/skills/boss-recommend-pipeline/SKILL.md +21 -31
  5. package/skills/boss-recruit-pipeline/README.md +17 -0
  6. package/skills/boss-recruit-pipeline/SKILL.md +55 -0
  7. package/src/chat-mcp.js +1333 -0
  8. package/src/chat-runtime-config.js +559 -0
  9. package/src/cli.js +1254 -225
  10. package/src/core/browser/index.js +378 -0
  11. package/src/core/capture/index.js +298 -0
  12. package/src/core/cv-acquisition/index.js +219 -0
  13. package/src/core/greet-quota/index.js +54 -0
  14. package/src/core/infinite-list/index.js +459 -0
  15. package/src/core/reporting/legacy-csv.js +332 -0
  16. package/src/core/run/index.js +286 -0
  17. package/src/core/screening/index.js +1166 -0
  18. package/src/core/self-heal/index.js +848 -0
  19. package/src/domains/chat/cards.js +129 -0
  20. package/src/domains/chat/constants.js +183 -0
  21. package/src/domains/chat/detail.js +1369 -0
  22. package/src/domains/chat/index.js +7 -0
  23. package/src/domains/chat/jobs.js +334 -0
  24. package/src/domains/chat/page-guard.js +88 -0
  25. package/src/domains/chat/roots.js +56 -0
  26. package/src/domains/chat/run-service.js +1101 -0
  27. package/src/domains/recommend/actions.js +457 -0
  28. package/src/domains/recommend/cards.js +228 -0
  29. package/src/domains/recommend/constants.js +141 -0
  30. package/src/domains/recommend/detail.js +341 -0
  31. package/src/domains/recommend/filters.js +581 -0
  32. package/src/domains/recommend/index.js +10 -0
  33. package/src/domains/recommend/jobs.js +232 -0
  34. package/src/domains/recommend/refresh.js +204 -0
  35. package/src/domains/recommend/roots.js +78 -0
  36. package/src/domains/recommend/run-service.js +903 -0
  37. package/src/domains/recommend/scopes.js +245 -0
  38. package/src/domains/recruit/actions.js +277 -0
  39. package/src/domains/recruit/cards.js +66 -0
  40. package/src/domains/recruit/constants.js +130 -0
  41. package/src/domains/recruit/detail.js +414 -0
  42. package/src/domains/recruit/index.js +9 -0
  43. package/src/domains/recruit/instruction-parser.js +451 -0
  44. package/src/domains/recruit/refresh.js +40 -0
  45. package/src/domains/recruit/roots.js +67 -0
  46. package/src/domains/recruit/run-service.js +580 -0
  47. package/src/domains/recruit/search.js +1149 -0
  48. package/src/index.js +578 -419
  49. package/src/recommend-mcp.js +1257 -0
  50. package/src/recruit-mcp.js +1035 -0
  51. package/src/adapters.js +0 -3079
  52. package/src/boss-chat.js +0 -1037
  53. package/src/pipeline.js +0 -2249
  54. package/src/recommend-healing-config.js +0 -131
  55. package/src/recommend-healing-rules.json +0 -261
  56. package/src/self-heal.js +0 -2237
  57. package/src/test-adapters-runtime.js +0 -628
  58. package/src/test-boss-chat.js +0 -3196
  59. package/src/test-index-async.js +0 -498
  60. package/src/test-parser.js +0 -742
  61. package/src/test-pipeline.js +0 -2703
  62. package/src/test-run-state.js +0 -152
  63. package/src/test-self-heal.js +0 -224
  64. package/vendor/boss-chat-cli/README.md +0 -134
  65. package/vendor/boss-chat-cli/package.json +0 -53
  66. package/vendor/boss-chat-cli/src/app.js +0 -1501
  67. package/vendor/boss-chat-cli/src/browser/chat-page.js +0 -3562
  68. package/vendor/boss-chat-cli/src/cli.js +0 -1713
  69. package/vendor/boss-chat-cli/src/mcp/server.js +0 -149
  70. package/vendor/boss-chat-cli/src/mcp/tool-runtime.js +0 -193
  71. package/vendor/boss-chat-cli/src/runtime/async-run-state.js +0 -260
  72. package/vendor/boss-chat-cli/src/runtime/interaction.js +0 -102
  73. package/vendor/boss-chat-cli/src/runtime/run-control.js +0 -102
  74. package/vendor/boss-chat-cli/src/services/chrome-client.js +0 -107
  75. package/vendor/boss-chat-cli/src/services/llm.js +0 -1292
  76. package/vendor/boss-chat-cli/src/services/llm.test.js +0 -326
  77. package/vendor/boss-chat-cli/src/services/profile-store.js +0 -173
  78. package/vendor/boss-chat-cli/src/services/report-store.js +0 -317
  79. package/vendor/boss-chat-cli/src/services/resume-capture.js +0 -469
  80. package/vendor/boss-chat-cli/src/services/resume-network.js +0 -727
  81. package/vendor/boss-chat-cli/src/services/state-store.js +0 -90
  82. package/vendor/boss-chat-cli/src/utils/customer-key.js +0 -82
  83. package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +0 -7072
  84. package/vendor/boss-recommend-screen-cli/scripts/capture-full-resume-canvas.cjs +0 -817
  85. package/vendor/boss-recommend-screen-cli/scripts/stitch_resume_chunks.py +0 -141
  86. package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +0 -2423
  87. package/vendor/boss-recommend-search-cli/src/cli.js +0 -1698
  88. package/vendor/boss-recommend-search-cli/src/test-job-selection.js +0 -211
@@ -1,317 +0,0 @@
1
- import { mkdir, writeFile } from 'node:fs/promises';
2
- import path from 'node:path';
3
-
4
- const TIMING_BUCKETS = [
5
- ['initialNetworkWaitMs', '初始 network 等待'],
6
- ['networkRetryMs', 'network 重试'],
7
- ['imageCaptureMs', '简历截图'],
8
- ['imageModelMs', '图片模型'],
9
- ['lateNetworkRetryMs', '晚到 network 重试'],
10
- ['domFallbackMs', 'DOM 兜底'],
11
- ['textModelMs', '文本模型'],
12
- ];
13
-
14
- const CSV_HEADER = [
15
- 'index',
16
- 'name',
17
- 'source_job',
18
- 'decision',
19
- 'passed',
20
- 'requested',
21
- 'resume_acquisition_mode',
22
- 'resume_acquisition_reason',
23
- 'evaluation_mode',
24
- 'evaluation_image_count',
25
- 'initial_network_wait_ms',
26
- 'network_retry_ms',
27
- 'image_capture_ms',
28
- 'image_model_ms',
29
- 'late_network_retry_ms',
30
- 'dom_fallback_ms',
31
- 'text_model_ms',
32
- 'timing_summary',
33
- 'reason',
34
- 'llm_summary',
35
- 'llm_cot',
36
- 'llm_evidence',
37
- 'llm_raw_reasoning',
38
- 'error_message',
39
- 'llm_raw_output',
40
- 'llm_raw_output_preview',
41
- ];
42
-
43
- function timestampToken(date = new Date()) {
44
- return date.toISOString().replace(/[:.]/g, '-');
45
- }
46
-
47
- function normalizeText(value) {
48
- if (value === null || value === undefined) return '';
49
- return String(value).replace(/\s+/g, ' ').trim();
50
- }
51
-
52
- function previewText(value, maxLength = 160) {
53
- const normalized = normalizeText(value);
54
- if (!normalized) return '';
55
- if (normalized.length <= maxLength) return normalized;
56
- return `${normalized.slice(0, Math.max(0, maxLength - 1))}…`;
57
- }
58
-
59
- function normalizeMs(value) {
60
- const parsed = Number(value);
61
- if (!Number.isFinite(parsed) || parsed < 0) return null;
62
- return Math.round(parsed);
63
- }
64
-
65
- function formatDurationMs(startedAt, finishedAt) {
66
- const started = startedAt ? Date.parse(startedAt) : NaN;
67
- const finished = finishedAt ? Date.parse(finishedAt) : NaN;
68
- if (!Number.isFinite(started) || !Number.isFinite(finished) || finished < started) {
69
- return '-';
70
- }
71
- const totalMs = Math.round(finished - started);
72
- if (totalMs < 1000) return `${totalMs}ms`;
73
- if (totalMs < 60_000) return `${(totalMs / 1000).toFixed(1)}s`;
74
- return `${(totalMs / 60_000).toFixed(1)}m`;
75
- }
76
-
77
- function csvEscape(value) {
78
- return `"${String(value ?? '').replace(/"/g, '""')}"`;
79
- }
80
-
81
- function toResults(summary) {
82
- return Array.isArray(summary?.results) ? summary.results : [];
83
- }
84
-
85
- function toOutcome(result) {
86
- if (normalizeText(result?.decision)) return normalizeText(result.decision);
87
- if (result?.passed) return 'passed';
88
- if (normalizeText(result?.error)) return 'error';
89
- return 'skipped';
90
- }
91
-
92
- function getArtifacts(result) {
93
- return result?.artifacts && typeof result.artifacts === 'object' ? result.artifacts : {};
94
- }
95
-
96
- function getAcquisitionMode(result) {
97
- return normalizeText(getArtifacts(result).resumeAcquisitionMode);
98
- }
99
-
100
- function getAcquisitionReason(result) {
101
- return normalizeText(getArtifacts(result).resumeAcquisitionReason);
102
- }
103
-
104
- function getTimingValue(result, key) {
105
- return normalizeMs(getArtifacts(result)[key]);
106
- }
107
-
108
- function getLlmSummary(result) {
109
- return normalizeText(getArtifacts(result).llmSummary);
110
- }
111
-
112
- function getLlmCot(result) {
113
- return normalizeText(getArtifacts(result).llmCot);
114
- }
115
-
116
- function getLlmEvidence(result) {
117
- const evidence = getArtifacts(result).llmEvidence;
118
- if (!Array.isArray(evidence)) return '';
119
- return evidence.map((item) => normalizeText(item)).filter(Boolean).join(' | ');
120
- }
121
-
122
- function getLlmRawReasoning(result) {
123
- return normalizeText(getArtifacts(result).llmRawReasoning);
124
- }
125
-
126
- function formatTimingSummary(result) {
127
- const parts = [];
128
- for (const [key, label] of TIMING_BUCKETS) {
129
- const value = getTimingValue(result, key);
130
- if (value === null) continue;
131
- parts.push(`${label} ${value}ms`);
132
- }
133
- return parts.length > 0 ? parts.join(' | ') : '-';
134
- }
135
-
136
- function formatResultNotes(result) {
137
- const parts = [];
138
- const reason = previewText(result?.reason, 120);
139
- const summary = previewText(getLlmSummary(result), 120);
140
- const cot = previewText(getLlmCot(result), 180);
141
- const errorMessage = previewText(result?.error, 120);
142
- const llmRawReasoning = previewText(getLlmRawReasoning(result), 180);
143
- const llmRawOutput = previewText(getArtifacts(result).llmRawOutput, 180);
144
- if (reason) parts.push(`原因: ${reason}`);
145
- if (summary) parts.push(`摘要: ${summary}`);
146
- if (cot) parts.push(`CoT: ${cot}`);
147
- if (errorMessage) parts.push(`错误: ${errorMessage}`);
148
- if (llmRawReasoning) parts.push(`Reasoning: ${llmRawReasoning}`);
149
- if (llmRawOutput) parts.push(`LLM: ${llmRawOutput}`);
150
- return parts.length > 0 ? parts.join(' | ') : '-';
151
- }
152
-
153
- function buildAcquisitionSummaryRows(results) {
154
- const counts = new Map();
155
- for (const result of results) {
156
- const mode = getAcquisitionMode(result) || 'unknown';
157
- const reason = getAcquisitionReason(result) || 'unspecified';
158
- const key = `${mode}__${reason}`;
159
- const current = counts.get(key) || { mode, reason, count: 0 };
160
- current.count += 1;
161
- counts.set(key, current);
162
- }
163
- return [...counts.values()].sort((left, right) => right.count - left.count || left.mode.localeCompare(right.mode));
164
- }
165
-
166
- function buildTimingSummaryRows(results) {
167
- return TIMING_BUCKETS.map(([key, label]) => {
168
- let count = 0;
169
- let total = 0;
170
- for (const result of results) {
171
- const value = getTimingValue(result, key);
172
- if (value === null) continue;
173
- count += 1;
174
- total += value;
175
- }
176
- return {
177
- key,
178
- label,
179
- count,
180
- total,
181
- average: count > 0 ? Math.round(total / count) : null,
182
- };
183
- }).filter((item) => item.count > 0);
184
- }
185
-
186
- function buildMarkdownSummary(summary) {
187
- const results = toResults(summary);
188
- const acquisitionRows = buildAcquisitionSummaryRows(results);
189
- const timingRows = buildTimingSummaryRows(results);
190
- const lines = [
191
- '# Boss Chat 运行报告',
192
- '',
193
- '## 概览',
194
- `- 开始时间: ${summary?.startedAt || '-'}`,
195
- `- 结束时间: ${summary?.finishedAt || '-'}`,
196
- `- 总耗时: ${formatDurationMs(summary?.startedAt, summary?.finishedAt)}`,
197
- `- 处理进度: inspected=${Number(summary?.inspected || 0)} / target=${summary?.profile?.targetCount || '∞'}`,
198
- `- 结果统计: passed=${Number(summary?.passed || 0)} | requested=${Number(summary?.requested || 0)} | skipped=${Number(summary?.skipped || 0)} | errors=${Number(summary?.errors || 0)}`,
199
- `- 停止状态: ${summary?.stopped ? `stopped (${summary?.stopReason || 'unknown'})` : 'completed'}`,
200
- `- 穷尽列表: ${summary?.exhausted === true ? 'yes' : 'no'}`,
201
- `- 报告文件: JSON=${summary?.reportPath || '-'} | Markdown=${summary?.reportMarkdownPath || '-'} | CSV=${summary?.reportCsvPath || '-'}`,
202
- '',
203
- '## Resume Acquisition 汇总',
204
- '',
205
- '| mode | retry_reason | count |',
206
- '| --- | --- | ---: |',
207
- ];
208
-
209
- if (acquisitionRows.length === 0) {
210
- lines.push('| - | - | 0 |');
211
- } else {
212
- for (const row of acquisitionRows) {
213
- lines.push(`| ${row.mode} | ${row.reason} | ${row.count} |`);
214
- }
215
- }
216
-
217
- lines.push('');
218
- lines.push('## Timing 汇总');
219
- lines.push('');
220
- lines.push('| bucket | hits | total | avg |');
221
- lines.push('| --- | ---: | ---: | ---: |');
222
- if (timingRows.length === 0) {
223
- lines.push('| - | 0 | - | - |');
224
- } else {
225
- for (const row of timingRows) {
226
- lines.push(`| ${row.label} | ${row.count} | ${row.total}ms | ${row.average === null ? '-' : `${row.average}ms`} |`);
227
- }
228
- }
229
-
230
- lines.push('');
231
- lines.push('## 候选人明细');
232
- lines.push('');
233
- lines.push('| # | 姓名 | 结论 | acquisition | retry_reason | timing | notes |');
234
- lines.push('| ---: | --- | --- | --- | --- | --- | --- |');
235
-
236
- if (results.length === 0) {
237
- lines.push('| 1 | - | - | - | - | - | - |');
238
- } else {
239
- results.forEach((result, index) => {
240
- lines.push(
241
- `| ${index + 1} | ${previewText(result?.name || '未知', 32) || '未知'} | ${toOutcome(result)} | ${getAcquisitionMode(result) || '-'} | ${getAcquisitionReason(result) || '-'} | ${formatTimingSummary(result)} | ${formatResultNotes(result)} |`,
242
- );
243
- });
244
- }
245
-
246
- lines.push('');
247
- return `${lines.join('\n')}\n`;
248
- }
249
-
250
- function buildCsvSummary(summary) {
251
- const results = toResults(summary);
252
- const lines = [CSV_HEADER.join(',')];
253
- results.forEach((result, index) => {
254
- const artifacts = getArtifacts(result);
255
- lines.push([
256
- csvEscape(index + 1),
257
- csvEscape(result?.name || ''),
258
- csvEscape(result?.sourceJob || ''),
259
- csvEscape(toOutcome(result)),
260
- csvEscape(result?.passed === true ? 'true' : 'false'),
261
- csvEscape(result?.requested === true ? 'true' : 'false'),
262
- csvEscape(getAcquisitionMode(result)),
263
- csvEscape(getAcquisitionReason(result)),
264
- csvEscape(artifacts.evaluationMode || ''),
265
- csvEscape(Number.isFinite(Number(artifacts.evaluationImageCount)) ? Number(artifacts.evaluationImageCount) : ''),
266
- csvEscape(getTimingValue(result, 'initialNetworkWaitMs') ?? ''),
267
- csvEscape(getTimingValue(result, 'networkRetryMs') ?? ''),
268
- csvEscape(getTimingValue(result, 'imageCaptureMs') ?? ''),
269
- csvEscape(getTimingValue(result, 'imageModelMs') ?? ''),
270
- csvEscape(getTimingValue(result, 'lateNetworkRetryMs') ?? ''),
271
- csvEscape(getTimingValue(result, 'domFallbackMs') ?? ''),
272
- csvEscape(getTimingValue(result, 'textModelMs') ?? ''),
273
- csvEscape(formatTimingSummary(result)),
274
- csvEscape(result?.reason || ''),
275
- csvEscape(getLlmSummary(result)),
276
- csvEscape(getLlmCot(result)),
277
- csvEscape(getLlmEvidence(result)),
278
- csvEscape(getLlmRawReasoning(result)),
279
- csvEscape(result?.error || ''),
280
- csvEscape(artifacts.llmRawOutput || ''),
281
- csvEscape(previewText(artifacts.llmRawOutput, 500)),
282
- ].join(','));
283
- });
284
- return `\uFEFF${lines.join('\n')}\n`;
285
- }
286
-
287
- export class ReportStore {
288
- constructor(baseDir) {
289
- this.reportsDir = path.join(baseDir, 'reports');
290
- }
291
-
292
- async write(summary) {
293
- await mkdir(this.reportsDir, { recursive: true });
294
- const baseName = `run-${timestampToken()}`;
295
- const jsonPath = path.join(this.reportsDir, `${baseName}.json`);
296
- const markdownPath = path.join(this.reportsDir, `${baseName}.md`);
297
- const csvPath = path.join(this.reportsDir, `${baseName}.csv`);
298
-
299
- if (summary && typeof summary === 'object') {
300
- summary.reportPath = jsonPath;
301
- summary.reportMarkdownPath = markdownPath;
302
- summary.reportCsvPath = csvPath;
303
- summary.reportArtifacts = {
304
- jsonPath,
305
- markdownPath,
306
- csvPath,
307
- };
308
- }
309
-
310
- await Promise.all([
311
- writeFile(jsonPath, `${JSON.stringify(summary, null, 2)}\n`, 'utf8'),
312
- writeFile(markdownPath, buildMarkdownSummary(summary), 'utf8'),
313
- writeFile(csvPath, buildCsvSummary(summary), 'utf8'),
314
- ]);
315
- return jsonPath;
316
- }
317
- }