Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chrome-extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const CONTENT_READY_RETRIES = 12;
const CONTENT_READY_INTERVAL_MS = 250;
const TAB_LOAD_TIMEOUT_MS = 10000;
const DELIVERY_NAVIGATION_TIMEOUT_MS = 15000;
const REQUIRED_BOSS_CONTENT_VERSION = "1.8.18";
const REQUIRED_BOSS_CONTENT_VERSION = "1.8.19";
const REQUIRED_ZHILIAN_CONTENT_VERSION = "1.8.16";
const LOCAL_API_BASE_URLS = ["http://127.0.0.1:6866"];
const BOSS_LOCAL_API_MAX_ATTEMPTS = 3;
Expand Down
5 changes: 3 additions & 2 deletions chrome-extension/boss-content.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(function () {
const EXTENSION_VERSION = "1.8.18";
const EXTENSION_VERSION = "1.8.19";
// Manifest injection and a readiness probe can meet in the same document.
// Reuse its runner instead of leaving the first runner alive without a listener.
if (window.__GET_JOBS_BOSS_CONTENT_VERSION__ === EXTENSION_VERSION) return;
Expand Down Expand Up @@ -3342,7 +3342,8 @@
return;
}
input.innerText = text;
input.textContent = text;
// innerText creates real line breaks in contenteditable. Replacing it with
// textContent would collapse those breaks under the editor's normal whitespace.
input.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true, inputType: "insertText", data: text }));
}

Expand Down
2 changes: 1 addition & 1 deletion chrome-extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "投递牛马 Chrome Bridge",
"version": "1.8.18",
"version": "1.8.19",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzzdIlNVOv76Y/cSWrjD5Tg2Vlsha8yWHzsn46PBsg724/2dftOUzIIr2n70VRaRgGwEd8FjO/Y768Ori443zF4pQpWvuxXxm05YO25ILQ/+aJLmUycAEdWbkdhcagr4YXnXJdYlSCGSAToSQBjk+owQOdlBLQn5wofPoshrqayoJjRQ5aAUj1SuSlnNv9iimle8GMA1IaA1l5rw6K/chfcgwMTg6HxRAIoludt5JGbIBryi2Lu1hOJRMaDnL7A57ofBnn3qx3H2HIGWGkkTW9EMkls0XMXwx8+mJVIj5HSYl0EeuCvEoTa1W3i1CbOf3kY2yCPKS3Qz3lOvJiwJ4ZQIDAQAB",
"description": "Use signed-in Chrome tabs to scan jobs, confirm deliveries, and review BOSS HR reply drafts for 投递牛马.",
"icons": {
Expand Down
2 changes: 1 addition & 1 deletion chrome-extension/tests/boss-hr-assistant.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test("manifest loads the direct HR bridge and one-minute alarm capability", () =
const bossScripts = manifest.content_scripts.find((entry) => entry.matches.includes("https://www.zhipin.com/*")).js;
assert.deepEqual(bossScripts.slice(-3), ["boss-hr-support.js", "boss-hr-bridge.js", "boss-hr-assistant.js"]);
assert.ok(manifest.permissions.includes("alarms"));
assert.equal(manifest.version, "1.8.18");
assert.equal(manifest.version, "1.8.19");
});

test("assistant exposes policy-gated dedicated watch and preserves explicit manual send", () => {
Expand Down
2 changes: 1 addition & 1 deletion chrome-extension/tests/manifest-id.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function extensionIdFromKey(key) {
test('manifest public key derives the backend allowlisted extension id', () => {
const manifestPath = path.join(__dirname, '..', 'manifest.json');
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
assert.equal(manifest.version, '1.8.18');
assert.equal(manifest.version, '1.8.19');
assert.equal(extensionIdFromKey(manifest.key), EXPECTED_EXTENSION_ID);

const publicKey = crypto.createPublicKey({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ test("extension release and both content scripts use the profile-scoped contract
const boss = source("boss-content.js");
const zhilian = source("zhilian-content.js");

assert.equal(manifest.version, "1.8.18");
assert.equal(manifest.version, "1.8.19");
assert.match(background, /BACKGROUND_VERSION = "2026-09-14-runtime-adapters"/);
assert.match(background, /REQUIRED_BOSS_CONTENT_VERSION = "1.8.18"/);
assert.match(boss, /EXTENSION_VERSION = "1.8.18"/);
assert.match(background, /REQUIRED_BOSS_CONTENT_VERSION = "1.8.19"/);
assert.match(boss, /EXTENSION_VERSION = "1.8.19"/);
assert.match(zhilian, /EXTENSION_VERSION = "1.8.16"/);
assert.match(background, /REQUIRED_ZHILIAN_CONTENT_VERSION = "1.8.16"/);
const frontendBridge = fs.readFileSync(path.resolve(extensionDir, "../front/lib/chromeBridge.ts"), "utf8");
Expand Down
3 changes: 2 additions & 1 deletion docs/delivery-recovery.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# BOSS / 智联投递恢复

扩展版本 1.8.18,后台与页面协议 `2026-09-14-runtime-adapters`。
扩展版本 1.8.19,后台与页面协议 `2026-09-14-runtime-adapters`。

- BOSS 富文本输入框保留确认话术中的真实换行,不再用 textContent 覆盖 innerText 生成的换行结构;发送前仍逐字核对原话术。
- BOSS 点击操作只触发一次 click,避免先派发 click 再调用 `.click()` 导致收藏切换两次、重复打开沟通入口或重复发送话术。
- 页面进入前进/后退缓存(BFCache)时立即撤销旧页面执行资格;返回页面后重新注入脚本,旧异步任务不得继续点击或填写话术。
- “立即沟通”打开完整聊天页时,由后台接续尚未发送的话术:详情页先确认 OPENING_CHAT 阶段,新聊天页核对选中招聘者和加密岗位 ID,并在点击发送前消耗 GREETING_STARTED 许可。不得重新点击沟通入口;已开始话术发送或扩展重启丢失阶段时仍暂停核对。身份信息来自 BOSS 当前选中会话组件,仅导出 UID 与岗位 ID,不能用姓名或职位文字替代。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ Object probe(String body) {
assertThat(page.locator("body").innerHTML()).isEqualTo(original);
}

@Test void bossGreetingKeepsNewlinesInTheRealContenteditable() throws Exception {
fixture("boss", "detail/redacted-header-only-20260915.html",
"<div id='chat-input' contenteditable='true' style='white-space:normal'></div>");
String source = Files.readString(Path.of("chrome-extension/boss-content.js"));
String functions = source.substring(source.indexOf(" function writeChatInput("),
source.indexOf(" function findSendButton("));
assertThat(probe(functions + """
function isCurrentContentInstance() { return true; }
const input = document.getElementById('chat-input');
const expected = '测试岗位沟通。\\n个人作品集:https://example.invalid/';
writeChatInput(input, expected);
return readChatInput(input);
""")).isEqualTo("测试岗位沟通。\n个人作品集:https://example.invalid/");
}

@Test void realLayoutRejectsHiddenSuccessAndQuotaOverridesVisibleSuccess() throws Exception {
fixture("zhilian", "states/success.html", "");
assertThat(probe("return GetJobsZhilianPageEvidence.detectStatus(document)")).isEqualTo("已投递");
Expand Down
Loading