Skip to content

Commit c4e9bc3

Browse files
[codex] exclude Pet root from operation UI
1 parent 52081be commit c4e9bc3

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

macos/scripts/injector.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,19 @@ function isValidCdpPageTarget(item, port) {
379379
}
380380
}
381381

382+
export function isCodexRendererCandidateTarget(target) {
383+
if (target?.type !== "page") return false;
384+
let url;
385+
try {
386+
url = new URL(target.url);
387+
} catch {
388+
return false;
389+
}
390+
if (url.protocol !== "app:" || url.host !== "-" || url.pathname !== "/index.html"
391+
|| url.username || url.password || url.hash) return false;
392+
return !url.searchParams.getAll("initialRoute").includes("/avatar-overlay");
393+
}
394+
382395
export function classifyPetActivityTarget(target) {
383396
if (target?.type !== "page" || target.title !== PET_COMPOSITION_TITLE) return null;
384397
let url;
@@ -601,6 +614,7 @@ async function connectCodexTargets(port, timeoutMs) {
601614
const targets = await listAppTargets(port);
602615
const connected = [];
603616
for (const target of targets) {
617+
if (!isCodexRendererCandidateTarget(target)) continue;
604618
let session;
605619
try {
606620
session = await connectTarget(target, port);
@@ -2063,6 +2077,7 @@ async function runWatch(options) {
20632077
}
20642078
continue;
20652079
}
2080+
if (!isCodexRendererCandidateTarget(target)) continue;
20662081
let session;
20672082
let record;
20682083
let connectionEpoch;

macos/tests/injector-bootstrap.test.mjs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
66
import {
77
classifyPetActivityTarget,
88
earlyPayloadFor,
9+
isCodexRendererCandidateTarget,
910
petActivityCompatibilityPayloadFor,
1011
} from "../scripts/injector.mjs";
1112

@@ -234,6 +235,21 @@ assert.equal(classifyPetActivityTarget(petTarget(
234235
"Unexpected Surface",
235236
)), null, "The exact native pet title is part of the auxiliary-target identity boundary.");
236237

238+
const codexTarget = (url, title = "Codex") => ({ type: "page", title, url });
239+
assert.equal(isCodexRendererCandidateTarget(codexTarget("app://-/index.html")), true);
240+
assert.equal(isCodexRendererCandidateTarget(codexTarget(
241+
"app://-/index.html?initialRoute=%2Fsettings",
242+
)), true, "Normal Codex initial routes must remain eligible for renderer probing.");
243+
for (const target of [
244+
codexTarget("app://-/index.html?initialRoute=%2Favatar-overlay"),
245+
codexTarget("app://-/index.html?initialRoute=%2Fsettings&initialRoute=%2Favatar-overlay"),
246+
codexTarget("app://-/avatar-overlay-composition-surface.html?surfaceId=mascot-badge"),
247+
codexTarget("https://example.com/index.html"),
248+
]) {
249+
assert.equal(isCodexRendererCandidateTarget(target), false,
250+
`Auxiliary or non-Codex targets must not receive operation UI or full Dream Skin: ${target.url}`);
251+
}
252+
237253
function createPetCompatibilityFixture(href) {
238254
const nodes = new Map();
239255
const head = {
@@ -282,10 +298,16 @@ assert.equal(petCompatWrongSurface.style, null,
282298
"Voice, mascot, and other auxiliary surfaces must remain completely untouched.");
283299
const targetLoopStart = source.indexOf("for (const target of targets)", source.indexOf("async function runWatch"));
284300
const petClassificationStart = source.indexOf("classifyPetActivityTarget(target)", targetLoopStart);
301+
const codexClassificationStart = source.indexOf("isCodexRendererCandidateTarget(target)", petClassificationStart);
285302
const mainEarlyRegistrationStart = source.indexOf("registerEarlyForRecord(", petClassificationStart);
286303
assert.ok(targetLoopStart >= 0 && petClassificationStart > targetLoopStart
287-
&& mainEarlyRegistrationStart > petClassificationStart,
288-
"Pet activity surfaces must be classified before the full Dream Skin early payload is registered.");
304+
&& codexClassificationStart > petClassificationStart
305+
&& mainEarlyRegistrationStart > codexClassificationStart,
306+
"Pet activity surfaces must be classified first, and only a true Codex renderer may receive the full payload.");
307+
const connectCodexTargetsStart = source.indexOf("async function connectCodexTargets");
308+
const operationUiStart = source.indexOf("function operationUiExpression", connectCodexTargetsStart);
309+
assert.match(source.slice(connectCodexTargetsStart, operationUiStart), /isCodexRendererCandidateTarget\(target\)/,
310+
"Operation UI discovery must reject the avatar-overlay root before probing or connecting it.");
289311
assert.match(source, /await setPetActivityCompatibility\(petSession, true\)/,
290312
"The watcher must install the bounded pet style only after live target identity verification.");
291313
assert.match(source, /petSession\.on\("Page\.loadEventFired"[\s\S]*livePetActivityTarget\(petSession\)[\s\S]*setPetActivityCompatibility\(petSession, true\)/,

0 commit comments

Comments
 (0)