@codexhost/cli-darwin-arm64 0.17.0 → 0.17.2
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/README.md +1 -1
- package/app/codexhost-distribution.json +1 -1
- package/app/console-server.mjs +15 -0
- package/app/console-web.js +16 -1
- package/app/desktop-controller.mjs +1040 -33
- package/app/host-runtime.mjs +1104 -43
- package/app/plugins/antigravity/plugin.mjs +42 -7
- package/app/plugins/claude-code/plugin.mjs +15 -0
- package/app/plugins/codebuddy/plugin.mjs +15 -0
- package/app/plugins/codex-usage/plugin.mjs +15 -0
- package/app/plugins/copilot/plugin.mjs +15 -0
- package/app/plugins/cursor-cli/plugin.mjs +34 -3
- package/app/plugins/deepseek-harness/plugin.mjs +15 -0
- package/app/plugins/devin/plugin.mjs +15 -0
- package/app/plugins/grok/plugin.mjs +15 -0
- package/app/plugins/hermes/plugin.mjs +15 -0
- package/app/plugins/kimi-code/plugin.mjs +65 -3
- package/app/plugins/kiro-cli/plugin.mjs +15 -0
- package/app/plugins/omp/plugin.mjs +15 -0
- package/app/plugins/opencode/plugin.mjs +15 -0
- package/app/plugins/pi/plugin.mjs +223 -88
- package/app/plugins/qoder/plugin.mjs +15 -0
- package/app/plugins/qoder-cn/plugin.mjs +15 -0
- package/app/plugins/qwen-code/plugin.mjs +15 -0
- package/app/plugins/workbuddy/plugin.mjs +15 -0
- package/app/plugins/zcode/plugin.mjs +157 -9
- package/app/renderer-extension.js +559 -216
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
|
@@ -15780,6 +15780,21 @@ var threadSteeringInspectParamsSchema = external_exports.object({
|
|
|
15780
15780
|
/** The text about to be steered; a Harness command always stops and restarts. */
|
|
15781
15781
|
text: external_exports.string().optional()
|
|
15782
15782
|
}).strict();
|
|
15783
|
+
var threadSteeringContextSchema = external_exports.object({
|
|
15784
|
+
kind: external_exports.literal("application"),
|
|
15785
|
+
value: external_exports.string().transform((text, context) => {
|
|
15786
|
+
try {
|
|
15787
|
+
return JSON.parse(text);
|
|
15788
|
+
} catch {
|
|
15789
|
+
context.addIssue({ code: "custom", message: "Invalid steering context JSON" });
|
|
15790
|
+
return external_exports.NEVER;
|
|
15791
|
+
}
|
|
15792
|
+
}).pipe(external_exports.object({
|
|
15793
|
+
expectedTurnId: hostTurnIdSchema,
|
|
15794
|
+
clientUserMessageId: external_exports.string().min(1),
|
|
15795
|
+
delivery: external_exports.enum(["newTurn", "activeTurn"])
|
|
15796
|
+
}).strict())
|
|
15797
|
+
}).strict().transform((context) => context.value);
|
|
15783
15798
|
var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
|
|
15784
15799
|
var threadSteeringInspectResultSchema = external_exports.object({
|
|
15785
15800
|
delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
|
|
@@ -16818,9 +16833,10 @@ function isolateRendererPrewarmConsumption(manager, discardExternal) {
|
|
|
16818
16833
|
}
|
|
16819
16834
|
|
|
16820
16835
|
// packages/desktop-control/src/renderer-draft-prewarm-runtime.ts
|
|
16821
|
-
function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewarmedThreadManager, isCurrentManager, retainResponses = retainRendererHostResponses, isolateConsumption = isolateRendererPrewarmConsumption) {
|
|
16836
|
+
function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewarmedThreadManager, isCurrentManager, retainResponses = retainRendererHostResponses, isolateConsumption = isolateRendererPrewarmConsumption, sendControlRequest) {
|
|
16822
16837
|
let disposed = false;
|
|
16823
16838
|
const originalSend = bridge.sendRequest;
|
|
16839
|
+
const controlSend = (method, parameters) => sendControlRequest ? sendControlRequest(method, parameters) : originalSend.call(bridge, method, parameters);
|
|
16824
16840
|
const originalPrewarm = bridge.prewarmThreadStart;
|
|
16825
16841
|
const originalOnNotification = manager.onNotification;
|
|
16826
16842
|
const originalDispatchAppServerResponse = manager.dispatchAppServerResponse;
|
|
@@ -16904,7 +16920,7 @@ function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewar
|
|
|
16904
16920
|
bridgeRequests.clear();
|
|
16905
16921
|
if (isRemoteControlHost && terminate) {
|
|
16906
16922
|
void Promise.resolve(
|
|
16907
|
-
|
|
16923
|
+
controlSend("process/kill", { processHandle: failedProcessHandle })
|
|
16908
16924
|
).catch(() => void 0);
|
|
16909
16925
|
}
|
|
16910
16926
|
};
|
|
@@ -17067,7 +17083,7 @@ function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewar
|
|
|
17067
17083
|
];
|
|
17068
17084
|
const startedProcessHandle = bridgeProcessHandle;
|
|
17069
17085
|
try {
|
|
17070
|
-
const started =
|
|
17086
|
+
const started = controlSend("process/spawn", {
|
|
17071
17087
|
command,
|
|
17072
17088
|
processHandle: startedProcessHandle,
|
|
17073
17089
|
cwd: "C:\\",
|
|
@@ -17088,7 +17104,7 @@ function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewar
|
|
|
17088
17104
|
const operation = async () => {
|
|
17089
17105
|
await startBridge();
|
|
17090
17106
|
if (bridgeState !== "ready") throw transportError("is not ready");
|
|
17091
|
-
await
|
|
17107
|
+
await controlSend("process/writeStdin", {
|
|
17092
17108
|
processHandle: bridgeProcessHandle,
|
|
17093
17109
|
deltaBase64: utf8Base64(`${JSON.stringify(value)}
|
|
17094
17110
|
`)
|
|
@@ -17363,7 +17379,7 @@ function createDraftPrewarmPolicyBridge(manager, bridge, hostId2, target, prewar
|
|
|
17363
17379
|
bridgeReadyTimeout = null;
|
|
17364
17380
|
if (isRemoteControlHost && (bridgeState === "starting" || bridgeState === "ready")) {
|
|
17365
17381
|
void Promise.resolve(
|
|
17366
|
-
|
|
17382
|
+
controlSend("process/kill", { processHandle: bridgeProcessHandle })
|
|
17367
17383
|
).catch(() => void 0);
|
|
17368
17384
|
}
|
|
17369
17385
|
bridgeState = "disposed";
|
|
@@ -17465,10 +17481,11 @@ function resolveRendererHostManager(discovery, hostId2, managerFrom = requestMan
|
|
|
17465
17481
|
}
|
|
17466
17482
|
|
|
17467
17483
|
// packages/desktop-control/src/renderer-host-routing.ts
|
|
17468
|
-
function installRendererHostRouting(root, target, discover, resolve, createPolicy) {
|
|
17484
|
+
function installRendererHostRouting(root, target, discover, resolve, createPolicy, readConnection, publishRouting = true) {
|
|
17469
17485
|
const existing = target.__codexhostHostRoutingV1;
|
|
17470
|
-
if (existing) return existing;
|
|
17471
|
-
|
|
17486
|
+
if (publishRouting && existing) return existing;
|
|
17487
|
+
if (publishRouting)
|
|
17488
|
+
target.__codexhostDraftPrewarmPolicyV1?.dispose?.();
|
|
17472
17489
|
let disposed = false;
|
|
17473
17490
|
let lastDiscovery = null;
|
|
17474
17491
|
const routes = /* @__PURE__ */ new Map();
|
|
@@ -17495,10 +17512,20 @@ function installRendererHostRouting(root, target, discover, resolve, createPolic
|
|
|
17495
17512
|
routes.delete(hostId2);
|
|
17496
17513
|
entry?.route.policy.dispose();
|
|
17497
17514
|
};
|
|
17515
|
+
const connectionFor = (hostId2) => {
|
|
17516
|
+
if (!hostId2.startsWith("remote-control:")) return void 0;
|
|
17517
|
+
try {
|
|
17518
|
+
return readConnection?.(hostId2);
|
|
17519
|
+
} catch {
|
|
17520
|
+
return null;
|
|
17521
|
+
}
|
|
17522
|
+
};
|
|
17523
|
+
const sameConnection = (expected, current) => expected === void 0 ? current === void 0 : current?.owner === expected.owner && current.revision === expected.revision;
|
|
17498
17524
|
const routeFor = (hostId2, discovery) => {
|
|
17499
17525
|
const manager = lookup(hostId2, discovery);
|
|
17526
|
+
const connection = connectionFor(hostId2);
|
|
17500
17527
|
const previous = routes.get(hostId2);
|
|
17501
|
-
if (manager && previous?.route.manager === manager && previous.bridge === manager.requestClient && previous.prewarmed === manager.prewarmedThreadManager && previous.route.policy.owns(
|
|
17528
|
+
if (manager && previous?.route.manager === manager && previous.bridge === manager.requestClient && previous.prewarmed === manager.prewarmedThreadManager && sameConnection(previous.connection, connection) && previous.route.policy.owns(
|
|
17502
17529
|
manager,
|
|
17503
17530
|
manager.requestClient,
|
|
17504
17531
|
hostId2,
|
|
@@ -17508,7 +17535,7 @@ function installRendererHostRouting(root, target, discover, resolve, createPolic
|
|
|
17508
17535
|
return previous.route;
|
|
17509
17536
|
}
|
|
17510
17537
|
retire(hostId2);
|
|
17511
|
-
if (!manager) return null;
|
|
17538
|
+
if (!manager || connection === null) return null;
|
|
17512
17539
|
const bridge = manager.requestClient;
|
|
17513
17540
|
const prewarmed = manager.prewarmedThreadManager;
|
|
17514
17541
|
const policy = createPolicy(
|
|
@@ -17517,13 +17544,14 @@ function installRendererHostRouting(root, target, discover, resolve, createPolic
|
|
|
17517
17544
|
hostId2,
|
|
17518
17545
|
target,
|
|
17519
17546
|
prewarmed,
|
|
17520
|
-
() => lookup(hostId2) === manager && manager.requestClient === bridge && manager.prewarmedThreadManager === prewarmed
|
|
17547
|
+
() => lookup(hostId2) === manager && sameConnection(connection, connectionFor(hostId2)) && manager.requestClient === bridge && manager.prewarmedThreadManager === prewarmed
|
|
17521
17548
|
);
|
|
17522
17549
|
const route = { hostId: hostId2, manager, policy };
|
|
17523
|
-
routes.set(hostId2, { route, bridge, prewarmed });
|
|
17550
|
+
routes.set(hostId2, { route, bridge, prewarmed, connection });
|
|
17524
17551
|
return route;
|
|
17525
17552
|
};
|
|
17526
17553
|
const publish = (route) => {
|
|
17554
|
+
if (!publishRouting) return;
|
|
17527
17555
|
const policy = route?.policy;
|
|
17528
17556
|
if (target.__codexhostDraftPrewarmPolicyV1 === policy) return;
|
|
17529
17557
|
Object.defineProperty(target, "__codexhostDraftPrewarmPolicyV1", {
|
|
@@ -17576,7 +17604,7 @@ function installRendererHostRouting(root, target, discover, resolve, createPolic
|
|
|
17576
17604
|
if (!composer) {
|
|
17577
17605
|
for (const [hostId3, entry] of routes) {
|
|
17578
17606
|
const manager = lookup(hostId3, discovery);
|
|
17579
|
-
if (manager !== entry.route.manager || manager.requestClient !== entry.bridge || manager.prewarmedThreadManager !== entry.prewarmed)
|
|
17607
|
+
if (manager !== entry.route.manager || manager.requestClient !== entry.bridge || manager.prewarmedThreadManager !== entry.prewarmed || !sameConnection(entry.connection, connectionFor(hostId3)))
|
|
17580
17608
|
retire(hostId3);
|
|
17581
17609
|
}
|
|
17582
17610
|
}
|
|
@@ -17596,7 +17624,11 @@ function installRendererHostRouting(root, target, discover, resolve, createPolic
|
|
|
17596
17624
|
}
|
|
17597
17625
|
}
|
|
17598
17626
|
};
|
|
17599
|
-
|
|
17627
|
+
if (publishRouting)
|
|
17628
|
+
Object.defineProperty(target, "__codexhostHostRoutingV1", {
|
|
17629
|
+
configurable: true,
|
|
17630
|
+
value: routing
|
|
17631
|
+
});
|
|
17600
17632
|
return routing;
|
|
17601
17633
|
}
|
|
17602
17634
|
|
|
@@ -17646,7 +17678,8 @@ function findRendererHostRpcFamily(store) {
|
|
|
17646
17678
|
if (!record3(definition) || definition.kind !== "signal-family") continue;
|
|
17647
17679
|
if (!record3(members) || typeof members.get !== "function") continue;
|
|
17648
17680
|
for (const [hostId2, member] of members) {
|
|
17649
|
-
if (typeof hostId2 !== "string" ||
|
|
17681
|
+
if (typeof hostId2 !== "string" || !/^(?:local$|durable$|remote[-:])/u.test(hostId2)) continue;
|
|
17682
|
+
if (!record3(member)) continue;
|
|
17650
17683
|
const signal = member.value;
|
|
17651
17684
|
if (!record3(signal) || typeof signal.get !== "function") continue;
|
|
17652
17685
|
let value;
|
|
@@ -17690,17 +17723,38 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17690
17723
|
const existing = target.__codexhostHostRoutingV1;
|
|
17691
17724
|
if (existing) return existing;
|
|
17692
17725
|
let disposed = false;
|
|
17726
|
+
let nativeRouting = null;
|
|
17693
17727
|
let discovery = null;
|
|
17694
17728
|
const routes = /* @__PURE__ */ new Map();
|
|
17695
17729
|
const read = () => {
|
|
17696
17730
|
if (disposed) return null;
|
|
17697
|
-
|
|
17731
|
+
try {
|
|
17698
17732
|
const store = dependencies.findStore(root);
|
|
17699
|
-
|
|
17733
|
+
const bound = store && discovery?.store === store ? [...store.familyBindings.values()].includes(discovery.family) : false;
|
|
17734
|
+
if (!bound) discovery = store ? dependencies.findFamily(store) : null;
|
|
17735
|
+
} catch {
|
|
17736
|
+
discovery = null;
|
|
17700
17737
|
}
|
|
17701
17738
|
return discovery;
|
|
17702
17739
|
};
|
|
17703
17740
|
if (!read()) return null;
|
|
17741
|
+
const native = () => {
|
|
17742
|
+
if (disposed) return null;
|
|
17743
|
+
try {
|
|
17744
|
+
nativeRouting ??= dependencies.nativeRouting?.() ?? null;
|
|
17745
|
+
} catch {
|
|
17746
|
+
}
|
|
17747
|
+
return nativeRouting;
|
|
17748
|
+
};
|
|
17749
|
+
const connectionFor = (hostId2) => {
|
|
17750
|
+
if (!hostId2.startsWith("remote-control:")) return void 0;
|
|
17751
|
+
try {
|
|
17752
|
+
return dependencies.readConnection?.(hostId2);
|
|
17753
|
+
} catch {
|
|
17754
|
+
return null;
|
|
17755
|
+
}
|
|
17756
|
+
};
|
|
17757
|
+
const sameConnection = (previous, current) => previous === void 0 ? current === void 0 : current?.owner === previous.owner && current.revision === previous.revision;
|
|
17704
17758
|
const isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17705
17759
|
const externalDrafts = /* @__PURE__ */ new Map();
|
|
17706
17760
|
const selectedModels = /* @__PURE__ */ new Map();
|
|
@@ -17778,16 +17832,25 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17778
17832
|
const postMessage = function(message, ...rest) {
|
|
17779
17833
|
let routed = message;
|
|
17780
17834
|
try {
|
|
17781
|
-
routed = disposed ? message : routeCreationCall(message);
|
|
17835
|
+
routed = disposed || routes.size === 0 ? message : routeCreationCall(message);
|
|
17782
17836
|
} catch {
|
|
17783
17837
|
routed = message;
|
|
17784
17838
|
}
|
|
17785
17839
|
return originalPostMessage.call(this, routed, ...rest);
|
|
17786
17840
|
};
|
|
17787
17841
|
port.postMessage = postMessage;
|
|
17788
|
-
const createRoute = (hostId2, rpc) => {
|
|
17842
|
+
const createRoute = (hostId2, rpc, connection) => {
|
|
17789
17843
|
let retired = false;
|
|
17790
|
-
const isCurrent = () =>
|
|
17844
|
+
const isCurrent = () => {
|
|
17845
|
+
if (retired || disposed || routes.get(hostId2)?.rpc !== rpc || !sameConnection(connection, connectionFor(hostId2)))
|
|
17846
|
+
return false;
|
|
17847
|
+
try {
|
|
17848
|
+
const current = read();
|
|
17849
|
+
return !!current && dependencies.resolve(current, hostId2) === rpc;
|
|
17850
|
+
} catch {
|
|
17851
|
+
return false;
|
|
17852
|
+
}
|
|
17853
|
+
};
|
|
17791
17854
|
const manager = Object.freeze({
|
|
17792
17855
|
kind: "main-process-rpc",
|
|
17793
17856
|
getHostId: () => hostId2,
|
|
@@ -17860,15 +17923,23 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17860
17923
|
routes.delete(hostId2);
|
|
17861
17924
|
entry?.route.policy.dispose();
|
|
17862
17925
|
};
|
|
17863
|
-
const routeFor = (hostId2) => {
|
|
17926
|
+
const routeFor = (hostId2, nativeRoute) => {
|
|
17927
|
+
if (disposed) return null;
|
|
17928
|
+
const connection = connectionFor(hostId2);
|
|
17929
|
+
const preferred = nativeRoute === void 0 ? native()?.forHost(hostId2) : nativeRoute;
|
|
17930
|
+
if (connection === null || preferred) {
|
|
17931
|
+
retire(hostId2);
|
|
17932
|
+
return connection === null ? null : preferred ?? null;
|
|
17933
|
+
}
|
|
17864
17934
|
const current = read();
|
|
17865
17935
|
const rpc = current ? dependencies.resolve(current, hostId2) : null;
|
|
17866
17936
|
const previous = routes.get(hostId2);
|
|
17867
|
-
if (rpc && previous?.rpc === rpc
|
|
17937
|
+
if (rpc && previous?.rpc === rpc && sameConnection(previous.connection, connection))
|
|
17938
|
+
return previous.route;
|
|
17868
17939
|
retire(hostId2);
|
|
17869
17940
|
if (!rpc) return null;
|
|
17870
|
-
const route = createRoute(hostId2, rpc);
|
|
17871
|
-
routes.set(hostId2, { route, rpc });
|
|
17941
|
+
const route = createRoute(hostId2, rpc, connection);
|
|
17942
|
+
routes.set(hostId2, { route, rpc, connection });
|
|
17872
17943
|
return route;
|
|
17873
17944
|
};
|
|
17874
17945
|
const publish = (route) => {
|
|
@@ -17883,14 +17954,22 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17883
17954
|
}
|
|
17884
17955
|
};
|
|
17885
17956
|
const composerHostId = (composer) => {
|
|
17957
|
+
const nativeHostId = native()?.hostIdForComposer(composer);
|
|
17958
|
+
if (nativeHostId) return nativeHostId;
|
|
17886
17959
|
const hostIds = new Set(dependencies.composerHostIds(composer).hostIds);
|
|
17887
17960
|
const hostId2 = hostIds.size === 1 ? hostIds.values().next().value : null;
|
|
17888
17961
|
return typeof hostId2 === "string" && hostId2 ? hostId2 : null;
|
|
17889
17962
|
};
|
|
17890
17963
|
const routing = {
|
|
17891
17964
|
knownHostIds() {
|
|
17965
|
+
if (disposed) return [];
|
|
17892
17966
|
const current = read();
|
|
17893
|
-
return
|
|
17967
|
+
return [
|
|
17968
|
+
.../* @__PURE__ */ new Set([
|
|
17969
|
+
...current ? dependencies.hostIds(current) : [],
|
|
17970
|
+
...native()?.knownHostIds?.() ?? []
|
|
17971
|
+
])
|
|
17972
|
+
];
|
|
17894
17973
|
},
|
|
17895
17974
|
forHost(hostId2) {
|
|
17896
17975
|
return hostId2 && !disposed ? routeFor(hostId2) : null;
|
|
@@ -17906,18 +17985,22 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17906
17985
|
forComposer(composer) {
|
|
17907
17986
|
if (disposed) return null;
|
|
17908
17987
|
let hostId2;
|
|
17988
|
+
let preferred = null;
|
|
17909
17989
|
try {
|
|
17910
|
-
|
|
17990
|
+
preferred = native()?.forComposer(composer) ?? null;
|
|
17991
|
+
hostId2 = preferred?.hostId ?? composerHostId(composer);
|
|
17911
17992
|
} catch {
|
|
17912
17993
|
hostId2 = null;
|
|
17913
17994
|
}
|
|
17914
|
-
const route = hostId2 ? routeFor(hostId2) : null;
|
|
17995
|
+
const route = hostId2 ? routeFor(hostId2, preferred) : null;
|
|
17915
17996
|
if (!composer) publish(route);
|
|
17916
17997
|
return route;
|
|
17917
17998
|
},
|
|
17918
17999
|
dispose() {
|
|
17919
18000
|
if (disposed) return;
|
|
17920
18001
|
disposed = true;
|
|
18002
|
+
nativeRouting?.dispose();
|
|
18003
|
+
nativeRouting = null;
|
|
17921
18004
|
for (const hostId2 of [...routes.keys()]) retire(hostId2);
|
|
17922
18005
|
discovery = null;
|
|
17923
18006
|
externalDrafts.clear();
|
|
@@ -17933,6 +18016,30 @@ function installRendererHostRpcRouting(root, target, dependencies) {
|
|
|
17933
18016
|
return routing;
|
|
17934
18017
|
}
|
|
17935
18018
|
|
|
18019
|
+
// packages/desktop-control/src/renderer-connection-generation.ts
|
|
18020
|
+
function readRendererConnectionGeneration(store, hostId2) {
|
|
18021
|
+
if (!store) return void 0;
|
|
18022
|
+
const record3 = (value) => value !== null && typeof value === "object";
|
|
18023
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
18024
|
+
for (const members of store.familyBindings.values()) {
|
|
18025
|
+
const value = members.get(hostId2)?.value;
|
|
18026
|
+
if (record3(value) && record3(value.state$) && record3(value.revision$) && record3(value.appServerVersion$) && typeof value.state$.get === "function" && typeof value.revision$.get === "function")
|
|
18027
|
+
candidates.add(value);
|
|
18028
|
+
}
|
|
18029
|
+
if (!candidates.size) return void 0;
|
|
18030
|
+
if (candidates.size !== 1) return null;
|
|
18031
|
+
const owner = candidates.values().next().value;
|
|
18032
|
+
if (!owner) return null;
|
|
18033
|
+
const state = owner.state$;
|
|
18034
|
+
const revision = owner.revision$;
|
|
18035
|
+
try {
|
|
18036
|
+
const current = revision.get();
|
|
18037
|
+
return state.get() === "connected" && typeof current === "number" && Number.isSafeInteger(current) ? { owner, revision: current } : null;
|
|
18038
|
+
} catch {
|
|
18039
|
+
return null;
|
|
18040
|
+
}
|
|
18041
|
+
}
|
|
18042
|
+
|
|
17936
18043
|
// packages/desktop-control/src/renderer-draft-prewarm-policy.ts
|
|
17937
18044
|
var REQUEST_MANAGER_WAIT_TIMEOUT_MS = 6e4;
|
|
17938
18045
|
var REQUEST_MANAGER_POLL_INTERVAL_MS = 25;
|
|
@@ -17945,15 +18052,19 @@ function directRendererInstaller() {
|
|
|
17945
18052
|
const retainRendererHostResponses = ${retainRendererHostResponses.toString()};
|
|
17946
18053
|
const createDraftPrewarmPolicyBridge = ${createDraftPrewarmPolicyBridge.toString()};
|
|
17947
18054
|
const isolateRendererPrewarmConsumption = ${isolateRendererPrewarmConsumption.toString()};
|
|
18055
|
+
const findRendererAppScopeStore = ${findRendererAppScopeStore.toString()};
|
|
18056
|
+
const readRendererConnectionGeneration = ${readRendererConnectionGeneration.toString()};
|
|
17948
18057
|
const discover = (root) =>
|
|
17949
18058
|
discoverRendererHosts(root, committedReactAncestors, requestManagerFromHookState);
|
|
17950
|
-
const installNative = () => (${installRendererHostRouting.toString()})(
|
|
18059
|
+
const installNative = (publishRouting = true) => (${installRendererHostRouting.toString()})(
|
|
17951
18060
|
document, window, discover,
|
|
17952
18061
|
(discovery, hostId) => resolveRendererHostManager(discovery, hostId, requestManagerFromHookState),
|
|
17953
18062
|
(manager, bridge, hostId, target, prewarmed, isCurrent) => createDraftPrewarmPolicyBridge(
|
|
17954
18063
|
manager, bridge, hostId, target, prewarmed, isCurrent, retainRendererHostResponses,
|
|
17955
18064
|
isolateRendererPrewarmConsumption,
|
|
17956
18065
|
),
|
|
18066
|
+
(hostId) => readRendererConnectionGeneration(findRendererAppScopeStore(document), hostId),
|
|
18067
|
+
publishRouting,
|
|
17957
18068
|
);
|
|
17958
18069
|
const installRpc = () => typeof MessagePort !== 'function' ? null : (${installRendererHostRpcRouting.toString()})(document, window, {
|
|
17959
18070
|
findStore: ${findRendererAppScopeStore.toString()},
|
|
@@ -17967,14 +18078,21 @@ function directRendererInstaller() {
|
|
|
17967
18078
|
return discover(source);
|
|
17968
18079
|
},
|
|
17969
18080
|
portPrototype: MessagePort.prototype,
|
|
18081
|
+
nativeRouting: () => {
|
|
18082
|
+
const native = discover(document);
|
|
18083
|
+
return native.managers.length || native.registries.length ? installNative(false) : null;
|
|
18084
|
+
},
|
|
18085
|
+
readConnection: (hostId) => readRendererConnectionGeneration(findRendererAppScopeStore(document), hostId),
|
|
17970
18086
|
});
|
|
17971
18087
|
const connected = (routing) => routing.forComposer() !== null ||
|
|
17972
18088
|
['local', ...(routing.knownHostIds?.() ?? [])].some((hostId) => routing.forHost(hostId) !== null);
|
|
17973
18089
|
let nativeReady = false;
|
|
17974
|
-
//
|
|
17975
|
-
//
|
|
18090
|
+
// Mixed layouts can expose native managers for only some Hosts. Keep one
|
|
18091
|
+
// router that selects a native owner or the current ready RPC peer per Host.
|
|
17976
18092
|
const routing = (() => {
|
|
17977
18093
|
if (window.__codexhostHostRoutingV1) return window.__codexhostHostRoutingV1;
|
|
18094
|
+
const rpc = installRpc();
|
|
18095
|
+
if (rpc) return rpc;
|
|
17978
18096
|
const native = discover(document);
|
|
17979
18097
|
if (native.managers.length || native.registries.length) {
|
|
17980
18098
|
const routing = installNative();
|
|
@@ -17984,8 +18102,6 @@ function directRendererInstaller() {
|
|
|
17984
18102
|
}
|
|
17985
18103
|
routing.dispose();
|
|
17986
18104
|
}
|
|
17987
|
-
const rpc = installRpc();
|
|
17988
|
-
if (rpc) return rpc;
|
|
17989
18105
|
throw new Error('Renderer Host request manager is unavailable');
|
|
17990
18106
|
})();
|
|
17991
18107
|
// Publish a default draft policy only when its Host is unambiguous. Host
|
|
@@ -18145,6 +18261,892 @@ async function installRendererLoadedModules(renderer) {
|
|
|
18145
18261
|
}
|
|
18146
18262
|
}
|
|
18147
18263
|
|
|
18264
|
+
// packages/desktop-control/src/renderer-native-rpc-discovery.ts
|
|
18265
|
+
function nativeManagerDependencies(factoryName, callers) {
|
|
18266
|
+
const identifier = "[$A-Z_a-z][$\\w]*";
|
|
18267
|
+
const escaped = factoryName.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
18268
|
+
const pattern = new RegExp(
|
|
18269
|
+
`${escaped}\\((${identifier}),(${identifier}),\\1\\.get\\((${identifier}),\\2\\),(${identifier})\\.bind\\(null,\\1\\),\\((${identifier}),(${identifier})\\)=>\\5\\((${identifier}),\\6\\)\\)`
|
|
18270
|
+
);
|
|
18271
|
+
const matches = callers.flatMap((source) => {
|
|
18272
|
+
const match = pattern.exec(source);
|
|
18273
|
+
return match?.[3] && match[4] && match[7] ? [
|
|
18274
|
+
{
|
|
18275
|
+
requestDefinition: match[3],
|
|
18276
|
+
isHostForConversation: match[4],
|
|
18277
|
+
imageDefinition: match[7]
|
|
18278
|
+
}
|
|
18279
|
+
] : [];
|
|
18280
|
+
});
|
|
18281
|
+
return matches.length === 1 ? matches[0] : void 0;
|
|
18282
|
+
}
|
|
18283
|
+
function nativeRpcRole(source) {
|
|
18284
|
+
if (["dispatchMessageFromView", "threadProjectAssignments", "queuedMessageCoordination"].every(
|
|
18285
|
+
(part) => source.includes(part)
|
|
18286
|
+
))
|
|
18287
|
+
return "createManager";
|
|
18288
|
+
if (["collectAppStateSnapshot", "getReviewPaneSnapshotMetrics", "registerReplayAdmission"].every(
|
|
18289
|
+
(part) => source.includes(part)
|
|
18290
|
+
))
|
|
18291
|
+
return "createController";
|
|
18292
|
+
if (["getWorkInProgress", "getCachedThreadSearchSnapshot", "registerReplayAdmission"].every(
|
|
18293
|
+
(part) => source.includes(part)
|
|
18294
|
+
))
|
|
18295
|
+
return "RpcManager";
|
|
18296
|
+
if (["prewarmedThreadManager", "onNotification", "dispatchAppServerResponse"].every(
|
|
18297
|
+
(part) => source.includes(part)
|
|
18298
|
+
))
|
|
18299
|
+
return "Manager";
|
|
18300
|
+
return void 0;
|
|
18301
|
+
}
|
|
18302
|
+
function nativeRpcObjectShape(value) {
|
|
18303
|
+
if (value === null || typeof value !== "object")
|
|
18304
|
+
return { scope: false, services: false, controller: false };
|
|
18305
|
+
const candidate = value;
|
|
18306
|
+
const own = (keys) => keys.every((key) => Object.hasOwn(candidate, key));
|
|
18307
|
+
const methods = (keys) => keys.every((key) => typeof candidate[key] === "function");
|
|
18308
|
+
return {
|
|
18309
|
+
scope: own(["node", "scope", "get", "set", "watch"]) && methods(["get", "set", "watch"]),
|
|
18310
|
+
services: own(["appServerManagers", "remoteConnections", "applicationMenu"]) && typeof candidate.appServerManagers?.subscribe === "function",
|
|
18311
|
+
controller: own(["forHost", "collectAppStateSnapshot", "getReviewPaneSnapshotMetrics", "dispose"]) && methods(["forHost", "collectAppStateSnapshot", "getReviewPaneSnapshotMetrics", "dispose"])
|
|
18312
|
+
};
|
|
18313
|
+
}
|
|
18314
|
+
async function withNativeRpcComponents(client, install) {
|
|
18315
|
+
const group = `codexhost-native-rpc-${crypto.randomUUID()}`;
|
|
18316
|
+
const command = async (method, params) => client.command(method, params);
|
|
18317
|
+
const evaluate = (expression) => command("Runtime.evaluate", { expression, awaitPromise: true, objectGroup: group });
|
|
18318
|
+
const properties = (objectId) => command("Runtime.getProperties", { objectId, ownProperties: true });
|
|
18319
|
+
const call = (objectId, functionDeclaration, args = []) => command("Runtime.callFunctionOn", {
|
|
18320
|
+
objectId,
|
|
18321
|
+
functionDeclaration,
|
|
18322
|
+
arguments: args,
|
|
18323
|
+
objectGroup: group,
|
|
18324
|
+
returnByValue: true
|
|
18325
|
+
});
|
|
18326
|
+
try {
|
|
18327
|
+
const initial = await evaluate(String.raw`(() => {
|
|
18328
|
+
const catalog = globalThis.__codexhostLoadedModulesV1;
|
|
18329
|
+
if (!catalog?.complete || catalog.documentUrl !== location.href) return null;
|
|
18330
|
+
const urls = catalog.urls.filter(url => /^app:\/\/-\/assets\/(?:renderer-app-server-managers|app-shared)-[^/]+\.js$/.test(url));
|
|
18331
|
+
return { document, urls };
|
|
18332
|
+
})()`);
|
|
18333
|
+
if (!initial.result.objectId) return false;
|
|
18334
|
+
const holder = initial.result.objectId;
|
|
18335
|
+
const catalog = await call(holder, "function(){return this.urls}");
|
|
18336
|
+
const urls = catalog.result.value;
|
|
18337
|
+
if (!Array.isArray(urls) || urls.length !== 2) return false;
|
|
18338
|
+
const managerUrl = urls.find((url2) => url2.includes("renderer-app-server-managers"));
|
|
18339
|
+
const sharedUrl = urls.find((url2) => url2.includes("app-shared"));
|
|
18340
|
+
if (!managerUrl || !sharedUrl) return false;
|
|
18341
|
+
const attach = async (name, objectId) => {
|
|
18342
|
+
const result = await call(
|
|
18343
|
+
holder,
|
|
18344
|
+
"function(name,value){if(this.document!==document)throw Error('Renderer Realm changed');this[name]=value;return true}",
|
|
18345
|
+
[{ value: name }, { objectId }]
|
|
18346
|
+
);
|
|
18347
|
+
if (result.exceptionDetails) throw new Error("Native RPC discovery lost its Renderer Realm");
|
|
18348
|
+
};
|
|
18349
|
+
const imported = await evaluate(`import(${JSON.stringify(managerUrl)})`);
|
|
18350
|
+
if (!imported.result.objectId) return false;
|
|
18351
|
+
const exports = (await properties(imported.result.objectId)).result.filter(
|
|
18352
|
+
(entry) => entry.value?.type === "function"
|
|
18353
|
+
);
|
|
18354
|
+
let bindings = [];
|
|
18355
|
+
for (const entry of exports.slice(0, 3)) {
|
|
18356
|
+
if (!entry.value?.objectId) continue;
|
|
18357
|
+
const scopes = (await properties(entry.value.objectId)).internalProperties?.find(
|
|
18358
|
+
(entry2) => entry2.name === "[[Scopes]]"
|
|
18359
|
+
)?.value?.objectId;
|
|
18360
|
+
if (!scopes) continue;
|
|
18361
|
+
const modules = (await properties(scopes)).result.filter(
|
|
18362
|
+
(entry2) => entry2.value?.description?.startsWith("Module") && entry2.value.objectId
|
|
18363
|
+
);
|
|
18364
|
+
const moduleId = modules[0]?.value?.objectId;
|
|
18365
|
+
if (modules.length !== 1 || !moduleId) continue;
|
|
18366
|
+
bindings = (await properties(moduleId)).result;
|
|
18367
|
+
break;
|
|
18368
|
+
}
|
|
18369
|
+
const functions = bindings.filter((entry) => entry.value?.type === "function");
|
|
18370
|
+
const roles = /* @__PURE__ */ new Map();
|
|
18371
|
+
for (const entry of functions) {
|
|
18372
|
+
const role = nativeRpcRole(entry.value?.description ?? "");
|
|
18373
|
+
if (role) roles.set(role, [...roles.get(role) ?? [], entry]);
|
|
18374
|
+
}
|
|
18375
|
+
if (["createManager", "Manager", "RpcManager", "createController"].some(
|
|
18376
|
+
(role) => roles.get(role)?.length !== 1
|
|
18377
|
+
))
|
|
18378
|
+
return false;
|
|
18379
|
+
const factory = roles.get("createManager")?.[0];
|
|
18380
|
+
if (!factory) return false;
|
|
18381
|
+
const dependencies = nativeManagerDependencies(
|
|
18382
|
+
factory.name,
|
|
18383
|
+
functions.map((entry) => entry.value?.description ?? "")
|
|
18384
|
+
);
|
|
18385
|
+
if (!dependencies) return false;
|
|
18386
|
+
for (const [role, entries] of roles) {
|
|
18387
|
+
const id = entries[0]?.value?.objectId;
|
|
18388
|
+
if (!id) return false;
|
|
18389
|
+
await attach(role, id);
|
|
18390
|
+
}
|
|
18391
|
+
for (const [role, name] of Object.entries(dependencies)) {
|
|
18392
|
+
const value = bindings.find((entry) => entry.name === name)?.value?.objectId;
|
|
18393
|
+
if (!value) return false;
|
|
18394
|
+
await attach(role, value);
|
|
18395
|
+
}
|
|
18396
|
+
const shared = await evaluate(`import(${JSON.stringify(sharedUrl)})`);
|
|
18397
|
+
if (!shared.result.objectId) return false;
|
|
18398
|
+
const sharedExports = (await properties(shared.result.objectId)).result;
|
|
18399
|
+
const sessions = sharedExports.filter(
|
|
18400
|
+
(entry) => entry.value?.type === "function" && ["getRemoteMain", "getStats", "drain", "getMainImport"].every(
|
|
18401
|
+
(word) => entry.value?.description?.includes(word)
|
|
18402
|
+
)
|
|
18403
|
+
);
|
|
18404
|
+
const sessionId = sessions[0]?.value?.objectId;
|
|
18405
|
+
if (sessions.length !== 1 || !sessionId) return false;
|
|
18406
|
+
await attach("RpcSession", sessionId);
|
|
18407
|
+
const serviceMatches = await command("Runtime.callFunctionOn", {
|
|
18408
|
+
objectId: shared.result.objectId,
|
|
18409
|
+
functionDeclaration: `function(){return [...new Set(Object.values(this).filter(value => (${nativeRpcObjectShape.toString()})(value).services))]}`,
|
|
18410
|
+
objectGroup: group
|
|
18411
|
+
});
|
|
18412
|
+
if (!serviceMatches.result.objectId) return false;
|
|
18413
|
+
const services = (await properties(serviceMatches.result.objectId)).result.flatMap(
|
|
18414
|
+
(entry) => entry.value?.type === "object" && entry.value.objectId ? [entry.value.objectId] : []
|
|
18415
|
+
);
|
|
18416
|
+
const serviceId = services[0];
|
|
18417
|
+
if (services.length !== 1 || !serviceId) return false;
|
|
18418
|
+
await attach("services", serviceId);
|
|
18419
|
+
const prototype = await evaluate("Object.getPrototypeOf(async function(){})");
|
|
18420
|
+
if (!prototype.result.objectId) return false;
|
|
18421
|
+
const objects = await command("Runtime.queryObjects", {
|
|
18422
|
+
prototypeObjectId: prototype.result.objectId,
|
|
18423
|
+
objectGroup: group
|
|
18424
|
+
});
|
|
18425
|
+
if (!objects.objects.objectId) return false;
|
|
18426
|
+
const filtered = await command("Runtime.callFunctionOn", {
|
|
18427
|
+
objectId: objects.objects.objectId,
|
|
18428
|
+
functionDeclaration: 'function(){return this.filter(fn=>fn.name==="collectAppStateSnapshot"&&String(fn).includes("collectSnapshot")).slice(0,9)}',
|
|
18429
|
+
objectGroup: group
|
|
18430
|
+
});
|
|
18431
|
+
if (!filtered.result.objectId) return false;
|
|
18432
|
+
const snapshots = (await properties(filtered.result.objectId)).result.filter(
|
|
18433
|
+
(entry) => entry.value?.type === "function"
|
|
18434
|
+
);
|
|
18435
|
+
if (snapshots.length > 8) return false;
|
|
18436
|
+
const owners = [];
|
|
18437
|
+
for (const snapshot of snapshots) {
|
|
18438
|
+
const fn = snapshot.value?.objectId;
|
|
18439
|
+
if (!fn) continue;
|
|
18440
|
+
const scopes = (await properties(fn)).internalProperties?.find(
|
|
18441
|
+
(entry) => entry.name === "[[Scopes]]"
|
|
18442
|
+
)?.value?.objectId;
|
|
18443
|
+
if (!scopes) continue;
|
|
18444
|
+
for (const scope of (await properties(scopes)).result) {
|
|
18445
|
+
if (!scope.value?.description?.startsWith("Closure") || !scope.value.objectId) continue;
|
|
18446
|
+
const candidates = (await properties(scope.value.objectId)).result;
|
|
18447
|
+
const controllers = [], handles = [];
|
|
18448
|
+
for (const binding of candidates) {
|
|
18449
|
+
if (binding.value?.type !== "object" || !binding.value.objectId) continue;
|
|
18450
|
+
const id = binding.value.objectId;
|
|
18451
|
+
const response = await call(
|
|
18452
|
+
id,
|
|
18453
|
+
`function(){return (${nativeRpcObjectShape.toString()})(this)}`
|
|
18454
|
+
);
|
|
18455
|
+
const shape = response.result.value;
|
|
18456
|
+
if (shape?.scope) handles.push(id);
|
|
18457
|
+
if (shape?.controller && (await call(id, "function(fn){return this.collectAppStateSnapshot===fn}", [
|
|
18458
|
+
{ objectId: fn }
|
|
18459
|
+
])).result.value === true)
|
|
18460
|
+
controllers.push(id);
|
|
18461
|
+
}
|
|
18462
|
+
const controller = controllers[0], handle = handles[0];
|
|
18463
|
+
if (controllers.length === 1 && handles.length === 1 && controller && handle)
|
|
18464
|
+
owners.push({ controller, scope: handle });
|
|
18465
|
+
}
|
|
18466
|
+
}
|
|
18467
|
+
const owner = owners[0];
|
|
18468
|
+
if (owners.length !== 1 || !owner) return false;
|
|
18469
|
+
await attach("controller", owner.controller);
|
|
18470
|
+
await attach("scope", owner.scope);
|
|
18471
|
+
return await install(holder);
|
|
18472
|
+
} finally {
|
|
18473
|
+
await client.command("Runtime.releaseObjectGroup", { objectGroup: group }).catch(() => void 0);
|
|
18474
|
+
}
|
|
18475
|
+
}
|
|
18476
|
+
|
|
18477
|
+
// packages/desktop-control/src/renderer-native-rpc-runtime.ts
|
|
18478
|
+
function installNativeRpcRemoteControl(components, target, dependencies) {
|
|
18479
|
+
if (target.__codexhostNativeRpcRemoteControlV1) return true;
|
|
18480
|
+
const routing = target.__codexhostHostRoutingV1;
|
|
18481
|
+
if (!routing) return false;
|
|
18482
|
+
const adapted = dependencies.createService(
|
|
18483
|
+
components,
|
|
18484
|
+
(hostId2, upstream) => dependencies.createManager(
|
|
18485
|
+
components,
|
|
18486
|
+
hostId2,
|
|
18487
|
+
upstream,
|
|
18488
|
+
target,
|
|
18489
|
+
dependencies.createPolicy,
|
|
18490
|
+
dependencies.createChannel,
|
|
18491
|
+
dependencies.retainInteractions
|
|
18492
|
+
)
|
|
18493
|
+
);
|
|
18494
|
+
const controller = components.controller;
|
|
18495
|
+
const originalHost = routing.forHost, originalComposer = routing.forComposer, originalDispose = routing.dispose;
|
|
18496
|
+
controller.dispose();
|
|
18497
|
+
let replacement;
|
|
18498
|
+
try {
|
|
18499
|
+
replacement = components.createController(components.scope, adapted.service);
|
|
18500
|
+
} catch (error51) {
|
|
18501
|
+
replacement = components.createController(
|
|
18502
|
+
components.scope,
|
|
18503
|
+
components.services.appServerManagers
|
|
18504
|
+
);
|
|
18505
|
+
throw error51;
|
|
18506
|
+
} finally {
|
|
18507
|
+
adapted.service[Symbol.dispose]();
|
|
18508
|
+
controller.forHost = (hostId2) => replacement.forHost(hostId2);
|
|
18509
|
+
controller.collectAppStateSnapshot = (hostId2, options) => replacement.collectAppStateSnapshot(hostId2, options);
|
|
18510
|
+
controller.getReviewPaneSnapshotMetrics = (hostId2) => replacement.getReviewPaneSnapshotMetrics(hostId2);
|
|
18511
|
+
controller.dispose = () => replacement.dispose();
|
|
18512
|
+
}
|
|
18513
|
+
const forHost = (hostId2) => {
|
|
18514
|
+
const route = adapted.route(hostId2);
|
|
18515
|
+
return route === void 0 ? originalHost.call(routing, hostId2) : route;
|
|
18516
|
+
};
|
|
18517
|
+
const forComposer = (composer) => {
|
|
18518
|
+
const hostId2 = routing.hostIdForComposer(composer);
|
|
18519
|
+
return hostId2 ? forHost(hostId2) : originalComposer.call(routing, composer);
|
|
18520
|
+
};
|
|
18521
|
+
routing.forHost = forHost;
|
|
18522
|
+
routing.forComposer = forComposer;
|
|
18523
|
+
const installation = {
|
|
18524
|
+
dispose() {
|
|
18525
|
+
if (target.__codexhostNativeRpcRemoteControlV1 !== installation) return;
|
|
18526
|
+
delete target.__codexhostNativeRpcRemoteControlV1;
|
|
18527
|
+
replacement.dispose();
|
|
18528
|
+
replacement = components.createController(
|
|
18529
|
+
components.scope,
|
|
18530
|
+
components.services.appServerManagers
|
|
18531
|
+
);
|
|
18532
|
+
if (routing.forHost === forHost) routing.forHost = originalHost;
|
|
18533
|
+
if (routing.forComposer === forComposer) routing.forComposer = originalComposer;
|
|
18534
|
+
routing.dispose = originalDispose;
|
|
18535
|
+
}
|
|
18536
|
+
};
|
|
18537
|
+
routing.dispose = () => {
|
|
18538
|
+
installation.dispose();
|
|
18539
|
+
originalDispose.call(routing);
|
|
18540
|
+
};
|
|
18541
|
+
target.__codexhostNativeRpcRemoteControlV1 = installation;
|
|
18542
|
+
return true;
|
|
18543
|
+
}
|
|
18544
|
+
|
|
18545
|
+
// packages/desktop-control/src/renderer-native-remote-manager.ts
|
|
18546
|
+
function createNativeRemoteManager(components, hostId2, original, target, createPolicy, createChannel, retainInteractions) {
|
|
18547
|
+
const source = components.scope.get(components.requestDefinition, hostId2);
|
|
18548
|
+
const upstream = original.dup();
|
|
18549
|
+
let manager;
|
|
18550
|
+
let policy;
|
|
18551
|
+
let interactions;
|
|
18552
|
+
let disposed = false;
|
|
18553
|
+
const pending = /* @__PURE__ */ new Set();
|
|
18554
|
+
const send = (method, params, options) => {
|
|
18555
|
+
const request = upstream.sendRequest(method, params, options);
|
|
18556
|
+
const result = Promise.resolve(request).finally(() => {
|
|
18557
|
+
request[Symbol.dispose]();
|
|
18558
|
+
pending.delete(result);
|
|
18559
|
+
});
|
|
18560
|
+
pending.add(result);
|
|
18561
|
+
return result;
|
|
18562
|
+
};
|
|
18563
|
+
const record3 = (value) => value !== null && typeof value === "object";
|
|
18564
|
+
const dispatch = (type, payload) => {
|
|
18565
|
+
if ((type === "mcp-request" || type === "thread-prewarm-start") && record3(payload) && record3(payload.request)) {
|
|
18566
|
+
const request = payload.request;
|
|
18567
|
+
const options = {};
|
|
18568
|
+
for (const key of ["priority", "timeoutMs", "source", "trace", "threadAccess"])
|
|
18569
|
+
if (payload[key] !== void 0) options[key] = payload[key];
|
|
18570
|
+
void send(String(request.method), request.params, options).then(
|
|
18571
|
+
(result) => {
|
|
18572
|
+
if (!disposed) client.onResult(request.id, result);
|
|
18573
|
+
},
|
|
18574
|
+
(error51) => {
|
|
18575
|
+
if (!disposed)
|
|
18576
|
+
client.onError(request.id, {
|
|
18577
|
+
code: record3(error51) ? error51.jsonRpcCode ?? error51.code ?? -32603 : -32603,
|
|
18578
|
+
message: error51 instanceof Error ? error51.message : String(error51)
|
|
18579
|
+
});
|
|
18580
|
+
}
|
|
18581
|
+
);
|
|
18582
|
+
return;
|
|
18583
|
+
}
|
|
18584
|
+
return source.dispatchMessage(type, payload);
|
|
18585
|
+
};
|
|
18586
|
+
const Constructor = source.constructor;
|
|
18587
|
+
let client;
|
|
18588
|
+
try {
|
|
18589
|
+
client = new Constructor(
|
|
18590
|
+
hostId2,
|
|
18591
|
+
dispatch,
|
|
18592
|
+
false,
|
|
18593
|
+
(id) => manager?.getConversation(id)?.threadAccess
|
|
18594
|
+
);
|
|
18595
|
+
client.setAppServerVersion(source.getAppServerVersion());
|
|
18596
|
+
manager = components.createManager(
|
|
18597
|
+
components.scope,
|
|
18598
|
+
hostId2,
|
|
18599
|
+
client,
|
|
18600
|
+
components.isHostForConversation.bind(null, components.scope),
|
|
18601
|
+
(get, id) => get(components.imageDefinition, id),
|
|
18602
|
+
{ dispatchMessageFromView: dispatch }
|
|
18603
|
+
);
|
|
18604
|
+
manager.dispatchAppServerResponse = manager.sendAppServerResponse;
|
|
18605
|
+
const owned = manager;
|
|
18606
|
+
const ownedPolicy = createPolicy(
|
|
18607
|
+
owned,
|
|
18608
|
+
client,
|
|
18609
|
+
hostId2,
|
|
18610
|
+
target,
|
|
18611
|
+
owned.prewarmedThreadManager,
|
|
18612
|
+
() => !disposed,
|
|
18613
|
+
void 0,
|
|
18614
|
+
void 0,
|
|
18615
|
+
(method, params) => send(method, params, { priority: "critical" })
|
|
18616
|
+
);
|
|
18617
|
+
policy = ownedPolicy;
|
|
18618
|
+
owned.sendAppServerResponse = (...args) => owned.dispatchAppServerResponse(...args);
|
|
18619
|
+
const channel = createChannel(components, owned);
|
|
18620
|
+
const nativeInteractions = retainInteractions(upstream, owned, hostId2);
|
|
18621
|
+
interactions = nativeInteractions;
|
|
18622
|
+
const notify = (event) => {
|
|
18623
|
+
const { data, source: source2, origin } = event;
|
|
18624
|
+
if (disposed || source2 != null && source2 !== target || !record3(data) || data.hostId !== hostId2)
|
|
18625
|
+
return;
|
|
18626
|
+
const ownOrigin = record3(target.location) ? target.location.origin : void 0;
|
|
18627
|
+
if (source2 === target && ownOrigin && ownOrigin !== "null" && origin !== ownOrigin) return;
|
|
18628
|
+
if (data.type === "mcp-notification" && typeof data.method === "string" && !data.method.startsWith("process/"))
|
|
18629
|
+
owned.onNotification(data.method, data.params);
|
|
18630
|
+
if (data.type === "mcp-request") owned.onRequest(record3(data.request) ? data.request : data);
|
|
18631
|
+
};
|
|
18632
|
+
target.addEventListener?.("message", notify);
|
|
18633
|
+
return {
|
|
18634
|
+
route: { hostId: hostId2, manager: owned, policy: ownedPolicy },
|
|
18635
|
+
rpc: channel.rpc,
|
|
18636
|
+
ready: nativeInteractions.ready,
|
|
18637
|
+
dispose() {
|
|
18638
|
+
if (disposed) return;
|
|
18639
|
+
disposed = true;
|
|
18640
|
+
target.removeEventListener?.("message", notify);
|
|
18641
|
+
nativeInteractions.dispose();
|
|
18642
|
+
ownedPolicy.dispose();
|
|
18643
|
+
client.queuedRequests.length = 0;
|
|
18644
|
+
for (const id of [...client.requestPromises.keys()])
|
|
18645
|
+
client.onError(id, new Error("Remote Control connection retired"));
|
|
18646
|
+
channel.dispose();
|
|
18647
|
+
components.Manager.dispose(owned);
|
|
18648
|
+
void Promise.allSettled([...pending]).then(() => upstream[Symbol.dispose]());
|
|
18649
|
+
}
|
|
18650
|
+
};
|
|
18651
|
+
} catch (error51) {
|
|
18652
|
+
interactions?.dispose();
|
|
18653
|
+
policy?.dispose();
|
|
18654
|
+
if (manager) components.Manager.dispose(manager);
|
|
18655
|
+
upstream[Symbol.dispose]();
|
|
18656
|
+
throw error51;
|
|
18657
|
+
}
|
|
18658
|
+
}
|
|
18659
|
+
|
|
18660
|
+
// packages/desktop-control/src/renderer-native-rpc-channel.ts
|
|
18661
|
+
function createNativeRpcChannel(components, manager) {
|
|
18662
|
+
const channel = new MessageChannel();
|
|
18663
|
+
const transports = [];
|
|
18664
|
+
const transport = (port) => {
|
|
18665
|
+
const values = [];
|
|
18666
|
+
const readers = [];
|
|
18667
|
+
let closed = false;
|
|
18668
|
+
let failure;
|
|
18669
|
+
port.addEventListener("message", (event) => {
|
|
18670
|
+
const value = JSON.stringify(event.data);
|
|
18671
|
+
const reader = readers.shift();
|
|
18672
|
+
if (reader) reader.resolve(value);
|
|
18673
|
+
else values.push(value);
|
|
18674
|
+
});
|
|
18675
|
+
port.start();
|
|
18676
|
+
const result = {
|
|
18677
|
+
send(message) {
|
|
18678
|
+
if (closed) throw failure;
|
|
18679
|
+
port.postMessage(JSON.parse(message));
|
|
18680
|
+
},
|
|
18681
|
+
receive() {
|
|
18682
|
+
if (closed) return Promise.reject(failure);
|
|
18683
|
+
const value = values.shift();
|
|
18684
|
+
return value !== void 0 ? Promise.resolve(value) : new Promise((resolve, reject) => readers.push({ resolve, reject }));
|
|
18685
|
+
},
|
|
18686
|
+
abort(error51) {
|
|
18687
|
+
if (closed) return;
|
|
18688
|
+
closed = true;
|
|
18689
|
+
failure = error51 ?? new Error("Remote Control RPC manager retired");
|
|
18690
|
+
values.length = 0;
|
|
18691
|
+
for (const reader of readers.splice(0)) reader.reject(failure);
|
|
18692
|
+
port.close();
|
|
18693
|
+
}
|
|
18694
|
+
};
|
|
18695
|
+
transports.push(result);
|
|
18696
|
+
return result;
|
|
18697
|
+
};
|
|
18698
|
+
try {
|
|
18699
|
+
new components.RpcSession(transport(channel.port1), new components.RpcManager(() => manager));
|
|
18700
|
+
const session = new components.RpcSession(transport(channel.port2));
|
|
18701
|
+
const rpc = session.getRemoteMain();
|
|
18702
|
+
return {
|
|
18703
|
+
rpc,
|
|
18704
|
+
dispose() {
|
|
18705
|
+
rpc[Symbol.dispose]();
|
|
18706
|
+
for (const transport2 of transports) transport2.abort();
|
|
18707
|
+
}
|
|
18708
|
+
};
|
|
18709
|
+
} catch (error51) {
|
|
18710
|
+
for (const transport2 of transports) transport2.abort(error51);
|
|
18711
|
+
channel.port1.close();
|
|
18712
|
+
channel.port2.close();
|
|
18713
|
+
throw error51;
|
|
18714
|
+
}
|
|
18715
|
+
}
|
|
18716
|
+
|
|
18717
|
+
// packages/desktop-control/src/renderer-native-rpc-service.ts
|
|
18718
|
+
function createNativeRpcService(components, createRemote) {
|
|
18719
|
+
const source = components.services.appServerManagers.dup();
|
|
18720
|
+
const routes = /* @__PURE__ */ new Map();
|
|
18721
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
18722
|
+
let refs = 1;
|
|
18723
|
+
const record3 = (value) => value !== null && typeof value === "object";
|
|
18724
|
+
const connectionSignals = (hostId2) => {
|
|
18725
|
+
let node = components.scope.node;
|
|
18726
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18727
|
+
while (node.parent && !seen.has(node.parent) && seen.size < 100) {
|
|
18728
|
+
seen.add(node);
|
|
18729
|
+
node = node.parent;
|
|
18730
|
+
}
|
|
18731
|
+
const found = [];
|
|
18732
|
+
for (const members of node.familyBindings.values()) {
|
|
18733
|
+
const value = members.get(hostId2)?.value;
|
|
18734
|
+
if (record3(value) && Object.hasOwn(value, "state$") && Object.hasOwn(value, "revision$") && Object.hasOwn(value, "appServerVersion$"))
|
|
18735
|
+
found.push({ state$: value.state$, revision$: value.revision$ });
|
|
18736
|
+
}
|
|
18737
|
+
return found.length === 1 ? found[0] : void 0;
|
|
18738
|
+
};
|
|
18739
|
+
const service = {
|
|
18740
|
+
dup() {
|
|
18741
|
+
refs++;
|
|
18742
|
+
return service;
|
|
18743
|
+
},
|
|
18744
|
+
onRpcBroken(listener) {
|
|
18745
|
+
source.onRpcBroken(listener);
|
|
18746
|
+
},
|
|
18747
|
+
openAccount(hostId2) {
|
|
18748
|
+
return source.openAccount(hostId2);
|
|
18749
|
+
},
|
|
18750
|
+
subscribe(hostId2, listener) {
|
|
18751
|
+
if (!hostId2.startsWith("remote-control:")) return source.subscribe(hostId2, listener);
|
|
18752
|
+
let active = true;
|
|
18753
|
+
let generation = 0;
|
|
18754
|
+
let upstream;
|
|
18755
|
+
let platformRequest;
|
|
18756
|
+
let remote;
|
|
18757
|
+
let stopWatch;
|
|
18758
|
+
let previousRevision;
|
|
18759
|
+
let previousState;
|
|
18760
|
+
const retire = () => {
|
|
18761
|
+
generation++;
|
|
18762
|
+
platformRequest?.[Symbol.dispose]();
|
|
18763
|
+
platformRequest = void 0;
|
|
18764
|
+
remote?.dispose();
|
|
18765
|
+
remote = void 0;
|
|
18766
|
+
routes.set(hostId2, null);
|
|
18767
|
+
};
|
|
18768
|
+
const cleanup = () => {
|
|
18769
|
+
if (!active) return;
|
|
18770
|
+
active = false;
|
|
18771
|
+
stopWatch?.();
|
|
18772
|
+
retire();
|
|
18773
|
+
upstream?.[Symbol.dispose]();
|
|
18774
|
+
upstream = void 0;
|
|
18775
|
+
routes.delete(hostId2);
|
|
18776
|
+
subscriptions.delete(cleanup);
|
|
18777
|
+
};
|
|
18778
|
+
subscriptions.add(cleanup);
|
|
18779
|
+
const publish = async () => {
|
|
18780
|
+
const owner = upstream;
|
|
18781
|
+
const current = generation;
|
|
18782
|
+
if (!owner || !active) return;
|
|
18783
|
+
let request;
|
|
18784
|
+
try {
|
|
18785
|
+
request = owner.getCodexHome();
|
|
18786
|
+
platformRequest = request;
|
|
18787
|
+
const home = await request;
|
|
18788
|
+
if (!active || current !== generation || owner !== upstream) return;
|
|
18789
|
+
if (!/^(?:[A-Za-z]:[\\/]|\\\\)/u.test(home)) {
|
|
18790
|
+
routes.delete(hostId2);
|
|
18791
|
+
listener({ status: "ready", manager: owner });
|
|
18792
|
+
return;
|
|
18793
|
+
}
|
|
18794
|
+
const created = createRemote(hostId2, owner);
|
|
18795
|
+
remote = created;
|
|
18796
|
+
await created.ready;
|
|
18797
|
+
if (!active || current !== generation || owner !== upstream) return;
|
|
18798
|
+
routes.set(hostId2, created.route);
|
|
18799
|
+
listener({ status: "ready", manager: created.rpc });
|
|
18800
|
+
} catch {
|
|
18801
|
+
if (active && current === generation) {
|
|
18802
|
+
remote?.dispose();
|
|
18803
|
+
remote = void 0;
|
|
18804
|
+
routes.delete(hostId2);
|
|
18805
|
+
listener({ status: "ready", manager: owner });
|
|
18806
|
+
}
|
|
18807
|
+
} finally {
|
|
18808
|
+
if (platformRequest === request) {
|
|
18809
|
+
platformRequest = void 0;
|
|
18810
|
+
request?.[Symbol.dispose]();
|
|
18811
|
+
}
|
|
18812
|
+
}
|
|
18813
|
+
};
|
|
18814
|
+
const changed = (state) => {
|
|
18815
|
+
if (!active) return;
|
|
18816
|
+
stopWatch?.();
|
|
18817
|
+
stopWatch = void 0;
|
|
18818
|
+
retire();
|
|
18819
|
+
upstream?.[Symbol.dispose]();
|
|
18820
|
+
upstream = void 0;
|
|
18821
|
+
if (state.status !== "ready") {
|
|
18822
|
+
listener(state);
|
|
18823
|
+
return;
|
|
18824
|
+
}
|
|
18825
|
+
upstream = state.manager.dup();
|
|
18826
|
+
listener({ status: "connecting" });
|
|
18827
|
+
const signals = connectionSignals(hostId2);
|
|
18828
|
+
if (!signals) {
|
|
18829
|
+
void publish();
|
|
18830
|
+
return;
|
|
18831
|
+
}
|
|
18832
|
+
previousState = void 0;
|
|
18833
|
+
previousRevision = void 0;
|
|
18834
|
+
stopWatch = components.scope.watch(({ get }) => {
|
|
18835
|
+
const connection = get(signals.state$), revision = get(signals.revision$);
|
|
18836
|
+
if (connection === previousState && revision === previousRevision) return;
|
|
18837
|
+
previousState = connection;
|
|
18838
|
+
previousRevision = revision;
|
|
18839
|
+
retire();
|
|
18840
|
+
listener({ status: connection === "connected" ? "connecting" : "disconnected" });
|
|
18841
|
+
if (connection === "connected") void publish();
|
|
18842
|
+
});
|
|
18843
|
+
};
|
|
18844
|
+
const original = source.subscribe(hostId2, changed);
|
|
18845
|
+
const result = original.then((lease) => {
|
|
18846
|
+
if (!active) lease[Symbol.dispose]();
|
|
18847
|
+
return {
|
|
18848
|
+
onRpcBroken: (listener2) => lease.onRpcBroken(listener2),
|
|
18849
|
+
[Symbol.dispose]() {
|
|
18850
|
+
cleanup();
|
|
18851
|
+
lease[Symbol.dispose]();
|
|
18852
|
+
}
|
|
18853
|
+
};
|
|
18854
|
+
});
|
|
18855
|
+
Object.assign(result, {
|
|
18856
|
+
onRpcBroken: (listener2) => original.onRpcBroken(listener2),
|
|
18857
|
+
[Symbol.dispose]() {
|
|
18858
|
+
cleanup();
|
|
18859
|
+
original[Symbol.dispose]();
|
|
18860
|
+
}
|
|
18861
|
+
});
|
|
18862
|
+
return result;
|
|
18863
|
+
},
|
|
18864
|
+
[Symbol.dispose]() {
|
|
18865
|
+
if (--refs !== 0) return;
|
|
18866
|
+
for (const cleanup of [...subscriptions]) cleanup();
|
|
18867
|
+
source[Symbol.dispose]();
|
|
18868
|
+
}
|
|
18869
|
+
};
|
|
18870
|
+
return { service, route: (hostId2) => routes.get(hostId2) };
|
|
18871
|
+
}
|
|
18872
|
+
|
|
18873
|
+
// packages/desktop-control/src/renderer-native-rpc-interactions.ts
|
|
18874
|
+
function retainNativeRpcInteractions(upstream, manager, hostId2) {
|
|
18875
|
+
let disposed = false;
|
|
18876
|
+
const retained = /* @__PURE__ */ new Set();
|
|
18877
|
+
const requests = /* @__PURE__ */ new Map();
|
|
18878
|
+
const reads = /* @__PURE__ */ new Map();
|
|
18879
|
+
const record3 = (value) => value !== null && typeof value === "object";
|
|
18880
|
+
const read = (threadId) => {
|
|
18881
|
+
const existing = reads.get(threadId);
|
|
18882
|
+
if (existing) {
|
|
18883
|
+
existing.dirty = true;
|
|
18884
|
+
return existing.promise;
|
|
18885
|
+
}
|
|
18886
|
+
const entry = { promise: Promise.resolve(), dirty: false };
|
|
18887
|
+
reads.set(threadId, entry);
|
|
18888
|
+
entry.promise = Promise.resolve().then(async () => {
|
|
18889
|
+
do {
|
|
18890
|
+
if (disposed) break;
|
|
18891
|
+
entry.dirty = false;
|
|
18892
|
+
const pending = upstream.getConversation(threadId);
|
|
18893
|
+
retained.add(pending);
|
|
18894
|
+
try {
|
|
18895
|
+
const conversation = await pending;
|
|
18896
|
+
if (disposed || entry.dirty || !record3(conversation) || !Array.isArray(conversation.requests))
|
|
18897
|
+
continue;
|
|
18898
|
+
const previous = requests.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
18899
|
+
const next = /* @__PURE__ */ new Set();
|
|
18900
|
+
for (const request of conversation.requests) {
|
|
18901
|
+
if (!record3(request) || typeof request.method !== "string" || !record3(request.params) || (request.params.threadId ?? request.params.conversationId) !== threadId || typeof request.id !== "string" && typeof request.id !== "number")
|
|
18902
|
+
continue;
|
|
18903
|
+
next.add(request.id);
|
|
18904
|
+
if (!previous.has(request.id)) manager.onRequest(request);
|
|
18905
|
+
}
|
|
18906
|
+
if (next.size) requests.set(threadId, next);
|
|
18907
|
+
else requests.delete(threadId);
|
|
18908
|
+
} finally {
|
|
18909
|
+
if (retained.delete(pending)) pending[Symbol.dispose]();
|
|
18910
|
+
}
|
|
18911
|
+
} while (!disposed && entry.dirty);
|
|
18912
|
+
}).finally(() => {
|
|
18913
|
+
reads.delete(threadId);
|
|
18914
|
+
});
|
|
18915
|
+
return entry.promise;
|
|
18916
|
+
};
|
|
18917
|
+
const event = (value) => {
|
|
18918
|
+
if (disposed || !record3(value) || typeof value.conversationId !== "string") return;
|
|
18919
|
+
void read(value.conversationId).catch(() => void 0);
|
|
18920
|
+
};
|
|
18921
|
+
const subscribe = (input) => {
|
|
18922
|
+
const pending = upstream.subscribe(input);
|
|
18923
|
+
retained.add(pending);
|
|
18924
|
+
return Promise.resolve(pending).then((lease) => {
|
|
18925
|
+
if (disposed) lease[Symbol.dispose]();
|
|
18926
|
+
else retained.add(lease);
|
|
18927
|
+
});
|
|
18928
|
+
};
|
|
18929
|
+
const subscriptions = [
|
|
18930
|
+
"approval-request",
|
|
18931
|
+
"user-input-request",
|
|
18932
|
+
"mcp-elicitation-request",
|
|
18933
|
+
"approval-resolved"
|
|
18934
|
+
].map((name) => subscribe({ type: "event", key: { hostId: hostId2 }, event: name, listener: event }));
|
|
18935
|
+
subscriptions.push(
|
|
18936
|
+
subscribe({
|
|
18937
|
+
type: "notification",
|
|
18938
|
+
key: { hostId: hostId2 },
|
|
18939
|
+
methods: ["serverRequest/resolved"],
|
|
18940
|
+
listener(value) {
|
|
18941
|
+
if (record3(value) && record3(value.params) && typeof value.params.threadId === "string")
|
|
18942
|
+
event({ conversationId: value.params.threadId });
|
|
18943
|
+
}
|
|
18944
|
+
})
|
|
18945
|
+
);
|
|
18946
|
+
const ready = Promise.all(subscriptions).then(async () => {
|
|
18947
|
+
if (disposed) return;
|
|
18948
|
+
const pending = upstream.getWorkInProgress();
|
|
18949
|
+
retained.add(pending);
|
|
18950
|
+
try {
|
|
18951
|
+
const work = await pending;
|
|
18952
|
+
if (disposed) return;
|
|
18953
|
+
if (!Array.isArray(work)) throw new Error("Native RPC interaction snapshot is unavailable");
|
|
18954
|
+
const threadIds = new Set(
|
|
18955
|
+
work.flatMap(
|
|
18956
|
+
(item) => record3(item) && typeof item.conversationId === "string" ? [item.conversationId] : []
|
|
18957
|
+
)
|
|
18958
|
+
);
|
|
18959
|
+
await Promise.all([...threadIds].map(read));
|
|
18960
|
+
} finally {
|
|
18961
|
+
if (retained.delete(pending)) pending[Symbol.dispose]();
|
|
18962
|
+
}
|
|
18963
|
+
});
|
|
18964
|
+
return {
|
|
18965
|
+
ready,
|
|
18966
|
+
dispose() {
|
|
18967
|
+
if (disposed) return;
|
|
18968
|
+
disposed = true;
|
|
18969
|
+
for (const lease of retained) lease[Symbol.dispose]();
|
|
18970
|
+
retained.clear();
|
|
18971
|
+
requests.clear();
|
|
18972
|
+
}
|
|
18973
|
+
};
|
|
18974
|
+
}
|
|
18975
|
+
|
|
18976
|
+
// packages/desktop-control/src/renderer-native-rpc-install.ts
|
|
18977
|
+
async function installNativeRpcRemoteControlDirect(renderer) {
|
|
18978
|
+
let attempt;
|
|
18979
|
+
const probeId = crypto.randomUUID();
|
|
18980
|
+
try {
|
|
18981
|
+
attempt = await renderer.evaluate(`(() => {
|
|
18982
|
+
if (window.__codexhostNativeRpcRemoteControlV1) return null;
|
|
18983
|
+
const routing = window.__codexhostHostRoutingV1;
|
|
18984
|
+
const owner = routing?.forHost('local')?.manager;
|
|
18985
|
+
if (owner?.kind !== 'main-process-rpc') return null;
|
|
18986
|
+
const catalog = window.__codexhostLoadedModulesV1;
|
|
18987
|
+
if (!catalog?.complete) return null;
|
|
18988
|
+
const key = JSON.stringify([catalog.owner, catalog.urls.filter(url => /renderer-app-server-managers|app-shared/.test(url)).sort()]);
|
|
18989
|
+
const previous = window.__codexhostNativeRpcDiscoveryV1;
|
|
18990
|
+
const sameOwner = previous?.key === key && previous.owner === owner;
|
|
18991
|
+
if (sameOwner && (previous.state !== 'unavailable' || previous.attempts >= 3 || Date.now() < previous.nextRetryAt)) return null;
|
|
18992
|
+
const token = ${JSON.stringify(probeId)};
|
|
18993
|
+
window.__codexhostNativeRpcDiscoveryV1 = {
|
|
18994
|
+
key, owner, token, state: 'discovering', attempts: sameOwner ? previous.attempts + 1 : 1,
|
|
18995
|
+
};
|
|
18996
|
+
return token;
|
|
18997
|
+
})()`);
|
|
18998
|
+
} catch {
|
|
18999
|
+
return false;
|
|
19000
|
+
}
|
|
19001
|
+
if (attempt === null) return false;
|
|
19002
|
+
let installed = false;
|
|
19003
|
+
try {
|
|
19004
|
+
installed = await withNativeRpcComponents(renderer, async (objectId) => {
|
|
19005
|
+
const result = await renderer.command("Runtime.callFunctionOn", {
|
|
19006
|
+
objectId,
|
|
19007
|
+
functionDeclaration: `function() {
|
|
19008
|
+
if (this.document !== document) return false;
|
|
19009
|
+
const retainRendererHostResponses = ${retainRendererHostResponses.toString()};
|
|
19010
|
+
const isolateRendererPrewarmConsumption = ${isolateRendererPrewarmConsumption.toString()};
|
|
19011
|
+
return (${installNativeRpcRemoteControl.toString()})(this, window, {
|
|
19012
|
+
createPolicy: ${createDraftPrewarmPolicyBridge.toString()},
|
|
19013
|
+
createManager: ${createNativeRemoteManager.toString()},
|
|
19014
|
+
createChannel: ${createNativeRpcChannel.toString()},
|
|
19015
|
+
createService: ${createNativeRpcService.toString()},
|
|
19016
|
+
retainInteractions: ${retainNativeRpcInteractions.toString()},
|
|
19017
|
+
});
|
|
19018
|
+
}`,
|
|
19019
|
+
returnByValue: true
|
|
19020
|
+
});
|
|
19021
|
+
return !result.exceptionDetails && result.result?.value === true;
|
|
19022
|
+
});
|
|
19023
|
+
return installed;
|
|
19024
|
+
} catch {
|
|
19025
|
+
return false;
|
|
19026
|
+
} finally {
|
|
19027
|
+
await renderer.evaluate(
|
|
19028
|
+
`(() => {
|
|
19029
|
+
const status = window.__codexhostNativeRpcDiscoveryV1;
|
|
19030
|
+
if (status?.token === ${JSON.stringify(attempt)}) {
|
|
19031
|
+
status.state = ${JSON.stringify(installed ? "ready" : "unavailable")};
|
|
19032
|
+
status.nextRetryAt = Date.now() + 5000 * 2 ** (status.attempts - 1);
|
|
19033
|
+
}
|
|
19034
|
+
})()`
|
|
19035
|
+
).catch(() => void 0);
|
|
19036
|
+
}
|
|
19037
|
+
}
|
|
19038
|
+
|
|
19039
|
+
// packages/desktop-control/src/renderer-rpc-steering.ts
|
|
19040
|
+
var RETRY_BASE_MS = 5e3;
|
|
19041
|
+
var RETRY_MAX_MS = 3e5;
|
|
19042
|
+
var retries = /* @__PURE__ */ new WeakMap();
|
|
19043
|
+
async function installRendererRpcSteeringDirect(client, now = Date.now) {
|
|
19044
|
+
try {
|
|
19045
|
+
const needed = await client.evaluate(`(() => {
|
|
19046
|
+
const steering = window.__codexhostRpcSteeringV1;
|
|
19047
|
+
if (steering && steering.controller.forHost === steering.forHost) return false;
|
|
19048
|
+
steering?.release();
|
|
19049
|
+
const routing=window.__codexhostHostRoutingV1;
|
|
19050
|
+
return ['local', ...(routing?.knownHostIds?.() ?? [])].some(id => routing?.forHost(id)?.manager.kind === 'main-process-rpc');
|
|
19051
|
+
})()`);
|
|
19052
|
+
if (!needed) return false;
|
|
19053
|
+
const retry = retries.get(client);
|
|
19054
|
+
if (retry && now() < retry.nextAt) return false;
|
|
19055
|
+
try {
|
|
19056
|
+
await discoverAndInstall(client);
|
|
19057
|
+
retries.delete(client);
|
|
19058
|
+
return true;
|
|
19059
|
+
} catch (error51) {
|
|
19060
|
+
const attempts = (retry?.attempts ?? 0) + 1;
|
|
19061
|
+
const delay = Math.min(RETRY_BASE_MS * 2 ** (attempts - 1), RETRY_MAX_MS);
|
|
19062
|
+
retries.set(client, { attempts, nextAt: now() + delay });
|
|
19063
|
+
console.error(
|
|
19064
|
+
`codexhost native steering discovery failed (attempt ${attempts}):`,
|
|
19065
|
+
error51 instanceof Error ? error51.message : String(error51)
|
|
19066
|
+
);
|
|
19067
|
+
return false;
|
|
19068
|
+
}
|
|
19069
|
+
} catch {
|
|
19070
|
+
return false;
|
|
19071
|
+
}
|
|
19072
|
+
}
|
|
19073
|
+
async function discoverAndInstall(client) {
|
|
19074
|
+
const group = `codexhost-rpc-steering-${crypto.randomUUID()}`;
|
|
19075
|
+
const command = (method, params) => client.command(method, params);
|
|
19076
|
+
const properties = (objectId) => command("Runtime.getProperties", { objectId, ownProperties: true });
|
|
19077
|
+
const call = (objectId, functionDeclaration, args = []) => command("Runtime.callFunctionOn", {
|
|
19078
|
+
objectId,
|
|
19079
|
+
functionDeclaration,
|
|
19080
|
+
arguments: args,
|
|
19081
|
+
objectGroup: group,
|
|
19082
|
+
returnByValue: true
|
|
19083
|
+
});
|
|
19084
|
+
try {
|
|
19085
|
+
const proto = await command("Runtime.evaluate", {
|
|
19086
|
+
expression: "Object.getPrototypeOf(async function(){})",
|
|
19087
|
+
objectGroup: group
|
|
19088
|
+
});
|
|
19089
|
+
if (!proto.result.objectId) throw new Error("Native RPC steering discovery is unavailable");
|
|
19090
|
+
const objects = await command("Runtime.queryObjects", {
|
|
19091
|
+
prototypeObjectId: proto.result.objectId,
|
|
19092
|
+
objectGroup: group
|
|
19093
|
+
});
|
|
19094
|
+
if (!objects.objects.objectId) throw new Error("Native RPC steering discovery is unavailable");
|
|
19095
|
+
const filtered = await command("Runtime.callFunctionOn", {
|
|
19096
|
+
objectId: objects.objects.objectId,
|
|
19097
|
+
functionDeclaration: 'function(){return this.filter(fn=>fn.name==="collectAppStateSnapshot"&&String(fn).includes("collectSnapshot")).slice(0,9)}',
|
|
19098
|
+
objectGroup: group
|
|
19099
|
+
});
|
|
19100
|
+
if (!filtered.result.objectId) throw new Error("Native RPC Controller is unavailable");
|
|
19101
|
+
const snapshots = (await properties(filtered.result.objectId)).result.flatMap(
|
|
19102
|
+
(entry) => entry.value?.type === "function" && entry.value.objectId ? [entry.value.objectId] : []
|
|
19103
|
+
);
|
|
19104
|
+
if (snapshots.length > 8) throw new Error("Native RPC Controller is ambiguous");
|
|
19105
|
+
const controllers = [];
|
|
19106
|
+
for (const snapshot of snapshots) {
|
|
19107
|
+
const scopes = (await properties(snapshot)).internalProperties?.find(
|
|
19108
|
+
(entry) => entry.name === "[[Scopes]]"
|
|
19109
|
+
)?.value?.objectId;
|
|
19110
|
+
if (!scopes) continue;
|
|
19111
|
+
for (const scope of (await properties(scopes)).result) {
|
|
19112
|
+
if (!scope.value?.objectId || !scope.value.description?.startsWith("Closure")) continue;
|
|
19113
|
+
const bindings = (await properties(scope.value.objectId)).result;
|
|
19114
|
+
const owners = [];
|
|
19115
|
+
let rootScope;
|
|
19116
|
+
for (const binding of bindings) {
|
|
19117
|
+
if (binding.value?.type !== "object" || !binding.value.objectId) continue;
|
|
19118
|
+
const id = binding.value.objectId;
|
|
19119
|
+
const result2 = await call(
|
|
19120
|
+
id,
|
|
19121
|
+
`function(){return (${nativeRpcObjectShape.toString()})(this)}`
|
|
19122
|
+
);
|
|
19123
|
+
const shape = result2.result.value;
|
|
19124
|
+
if (shape?.scope) rootScope = id;
|
|
19125
|
+
if (shape?.controller && (await call(id, "function(fn){return this.collectAppStateSnapshot===fn}", [
|
|
19126
|
+
{ objectId: snapshot }
|
|
19127
|
+
])).result.value === true)
|
|
19128
|
+
owners.push(id);
|
|
19129
|
+
}
|
|
19130
|
+
if (owners.length !== 1 || !rootScope) continue;
|
|
19131
|
+
const root = await call(
|
|
19132
|
+
rootScope,
|
|
19133
|
+
`function(){let node=this.node;const seen=new Set();while(node?.parent&&!seen.has(node.parent)&&seen.size<100){seen.add(node);node=node.parent}return (${findRendererAppScopeStore.toString()})(document)===node}`
|
|
19134
|
+
);
|
|
19135
|
+
if (root.result.value === true) controllers.push(owners[0]);
|
|
19136
|
+
}
|
|
19137
|
+
}
|
|
19138
|
+
if (controllers.length !== 1) throw new Error("Native RPC Controller is missing or ambiguous");
|
|
19139
|
+
const result = await call(
|
|
19140
|
+
controllers[0],
|
|
19141
|
+
"function(){return window.__codexhostInstallRpcSteeringV1?.(this) === true}"
|
|
19142
|
+
);
|
|
19143
|
+
if (result.exceptionDetails || result.result.value !== true)
|
|
19144
|
+
throw new Error("Native RPC steering installation failed");
|
|
19145
|
+
} finally {
|
|
19146
|
+
await client.command("Runtime.releaseObjectGroup", { objectGroup: group }).catch(() => void 0);
|
|
19147
|
+
}
|
|
19148
|
+
}
|
|
19149
|
+
|
|
18148
19150
|
// packages/desktop-control/src/renderer-cdp-control-session.ts
|
|
18149
19151
|
function isRecord2(value) {
|
|
18150
19152
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -18402,7 +19404,12 @@ var InstalledRendererCdpControlSession = class {
|
|
|
18402
19404
|
var defaultOperations = {
|
|
18403
19405
|
listTargets: (endpoint, signal) => listCdpTargets(endpoint, fetch, signal),
|
|
18404
19406
|
connect: (webSocketDebuggerUrl) => CdpClient.connect(webSocketDebuggerUrl),
|
|
18405
|
-
installDraftPrewarmPolicy
|
|
19407
|
+
async installDraftPrewarmPolicy(renderer) {
|
|
19408
|
+
const status = await installRendererDraftPrewarmPolicyDirect(renderer);
|
|
19409
|
+
await installNativeRpcRemoteControlDirect(renderer);
|
|
19410
|
+
await installRendererRpcSteeringDirect(renderer);
|
|
19411
|
+
return status;
|
|
19412
|
+
}
|
|
18406
19413
|
};
|
|
18407
19414
|
async function createRendererCdpControlSession(options) {
|
|
18408
19415
|
const enabledAgents = options.enabledAgents;
|