@viyzhu/boss-cli-fork 0.6.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.
- package/AGENTS.md +30 -0
- package/LICENSE +674 -0
- package/README.md +223 -0
- package/dist/browser/browser_session.d.ts +27 -0
- package/dist/browser/browser_session.d.ts.map +1 -0
- package/dist/browser/browser_session.js +246 -0
- package/dist/browser/browser_session.js.map +1 -0
- package/dist/browser/cdp_browser.d.ts +50 -0
- package/dist/browser/cdp_browser.d.ts.map +1 -0
- package/dist/browser/cdp_browser.js +315 -0
- package/dist/browser/cdp_browser.js.map +1 -0
- package/dist/browser/human_delay.d.ts +117 -0
- package/dist/browser/human_delay.d.ts.map +1 -0
- package/dist/browser/human_delay.js +71 -0
- package/dist/browser/human_delay.js.map +1 -0
- package/dist/browser/index.d.ts +9 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +9 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/timing.d.ts +7 -0
- package/dist/browser/timing.d.ts.map +1 -0
- package/dist/browser/timing.js +34 -0
- package/dist/browser/timing.js.map +1 -0
- 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 +2 -0
- package/dist/cli/banner.d.ts.map +1 -0
- package/dist/cli/banner.js +69 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/cliRouter.d.ts +9 -0
- package/dist/cli/cliRouter.d.ts.map +1 -0
- package/dist/cli/cliRouter.js +604 -0
- package/dist/cli/cliRouter.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +34 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/version.d.ts +29 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +180 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/common/auth.d.ts +44 -0
- package/dist/common/auth.d.ts.map +1 -0
- package/dist/common/auth.js +168 -0
- package/dist/common/auth.js.map +1 -0
- package/dist/common/baidu_user_env.d.ts +7 -0
- package/dist/common/baidu_user_env.d.ts.map +1 -0
- package/dist/common/baidu_user_env.js +56 -0
- package/dist/common/baidu_user_env.js.map +1 -0
- package/dist/common/boss_availability.d.ts +5 -0
- package/dist/common/boss_availability.d.ts.map +1 -0
- package/dist/common/boss_availability.js +245 -0
- package/dist/common/boss_availability.js.map +1 -0
- package/dist/common/boss_modal.d.ts +14 -0
- package/dist/common/boss_modal.d.ts.map +1 -0
- package/dist/common/boss_modal.js +81 -0
- package/dist/common/boss_modal.js.map +1 -0
- package/dist/common/boss_page_guards.d.ts +14 -0
- package/dist/common/boss_page_guards.d.ts.map +1 -0
- package/dist/common/boss_page_guards.js +596 -0
- package/dist/common/boss_page_guards.js.map +1 -0
- package/dist/common/boss_paywall_popup.d.ts +28 -0
- package/dist/common/boss_paywall_popup.d.ts.map +1 -0
- package/dist/common/boss_paywall_popup.js +158 -0
- package/dist/common/boss_paywall_popup.js.map +1 -0
- package/dist/common/boss_session_lock.d.ts +2 -0
- package/dist/common/boss_session_lock.d.ts.map +1 -0
- package/dist/common/boss_session_lock.js +127 -0
- package/dist/common/boss_session_lock.js.map +1 -0
- package/dist/common/boss_session_page.d.ts +27 -0
- package/dist/common/boss_session_page.d.ts.map +1 -0
- package/dist/common/boss_session_page.js +173 -0
- package/dist/common/boss_session_page.js.map +1 -0
- package/dist/common/boss_sidebar_nav.d.ts +7 -0
- package/dist/common/boss_sidebar_nav.d.ts.map +1 -0
- package/dist/common/boss_sidebar_nav.js +53 -0
- package/dist/common/boss_sidebar_nav.js.map +1 -0
- package/dist/common/c_resume_capture.d.ts +19 -0
- package/dist/common/c_resume_capture.d.ts.map +1 -0
- package/dist/common/c_resume_capture.js +185 -0
- package/dist/common/c_resume_capture.js.map +1 -0
- package/dist/common/ensure_page.d.ts +9 -0
- package/dist/common/ensure_page.d.ts.map +1 -0
- package/dist/common/ensure_page.js +14 -0
- package/dist/common/ensure_page.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/ocr/baidu_ocr.d.ts +13 -0
- package/dist/ocr/baidu_ocr.d.ts.map +1 -0
- package/dist/ocr/baidu_ocr.js +80 -0
- package/dist/ocr/baidu_ocr.js.map +1 -0
- package/dist/ocr/index.d.ts +3 -0
- package/dist/ocr/index.d.ts.map +1 -0
- package/dist/ocr/index.js +3 -0
- package/dist/ocr/index.js.map +1 -0
- package/dist/ocr/resume_ocr.d.ts +13 -0
- package/dist/ocr/resume_ocr.d.ts.map +1 -0
- package/dist/ocr/resume_ocr.js +38 -0
- package/dist/ocr/resume_ocr.js.map +1 -0
- package/dist/toolset/action.d.ts +12 -0
- package/dist/toolset/action.d.ts.map +1 -0
- package/dist/toolset/action.js +521 -0
- package/dist/toolset/action.js.map +1 -0
- package/dist/toolset/baidu_credentials.d.ts +5 -0
- package/dist/toolset/baidu_credentials.d.ts.map +1 -0
- package/dist/toolset/baidu_credentials.js +24 -0
- package/dist/toolset/baidu_credentials.js.map +1 -0
- package/dist/toolset/chat.d.ts +10 -0
- package/dist/toolset/chat.d.ts.map +1 -0
- package/dist/toolset/chat.js +763 -0
- package/dist/toolset/chat.js.map +1 -0
- package/dist/toolset/deep-search.d.ts +35 -0
- package/dist/toolset/deep-search.d.ts.map +1 -0
- package/dist/toolset/deep-search.js +1505 -0
- package/dist/toolset/deep-search.js.map +1 -0
- package/dist/toolset/greet.d.ts +6 -0
- package/dist/toolset/greet.d.ts.map +1 -0
- package/dist/toolset/greet.js +81 -0
- package/dist/toolset/greet.js.map +1 -0
- package/dist/toolset/index.d.ts +48 -0
- package/dist/toolset/index.d.ts.map +1 -0
- package/dist/toolset/index.js +71 -0
- package/dist/toolset/index.js.map +1 -0
- package/dist/toolset/jd.d.ts +10 -0
- package/dist/toolset/jd.d.ts.map +1 -0
- package/dist/toolset/jd.js +406 -0
- package/dist/toolset/jd.js.map +1 -0
- package/dist/toolset/list.d.ts +6 -0
- package/dist/toolset/list.d.ts.map +1 -0
- package/dist/toolset/list.js +146 -0
- package/dist/toolset/list.js.map +1 -0
- package/dist/toolset/login.d.ts +6 -0
- package/dist/toolset/login.d.ts.map +1 -0
- package/dist/toolset/login.js +76 -0
- package/dist/toolset/login.js.map +1 -0
- package/dist/toolset/normal-search.d.ts +12 -0
- package/dist/toolset/normal-search.d.ts.map +1 -0
- package/dist/toolset/normal-search.js +301 -0
- package/dist/toolset/normal-search.js.map +1 -0
- package/dist/toolset/preview.d.ts +5 -0
- package/dist/toolset/preview.d.ts.map +1 -0
- package/dist/toolset/preview.js +100 -0
- package/dist/toolset/preview.js.map +1 -0
- package/dist/toolset/recommend.d.ts +36 -0
- package/dist/toolset/recommend.d.ts.map +1 -0
- package/dist/toolset/recommend.js +428 -0
- package/dist/toolset/recommend.js.map +1 -0
- package/dist/toolset/send.d.ts +7 -0
- package/dist/toolset/send.d.ts.map +1 -0
- package/dist/toolset/send.js +52 -0
- package/dist/toolset/send.js.map +1 -0
- package/package.json +69 -0
- package/skills/boss-frontend-analysis/SKILL.md +58 -0
- package/skills/boss-frontend-analysis/agents/openai.yaml +4 -0
- package/skills/boss-frontend-analysis/scripts/capture_boss_frontend.mjs +604 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { JOB_SEARCH_ACTION_GAP_MS, JOB_SELECT_ACTION_GAP_MS, RESUME_PREVIEW_OPEN_GAP_MS, sleepRandom, } from '../browser/index.js';
|
|
2
|
+
import { withBossSessionPage } from '../common/boss_session_page.js';
|
|
3
|
+
import { ensurePage } from '../common/ensure_page.js';
|
|
4
|
+
const BOSS_CHAT_RECOMMEND_URL = 'https://www.zhipin.com/web/chat/recommend';
|
|
5
|
+
/** 会话内记录:通过 greet 新出现的推荐卡片(以 geekId 识别) */
|
|
6
|
+
const sessionGreetProducedGeekIds = new Set();
|
|
7
|
+
/**
|
|
8
|
+
* 推荐列表里「一张候选人卡片」的根节点(新版 `.candidate-card-wrap` 与旧版 `.card-item` / `.geek-card` 并存)。
|
|
9
|
+
* 在线简历预览:点击卡片主体 `.card-inner`,而非「在线简历」链接或「打招呼」。
|
|
10
|
+
*/
|
|
11
|
+
const RECOMMEND_CARD_ROOT_SELECTOR = '.candidate-card-wrap, .card-list .card-item, .geek-list .geek-card';
|
|
12
|
+
export function isBossChatRecommendUrl(url) {
|
|
13
|
+
try {
|
|
14
|
+
const u = new URL(url);
|
|
15
|
+
if (!u.hostname.includes('zhipin.com')) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const p = u.pathname.replace(/\/+$/, '') || '/';
|
|
19
|
+
return p === '/web/chat/recommend';
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function getRecommendFrame(page) {
|
|
26
|
+
const timeoutMs = 18_000;
|
|
27
|
+
const iframe = await page.waitForSelector('iframe[name="recommendFrame"]', {
|
|
28
|
+
timeout: timeoutMs,
|
|
29
|
+
});
|
|
30
|
+
if (!iframe) {
|
|
31
|
+
throw new Error('未找到推荐 iframe(iframe[name="recommendFrame"])。');
|
|
32
|
+
}
|
|
33
|
+
const deadline = Date.now() + timeoutMs;
|
|
34
|
+
while (Date.now() < deadline) {
|
|
35
|
+
const frame = await iframe.contentFrame();
|
|
36
|
+
if (frame && frame.url().includes('/web/frame/recommend')) {
|
|
37
|
+
return frame;
|
|
38
|
+
}
|
|
39
|
+
await sleepRandom(120, 220);
|
|
40
|
+
}
|
|
41
|
+
const iframeSrc = (await page.evaluate(`(() => document.querySelector('iframe[name="recommendFrame"]')?.getAttribute("src") ?? "")()`));
|
|
42
|
+
const frameUrls = page.frames().map((f) => f.url()).join(' | ');
|
|
43
|
+
throw new Error(`已检测到推荐 iframe,但无法获取其页面上下文。iframe src:${iframeSrc || 'unknown'};frames:${frameUrls || 'empty'}`);
|
|
44
|
+
}
|
|
45
|
+
async function ensureRecommendFrameReady(frame) {
|
|
46
|
+
await frame.waitForFunction(`(() => {
|
|
47
|
+
const sel = ${JSON.stringify(RECOMMEND_CARD_ROOT_SELECTOR)};
|
|
48
|
+
if (document.querySelector(sel)) return true;
|
|
49
|
+
const root = document.querySelector(".card-list, .geek-list-wrap .geek-list");
|
|
50
|
+
return !!root;
|
|
51
|
+
})()`, { timeout: 18_000 });
|
|
52
|
+
}
|
|
53
|
+
async function readCurrentRecommendJobLabel(frame) {
|
|
54
|
+
return (await frame.evaluate(`(() => {
|
|
55
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
56
|
+
return norm(document.querySelector(".job-selecter-wrap .ui-dropmenu-label")?.textContent);
|
|
57
|
+
})()`));
|
|
58
|
+
}
|
|
59
|
+
async function waitForRecommendJobDropdownReady(frame) {
|
|
60
|
+
await frame.waitForFunction(`(() => {
|
|
61
|
+
const options = document.querySelector(".job-selecter-options");
|
|
62
|
+
if (!(options instanceof HTMLElement)) return false;
|
|
63
|
+
const rect = options.getBoundingClientRect();
|
|
64
|
+
const style = window.getComputedStyle(options);
|
|
65
|
+
if (rect.width <= 0 || rect.height <= 0 || style.display === "none" || style.visibility === "hidden") {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return !!options.querySelector(".top-chat-search .chat-job-search");
|
|
69
|
+
})()`, { timeout: 8_000 });
|
|
70
|
+
}
|
|
71
|
+
async function waitForRecommendJobSearchResults(frame, keyword) {
|
|
72
|
+
await frame.waitForFunction(`((kw) => {
|
|
73
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, "").trim().toLowerCase();
|
|
74
|
+
const rows = Array.from(document.querySelectorAll(".job-selecter-options .job-list .job-item"));
|
|
75
|
+
if (rows.length === 0) return false;
|
|
76
|
+
if (!kw) return true;
|
|
77
|
+
return rows.some((el) => {
|
|
78
|
+
const label = norm(el.querySelector(".label")?.textContent || el.textContent || "");
|
|
79
|
+
return label.includes(norm(kw));
|
|
80
|
+
});
|
|
81
|
+
})`, { timeout: 10_000 }, keyword);
|
|
82
|
+
}
|
|
83
|
+
async function waitForRecommendJobSelected(frame, expectedLabel) {
|
|
84
|
+
await frame.waitForFunction(`((label) => {
|
|
85
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
86
|
+
const current = norm(document.querySelector(".job-selecter-wrap .ui-dropmenu-label")?.textContent);
|
|
87
|
+
return !!current && current === label;
|
|
88
|
+
})`, { timeout: 10_000 }, expectedLabel);
|
|
89
|
+
await ensureRecommendFrameReady(frame);
|
|
90
|
+
}
|
|
91
|
+
export async function selectRecommendJob(frame, keyword) {
|
|
92
|
+
const kw = keyword.trim();
|
|
93
|
+
if (!kw) {
|
|
94
|
+
return readCurrentRecommendJobLabel(frame);
|
|
95
|
+
}
|
|
96
|
+
const kwLiteral = JSON.stringify(kw);
|
|
97
|
+
const opened = (await frame.evaluate(`(() => {
|
|
98
|
+
const host = document.querySelector(".job-selecter-wrap .ui-dropmenu-label");
|
|
99
|
+
if (!(host instanceof HTMLElement)) return false;
|
|
100
|
+
host.scrollIntoView({ block: "center", inline: "nearest" });
|
|
101
|
+
host.click();
|
|
102
|
+
return true;
|
|
103
|
+
})()`));
|
|
104
|
+
if (!opened) {
|
|
105
|
+
throw new Error('未找到岗位下拉入口(.job-selecter-wrap .ui-dropmenu-label)。');
|
|
106
|
+
}
|
|
107
|
+
await sleepRandom(JOB_SELECT_ACTION_GAP_MS.min, JOB_SELECT_ACTION_GAP_MS.max);
|
|
108
|
+
await waitForRecommendJobDropdownReady(frame);
|
|
109
|
+
const searched = (await frame.evaluate(`(() => {
|
|
110
|
+
const kw = ${kwLiteral};
|
|
111
|
+
const input = document.querySelector(".job-selecter-options .top-chat-search .chat-job-search");
|
|
112
|
+
if (!(input instanceof HTMLInputElement)) return false;
|
|
113
|
+
input.focus();
|
|
114
|
+
input.value = kw;
|
|
115
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
116
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
117
|
+
return true;
|
|
118
|
+
})()`));
|
|
119
|
+
if (!searched) {
|
|
120
|
+
throw new Error('已打开岗位下拉,但未找到职位搜索框(.chat-job-search)。');
|
|
121
|
+
}
|
|
122
|
+
await sleepRandom(JOB_SEARCH_ACTION_GAP_MS.min, JOB_SEARCH_ACTION_GAP_MS.max);
|
|
123
|
+
await waitForRecommendJobSearchResults(frame, kw);
|
|
124
|
+
const picked = (await frame.evaluate(`(() => {
|
|
125
|
+
const kw = ${kwLiteral};
|
|
126
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, "").trim().toLowerCase();
|
|
127
|
+
const rows = Array.from(document.querySelectorAll(".job-selecter-options .job-list .job-item"));
|
|
128
|
+
if (rows.length === 0) return { ok: false, reason: "empty" };
|
|
129
|
+
const target = rows.find((el) => {
|
|
130
|
+
const label = norm(el.querySelector(".label")?.textContent || el.textContent || "");
|
|
131
|
+
return label.includes(norm(kw));
|
|
132
|
+
});
|
|
133
|
+
if (!(target instanceof HTMLElement)) return { ok: false, reason: "not_found" };
|
|
134
|
+
const label = (target.querySelector(".label")?.textContent ?? target.textContent ?? "")
|
|
135
|
+
.replace(/\\s+/g, " ")
|
|
136
|
+
.trim();
|
|
137
|
+
target.scrollIntoView({ block: "center", inline: "nearest" });
|
|
138
|
+
target.click();
|
|
139
|
+
return { ok: true, label };
|
|
140
|
+
})()`));
|
|
141
|
+
if (!picked.ok) {
|
|
142
|
+
throw new Error(`未找到匹配岗位“${kw}”。`);
|
|
143
|
+
}
|
|
144
|
+
const label = picked.label ?? kw;
|
|
145
|
+
await sleepRandom(JOB_SELECT_ACTION_GAP_MS.min, JOB_SELECT_ACTION_GAP_MS.max);
|
|
146
|
+
await waitForRecommendJobSelected(frame, label);
|
|
147
|
+
return label;
|
|
148
|
+
}
|
|
149
|
+
export async function ensureInRecommendPage(page) {
|
|
150
|
+
await ensurePage(page, {
|
|
151
|
+
name: '推荐列表页',
|
|
152
|
+
targetUrl: BOSS_CHAT_RECOMMEND_URL,
|
|
153
|
+
matches: isBossChatRecommendUrl,
|
|
154
|
+
});
|
|
155
|
+
const frame = await getRecommendFrame(page);
|
|
156
|
+
await ensureRecommendFrameReady(frame);
|
|
157
|
+
return frame;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 供 `preview` 使用:不导航;若当前主页面不在推荐页或未就绪推荐 iframe,直接抛错。
|
|
161
|
+
*/
|
|
162
|
+
export async function assertRecommendPageReady(page, actionName) {
|
|
163
|
+
if (!isBossChatRecommendUrl(page.url())) {
|
|
164
|
+
throw new Error(`当前不在推荐列表页(/web/chat/recommend),无法${actionName}。`);
|
|
165
|
+
}
|
|
166
|
+
const frame = await getRecommendFrame(page);
|
|
167
|
+
await ensureRecommendFrameReady(frame);
|
|
168
|
+
return frame;
|
|
169
|
+
}
|
|
170
|
+
export async function assertRecommendPageReadyForPreview(page) {
|
|
171
|
+
return assertRecommendPageReady(page, '预览候选人');
|
|
172
|
+
}
|
|
173
|
+
export async function readRecommendList(frame) {
|
|
174
|
+
return (await frame.evaluate(`(() => {
|
|
175
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
176
|
+
const cardSel = ${JSON.stringify(RECOMMEND_CARD_ROOT_SELECTOR)};
|
|
177
|
+
const cards = Array.from(document.querySelectorAll(cardSel));
|
|
178
|
+
return cards.map((item) => {
|
|
179
|
+
const inner = item.querySelector(".card-inner") || item;
|
|
180
|
+
const wrap = item.matches(".candidate-card-wrap")
|
|
181
|
+
? item
|
|
182
|
+
: item.querySelector(".candidate-card-wrap");
|
|
183
|
+
const hasViewed = Boolean(
|
|
184
|
+
(wrap && wrap.classList.contains("has-viewed")) ||
|
|
185
|
+
(inner && inner.classList.contains("has-viewed")),
|
|
186
|
+
);
|
|
187
|
+
const geekId =
|
|
188
|
+
inner?.getAttribute("data-geekid") ??
|
|
189
|
+
inner?.getAttribute("data-geek") ??
|
|
190
|
+
"";
|
|
191
|
+
const name =
|
|
192
|
+
norm(item.querySelector(".name-wrap .name")?.textContent) ||
|
|
193
|
+
norm(item.querySelector(".name")?.textContent);
|
|
194
|
+
const salary = norm(item.querySelector(".salary-wrap span")?.textContent);
|
|
195
|
+
const baseInfo = Array.from(item.querySelectorAll(".base-info span"))
|
|
196
|
+
.map((el) => norm(el.textContent))
|
|
197
|
+
.filter(Boolean)
|
|
198
|
+
.join(" / ");
|
|
199
|
+
const expect =
|
|
200
|
+
norm(item.querySelector(".expect-wrap .content")?.textContent) ||
|
|
201
|
+
norm(item.querySelector(".expect-wrap .join-text-wrap")?.textContent);
|
|
202
|
+
const experience = norm(item.querySelector(".experience-wrap .join-text-wrap")?.textContent);
|
|
203
|
+
const advantage = norm(item.querySelector(".geek-desc .content")?.textContent);
|
|
204
|
+
const highlightLabels = [
|
|
205
|
+
...Array.from(item.querySelectorAll(".operate .labels .label")),
|
|
206
|
+
...Array.from(item.querySelectorAll(".tags-wrap .tag-item")),
|
|
207
|
+
]
|
|
208
|
+
.map((el) => norm(el.textContent))
|
|
209
|
+
.filter(Boolean);
|
|
210
|
+
const highlights = [...new Set(highlightLabels)];
|
|
211
|
+
const greetBtn = item.querySelector(".button-chat-wrap .btn.btn-greet");
|
|
212
|
+
const btnCls = greetBtn?.className ?? "";
|
|
213
|
+
const disabled =
|
|
214
|
+
!greetBtn ||
|
|
215
|
+
/disabled|forbid|ban/i.test(btnCls) ||
|
|
216
|
+
greetBtn.getAttribute("disabled") !== null;
|
|
217
|
+
const hasHistoryChat = (() => {
|
|
218
|
+
if (item.querySelector(".tooltip-wrap.chat-history .icon-chat-history")) return true;
|
|
219
|
+
const uses = Array.from(item.querySelectorAll("use"));
|
|
220
|
+
return uses.some((u) => {
|
|
221
|
+
const href = u.getAttribute("href") ?? u.getAttributeNS("http://www.w3.org/1999/xlink", "href") ?? "";
|
|
222
|
+
return href.includes("icon-chat-history");
|
|
223
|
+
});
|
|
224
|
+
})();
|
|
225
|
+
return {
|
|
226
|
+
geekId,
|
|
227
|
+
name,
|
|
228
|
+
salary,
|
|
229
|
+
baseInfo,
|
|
230
|
+
expect,
|
|
231
|
+
experience,
|
|
232
|
+
advantage,
|
|
233
|
+
highlights,
|
|
234
|
+
canGreet: !disabled,
|
|
235
|
+
hasHistoryChat,
|
|
236
|
+
hasViewed,
|
|
237
|
+
};
|
|
238
|
+
}).filter((x) => x.name);
|
|
239
|
+
})()`));
|
|
240
|
+
}
|
|
241
|
+
export function renderRecommendList(candidates) {
|
|
242
|
+
if (candidates.length === 0) {
|
|
243
|
+
return '推荐列表为空。';
|
|
244
|
+
}
|
|
245
|
+
const greetProduced = [];
|
|
246
|
+
const normal = [];
|
|
247
|
+
candidates.forEach((c) => {
|
|
248
|
+
if (c.geekId && sessionGreetProducedGeekIds.has(c.geekId)) {
|
|
249
|
+
greetProduced.push(c);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
normal.push(c);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
const renderItems = (title, items) => {
|
|
256
|
+
const lines = [];
|
|
257
|
+
lines.push(`${title}(${items.length})`);
|
|
258
|
+
if (items.length === 0) {
|
|
259
|
+
lines.push(' - 暂无');
|
|
260
|
+
return lines;
|
|
261
|
+
}
|
|
262
|
+
items.forEach((m, idx) => {
|
|
263
|
+
const advantageText = m.advantage ||
|
|
264
|
+
(m.highlights.length > 0 ? m.highlights.slice(0, 3).join(' / ') : '(无)');
|
|
265
|
+
const fields = [
|
|
266
|
+
m.salary ? `薪资:${m.salary}` : '',
|
|
267
|
+
m.baseInfo ? `信息:${m.baseInfo}` : '',
|
|
268
|
+
m.expect ? `期望:${m.expect}` : '',
|
|
269
|
+
m.experience ? `经历:${m.experience}` : '',
|
|
270
|
+
m.hasHistoryChat ? '同事沟通过' : '',
|
|
271
|
+
m.canGreet ? '可打招呼' : '已打招呼',
|
|
272
|
+
]
|
|
273
|
+
.filter(Boolean)
|
|
274
|
+
.join('|');
|
|
275
|
+
const nameWithViewed = m.hasViewed ? `${m.name} | 看过` : m.name;
|
|
276
|
+
lines.push(` - ${idx + 1}. ${nameWithViewed}|${fields}`);
|
|
277
|
+
lines.push(` 优势: ${advantageText}`);
|
|
278
|
+
});
|
|
279
|
+
return lines;
|
|
280
|
+
};
|
|
281
|
+
const out = [];
|
|
282
|
+
out.push(`推荐列表(按来源分组):共 ${candidates.length} 人。`);
|
|
283
|
+
out.push('');
|
|
284
|
+
out.push(...renderItems('常规推荐', normal));
|
|
285
|
+
out.push('');
|
|
286
|
+
out.push(...renderItems('打招呼产生的推荐', greetProduced));
|
|
287
|
+
return out.join('\n');
|
|
288
|
+
}
|
|
289
|
+
export async function clickGreet(frame, target) {
|
|
290
|
+
const targetLiteral = JSON.stringify(target.trim());
|
|
291
|
+
const result = (await frame.evaluate(`(() => {
|
|
292
|
+
const raw = ${targetLiteral};
|
|
293
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
294
|
+
const cardSel = ${JSON.stringify(RECOMMEND_CARD_ROOT_SELECTOR)};
|
|
295
|
+
const cards = Array.from(document.querySelectorAll(cardSel));
|
|
296
|
+
if (cards.length === 0) {
|
|
297
|
+
return { kind: "empty" };
|
|
298
|
+
}
|
|
299
|
+
const targetCard = cards.find((item) => {
|
|
300
|
+
const name =
|
|
301
|
+
norm(item.querySelector(".name-wrap .name")?.textContent) ||
|
|
302
|
+
norm(item.querySelector(".name")?.textContent);
|
|
303
|
+
return name === raw || name.includes(raw);
|
|
304
|
+
}) ?? null;
|
|
305
|
+
if (!targetCard) {
|
|
306
|
+
return { kind: "not_found", target: raw };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const name =
|
|
310
|
+
norm(targetCard.querySelector(".name-wrap .name")?.textContent) ||
|
|
311
|
+
norm(targetCard.querySelector(".name")?.textContent);
|
|
312
|
+
const inner = targetCard.querySelector(".card-inner") || targetCard;
|
|
313
|
+
const geekId =
|
|
314
|
+
inner?.getAttribute("data-geekid") ??
|
|
315
|
+
inner?.getAttribute("data-geek") ??
|
|
316
|
+
"";
|
|
317
|
+
const btn = targetCard.querySelector(".button-chat-wrap .btn.btn-greet");
|
|
318
|
+
if (!(btn instanceof HTMLElement)) {
|
|
319
|
+
return { kind: "no_btn", name };
|
|
320
|
+
}
|
|
321
|
+
const cls = btn.className ?? "";
|
|
322
|
+
const disabled = /disabled|forbid|ban/i.test(cls) || btn.getAttribute("disabled") !== null;
|
|
323
|
+
if (disabled) {
|
|
324
|
+
return { kind: "disabled", name };
|
|
325
|
+
}
|
|
326
|
+
btn.scrollIntoView({ block: "center", inline: "nearest" });
|
|
327
|
+
btn.click();
|
|
328
|
+
return { kind: "clicked", name, geekId };
|
|
329
|
+
})()`));
|
|
330
|
+
switch (result.kind) {
|
|
331
|
+
case 'empty':
|
|
332
|
+
throw new Error('推荐列表为空,无法执行打招呼。');
|
|
333
|
+
case 'not_found':
|
|
334
|
+
throw new Error(`未在推荐列表中找到目标:${result.target}`);
|
|
335
|
+
case 'no_btn':
|
|
336
|
+
throw new Error(`候选人 ${result.name} 缺少“打招呼”按钮,无法执行。`);
|
|
337
|
+
case 'disabled':
|
|
338
|
+
throw new Error(`候选人 ${result.name} 已打招呼。`);
|
|
339
|
+
case 'clicked':
|
|
340
|
+
return {
|
|
341
|
+
message: `已对 ${result.name} 点击“打招呼”。`,
|
|
342
|
+
};
|
|
343
|
+
default: {
|
|
344
|
+
const _x = result;
|
|
345
|
+
throw new Error(`未知结果:${String(_x)}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
export function markGreetProduced(before, after) {
|
|
350
|
+
const beforeIds = new Set(before.map((x) => x.geekId).filter(Boolean));
|
|
351
|
+
after.forEach((x) => {
|
|
352
|
+
if (x.geekId && !beforeIds.has(x.geekId)) {
|
|
353
|
+
sessionGreetProducedGeekIds.add(x.geekId);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* 在推荐 iframe 内根据姓名打开在线简历预览:点击候选人卡片主体 `.card-inner`(与侧栏「打招呼」分离)。
|
|
359
|
+
* 父页随后出现 `c-resume` iframe(如 `source=recommend`)。旧版仅有「在线简历」链接时仍尝试点击链接。
|
|
360
|
+
*/
|
|
361
|
+
export async function openRecommendResumePreview(frame, target) {
|
|
362
|
+
const raw = target.trim();
|
|
363
|
+
const targetLiteral = JSON.stringify(raw);
|
|
364
|
+
const opened = (await frame.evaluate(`(() => {
|
|
365
|
+
const raw = ${targetLiteral};
|
|
366
|
+
const norm = (v) => (v ?? "").replace(/\\s+/g, " ").trim();
|
|
367
|
+
const cardSel = ${JSON.stringify(RECOMMEND_CARD_ROOT_SELECTOR)};
|
|
368
|
+
const cards = Array.from(document.querySelectorAll(cardSel));
|
|
369
|
+
if (cards.length === 0) return false;
|
|
370
|
+
const targetCard = cards.find((item) => {
|
|
371
|
+
const name =
|
|
372
|
+
norm(item.querySelector(".name-wrap .name")?.textContent) ||
|
|
373
|
+
norm(item.querySelector(".name")?.textContent);
|
|
374
|
+
return name === raw || name.includes(raw);
|
|
375
|
+
}) ?? null;
|
|
376
|
+
if (!targetCard) return false;
|
|
377
|
+
|
|
378
|
+
function tryOpen(el) {
|
|
379
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
380
|
+
if (el.classList.contains("disabled")) return false;
|
|
381
|
+
const st = window.getComputedStyle(el);
|
|
382
|
+
if (st.pointerEvents === "none" || Number(st.opacity) < 0.3) return false;
|
|
383
|
+
el.scrollIntoView({ block: "center", inline: "nearest" });
|
|
384
|
+
el.click();
|
|
385
|
+
return true;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const inner = targetCard.querySelector(".card-inner");
|
|
389
|
+
if (inner instanceof HTMLElement) {
|
|
390
|
+
inner.scrollIntoView({ block: "center", inline: "nearest" });
|
|
391
|
+
inner.click();
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const resumeOnline = targetCard.querySelector("a.resume-btn-online");
|
|
396
|
+
if (tryOpen(resumeOnline)) return true;
|
|
397
|
+
const hrefResume = targetCard.querySelector('a[href*="c-resume"], a[href*="frame/c-resume"]');
|
|
398
|
+
if (tryOpen(hrefResume)) return true;
|
|
399
|
+
|
|
400
|
+
const links = Array.from(targetCard.querySelectorAll("a, button, .btn")).filter((node) => {
|
|
401
|
+
const t = norm(node.textContent);
|
|
402
|
+
return /在线简历|查看简历|简历预览|预览/.test(t);
|
|
403
|
+
});
|
|
404
|
+
if (links.length > 0 && tryOpen(links[0])) return true;
|
|
405
|
+
|
|
406
|
+
return false;
|
|
407
|
+
})()`));
|
|
408
|
+
if (opened) {
|
|
409
|
+
await sleepRandom(RESUME_PREVIEW_OPEN_GAP_MS.min, RESUME_PREVIEW_OPEN_GAP_MS.max);
|
|
410
|
+
}
|
|
411
|
+
return opened;
|
|
412
|
+
}
|
|
413
|
+
export async function runRecommend(jobKeyword) {
|
|
414
|
+
try {
|
|
415
|
+
return await withBossSessionPage(async (page) => {
|
|
416
|
+
const frame = await ensureInRecommendPage(page);
|
|
417
|
+
const selectedJob = await selectRecommendJob(frame, (jobKeyword ?? '').trim());
|
|
418
|
+
const candidates = await readRecommendList(frame);
|
|
419
|
+
const title = selectedJob ? `当前岗位:${selectedJob}` : '当前岗位:默认';
|
|
420
|
+
return [title, '', renderRecommendList(candidates)].join('\n');
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
catch (e) {
|
|
424
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
425
|
+
throw new Error(`读取推荐列表失败:${message}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
//# 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 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/toolset/send.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyDzF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { randomIntInclusive, selectAllModifierKey, SEND_AFTER_ENTER_MS, SEND_INPUT_CLICK_MS, SEND_TYPING_GAP_MS, sleepRandom, typeTextWithRandomKeyDelay, } from '../browser/index.js';
|
|
2
|
+
import { isBossChatIndexUrl } from '../common/auth.js';
|
|
3
|
+
import { withBossSessionPage } from '../common/boss_session_page.js';
|
|
4
|
+
import { runRequestAttachmentResume } from './action.js';
|
|
5
|
+
export async function runSendChatMessage(options) {
|
|
6
|
+
const messageText = (options.text ?? '').trim();
|
|
7
|
+
const signal = options.signal;
|
|
8
|
+
const requestResume = options.requestResume ?? false;
|
|
9
|
+
if (!messageText) {
|
|
10
|
+
throw new Error('请指定 --text <消息> 或 -t <消息>。');
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
return await withBossSessionPage(async (page) => {
|
|
14
|
+
const currentUrl = page.url();
|
|
15
|
+
if (!isBossChatIndexUrl(currentUrl)) {
|
|
16
|
+
throw new Error('请先进入聊天列表页(/web/chat/index)并打开候选人聊天。');
|
|
17
|
+
}
|
|
18
|
+
const input = await page.$('#boss-chat-editor-input');
|
|
19
|
+
if (!input) {
|
|
20
|
+
throw new Error('未找到聊天输入框(#boss-chat-editor-input)。');
|
|
21
|
+
}
|
|
22
|
+
await input.click({
|
|
23
|
+
delay: randomIntInclusive(SEND_INPUT_CLICK_MS.min, SEND_INPUT_CLICK_MS.max),
|
|
24
|
+
});
|
|
25
|
+
await sleepRandom(60, 220, signal);
|
|
26
|
+
const selectAllMod = selectAllModifierKey();
|
|
27
|
+
await page.keyboard.down(selectAllMod);
|
|
28
|
+
await page.keyboard.press('KeyA');
|
|
29
|
+
await page.keyboard.up(selectAllMod);
|
|
30
|
+
await sleepRandom(45, 180, signal);
|
|
31
|
+
await page.keyboard.press('Backspace');
|
|
32
|
+
await sleepRandom(80, 260, signal);
|
|
33
|
+
await typeTextWithRandomKeyDelay(page, messageText, SEND_TYPING_GAP_MS.min, SEND_TYPING_GAP_MS.max, signal);
|
|
34
|
+
await sleepRandom(120, 420, signal);
|
|
35
|
+
await page.keyboard.press('Enter');
|
|
36
|
+
await sleepRandom(SEND_AFTER_ENTER_MS.min, SEND_AFTER_ENTER_MS.max, signal);
|
|
37
|
+
if (!requestResume) {
|
|
38
|
+
return `已发送消息:${messageText}`;
|
|
39
|
+
}
|
|
40
|
+
await sleepRandom(1200, 2800, signal);
|
|
41
|
+
const resumeResult = await runRequestAttachmentResume(page);
|
|
42
|
+
return `已发送消息:${messageText}\n${resumeResult}`;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
if (e instanceof Error) {
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(`发送消息失败:${String(e)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# 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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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@viyzhu/boss-cli-fork",
|
|
3
|
+
"version": "0.6.8",
|
|
4
|
+
"description": "Boss直聘自动化 CLI(@joohw/boss-cli 的 fork,含风控页反弹熔断等修复):批量发消息、自动打招呼、候选人管理、深度搜索。基于 Puppeteer/CDP 驱动本机 Chrome,支持 AI Agent 编排",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"boss",
|
|
7
|
+
"boss-cli",
|
|
8
|
+
"boss直聘",
|
|
9
|
+
"boss-zhipin",
|
|
10
|
+
"zhipin",
|
|
11
|
+
"bosszp",
|
|
12
|
+
"招聘自动化",
|
|
13
|
+
"hr-automation",
|
|
14
|
+
"recruitment-automation",
|
|
15
|
+
"puppeteer",
|
|
16
|
+
"cdp",
|
|
17
|
+
"chrome-devtools-protocol",
|
|
18
|
+
"cli",
|
|
19
|
+
"agent",
|
|
20
|
+
"ai-agent",
|
|
21
|
+
"自动打招呼",
|
|
22
|
+
"批量发消息",
|
|
23
|
+
"候选人管理",
|
|
24
|
+
"hr-tools",
|
|
25
|
+
"boss-direct"
|
|
26
|
+
],
|
|
27
|
+
"homepage": "https://github.com/Viy1204/boss-cli#readme",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/Viy1204/boss-cli.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/Viy1204/boss-cli/issues"
|
|
34
|
+
},
|
|
35
|
+
"type": "module",
|
|
36
|
+
"main": "dist/cli/index.js",
|
|
37
|
+
"types": "dist/cli/index.d.ts",
|
|
38
|
+
"bin": {
|
|
39
|
+
"boss": "dist/cli/index.js"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"skills",
|
|
44
|
+
"README.md",
|
|
45
|
+
"AGENTS.md",
|
|
46
|
+
"LICENSE"
|
|
47
|
+
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc",
|
|
50
|
+
"dev": "npm run build && node dist/cli/index.js",
|
|
51
|
+
"deploy": "node scripts/deploy.mjs",
|
|
52
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
53
|
+
"test:baidu": "node --env-file=.env scripts/test-baidu-ocr.mjs"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"dotenv": "^17.4.2",
|
|
57
|
+
"puppeteer-core": "^24.29.1"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^24.10.0",
|
|
61
|
+
"ssh2": "^1.17.0",
|
|
62
|
+
"typescript": "^5.3.3"
|
|
63
|
+
},
|
|
64
|
+
"author": "Joo <1546635571@qq.com>",
|
|
65
|
+
"license": "GPL-3.0",
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boss-frontend-analysis
|
|
3
|
+
description: Capture, archive, diff, and assess Boss/Zhipin frontend JavaScript for boss-cli safety gates and anti-debug guard updates. Use when Codex needs to re-analyze current Boss frontend scripts, compare online JS with docs/research/boss-online-js baselines, update boss_availability, or recommend code changes after Boss changes zhipin-boss, zhipin-sign, risk-detection, remoteEntry, or security scripts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Boss Frontend Analysis
|
|
7
|
+
|
|
8
|
+
Use this skill when Boss online frontend assets changed and boss-cli must decide whether to stay disabled, update the verified baseline, or change page guards.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Run the capture script from the repository root:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node skills/boss-frontend-analysis/scripts/capture_boss_frontend.mjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Read the generated files under `docs/research/boss-online-js/<date>/`:
|
|
19
|
+
|
|
20
|
+
- `manifest.json`: captured URLs, final URLs, byte sizes, SHA-256 hashes, and source category.
|
|
21
|
+
- `analysis.md`: version changes, high-risk script notes, and code-change recommendations.
|
|
22
|
+
- `raw/`: unmodified script bodies for diffing.
|
|
23
|
+
|
|
24
|
+
3. Compare against the previous verified baseline, usually the latest dated folder under `docs/research/boss-online-js/`.
|
|
25
|
+
|
|
26
|
+
4. Inspect these repo files before recommending or changing code:
|
|
27
|
+
|
|
28
|
+
- `src/common/boss_availability.ts`
|
|
29
|
+
- `src/common/boss_page_guards.ts`
|
|
30
|
+
- `docs/anti-detection.md`
|
|
31
|
+
- `docs/browser-session.md`
|
|
32
|
+
|
|
33
|
+
5. Keep the policy strict:
|
|
34
|
+
|
|
35
|
+
- Do not add fallback or bypass switches for availability checks.
|
|
36
|
+
- If online entry pages reference unverified Boss JS versions, boss-cli must remain disabled.
|
|
37
|
+
- Only update `boss_availability.ts` after raw scripts are archived and the risk strategy has been reviewed.
|
|
38
|
+
- Puppeteer `page.evaluate` / `page.waitForFunction` additions must use string scripts, not callback functions.
|
|
39
|
+
|
|
40
|
+
## Analysis Checklist
|
|
41
|
+
|
|
42
|
+
- Chat entry page: identify current `zhipin-boss/index/v*/static/js/app.js`, `polyfill.js`, and `risk-detection.js`.
|
|
43
|
+
- Remote bundle: identify current `zhipin-boss/bundle/v*/static/remoteEntry.js` and downloaded chunks.
|
|
44
|
+
- Sign/login page: identify `zhipin-sign/v*/static/js/app.*.js`, `iframe-core.*.js`, and `vendors~app.*.js`.
|
|
45
|
+
- Security scripts: note `zhipin-security`, `browser-check`, Warlock, APM, MQTT, and reporting SDK version changes.
|
|
46
|
+
- Risk detector: search for codes such as `99001`, `99002`, `99004`, `99005`, `srcdoc`, `MutationObserver`, `isTrusted`, `sendAction`, and security redirects.
|
|
47
|
+
- Sign vendor anti-debug: search for `debugger`, `Function(`, `constructor`, `setInterval`, `console`, `devtools`, and obfuscated modules around those hits.
|
|
48
|
+
- Guard coverage: verify request-blocking patterns in `boss_page_guards.ts` still cover risk scripts and security redirects.
|
|
49
|
+
|
|
50
|
+
## Output Guidance
|
|
51
|
+
|
|
52
|
+
When reporting results, include:
|
|
53
|
+
|
|
54
|
+
- Current online versions and whether they match the verified baseline.
|
|
55
|
+
- Whether boss-cli should remain disabled.
|
|
56
|
+
- Exact files or constants that need updates.
|
|
57
|
+
- Any selectors, request patterns, or script guards that changed.
|
|
58
|
+
- Build and runtime checks performed.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Boss Frontend Analysis"
|
|
3
|
+
short_description: "Capture and diff Boss frontend JS"
|
|
4
|
+
default_prompt: "Use $boss-frontend-analysis to capture current Boss frontend scripts, compare them with the verified baseline, and recommend boss-cli code changes."
|