@joohw/boss-cli 0.1.8 → 0.2.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.
- package/AGENTS.md +25 -25
- package/README.md +34 -19
- package/dist/browser/agent_operating_indicator.d.ts +9 -0
- package/dist/browser/agent_operating_indicator.d.ts.map +1 -0
- package/dist/browser/agent_operating_indicator.js +92 -0
- package/dist/browser/agent_operating_indicator.js.map +1 -0
- package/dist/browser/c_resume_capture.d.ts +11 -0
- package/dist/browser/c_resume_capture.d.ts.map +1 -0
- package/dist/browser/c_resume_capture.js +76 -0
- package/dist/browser/c_resume_capture.js.map +1 -0
- package/dist/browser/chat.d.ts +3 -3
- package/dist/browser/chat.d.ts.map +1 -1
- package/dist/browser/chat.js +43 -5
- package/dist/browser/chat.js.map +1 -1
- package/dist/browser/human_delay.d.ts +5 -0
- package/dist/browser/human_delay.d.ts.map +1 -1
- package/dist/browser/human_delay.js +5 -0
- package/dist/browser/human_delay.js.map +1 -1
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/viewport_temp.d.ts +15 -0
- package/dist/browser/viewport_temp.d.ts.map +1 -0
- package/dist/browser/viewport_temp.js +78 -0
- package/dist/browser/viewport_temp.js.map +1 -0
- package/dist/cli/banner.d.ts +1 -1
- package/dist/cli/banner.d.ts.map +1 -1
- package/dist/cli/banner.js +8 -39
- package/dist/cli/banner.js.map +1 -1
- package/dist/cli/cliRouter.d.ts.map +1 -1
- package/dist/cli/cliRouter.js +40 -11
- package/dist/cli/cliRouter.js.map +1 -1
- package/dist/common/auth.d.ts +38 -0
- package/dist/common/auth.d.ts.map +1 -0
- package/dist/common/auth.js +150 -0
- package/dist/common/auth.js.map +1 -0
- package/dist/common/boss_paywall_popup.d.ts +17 -0
- package/dist/common/boss_paywall_popup.d.ts.map +1 -0
- package/dist/common/boss_paywall_popup.js +132 -0
- package/dist/common/boss_paywall_popup.js.map +1 -0
- package/dist/common/boss_session_page.d.ts +11 -0
- package/dist/common/boss_session_page.d.ts.map +1 -0
- package/dist/common/boss_session_page.js +155 -0
- package/dist/common/boss_session_page.js.map +1 -0
- package/dist/common/boss_sidebar_nav.d.ts +6 -0
- package/dist/common/boss_sidebar_nav.d.ts.map +1 -0
- package/dist/common/boss_sidebar_nav.js +37 -0
- package/dist/common/boss_sidebar_nav.js.map +1 -0
- package/dist/common/c_resume_capture.d.ts +18 -0
- package/dist/common/c_resume_capture.d.ts.map +1 -0
- package/dist/common/c_resume_capture.js +125 -0
- package/dist/common/c_resume_capture.js.map +1 -0
- package/dist/toolset/action.d.ts +1 -1
- package/dist/toolset/action.d.ts.map +1 -1
- package/dist/toolset/action.js +193 -152
- package/dist/toolset/action.js.map +1 -1
- package/dist/toolset/c_resume_capture.d.ts +11 -0
- package/dist/toolset/c_resume_capture.d.ts.map +1 -0
- package/dist/toolset/c_resume_capture.js +76 -0
- package/dist/toolset/c_resume_capture.js.map +1 -0
- package/dist/toolset/chat.d.ts.map +1 -1
- package/dist/toolset/chat.js +6 -4
- package/dist/toolset/chat.js.map +1 -1
- package/dist/toolset/deep-search.d.ts +31 -0
- package/dist/toolset/deep-search.d.ts.map +1 -0
- package/dist/toolset/deep-search.js +1057 -0
- package/dist/toolset/deep-search.js.map +1 -0
- package/dist/toolset/greet.d.ts.map +1 -1
- package/dist/toolset/greet.js +32 -10
- package/dist/toolset/greet.js.map +1 -1
- package/dist/toolset/index.d.ts +13 -1
- package/dist/toolset/index.d.ts.map +1 -1
- package/dist/toolset/index.js +13 -6
- package/dist/toolset/index.js.map +1 -1
- package/dist/toolset/jd.d.ts.map +1 -1
- package/dist/toolset/jd.js +6 -35
- package/dist/toolset/jd.js.map +1 -1
- package/dist/toolset/list.d.ts +6 -0
- package/dist/toolset/list.d.ts.map +1 -1
- package/dist/toolset/list.js +38 -60
- package/dist/toolset/list.js.map +1 -1
- package/dist/toolset/login.d.ts.map +1 -1
- package/dist/toolset/login.js +2 -5
- package/dist/toolset/login.js.map +1 -1
- package/dist/toolset/preview.d.ts +6 -0
- package/dist/toolset/preview.d.ts.map +1 -0
- package/dist/toolset/preview.js +103 -0
- package/dist/toolset/preview.js.map +1 -0
- package/dist/toolset/recommend.d.ts +13 -0
- package/dist/toolset/recommend.d.ts.map +1 -1
- package/dist/toolset/recommend.js +104 -46
- package/dist/toolset/recommend.js.map +1 -1
- package/dist/toolset/search.d.ts +23 -1
- package/dist/toolset/search.d.ts.map +1 -1
- package/dist/toolset/search.js +556 -48
- package/dist/toolset/search.js.map +1 -1
- package/dist/toolset/send.d.ts.map +1 -1
- package/dist/toolset/send.js +4 -2
- package/dist/toolset/send.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ONLINE_RESUME_IFRAME_WAIT_MAX_MS } from '../browser/human_delay.js';
|
|
2
|
+
import { sleepRandom } from '../browser/timing.js';
|
|
3
|
+
import { frameHasVisibleCResumeIframe } from './c_resume_capture.js';
|
|
4
|
+
/** 付费墙仅在主文档轮询(遮罩层挂在顶层);与 {@link describeBossPaywallPopupIfPresent} 判定一致 */
|
|
5
|
+
const HAS_PAYWALL_SCRIPT = `(() => {
|
|
6
|
+
const roots = Array.from(
|
|
7
|
+
document.querySelectorAll(".boss-popup__wrapper, .boss-dialog__wrapper"),
|
|
8
|
+
);
|
|
9
|
+
for (const root of roots) {
|
|
10
|
+
if (!(root instanceof HTMLElement)) continue;
|
|
11
|
+
const st = window.getComputedStyle(root);
|
|
12
|
+
if (st.display === "none" || st.visibility === "hidden" || Number(st.opacity) < 0.05) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const rect = root.getBoundingClientRect();
|
|
16
|
+
if (rect.width < 20 || rect.height < 20) continue;
|
|
17
|
+
const hasVipUi = root.querySelector(
|
|
18
|
+
".block-vip2, .vip2-layout, .payment-layout-v2, .rights-table-vip, .qrcode-v1, .pay-wrap-qrcode-v1, .panel-deadline",
|
|
19
|
+
);
|
|
20
|
+
const text = (root.textContent || "").replace(/\\s+/g, " ");
|
|
21
|
+
const hasPayText =
|
|
22
|
+
/VIP账号|商品需付|直豆|扫码支付|请使用.*支付宝|请使用.*微信|增值服务协议|VIP\\s*\\d+项|限时特惠|直豆抵扣/.test(
|
|
23
|
+
text,
|
|
24
|
+
);
|
|
25
|
+
if (!hasVipUi && !hasPayText) continue;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
})()`;
|
|
30
|
+
/**
|
|
31
|
+
* 轮询直到出现 c-resume iframe、或出现付费墙、或超时。
|
|
32
|
+
* c-resume 可能在主文档,也可能在 `recommendFrame` 等子 frame 内(推荐预览),故遍历 {@link Page.frames}。
|
|
33
|
+
*/
|
|
34
|
+
export async function waitForCResumeIframeOrPaywall(page, timeoutMs = ONLINE_RESUME_IFRAME_WAIT_MAX_MS) {
|
|
35
|
+
const deadline = Date.now() + timeoutMs;
|
|
36
|
+
while (Date.now() < deadline) {
|
|
37
|
+
const paywall = (await page.evaluate(HAS_PAYWALL_SCRIPT));
|
|
38
|
+
if (paywall) {
|
|
39
|
+
return 'paywall';
|
|
40
|
+
}
|
|
41
|
+
const frames = page.frames();
|
|
42
|
+
for (const frame of frames) {
|
|
43
|
+
if (await frameHasVisibleCResumeIframe(frame)) {
|
|
44
|
+
return 'iframe';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
await sleepRandom(160, 240);
|
|
48
|
+
}
|
|
49
|
+
return 'neither';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 若当前存在 VIP/付费类弹层(判定规则与 {@link describeBossPaywallPopupIfPresent} 一致),
|
|
53
|
+
* 则点击关闭按钮以恢复页面可操作状态。返回是否执行了关闭。
|
|
54
|
+
*/
|
|
55
|
+
export async function closeBossPaywallPopupIfPresent(page) {
|
|
56
|
+
const closed = (await page.evaluate(`(() => {
|
|
57
|
+
const roots = Array.from(
|
|
58
|
+
document.querySelectorAll(".boss-popup__wrapper, .boss-dialog__wrapper"),
|
|
59
|
+
);
|
|
60
|
+
for (const root of roots) {
|
|
61
|
+
if (!(root instanceof HTMLElement)) continue;
|
|
62
|
+
const st = window.getComputedStyle(root);
|
|
63
|
+
if (st.display === "none" || st.visibility === "hidden" || Number(st.opacity) < 0.05) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const rect = root.getBoundingClientRect();
|
|
67
|
+
if (rect.width < 20 || rect.height < 20) continue;
|
|
68
|
+
const hasVipUi = root.querySelector(
|
|
69
|
+
".block-vip2, .vip2-layout, .payment-layout-v2, .rights-table-vip, .qrcode-v1, .pay-wrap-qrcode-v1, .panel-deadline",
|
|
70
|
+
);
|
|
71
|
+
const text = (root.textContent || "").replace(/\\s+/g, " ");
|
|
72
|
+
const hasPayText =
|
|
73
|
+
/VIP账号|商品需付|直豆|扫码支付|请使用.*支付宝|请使用.*微信|增值服务协议|VIP\\s*\\d+项|限时特惠|直豆抵扣/.test(
|
|
74
|
+
text,
|
|
75
|
+
);
|
|
76
|
+
if (!hasVipUi && !hasPayText) continue;
|
|
77
|
+
const closeBtn = root.querySelector(
|
|
78
|
+
".boss-popup__close, .boss-dialog__close, .drawer-close, .icon-close",
|
|
79
|
+
);
|
|
80
|
+
if (closeBtn instanceof HTMLElement) {
|
|
81
|
+
closeBtn.click();
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
})()`));
|
|
87
|
+
if (closed) {
|
|
88
|
+
await sleepRandom(220, 480);
|
|
89
|
+
}
|
|
90
|
+
return closed;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 检测 Boss 页面上是否出现 VIP/付费购买类弹层(如点击「在线简历」或推荐预览后拦截权益时)。
|
|
94
|
+
* 命中则返回简短中文说明,供与「未出现 c-resume iframe」类错误拼接。
|
|
95
|
+
*/
|
|
96
|
+
export async function describeBossPaywallPopupIfPresent(page) {
|
|
97
|
+
return (await page.evaluate(`(() => {
|
|
98
|
+
const roots = Array.from(
|
|
99
|
+
document.querySelectorAll(".boss-popup__wrapper, .boss-dialog__wrapper"),
|
|
100
|
+
);
|
|
101
|
+
for (const root of roots) {
|
|
102
|
+
if (!(root instanceof HTMLElement)) continue;
|
|
103
|
+
const st = window.getComputedStyle(root);
|
|
104
|
+
if (st.display === "none" || st.visibility === "hidden" || Number(st.opacity) < 0.05) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const rect = root.getBoundingClientRect();
|
|
108
|
+
if (rect.width < 20 || rect.height < 20) continue;
|
|
109
|
+
const hasVipUi = root.querySelector(
|
|
110
|
+
".block-vip2, .vip2-layout, .payment-layout-v2, .rights-table-vip, .qrcode-v1, .pay-wrap-qrcode-v1, .panel-deadline",
|
|
111
|
+
);
|
|
112
|
+
const text = (root.textContent || "").replace(/\\s+/g, " ");
|
|
113
|
+
const hasPayText =
|
|
114
|
+
/VIP账号|商品需付|直豆|扫码支付|请使用.*支付宝|请使用.*微信|增值服务协议|VIP\\s*\\d+项|限时特惠|直豆抵扣/.test(
|
|
115
|
+
text,
|
|
116
|
+
);
|
|
117
|
+
if (!hasVipUi && !hasPayText) continue;
|
|
118
|
+
const h = root.querySelector("h3.title, h4.title, .card-header .title");
|
|
119
|
+
const title = (h?.textContent || "").replace(/\\s+/g, " ").trim();
|
|
120
|
+
if (title) {
|
|
121
|
+
return (
|
|
122
|
+
"页面出现付费弹层(" +
|
|
123
|
+
title +
|
|
124
|
+
"),可能需开通 VIP 或购买权益后才能查看在线简历。"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return "页面出现 VIP/付费购买弹层,可能需开通权益后才能查看在线简历。";
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
})()`));
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=boss_paywall_popup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss_paywall_popup.js","sourceRoot":"","sources":["../../src/common/boss_paywall_popup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAErE,2EAA2E;AAC3E,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;KAwBtB,CAAC;AAEN;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,IAAU,EACV,YAAoB,gCAAgC;IAEpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAY,CAAC;QACrE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,MAAM,4BAA4B,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9C,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;QAED,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAAC,IAAU;IAC7D,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8B/B,CAAC,CAAY,CAAC;IACnB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iCAAiC,CAAC,IAAU;IAChE,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCvB,CAAC,CAAkB,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boss B 端「已登录主壳」会话:选页、必要时进入沟通页、侧栏 `.menu-list` 探测与稳定检测,
|
|
3
|
+
* 再执行 {@link withBossSessionPage} 回调。与 `src/toolset/chat.ts`(按姓名打开会话等业务)无关。
|
|
4
|
+
*/
|
|
5
|
+
import type { Page } from 'puppeteer-core';
|
|
6
|
+
/**
|
|
7
|
+
* 在已连接浏览器、且当前页为 Boss 已登录主壳(含侧栏 `.menu-list` 稳定)的前提下执行回调。
|
|
8
|
+
* 若当前不在 zhipin.com 则先进入沟通页 `/web/chat/index`,再校验侧栏;已在 Boss 站内(如推荐页)则不强制跳转。
|
|
9
|
+
*/
|
|
10
|
+
export declare function withBossSessionPage<T>(callback: (page: Page) => Promise<T>): Promise<T>;
|
|
11
|
+
//# sourceMappingURL=boss_session_page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss_session_page.d.ts","sourceRoot":"","sources":["../../src/common/boss_session_page.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAwIpD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAuD7F"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { BOSS_CHAT_INDEX_URL, isBossZhipinSiteUrl } from './auth.js';
|
|
2
|
+
import { hideAgentOperatingIndicator, showAgentOperatingIndicator, } from '../browser/agent_operating_indicator.js';
|
|
3
|
+
import { ensureBrowserSession, getBrowserRef, getPageRef, setSessionPage, } from '../browser/browser_session.js';
|
|
4
|
+
import { CONTEXT_DESTROY_RETRY_MS } from '../browser/human_delay.js';
|
|
5
|
+
import { sleepRandom } from '../browser/timing.js';
|
|
6
|
+
const SHOULD_DISABLE_JS = process.env.BOSS_BROWSER_DISABLE_JS === 'true' || process.env.BOSS_BROWSER_DISABLE_JS === '1';
|
|
7
|
+
/** 设为 `1` / `true` 时不注入顶栏滚动提示(调试或截图对比用)。 */
|
|
8
|
+
const SKIP_AGENT_OPERATING_OVERLAY = process.env.BOSS_CLI_NO_AGENT_OVERLAY === '1' ||
|
|
9
|
+
process.env.BOSS_CLI_NO_AGENT_OVERLAY === 'true';
|
|
10
|
+
/** Boss 为 SPA:`load` 后侧栏可能尚未挂载,需单独等待 `.menu-list` 出现 */
|
|
11
|
+
const MENU_LIST_MOUNT_TIMEOUT_MS = 30_000;
|
|
12
|
+
async function pickExistingPage(browser) {
|
|
13
|
+
const pages = (await browser.pages()).filter((p) => !p.isClosed());
|
|
14
|
+
if (pages.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
const urls = await Promise.all(pages.map((p) => {
|
|
17
|
+
try {
|
|
18
|
+
return p.url();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
}));
|
|
24
|
+
const zhipin = pages.find((p, i) => {
|
|
25
|
+
const u = urls[i] ?? '';
|
|
26
|
+
return u.length > 0 && u !== 'about:blank' && u.includes('zhipin.com');
|
|
27
|
+
});
|
|
28
|
+
if (zhipin)
|
|
29
|
+
return zhipin;
|
|
30
|
+
const nonBlank = pages.find((p, i) => {
|
|
31
|
+
const u = urls[i] ?? '';
|
|
32
|
+
return u.length > 0 && u !== 'about:blank';
|
|
33
|
+
});
|
|
34
|
+
return nonBlank ?? null;
|
|
35
|
+
}
|
|
36
|
+
function normalizeMenuText(raw) {
|
|
37
|
+
return (raw ?? '').replace(/\s+/g, ' ').trim();
|
|
38
|
+
}
|
|
39
|
+
async function readMenuListSnapshot(page) {
|
|
40
|
+
return (await page.evaluate(`(() => {
|
|
41
|
+
const root = document.querySelector(".menu-list");
|
|
42
|
+
if (!root) {
|
|
43
|
+
return { exists: false, signature: "" };
|
|
44
|
+
}
|
|
45
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
46
|
+
const links = Array.from(root.querySelectorAll("dl > dt > a"));
|
|
47
|
+
const entries = links.map((a) => {
|
|
48
|
+
const href = a.getAttribute("href") ?? "";
|
|
49
|
+
const labelNode = a.querySelector(".menu-item-content span");
|
|
50
|
+
const label = norm(labelNode?.textContent || a.textContent || "");
|
|
51
|
+
return label + "::" + href;
|
|
52
|
+
});
|
|
53
|
+
return { exists: true, signature: entries.join("|") };
|
|
54
|
+
})()`));
|
|
55
|
+
}
|
|
56
|
+
/** 仅当当前页不在 Boss 站点(非 zhipin.com / 空白等)时进入沟通页,再交由 {@link ensureMenuListStableAfterLoad} 查 `.menu-list` */
|
|
57
|
+
async function ensureBossZhipinLandingBeforeMenuList(page) {
|
|
58
|
+
if (isBossZhipinSiteUrl(page.url())) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
await page.goto(BOSS_CHAT_INDEX_URL, { waitUntil: 'load', timeout: 60_000 });
|
|
62
|
+
}
|
|
63
|
+
async function ensureMenuListStableAfterLoad(page) {
|
|
64
|
+
await page.waitForFunction(`(() => document.readyState === "complete" || document.readyState === "interactive")()`, { timeout: 12_000 });
|
|
65
|
+
try {
|
|
66
|
+
await page.waitForFunction(`(() => !!document.querySelector(".menu-list"))()`, { timeout: MENU_LIST_MOUNT_TIMEOUT_MS });
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
70
|
+
const timedOut = err.name === 'TimeoutError' || /timeout|waiting failed/i.test(err.message);
|
|
71
|
+
if (timedOut) {
|
|
72
|
+
throw new Error(`在 ${MENU_LIST_MOUNT_TIMEOUT_MS / 1000}s 内未出现侧栏 .menu-list(页面或仍在加载,或未登录无法进入主壳)。`);
|
|
73
|
+
}
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
const first = await readMenuListSnapshot(page);
|
|
77
|
+
if (!first.exists) {
|
|
78
|
+
throw new Error('当前页面可能未登录或未进入 Boss 主界面。');
|
|
79
|
+
}
|
|
80
|
+
if (!normalizeMenuText(first.signature)) {
|
|
81
|
+
throw new Error('检测到 .menu-list 但菜单内容为空,当前页面状态异常。');
|
|
82
|
+
}
|
|
83
|
+
const stableWindowMs = 3_000;
|
|
84
|
+
const pollMs = 300;
|
|
85
|
+
const deadline = Date.now() + stableWindowMs;
|
|
86
|
+
const expected = first.signature;
|
|
87
|
+
while (Date.now() < deadline) {
|
|
88
|
+
await sleepRandom(pollMs, pollMs);
|
|
89
|
+
const snap = await readMenuListSnapshot(page);
|
|
90
|
+
if (!snap.exists) {
|
|
91
|
+
throw new Error('页面中的 .menu-list 在 3 秒稳定检测内消失,疑似未登录或页面仍在跳转。');
|
|
92
|
+
}
|
|
93
|
+
if (snap.signature !== expected) {
|
|
94
|
+
throw new Error('页面中的 .menu-list 在 3 秒稳定检测内发生变化,疑似页面仍在重定向或刷新。');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 在已连接浏览器、且当前页为 Boss 已登录主壳(含侧栏 `.menu-list` 稳定)的前提下执行回调。
|
|
100
|
+
* 若当前不在 zhipin.com 则先进入沟通页 `/web/chat/index`,再校验侧栏;已在 Boss 站内(如推荐页)则不强制跳转。
|
|
101
|
+
*/
|
|
102
|
+
export async function withBossSessionPage(callback) {
|
|
103
|
+
const isContextDestroyed = (e) => {
|
|
104
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
105
|
+
return (msg.includes('Execution context was destroyed') ||
|
|
106
|
+
msg.includes('Cannot find context with specified id') ||
|
|
107
|
+
msg.includes('Most likely because of a navigation'));
|
|
108
|
+
};
|
|
109
|
+
const maxAttempts = 2;
|
|
110
|
+
let lastErr;
|
|
111
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
112
|
+
try {
|
|
113
|
+
await ensureBrowserSession();
|
|
114
|
+
const browser = getBrowserRef();
|
|
115
|
+
if (!browser) {
|
|
116
|
+
throw new Error('无法获取浏览器实例。');
|
|
117
|
+
}
|
|
118
|
+
let page = getPageRef();
|
|
119
|
+
if (!page || page.isClosed()) {
|
|
120
|
+
page = (await pickExistingPage(browser)) ?? (await browser.newPage());
|
|
121
|
+
}
|
|
122
|
+
setSessionPage(page);
|
|
123
|
+
await page.bringToFront();
|
|
124
|
+
await ensureBossZhipinLandingBeforeMenuList(page);
|
|
125
|
+
if (SHOULD_DISABLE_JS) {
|
|
126
|
+
await page.setJavaScriptEnabled(false);
|
|
127
|
+
}
|
|
128
|
+
await ensureMenuListStableAfterLoad(page);
|
|
129
|
+
if (!SHOULD_DISABLE_JS && !SKIP_AGENT_OPERATING_OVERLAY) {
|
|
130
|
+
await showAgentOperatingIndicator(page).catch(() => {
|
|
131
|
+
/* 注入失败不阻断业务 */
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
return await callback(page);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
if (!SHOULD_DISABLE_JS && !SKIP_AGENT_OPERATING_OVERLAY) {
|
|
139
|
+
await hideAgentOperatingIndicator(page);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
lastErr = e;
|
|
145
|
+
if (attempt < maxAttempts - 1 && isContextDestroyed(e)) {
|
|
146
|
+
// Boss 页面偶发跳转/重渲染会销毁执行上下文;短暂等待并重试一次即可。
|
|
147
|
+
await sleepRandom(CONTEXT_DESTROY_RETRY_MS.min, CONTEXT_DESTROY_RETRY_MS.max);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=boss_session_page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss_session_page.js","sourceRoot":"","sources":["../../src/common/boss_session_page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Page } from 'puppeteer-core';
|
|
2
|
+
/**
|
|
3
|
+
* 点击 Boss 左侧 `.menu-list` 中的菜单项,并等待导航到给定 pathname(如 `/web/chat/index`)。
|
|
4
|
+
*/
|
|
5
|
+
export declare function clickBossSidebarMenuToPath(page: Page, menuLabel: string, targetPath: string): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=boss_sidebar_nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss_sidebar_nav.d.ts","sourceRoot":"","sources":["../../src/common/boss_sidebar_nav.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAI3C;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAuCf"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const SIDEBAR_NAV_WAIT_MS = 15_000;
|
|
2
|
+
/**
|
|
3
|
+
* 点击 Boss 左侧 `.menu-list` 中的菜单项,并等待导航到给定 pathname(如 `/web/chat/index`)。
|
|
4
|
+
*/
|
|
5
|
+
export async function clickBossSidebarMenuToPath(page, menuLabel, targetPath) {
|
|
6
|
+
const clicked = (await page.evaluate(({ label, path }) => {
|
|
7
|
+
const norm = (v) => (v ?? '').replace(/\s+/g, '');
|
|
8
|
+
const links = Array.from(document.querySelectorAll('.menu-list a'));
|
|
9
|
+
const target = links.find((a) => {
|
|
10
|
+
const href = a.getAttribute('href') ?? '';
|
|
11
|
+
if (href.includes(path)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
const text = norm(a.querySelector('.menu-item-content span')?.textContent ?? a.textContent);
|
|
15
|
+
return text.includes(label);
|
|
16
|
+
});
|
|
17
|
+
if (!(target instanceof HTMLElement)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
target.scrollIntoView({ block: 'center', inline: 'nearest' });
|
|
21
|
+
target.click();
|
|
22
|
+
return true;
|
|
23
|
+
}, { label: menuLabel, path: targetPath }));
|
|
24
|
+
if (!clicked) {
|
|
25
|
+
throw new Error(`未找到侧边栏菜单“${menuLabel}”,无法跳转到 ${targetPath}。`);
|
|
26
|
+
}
|
|
27
|
+
await page.waitForFunction((path) => {
|
|
28
|
+
try {
|
|
29
|
+
const p = window.location.pathname.replace(/\/+$/, '') || '/';
|
|
30
|
+
return p === path;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}, { timeout: SIDEBAR_NAV_WAIT_MS }, targetPath);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=boss_sidebar_nav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss_sidebar_nav.js","sourceRoot":"","sources":["../../src/common/boss_sidebar_nav.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,IAAU,EACV,SAAiB,EACjB,UAAkB;IAElB,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAClC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QAClB,MAAM,IAAI,GAAG,CAAC,CAA4B,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,yBAAyB,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;YAC5F,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,YAAY,WAAW,CAAC,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC,EACD,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,CACvC,CAAY,CAAC;IAEd,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,WAAW,UAAU,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,IAAI,CAAC,eAAe,CACxB,CAAC,IAAI,EAAE,EAAE;QACP,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;YAC9D,OAAO,CAAC,KAAK,IAAI,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,EACD,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAChC,UAAU,CACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ElementHandle, Frame, Page } from 'puppeteer-core';
|
|
2
|
+
/** 在线简历 iframe:`src` 常为相对路径 `/web/frame/c-resume/...`,故用子串匹配 */
|
|
3
|
+
export declare const C_RESUME_IFRAME_SELECTOR: "iframe[src*=\"c-resume\"], iframe[src*=\"frame/c-resume\"]";
|
|
4
|
+
export declare function frameHasVisibleCResumeIframe(frame: Frame): Promise<boolean>;
|
|
5
|
+
/** 截图文件名安全段(在线简历 / 推荐预览共用) */
|
|
6
|
+
export declare function safeResumeScreenshotFileBase(name: string): string;
|
|
7
|
+
/** 关闭含 `c-resume` iframe 的弹层(聊天「在线简历」与推荐「预览」共用)。含 `.boss-popup__close`、`.btn-quxiao`(取消)等。会在主文档与各子 frame 中尝试。 */
|
|
8
|
+
export declare function closeCResumePanel(page: Page): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 在任意 frame(含主 frame、`recommendFrame` 等)中查找已挂载且尺寸可见的 c-resume iframe。
|
|
11
|
+
*/
|
|
12
|
+
export declare function findVisibleCResumeIframeHandle(page: Page): Promise<ElementHandle<Element> | null>;
|
|
13
|
+
/**
|
|
14
|
+
* 在已出现 `c-resume` iframe 的页面上,对 iframe 整框截图并关闭弹层。
|
|
15
|
+
* `preOpenViewport` 为打开弹层前的视口快照,请用 `snapshotBossPageViewport(page)`(`page.viewport()` 常为 null 时勿直接用默认尺寸)。
|
|
16
|
+
*/
|
|
17
|
+
export declare function captureCResumeIframeToFile(page: Page, preOpenViewport: Awaited<ReturnType<Page['viewport']>>, absPath: string): Promise<boolean>;
|
|
18
|
+
//# sourceMappingURL=c_resume_capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"c_resume_capture.d.ts","sourceRoot":"","sources":["../../src/common/c_resume_capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAIjE,gEAAgE;AAChE,eAAO,MAAM,wBAAwB,EACnC,4DAAiE,CAAC;AAqCpE,wBAAsB,4BAA4B,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAMjF;AAED,8BAA8B;AAC9B,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,iHAAiH;AACjH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAajE;AAED;;GAEG;AACH,wBAAsB,8BAA8B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAevG;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,IAAI,EACV,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EACtD,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAmClB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { sleepRandom } from '../browser/timing.js';
|
|
2
|
+
import { resumeHeight, setTempHeight } from '../browser/viewport_temp.js';
|
|
3
|
+
/** 在线简历 iframe:`src` 常为相对路径 `/web/frame/c-resume/...`,故用子串匹配 */
|
|
4
|
+
export const C_RESUME_IFRAME_SELECTOR = 'iframe[src*="c-resume"], iframe[src*="frame/c-resume"]';
|
|
5
|
+
const CLOSE_C_RESUME_PANEL_SCRIPT = `(() => {
|
|
6
|
+
const sel = ${JSON.stringify(C_RESUME_IFRAME_SELECTOR)};
|
|
7
|
+
const wraps = Array.from(document.querySelectorAll('.boss-popup__wrapper'));
|
|
8
|
+
for (var wi = 0; wi < wraps.length; wi++) {
|
|
9
|
+
var w = wraps[wi];
|
|
10
|
+
if (w.querySelector(sel)) {
|
|
11
|
+
var c = w.querySelector('.boss-popup__close') || w.querySelector('.btn-quxiao');
|
|
12
|
+
if (c) {
|
|
13
|
+
c.click();
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
var iframe = document.querySelector(sel);
|
|
19
|
+
var node = iframe ? iframe.parentElement : null;
|
|
20
|
+
for (var i = 0; i < 12 && node; i++) {
|
|
21
|
+
var closeBtn = node.querySelector(
|
|
22
|
+
'.boss-popup__close, .drawer-close, .icon-close, .btn-quxiao',
|
|
23
|
+
);
|
|
24
|
+
if (closeBtn) {
|
|
25
|
+
closeBtn.click();
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
node = node.parentElement;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
})()`;
|
|
32
|
+
const VISIBLE_C_RESUME_IN_FRAME_SCRIPT = `(() => {
|
|
33
|
+
var iframe = document.querySelector(${JSON.stringify(C_RESUME_IFRAME_SELECTOR)});
|
|
34
|
+
if (!(iframe instanceof HTMLElement)) return false;
|
|
35
|
+
var r = iframe.getBoundingClientRect();
|
|
36
|
+
return r.width > 8 && r.height > 8;
|
|
37
|
+
})()`;
|
|
38
|
+
export async function frameHasVisibleCResumeIframe(frame) {
|
|
39
|
+
try {
|
|
40
|
+
return (await frame.evaluate(VISIBLE_C_RESUME_IN_FRAME_SCRIPT));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** 截图文件名安全段(在线简历 / 推荐预览共用) */
|
|
47
|
+
export function safeResumeScreenshotFileBase(name) {
|
|
48
|
+
const t = name.replace(/[/\\?%*:|"<>]/g, '_').trim().slice(0, 64);
|
|
49
|
+
return t.length > 0 ? t : 'candidate';
|
|
50
|
+
}
|
|
51
|
+
/** 关闭含 `c-resume` iframe 的弹层(聊天「在线简历」与推荐「预览」共用)。含 `.boss-popup__close`、`.btn-quxiao`(取消)等。会在主文档与各子 frame 中尝试。 */
|
|
52
|
+
export async function closeCResumePanel(page) {
|
|
53
|
+
try {
|
|
54
|
+
for (const frame of page.frames()) {
|
|
55
|
+
try {
|
|
56
|
+
await frame.evaluate(CLOSE_C_RESUME_PANEL_SCRIPT);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
/* detached / 无权限 */
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
await sleepRandom(200, 450);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* ignore */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 在任意 frame(含主 frame、`recommendFrame` 等)中查找已挂载且尺寸可见的 c-resume iframe。
|
|
70
|
+
*/
|
|
71
|
+
export async function findVisibleCResumeIframeHandle(page) {
|
|
72
|
+
for (const frame of page.frames()) {
|
|
73
|
+
try {
|
|
74
|
+
if (!(await frameHasVisibleCResumeIframe(frame))) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const h = await frame.$(C_RESUME_IFRAME_SELECTOR);
|
|
78
|
+
if (h) {
|
|
79
|
+
return h;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* detached */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 在已出现 `c-resume` iframe 的页面上,对 iframe 整框截图并关闭弹层。
|
|
90
|
+
* `preOpenViewport` 为打开弹层前的视口快照,请用 `snapshotBossPageViewport(page)`(`page.viewport()` 常为 null 时勿直接用默认尺寸)。
|
|
91
|
+
*/
|
|
92
|
+
export async function captureCResumeIframeToFile(page, preOpenViewport, absPath) {
|
|
93
|
+
try {
|
|
94
|
+
await setTempHeight(page, preOpenViewport);
|
|
95
|
+
await sleepRandom(100, 320);
|
|
96
|
+
const iframe = await findVisibleCResumeIframeHandle(page);
|
|
97
|
+
if (!iframe) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
await iframe.evaluate((el) => {
|
|
101
|
+
el.scrollIntoView({ block: 'start', inline: 'nearest' });
|
|
102
|
+
});
|
|
103
|
+
const box = await iframe.boundingBox();
|
|
104
|
+
if (!box) {
|
|
105
|
+
await iframe.dispose();
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
await iframe.screenshot({
|
|
110
|
+
path: absPath,
|
|
111
|
+
type: 'png',
|
|
112
|
+
captureBeyondViewport: true,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await iframe.dispose();
|
|
117
|
+
}
|
|
118
|
+
await closeCResumePanel(page);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
await resumeHeight(page, preOpenViewport);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=c_resume_capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"c_resume_capture.js","sourceRoot":"","sources":["../../src/common/c_resume_capture.ts"],"names":[],"mappings":"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"}
|
package/dist/toolset/action.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Page } from 'puppeteer-core';
|
|
2
|
-
export type ChatPageAction = 'resume' | 'not-fit' | 'remark' | 'agree-resume' | 'history' | 'exchange-wechat';
|
|
2
|
+
export type ChatPageAction = 'resume' | 'not-fit' | 'remark' | 'agree-resume' | 'request-attachment-resume' | 'history' | 'exchange-wechat';
|
|
3
3
|
export declare function runChatActionOnCurrentConversation(page: Page, options: {
|
|
4
4
|
action: ChatPageAction;
|
|
5
5
|
remark?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/toolset/action.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../src/toolset/action.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAmiB3C,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,cAAc,GACd,2BAA2B,GAC3B,SAAS,GACT,iBAAiB,CAAC;AAEtB,wBAAsB,kCAAkC,CACtD,IAAI,EAAE,IAAI,EACV,OAAO,EAAE;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,MAAM,CAAC,CAsCjB"}
|