Skip to content
Open
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
11 changes: 4 additions & 7 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
*.sh text eol=lf
.github/workflows/*.yml text eol=lf

# Preserve the original Snow Skin asset line endings for byte-exact bundling.
assets/inject/upstream/snow-skin/*.js text eol=lf
assets/inject/upstream/snow-skin/*.css text eol=lf

# Keep byte-exact macOS theme assets identical on every checkout platform.
assets/inject/upstream/*/macos/*.js text eol=lf
assets/inject/upstream/*/macos/*.css text eol=lf
# Keep every byte-exact upstream theme asset stable on all checkout platforms.
assets/inject/upstream/**/*.js text eol=lf
assets/inject/upstream/**/*.css text eol=lf
assets/inject/upstream/skin-packs/packs/*/theme.json text eol=lf
24 changes: 18 additions & 6 deletions assets/inject/renderer-inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -7478,11 +7478,23 @@

async function refreshRecentConversationsForHost() {
try {
const signals = await import("./assets/app-server-manager-signals-C1h8B-R-.js");
if (typeof signals.rn === "function") await signals.rn("refresh-recent-conversations-for-host", { hostId: "local", sortKey: "updated_at" });
const signals = await loadOptionalCodexAppModule("app-server-manager-signals-");
const sendRequest = Object.values(signals || {}).find((candidate) => {
if (typeof candidate !== "function") return false;
try {
const source = Function.prototype.toString.call(candidate).replace(/\s+/g, "");
return /^function[$\w]+\(e,t\)\{return[$\w]+\.sendRequest\(e,t\)\}$/.test(source);
} catch {
return false;
}
});
if (typeof sendRequest !== "function") return false;
await sendRequest("refresh-recent-conversations-for-host", { hostId: "local", sortKey: "updated_at" });
return true;
} catch (error) {
window.__codexProjectMoveRefreshFailures = window.__codexProjectMoveRefreshFailures || [];
window.__codexProjectMoveRefreshFailures.push(String(error?.stack || error));
return false;
}
}

Expand Down Expand Up @@ -7677,7 +7689,10 @@
undo.addEventListener("click", async () => {
const result = await postJson("/undo", { undo_token: undoToken });
toast.textContent = result.message || "撤销完成";
if (result.status === "undone") window.location.reload();
if (result.status === "undone") {
const refreshed = await refreshRecentConversationsForHost();
if (!refreshed) window.location.reload();
}
setTimeout(() => toast.remove(), 5000);
});
toast.appendChild(undo);
Expand Down Expand Up @@ -8874,7 +8889,6 @@
}

function installDeleteButtonEventDelegation() {
document.removeEventListener("pointerup", window.__codexSessionDeleteDocumentDeleteHandler, true);
document.removeEventListener("click", window.__codexSessionDeleteDocumentDeleteHandler, true);
const handler = (event) => {
const button = event.target?.closest?.(`.${buttonClass}`);
Expand All @@ -8885,7 +8899,6 @@
openDeleteConfirmForRow(row, button, ref, event);
};
window.__codexSessionDeleteDocumentDeleteHandler = handler;
document.addEventListener("pointerup", handler, true);
document.addEventListener("click", handler, true);
}

Expand Down Expand Up @@ -8965,7 +8978,6 @@
button.addEventListener("pointerleave", hideActionButtonTooltip);
button.addEventListener("focus", () => showActionButtonTooltip(button));
button.addEventListener("blur", hideActionButtonTooltip);
button.addEventListener("pointerup", onActivate, true);
button.addEventListener("click", (event) => {
hideActionButtonTooltip();
onActivate(event);
Expand Down
63 changes: 63 additions & 0 deletions crates/codex-plus-core/tests/cdp_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,56 @@ fn injection_script_keeps_session_action_buttons_in_pr_style() {
assert!(script.contains("cursor: default;"));
}

#[test]
fn injection_script_activates_session_delete_once_per_click() {
let script = assets::injection_script(57321);
let delegated_delete = script
.split_once("function installDeleteButtonEventDelegation()")
.expect("delete event delegation should exist")
.1
.split_once("function actionGroupFromRow")
.expect("delete event delegation should end before action group helpers")
.0;
let action_button_events = script
.split_once("function installActionButtonEvents")
.expect("action button event setup should exist")
.1
.split_once("function installMoreButtonEvents")
.expect("action button setup should end before more button setup")
.0;

assert!(delegated_delete.contains("document.addEventListener(\"click\", handler, true);"));
assert!(!delegated_delete.contains("document.addEventListener(\"pointerup\", handler, true);"));
assert!(
!action_button_events.contains("button.addEventListener(\"pointerup\", onActivate, true);")
);
assert!(action_button_events.contains("button.addEventListener(\"click\", (event) => {"));
}

#[test]
fn injection_script_refreshes_sidebar_after_session_undo() {
let script = assets::injection_script(57321);
let refresh = script
.split_once("async function refreshRecentConversationsForHost()")
.expect("recent conversation refresh helper should exist")
.1
.split_once("function refreshAfterProjectMove")
.expect("refresh helper should end before project move refresh")
.0;
let toast = script
.split_once("function showToast(message, undoToken)")
.expect("undo toast should exist")
.1
.split_once("function upstreamWorktreeField")
.expect("undo toast should end before worktree helpers")
.0;

assert!(refresh.contains("loadOptionalCodexAppModule(\"app-server-manager-signals-\")"));
assert!(!refresh.contains("app-server-manager-signals-C1h8B-R-.js"));
assert!(toast.contains("const refreshed = await refreshRecentConversationsForHost();"));
assert!(toast.contains("if (!refreshed) window.location.reload();"));
}

#[test]
fn injection_script_moves_export_and_project_move_into_more_menu() {
let script = assets::injection_script(57321).replace("\r\n", "\n");
Expand Down Expand Up @@ -1431,6 +1481,19 @@ fn injection_script_discovers_app_server_request_clients_without_hardcoded_hash(
);
}

#[test]
fn injection_script_refreshes_sidebar_after_undo_without_stale_asset_exports() {
let script = assets::injection_script(57321);

assert!(script.contains("loadOptionalCodexAppModule(\"app-server-manager-signals-\")"));
assert!(script.contains("Object.values(signals || {}).find"));
assert!(script.contains("refresh-recent-conversations-for-host"));
assert!(script.contains("const refreshed = await refreshRecentConversationsForHost()"));
assert!(script.contains("if (!refreshed) window.location.reload()"));
assert!(!script.contains("app-server-manager-signals-C1h8B-R-.js"));
assert!(!script.contains("typeof signals.rn"));
}

#[test]
fn injection_script_clears_project_state_when_moving_to_projectless() {
let script = assets::injection_script(57321);
Expand Down
Loading