@joohw/boss-cli 0.1.5 → 0.1.8

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 (80) hide show
  1. package/README.md +7 -2
  2. package/dist/browser/browser_session.d.ts.map +1 -1
  3. package/dist/browser/browser_session.js +38 -0
  4. package/dist/browser/browser_session.js.map +1 -1
  5. package/dist/browser/cdp_browser.d.ts +1 -2
  6. package/dist/browser/cdp_browser.d.ts.map +1 -1
  7. package/dist/browser/cdp_browser.js +29 -5
  8. package/dist/browser/cdp_browser.js.map +1 -1
  9. package/dist/browser/chat.d.ts +2 -2
  10. package/dist/browser/chat.d.ts.map +1 -1
  11. package/dist/browser/chat.js +48 -18
  12. package/dist/browser/chat.js.map +1 -1
  13. package/dist/browser/index.d.ts +0 -1
  14. package/dist/browser/index.d.ts.map +1 -1
  15. package/dist/browser/index.js +0 -1
  16. package/dist/browser/index.js.map +1 -1
  17. package/dist/cli/banner.d.ts +1 -1
  18. package/dist/cli/banner.d.ts.map +1 -1
  19. package/dist/cli/banner.js +40 -1
  20. package/dist/cli/banner.js.map +1 -1
  21. package/dist/cli/cliRouter.d.ts.map +1 -1
  22. package/dist/cli/cliRouter.js +145 -57
  23. package/dist/cli/cliRouter.js.map +1 -1
  24. package/dist/cli/index.js +2 -2
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/version.d.ts +7 -0
  27. package/dist/cli/version.d.ts.map +1 -0
  28. package/dist/cli/version.js +59 -0
  29. package/dist/cli/version.js.map +1 -0
  30. package/dist/toolset/action.d.ts +7 -0
  31. package/dist/toolset/action.d.ts.map +1 -0
  32. package/dist/toolset/action.js +476 -0
  33. package/dist/toolset/action.js.map +1 -0
  34. package/dist/toolset/chat.d.ts +4 -0
  35. package/dist/toolset/chat.d.ts.map +1 -0
  36. package/dist/toolset/chat.js +434 -0
  37. package/dist/toolset/chat.js.map +1 -0
  38. package/dist/toolset/chat_action.d.ts +7 -0
  39. package/dist/toolset/chat_action.d.ts.map +1 -0
  40. package/dist/toolset/chat_action.js +355 -0
  41. package/dist/toolset/chat_action.js.map +1 -0
  42. package/dist/toolset/greet.d.ts +2 -0
  43. package/dist/toolset/greet.d.ts.map +1 -0
  44. package/dist/toolset/greet.js +27 -0
  45. package/dist/toolset/greet.js.map +1 -0
  46. package/dist/toolset/index.d.ts +13 -8
  47. package/dist/toolset/index.d.ts.map +1 -1
  48. package/dist/toolset/index.js +27 -10
  49. package/dist/toolset/index.js.map +1 -1
  50. package/dist/toolset/jd.d.ts +10 -0
  51. package/dist/toolset/jd.d.ts.map +1 -0
  52. package/dist/toolset/jd.js +443 -0
  53. package/dist/toolset/jd.js.map +1 -0
  54. package/dist/toolset/list.d.ts +4 -0
  55. package/dist/toolset/list.d.ts.map +1 -0
  56. package/dist/toolset/list.js +156 -0
  57. package/dist/toolset/list.js.map +1 -0
  58. package/dist/toolset/open_chat.d.ts +1 -4
  59. package/dist/toolset/open_chat.d.ts.map +1 -1
  60. package/dist/toolset/open_chat.js +66 -164
  61. package/dist/toolset/open_chat.js.map +1 -1
  62. package/dist/toolset/recommend.d.ts +22 -0
  63. package/dist/toolset/recommend.d.ts.map +1 -0
  64. package/dist/toolset/recommend.js +346 -0
  65. package/dist/toolset/recommend.js.map +1 -0
  66. package/dist/toolset/recommend_greet.d.ts +2 -0
  67. package/dist/toolset/recommend_greet.d.ts.map +1 -0
  68. package/dist/toolset/recommend_greet.js +27 -0
  69. package/dist/toolset/recommend_greet.js.map +1 -0
  70. package/dist/toolset/search.d.ts +2 -0
  71. package/dist/toolset/search.d.ts.map +1 -0
  72. package/dist/toolset/search.js +174 -0
  73. package/dist/toolset/search.js.map +1 -0
  74. package/dist/toolset/send.d.ts +6 -0
  75. package/dist/toolset/send.d.ts.map +1 -0
  76. package/dist/toolset/send.js +46 -0
  77. package/dist/toolset/send.js.map +1 -0
  78. package/package.json +1 -1
  79. package/skills/README.md +0 -11
  80. package/skills/boss-cli/SKILL.md +0 -58
@@ -0,0 +1,346 @@
1
+ import { createWaitManualLoginRequiredText, sleepRandom, withChatPage, } from '../browser/index.js';
2
+ const BOSS_CHAT_RECOMMEND_URL = 'https://www.zhipin.com/web/chat/recommend';
3
+ const RECOMMEND_SETTLE_MS = { min: 1400, max: 2400 };
4
+ /** 会话内记录:通过 greet 新出现的推荐卡片(以 geekId 识别) */
5
+ const sessionGreetProducedGeekIds = new Set();
6
+ function isBossChatRecommendUrl(url) {
7
+ try {
8
+ const u = new URL(url);
9
+ if (!u.hostname.includes('zhipin.com')) {
10
+ return false;
11
+ }
12
+ const p = u.pathname.replace(/\/+$/, '') || '/';
13
+ return p === '/web/chat/recommend';
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ async function clickSidebarMenuToPath(page, menuLabel, targetPath) {
20
+ const labelLiteral = JSON.stringify(menuLabel);
21
+ const pathLiteral = JSON.stringify(targetPath);
22
+ const clicked = (await page.evaluate(`(() => {
23
+ const label = ${labelLiteral};
24
+ const path = ${pathLiteral};
25
+ const norm = (v) => (v ?? "").replace(/\\s+/g, "");
26
+ const links = Array.from(document.querySelectorAll(".menu-list a"));
27
+ const target = links.find((a) => {
28
+ const href = a.getAttribute("href") ?? "";
29
+ if (href.includes(path)) return true;
30
+ const text = norm(a.querySelector(".menu-item-content span")?.textContent ?? a.textContent);
31
+ return text.includes(label);
32
+ });
33
+ if (!(target instanceof HTMLElement)) return false;
34
+ target.scrollIntoView({ block: "center", inline: "nearest" });
35
+ target.click();
36
+ return true;
37
+ })()`));
38
+ if (!clicked) {
39
+ throw new Error(`未找到侧边栏菜单“${menuLabel}”,无法跳转到 ${targetPath}。`);
40
+ }
41
+ await page.waitForFunction(`(() => {
42
+ const path = ${pathLiteral};
43
+ try {
44
+ const p = window.location.pathname.replace(/\\/+$/g, "") || "/";
45
+ return p === path;
46
+ } catch {
47
+ return false;
48
+ }
49
+ })()`, { timeout: 15_000 });
50
+ }
51
+ async function getRecommendFrame(page) {
52
+ await page.waitForSelector('iframe[name="recommendFrame"]', { timeout: 15_000 });
53
+ const frameByName = page.frames().find((f) => f.name() === 'recommendFrame') ?? null;
54
+ if (frameByName) {
55
+ return frameByName;
56
+ }
57
+ const frameByUrl = page.frames().find((f) => {
58
+ try {
59
+ return f.url().includes('/web/frame/recommend');
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }) ?? null;
65
+ if (frameByUrl) {
66
+ return frameByUrl;
67
+ }
68
+ throw new Error('已检测到推荐 iframe,但无法获取其页面上下文(recommendFrame)。');
69
+ }
70
+ async function ensureRecommendFrameReady(frame) {
71
+ await frame.waitForFunction(`(() => {
72
+ const root = document.querySelector(".card-list, .geek-list-wrap .geek-list");
73
+ return !!root;
74
+ })()`, { timeout: 15_000 });
75
+ }
76
+ async function readCurrentRecommendJobLabel(frame) {
77
+ return (await frame.evaluate(`(() => {
78
+ const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
79
+ return norm(document.querySelector(".job-selecter-wrap .ui-dropmenu-label")?.textContent);
80
+ })()`));
81
+ }
82
+ async function selectRecommendJob(frame, keyword) {
83
+ const kw = keyword.trim();
84
+ if (!kw) {
85
+ return readCurrentRecommendJobLabel(frame);
86
+ }
87
+ const kwLiteral = JSON.stringify(kw);
88
+ const opened = (await frame.evaluate(`(() => {
89
+ const host = document.querySelector(".job-selecter-wrap .ui-dropmenu-label");
90
+ if (!(host instanceof HTMLElement)) return false;
91
+ host.scrollIntoView({ block: "center", inline: "nearest" });
92
+ host.click();
93
+ return true;
94
+ })()`));
95
+ if (!opened) {
96
+ throw new Error('未找到岗位下拉入口(.job-selecter-wrap .ui-dropmenu-label)。');
97
+ }
98
+ await sleepRandom(380, 820);
99
+ const searched = (await frame.evaluate(`(() => {
100
+ const kw = ${kwLiteral};
101
+ const input = document.querySelector(".job-selecter-options .top-chat-search .chat-job-search");
102
+ if (!(input instanceof HTMLInputElement)) return false;
103
+ input.focus();
104
+ input.value = kw;
105
+ input.dispatchEvent(new Event("input", { bubbles: true }));
106
+ input.dispatchEvent(new Event("change", { bubbles: true }));
107
+ return true;
108
+ })()`));
109
+ if (!searched) {
110
+ throw new Error('已打开岗位下拉,但未找到职位搜索框(.chat-job-search)。');
111
+ }
112
+ await sleepRandom(520, 1080);
113
+ const picked = (await frame.evaluate(`(() => {
114
+ const kw = ${kwLiteral};
115
+ const norm = (v) => (v ?? "").replace(/\\s+/g, "").trim().toLowerCase();
116
+ const rows = Array.from(document.querySelectorAll(".job-selecter-options .job-list .job-item"));
117
+ if (rows.length === 0) return { ok: false, reason: "empty" };
118
+ const target = rows.find((el) => {
119
+ const label = norm(el.querySelector(".label")?.textContent || el.textContent || "");
120
+ return label.includes(norm(kw));
121
+ });
122
+ if (!(target instanceof HTMLElement)) return { ok: false, reason: "not_found" };
123
+ const label = (target.querySelector(".label")?.textContent ?? target.textContent ?? "")
124
+ .replace(/\\s+/g, " ")
125
+ .trim();
126
+ target.scrollIntoView({ block: "center", inline: "nearest" });
127
+ target.click();
128
+ return { ok: true, label };
129
+ })()`));
130
+ if (!picked.ok) {
131
+ throw new Error(`未找到匹配岗位“${kw}”。`);
132
+ }
133
+ await sleepRandom(900, 1500);
134
+ return picked.label ?? kw;
135
+ }
136
+ export async function ensureInRecommendPage(page) {
137
+ if (!isBossChatRecommendUrl(page.url())) {
138
+ await clickSidebarMenuToPath(page, '推荐', '/web/chat/recommend');
139
+ await sleepRandom(RECOMMEND_SETTLE_MS.min, RECOMMEND_SETTLE_MS.max);
140
+ }
141
+ if (!isBossChatRecommendUrl(page.url())) {
142
+ throw new Error('通过侧边栏“推荐”进入页面失败,请确认已登录并可访问 /web/chat/recommend。');
143
+ }
144
+ const frame = await getRecommendFrame(page);
145
+ await ensureRecommendFrameReady(frame);
146
+ return frame;
147
+ }
148
+ export async function readRecommendList(frame) {
149
+ return (await frame.evaluate(`(() => {
150
+ const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
151
+ const cards = Array.from(
152
+ document.querySelectorAll(".card-list .card-item, .geek-list .geek-card"),
153
+ );
154
+ return cards.map((item) => {
155
+ const inner = item.querySelector(".card-inner") || item;
156
+ const geekId =
157
+ inner?.getAttribute("data-geekid") ??
158
+ inner?.getAttribute("data-geek") ??
159
+ "";
160
+ const name =
161
+ norm(item.querySelector(".name-wrap .name")?.textContent) ||
162
+ norm(item.querySelector(".name")?.textContent);
163
+ const salary = norm(item.querySelector(".salary-wrap span")?.textContent);
164
+ const baseInfo = Array.from(item.querySelectorAll(".base-info span"))
165
+ .map((el) => norm(el.textContent))
166
+ .filter(Boolean)
167
+ .join(" / ");
168
+ const expect =
169
+ norm(item.querySelector(".expect-wrap .content")?.textContent) ||
170
+ norm(item.querySelector(".expect-wrap .join-text-wrap")?.textContent);
171
+ const experience = norm(item.querySelector(".experience-wrap .join-text-wrap")?.textContent);
172
+ const advantage = norm(item.querySelector(".geek-desc .content")?.textContent);
173
+ const highlights = Array.from(item.querySelectorAll(".operate .labels .label"))
174
+ .map((el) => norm(el.textContent))
175
+ .filter(Boolean);
176
+ const greetBtn = item.querySelector(".button-chat-wrap .btn.btn-greet");
177
+ const btnCls = greetBtn?.className ?? "";
178
+ const disabled =
179
+ !greetBtn ||
180
+ /disabled|forbid|ban/i.test(btnCls) ||
181
+ greetBtn.getAttribute("disabled") !== null;
182
+ const hasHistoryChat = (() => {
183
+ if (item.querySelector(".tooltip-wrap.chat-history .icon-chat-history")) return true;
184
+ const uses = Array.from(item.querySelectorAll("use"));
185
+ return uses.some((u) => {
186
+ const href = u.getAttribute("href") ?? u.getAttributeNS("http://www.w3.org/1999/xlink", "href") ?? "";
187
+ return href.includes("icon-chat-history");
188
+ });
189
+ })();
190
+ return {
191
+ geekId,
192
+ name,
193
+ salary,
194
+ baseInfo,
195
+ expect,
196
+ experience,
197
+ advantage,
198
+ highlights,
199
+ canGreet: !disabled,
200
+ hasHistoryChat,
201
+ };
202
+ }).filter((x) => x.name);
203
+ })()`));
204
+ }
205
+ export function renderRecommendList(candidates) {
206
+ if (candidates.length === 0) {
207
+ return '推荐列表为空。';
208
+ }
209
+ const greetProduced = [];
210
+ const normal = [];
211
+ candidates.forEach((c) => {
212
+ if (c.geekId && sessionGreetProducedGeekIds.has(c.geekId)) {
213
+ greetProduced.push(c);
214
+ }
215
+ else {
216
+ normal.push(c);
217
+ }
218
+ });
219
+ const renderItems = (title, items) => {
220
+ const lines = [];
221
+ lines.push(`${title}(${items.length})`);
222
+ if (items.length === 0) {
223
+ lines.push(' - 暂无');
224
+ return lines;
225
+ }
226
+ items.forEach((m, idx) => {
227
+ const advantageText = m.advantage ||
228
+ (m.highlights.length > 0 ? m.highlights.slice(0, 3).join(' / ') : '(无)');
229
+ const fields = [
230
+ m.salary ? `薪资:${m.salary}` : '',
231
+ m.baseInfo ? `信息:${m.baseInfo}` : '',
232
+ m.expect ? `期望:${m.expect}` : '',
233
+ m.experience ? `经历:${m.experience}` : '',
234
+ m.hasHistoryChat ? '有历史沟通' : '',
235
+ m.canGreet ? '可打招呼' : '已打招呼',
236
+ ]
237
+ .filter(Boolean)
238
+ .join('|');
239
+ lines.push(` - ${idx + 1}. ${m.name}|${fields}`);
240
+ lines.push(` 优势: ${advantageText}`);
241
+ });
242
+ return lines;
243
+ };
244
+ const out = [];
245
+ out.push(`推荐列表(按来源分组):共 ${candidates.length} 人。`);
246
+ out.push('');
247
+ out.push(...renderItems('常规推荐', normal));
248
+ out.push('');
249
+ out.push(...renderItems('打招呼产生的推荐', greetProduced));
250
+ return out.join('\n');
251
+ }
252
+ export async function clickGreet(frame, target) {
253
+ const targetLiteral = JSON.stringify(target.trim());
254
+ const result = (await frame.evaluate(`(() => {
255
+ const raw = ${targetLiteral};
256
+ const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
257
+ const cards = Array.from(
258
+ document.querySelectorAll(".card-list .card-item, .geek-list .geek-card"),
259
+ );
260
+ if (cards.length === 0) {
261
+ return { kind: "empty" };
262
+ }
263
+
264
+ const idxNum = Number.parseInt(raw, 10);
265
+ let targetCard = null;
266
+ if (Number.isFinite(idxNum) && idxNum >= 1 && idxNum <= cards.length) {
267
+ targetCard = cards[idxNum - 1];
268
+ } else {
269
+ targetCard = cards.find((item) => {
270
+ const name =
271
+ norm(item.querySelector(".name-wrap .name")?.textContent) ||
272
+ norm(item.querySelector(".name")?.textContent);
273
+ return name === raw || name.includes(raw);
274
+ }) ?? null;
275
+ }
276
+ if (!targetCard) {
277
+ return { kind: "not_found", target: raw };
278
+ }
279
+
280
+ const name =
281
+ norm(targetCard.querySelector(".name-wrap .name")?.textContent) ||
282
+ norm(targetCard.querySelector(".name")?.textContent);
283
+ const inner = targetCard.querySelector(".card-inner") || targetCard;
284
+ const geekId =
285
+ inner?.getAttribute("data-geekid") ??
286
+ inner?.getAttribute("data-geek") ??
287
+ "";
288
+ const btn = targetCard.querySelector(".button-chat-wrap .btn.btn-greet");
289
+ if (!(btn instanceof HTMLElement)) {
290
+ return { kind: "no_btn", name };
291
+ }
292
+ const cls = btn.className ?? "";
293
+ const disabled = /disabled|forbid|ban/i.test(cls) || btn.getAttribute("disabled") !== null;
294
+ if (disabled) {
295
+ return { kind: "disabled", name };
296
+ }
297
+ btn.scrollIntoView({ block: "center", inline: "nearest" });
298
+ btn.click();
299
+ return { kind: "clicked", name, geekId };
300
+ })()`));
301
+ switch (result.kind) {
302
+ case 'empty':
303
+ throw new Error('推荐列表为空,无法执行打招呼。');
304
+ case 'not_found':
305
+ throw new Error(`未在推荐列表中找到目标:${result.target}`);
306
+ case 'no_btn':
307
+ throw new Error(`候选人 ${result.name} 缺少“打招呼”按钮,无法执行。`);
308
+ case 'disabled':
309
+ throw new Error(`候选人 ${result.name} 已打招呼。`);
310
+ case 'clicked':
311
+ return {
312
+ message: `已对 ${result.name} 点击“打招呼”。`,
313
+ };
314
+ default: {
315
+ const _x = result;
316
+ throw new Error(`未知结果:${String(_x)}`);
317
+ }
318
+ }
319
+ }
320
+ export function markGreetProduced(before, after) {
321
+ const beforeIds = new Set(before.map((x) => x.geekId).filter(Boolean));
322
+ after.forEach((x) => {
323
+ if (x.geekId && !beforeIds.has(x.geekId)) {
324
+ sessionGreetProducedGeekIds.add(x.geekId);
325
+ }
326
+ });
327
+ }
328
+ export async function runRecommend(jobKeyword) {
329
+ try {
330
+ return await withChatPage(async (page) => {
331
+ const frame = await ensureInRecommendPage(page);
332
+ const selectedJob = await selectRecommendJob(frame, (jobKeyword ?? '').trim());
333
+ const candidates = await readRecommendList(frame);
334
+ const title = selectedJob ? `当前岗位:${selectedJob}` : '当前岗位:默认';
335
+ return [title, '', renderRecommendList(candidates)].join('\n');
336
+ });
337
+ }
338
+ catch (e) {
339
+ const message = e instanceof Error ? e.message : String(e);
340
+ if (e instanceof Error && e.message.includes('浏览器会话尚未初始化')) {
341
+ throw new Error(createWaitManualLoginRequiredText('查看推荐列表'));
342
+ }
343
+ throw new Error(`读取推荐列表失败:${message}`);
344
+ }
345
+ }
346
+ //# sourceMappingURL=recommend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend.js","sourceRoot":"","sources":["../../src/toolset/recommend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runRecommendGreet(target: string): Promise<string>;
2
+ //# sourceMappingURL=recommend_greet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend_greet.d.ts","sourceRoot":"","sources":["../../src/toolset/recommend_greet.ts"],"names":[],"mappings":"AAaA,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvE"}
@@ -0,0 +1,27 @@
1
+ import { createWaitManualLoginRequiredText, sleepRandom, withChatPage, } from '../browser/index.js';
2
+ import { clickGreet, ensureInRecommendPage, markGreetProduced, readRecommendList, renderRecommendList, } from './recommend.js';
3
+ export async function runRecommendGreet(target) {
4
+ const t = target.trim();
5
+ if (!t) {
6
+ throw new Error('请提供打招呼目标(姓名或序号)。');
7
+ }
8
+ try {
9
+ return await withChatPage(async (page) => {
10
+ const frame = await ensureInRecommendPage(page);
11
+ const before = await readRecommendList(frame);
12
+ const greetResult = await clickGreet(frame, t);
13
+ await sleepRandom(380, 1000);
14
+ const after = await readRecommendList(frame);
15
+ markGreetProduced(before, after);
16
+ return [greetResult.message, '', '当前推荐列表(来源分组):', renderRecommendList(after)].join('\n');
17
+ });
18
+ }
19
+ catch (e) {
20
+ const message = e instanceof Error ? e.message : String(e);
21
+ if (e instanceof Error && e.message.includes('浏览器会话尚未初始化')) {
22
+ throw new Error(createWaitManualLoginRequiredText('推荐打招呼'));
23
+ }
24
+ throw new Error(`执行推荐打招呼失败:${message}`);
25
+ }
26
+ }
27
+ //# sourceMappingURL=recommend_greet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recommend_greet.js","sourceRoot":"","sources":["../../src/toolset/recommend_greet.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EACjC,WAAW,EACX,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc;IACpD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YACvC,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC9C,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC/C,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC7C,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACjC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runBossSearch(): Promise<string>;
2
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/toolset/search.ts"],"names":[],"mappings":"AAwLA,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CA2BrD"}
@@ -0,0 +1,174 @@
1
+ import { createWaitManualLoginRequiredText, sleepRandom, withChatPage, } from '../browser/index.js';
2
+ const BOSS_CHAT_AI_FORM_URL = 'https://www.zhipin.com/web/chat/aiform';
3
+ const AI_FORM_SETTLE_MS = { min: 1600, max: 2600 };
4
+ function isBossChatAiFormUrl(url) {
5
+ try {
6
+ const u = new URL(url);
7
+ if (!u.hostname.includes('zhipin.com')) {
8
+ return false;
9
+ }
10
+ const p = u.pathname.replace(/\/+$/, '') || '/';
11
+ return p === '/web/chat/aiform';
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ async function clickSidebarMenuToPath(page, menuLabel, targetPath) {
18
+ const labelLiteral = JSON.stringify(menuLabel);
19
+ const pathLiteral = JSON.stringify(targetPath);
20
+ const clicked = (await page.evaluate(`(() => {
21
+ const label = ${labelLiteral};
22
+ const path = ${pathLiteral};
23
+ const norm = (v) => (v ?? "").replace(/\\s+/g, "");
24
+ const links = Array.from(document.querySelectorAll(".menu-list a"));
25
+ const target = links.find((a) => {
26
+ const href = a.getAttribute("href") ?? "";
27
+ if (href.includes(path)) {
28
+ return true;
29
+ }
30
+ const text = norm(a.querySelector(".menu-item-content span")?.textContent ?? a.textContent);
31
+ return text.includes(label);
32
+ });
33
+ if (!(target instanceof HTMLElement)) {
34
+ return false;
35
+ }
36
+ target.scrollIntoView({ block: "center", inline: "nearest" });
37
+ target.click();
38
+ return true;
39
+ })()`));
40
+ if (!clicked) {
41
+ throw new Error(`未找到侧边栏菜单“${menuLabel}”,无法跳转到 ${targetPath}。`);
42
+ }
43
+ await page.waitForFunction(`(() => {
44
+ const path = ${pathLiteral};
45
+ try {
46
+ const p = window.location.pathname.replace(/\\/+$/g, "") || "/";
47
+ return p === path;
48
+ } catch {
49
+ return false;
50
+ }
51
+ })()`, { timeout: 15_000 });
52
+ }
53
+ async function waitForAiFormReady(page) {
54
+ await page.waitForFunction(`(() => {
55
+ const root = document.querySelector(".ai-form-left");
56
+ const submit = document.querySelector(".ai-form-match-footer .btn-ai-match-v2");
57
+ const selected = document.querySelector(".job-dropmenu-select .job-main-text");
58
+ if (!root || !submit || !selected) {
59
+ return false;
60
+ }
61
+ const text = (selected.textContent ?? "").replace(/\\s+/g, " ").trim();
62
+ return text.length > 0;
63
+ })()`, { timeout: 15_000 });
64
+ }
65
+ async function ensureInDeepSearchPage(page) {
66
+ if (!isBossChatAiFormUrl(page.url())) {
67
+ throw new Error('当前不在深度搜索页(/web/chat/aiform),请先进入后再执行 search。');
68
+ }
69
+ await waitForAiFormReady(page);
70
+ }
71
+ async function readSearchFormSnapshot(page) {
72
+ return (await page.evaluate(`(() => {
73
+ const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
74
+ const selectedJob = norm(document.querySelector(".job-dropmenu-select .job-main-text")?.textContent);
75
+ const sections = Array.from(document.querySelectorAll(".form-content"));
76
+ const coreRequirements = [];
77
+ const bonusRequirements = [];
78
+ for (const section of sections) {
79
+ const title = norm(section.querySelector(".form-content-header .form-content-title-h3")?.textContent);
80
+ const words = Array.from(section.querySelectorAll(".form-content-list-item .form-content-word"))
81
+ .map((el) => norm(el.textContent))
82
+ .filter(Boolean);
83
+ if (title.includes("核心要求")) {
84
+ coreRequirements.push(...words);
85
+ continue;
86
+ }
87
+ if (title.includes("加分项")) {
88
+ bonusRequirements.push(...words);
89
+ }
90
+ }
91
+ const remainingCountText = norm(document.querySelector(".ai-form-match-footer-text-count")?.textContent);
92
+ return {
93
+ selectedJob,
94
+ coreRequirements,
95
+ bonusRequirements,
96
+ remainingCountText,
97
+ };
98
+ })()`));
99
+ }
100
+ async function clickMatchNow(page) {
101
+ const clicked = (await page.evaluate(`(() => {
102
+ function norm(v) {
103
+ return (v ?? "").replace(/\\s+/g, "").trim();
104
+ }
105
+ function isVisible(el) {
106
+ if (!(el instanceof HTMLElement)) return false;
107
+ const st = window.getComputedStyle(el);
108
+ if (st.display === "none" || st.visibility === "hidden") return false;
109
+ const r = el.getBoundingClientRect();
110
+ return r.width > 0 && r.height > 0;
111
+ }
112
+ const buttons = Array.from(
113
+ document.querySelectorAll(".ai-form-match-footer .btn-ai-match-v2, .ai-form-match-footer-btn .btn-ai-common, .ai-form-match-footer-btn .light-flow-btn-content"),
114
+ ).filter((el) => isVisible(el));
115
+ if (buttons.length === 0) {
116
+ return false;
117
+ }
118
+ const preferred = buttons.find((el) => norm(el.textContent).includes("立即匹配")) ?? buttons[0];
119
+ if (!(preferred instanceof HTMLElement)) {
120
+ return false;
121
+ }
122
+ preferred.scrollIntoView({ block: "center", inline: "nearest" });
123
+ preferred.click();
124
+ return true;
125
+ })()`));
126
+ if (!clicked) {
127
+ throw new Error('未找到“立即匹配”按钮,无法执行深度搜索。');
128
+ }
129
+ }
130
+ function renderSearchResultText(before, after) {
131
+ const core = before.coreRequirements.length > 0 ? before.coreRequirements.join('|') : '(空)';
132
+ const bonus = before.bonusRequirements.length > 0 ? before.bonusRequirements.join('|') : '(空)';
133
+ const remain = before.remainingCountText || '未知';
134
+ const remainAfter = after.remainingCountText || '未知';
135
+ const remainLine = remain === remainAfter ? `今日匹配剩余:${remain}` : `今日匹配剩余:${remain} -> ${remainAfter}`;
136
+ return [
137
+ '已进入深度搜索并触发“立即匹配”。',
138
+ `职位:${before.selectedJob || '未知职位'}`,
139
+ `核心要求(${before.coreRequirements.length}):${core}`,
140
+ `加分项(${before.bonusRequirements.length}):${bonus}`,
141
+ remainLine,
142
+ `来源页面:${BOSS_CHAT_AI_FORM_URL}`,
143
+ ].join('\n');
144
+ }
145
+ export async function runBossSearch() {
146
+ try {
147
+ return await withChatPage(async (page) => {
148
+ const currentUrl = page.url();
149
+ if (!isBossChatAiFormUrl(currentUrl)) {
150
+ await clickSidebarMenuToPath(page, '深度搜索', '/web/chat/aiform');
151
+ await sleepRandom(AI_FORM_SETTLE_MS.min, AI_FORM_SETTLE_MS.max);
152
+ }
153
+ if (!isBossChatAiFormUrl(page.url())) {
154
+ throw new Error('通过侧边栏“深度搜索”进入页面失败,请确认已登录并可访问 /web/chat/aiform。');
155
+ }
156
+ await ensureInDeepSearchPage(page);
157
+ const before = await readSearchFormSnapshot(page);
158
+ await clickMatchNow(page);
159
+ await sleepRandom(1200, 1800);
160
+ await ensureInDeepSearchPage(page);
161
+ const after = await readSearchFormSnapshot(page);
162
+ return renderSearchResultText(before, after);
163
+ });
164
+ }
165
+ catch (e) {
166
+ const message = e instanceof Error ? e.message : String(e);
167
+ if (e instanceof Error && e.message.includes('浏览器会话尚未初始化')) {
168
+ throw new Error(createWaitManualLoginRequiredText('执行深度搜索'));
169
+ }
170
+ console.error(`[boss-cli] boss_search error: ${message}`);
171
+ throw new Error(`执行深度搜索失败:${message}`);
172
+ }
173
+ }
174
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/toolset/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type SendChatMessageOptions = {
2
+ text?: string;
3
+ signal?: AbortSignal;
4
+ };
5
+ export declare function runSendChatMessage(options: SendChatMessageOptions): Promise<string>;
6
+ //# sourceMappingURL=send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/toolset/send.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDzF"}
@@ -0,0 +1,46 @@
1
+ import { createWaitManualLoginRequiredText, isBossChatIndexUrl, randomIntInclusive, SEND_AFTER_ENTER_MS, SEND_INPUT_CLICK_MS, SEND_TYPING_GAP_MS, sleepRandom, typeTextWithRandomKeyDelay, withChatPage, } from '../browser/index.js';
2
+ export async function runSendChatMessage(options) {
3
+ const messageText = (options.text ?? '').trim();
4
+ const signal = options.signal;
5
+ if (!messageText) {
6
+ throw new Error('请指定 --text <消息> 或 -t <消息>。');
7
+ }
8
+ try {
9
+ return await withChatPage(async (page) => {
10
+ const currentUrl = page.url();
11
+ if (!isBossChatIndexUrl(currentUrl)) {
12
+ throw new Error('请先进入聊天列表页(/web/chat/index)并打开候选人聊天。');
13
+ }
14
+ const input = await page.$('#boss-chat-editor-input');
15
+ if (!input) {
16
+ throw new Error('未找到聊天输入框(#boss-chat-editor-input)。');
17
+ }
18
+ await input.click({
19
+ delay: randomIntInclusive(SEND_INPUT_CLICK_MS.min, SEND_INPUT_CLICK_MS.max),
20
+ });
21
+ await sleepRandom(60, 220, signal);
22
+ await page.keyboard.down('Control');
23
+ await page.keyboard.press('KeyA');
24
+ await page.keyboard.up('Control');
25
+ await sleepRandom(45, 180, signal);
26
+ await page.keyboard.press('Backspace');
27
+ await sleepRandom(80, 260, signal);
28
+ await typeTextWithRandomKeyDelay(page, messageText, SEND_TYPING_GAP_MS.min, SEND_TYPING_GAP_MS.max, signal);
29
+ await sleepRandom(120, 420, signal);
30
+ await page.keyboard.press('Enter');
31
+ await sleepRandom(SEND_AFTER_ENTER_MS.min, SEND_AFTER_ENTER_MS.max, signal);
32
+ return `已发送消息:${messageText}`;
33
+ });
34
+ }
35
+ catch (e) {
36
+ const message = e instanceof Error ? e.message : String(e);
37
+ if (e instanceof Error) {
38
+ if (e.message.includes('浏览器会话尚未初始化')) {
39
+ throw new Error(createWaitManualLoginRequiredText('发送消息'));
40
+ }
41
+ throw e;
42
+ }
43
+ throw new Error(`发送消息失败:${message}`);
44
+ }
45
+ }
46
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/toolset/send.ts"],"names":[],"mappings":"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"}