@codexhost/cli-linux-arm64 0.9.1 → 0.10.0
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/THIRD_PARTY_NOTICES.txt +0 -4
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +304 -197
- package/app/host-runtime.mjs +1163 -666
- package/app/plugins/antigravity/plugin.mjs +73 -3
- package/app/plugins/claude-code/plugin.mjs +446 -48
- package/app/plugins/codebuddy/plugin.mjs +159 -6
- package/app/plugins/cursor-cli/plugin.mjs +207 -53
- package/app/plugins/deepseek-harness/plugin.mjs +89 -21
- package/app/plugins/enabled.json +2 -1
- package/app/plugins/grok/plugin.mjs +449 -160
- package/app/plugins/hermes/plugin.mjs +217 -63
- package/app/plugins/kimi-code/manifest.json +11 -0
- package/app/plugins/kimi-code/plugin.mjs +24226 -0
- package/app/plugins/kiro-cli/plugin.mjs +312 -65
- package/app/plugins/omp/plugin.mjs +313 -67
- package/app/plugins/opencode/plugin.mjs +73 -3
- package/app/plugins/pi/plugin.mjs +3029 -1671
- package/app/plugins/qoder/plugin.mjs +334 -187
- package/app/plugins/qoder-cn/plugin.mjs +334 -187
- package/app/plugins/workbuddy/plugin.mjs +158 -6
- package/app/renderer-extension.js +5580 -3301
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
- package/licenses/opencodex-LICENSE.txt +0 -21
|
@@ -29,6 +29,7 @@ async function startControllerAttachmentServer(options) {
|
|
|
29
29
|
throw new Error("attachment nonce must be 32 lowercase hexadecimal characters");
|
|
30
30
|
}
|
|
31
31
|
const sockets = /* @__PURE__ */ new Set();
|
|
32
|
+
let attachment;
|
|
32
33
|
const server = createServer((socket) => {
|
|
33
34
|
sockets.add(socket);
|
|
34
35
|
socket.once("close", () => sockets.delete(socket));
|
|
@@ -49,10 +50,19 @@ async function startControllerAttachmentServer(options) {
|
|
|
49
50
|
handled = true;
|
|
50
51
|
const line = request.slice(0, newline).replace(/\r$/, "");
|
|
51
52
|
if (line === `ATTACH ${options.nonce}`) {
|
|
52
|
-
|
|
53
|
+
if (attachment) {
|
|
54
|
+
respond(socket, "busy");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
socket.setTimeout(0);
|
|
58
|
+
const current = Promise.resolve().then(() => options.attach());
|
|
59
|
+
attachment = current;
|
|
60
|
+
void current.then(
|
|
53
61
|
() => respond(socket, "ready"),
|
|
54
62
|
() => respond(socket, "failed")
|
|
55
|
-
)
|
|
63
|
+
).finally(() => {
|
|
64
|
+
if (attachment === current) attachment = void 0;
|
|
65
|
+
});
|
|
56
66
|
return;
|
|
57
67
|
}
|
|
58
68
|
respond(socket, "rejected");
|
|
@@ -81,12 +91,6 @@ async function startControllerAttachmentServer(options) {
|
|
|
81
91
|
function isRecord(value) {
|
|
82
92
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
83
93
|
}
|
|
84
|
-
function nonEmptyString(value, field) {
|
|
85
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
86
|
-
throw new Error(`CDP target '${field}' must be non-empty text`);
|
|
87
|
-
}
|
|
88
|
-
return value;
|
|
89
|
-
}
|
|
90
94
|
function loopbackUrl(value, protocols) {
|
|
91
95
|
const url = new URL(value);
|
|
92
96
|
if (!protocols.includes(url.protocol)) {
|
|
@@ -97,17 +101,24 @@ function loopbackUrl(value, protocols) {
|
|
|
97
101
|
}
|
|
98
102
|
return url;
|
|
99
103
|
}
|
|
104
|
+
function optionalText(value) {
|
|
105
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
106
|
+
}
|
|
100
107
|
function parseTarget(value) {
|
|
101
108
|
if (!isRecord(value)) throw new Error("CDP target must be an object");
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
const id = optionalText(value.id);
|
|
110
|
+
const type = optionalText(value.type);
|
|
111
|
+
const url = optionalText(value.url);
|
|
112
|
+
const webSocketDebuggerUrl = optionalText(value.webSocketDebuggerUrl);
|
|
113
|
+
if (webSocketDebuggerUrl) loopbackUrl(webSocketDebuggerUrl, ["ws:", "wss:"]);
|
|
114
|
+
if (!id || !type || !url || !webSocketDebuggerUrl) return null;
|
|
115
|
+
return {
|
|
116
|
+
id,
|
|
117
|
+
type,
|
|
105
118
|
title: typeof value.title === "string" ? value.title : "",
|
|
106
|
-
url
|
|
107
|
-
webSocketDebuggerUrl
|
|
119
|
+
url,
|
|
120
|
+
webSocketDebuggerUrl
|
|
108
121
|
};
|
|
109
|
-
loopbackUrl(target.webSocketDebuggerUrl, ["ws:", "wss:"]);
|
|
110
|
-
return target;
|
|
111
122
|
}
|
|
112
123
|
function defaultFetch(url) {
|
|
113
124
|
return fetch(url);
|
|
@@ -144,7 +155,7 @@ async function listCdpTargets(endpoint, fetchImpl = defaultFetch) {
|
|
|
144
155
|
if (!response.ok) throw new Error(`CDP target discovery failed with HTTP ${response.status}`);
|
|
145
156
|
const value = await response.json();
|
|
146
157
|
if (!Array.isArray(value)) throw new Error("CDP target discovery did not return an array");
|
|
147
|
-
return value.map(parseTarget);
|
|
158
|
+
return value.map(parseTarget).filter((target) => target !== null);
|
|
148
159
|
}
|
|
149
160
|
var CdpClient = class _CdpClient {
|
|
150
161
|
#commandTimeoutMs;
|
|
@@ -329,7 +340,7 @@ function retainRendererHostResponses(client, hostId, target) {
|
|
|
329
340
|
if (typeof client.addRequestLifecycleListener !== "function" || typeof target.addEventListener !== "function" || typeof target.removeEventListener !== "function")
|
|
330
341
|
return () => {
|
|
331
342
|
};
|
|
332
|
-
const
|
|
343
|
+
const isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
333
344
|
const pending = /* @__PURE__ */ new Set();
|
|
334
345
|
let retired = false;
|
|
335
346
|
let unsubscribe = () => {
|
|
@@ -343,12 +354,12 @@ function retainRendererHostResponses(client, hostId, target) {
|
|
|
343
354
|
if (source != null && source !== target) return;
|
|
344
355
|
const ownOrigin = target.location?.origin;
|
|
345
356
|
if (source === target && ownOrigin && ownOrigin !== "null" && origin !== ownOrigin) return;
|
|
346
|
-
if (!
|
|
357
|
+
if (!isRecord3(data) || data.type !== "mcp-response" || data.hostId !== hostId) return;
|
|
347
358
|
const message = data.message;
|
|
348
|
-
if (!
|
|
359
|
+
if (!isRecord3(message)) return;
|
|
349
360
|
const id = message.id;
|
|
350
361
|
if (typeof id !== "string" && typeof id !== "number" || !pending.has(id)) return;
|
|
351
|
-
const hasError =
|
|
362
|
+
const hasError = isRecord3(message.error);
|
|
352
363
|
if (!hasError && !Object.prototype.hasOwnProperty.call(message, "result")) return;
|
|
353
364
|
queueMicrotask(() => {
|
|
354
365
|
if (!pending.has(id)) return;
|
|
@@ -358,7 +369,7 @@ function retainRendererHostResponses(client, hostId, target) {
|
|
|
358
369
|
};
|
|
359
370
|
target.addEventListener("message", receive);
|
|
360
371
|
unsubscribe = client.addRequestLifecycleListener((event) => {
|
|
361
|
-
if (!
|
|
372
|
+
if (!isRecord3(event) || event.hostId !== hostId) return;
|
|
362
373
|
const id = event.id;
|
|
363
374
|
if (typeof id !== "string" && typeof id !== "number") return;
|
|
364
375
|
if (!retired && event.type === "started" && typeof event.method === "string" && event.method.startsWith("codexhost/"))
|
|
@@ -375,24 +386,21 @@ function retainRendererHostResponses(client, hostId, target) {
|
|
|
375
386
|
}
|
|
376
387
|
|
|
377
388
|
// packages/desktop-control/src/renderer-draft-prewarm-runtime.ts
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
if (existing?.owns?.length === 5 && existing.owns(manager, bridge, hostId, prewarmedThreadManager, !!isCurrentManager) === true) {
|
|
381
|
-
return { state: "ready", reason: "owned-request-bridge" };
|
|
382
|
-
}
|
|
383
|
-
existing?.dispose?.();
|
|
389
|
+
function createDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewarmedThreadManager, isCurrentManager, retainResponses = retainRendererHostResponses) {
|
|
390
|
+
let disposed = false;
|
|
384
391
|
const originalSend = bridge.sendRequest;
|
|
385
392
|
const originalPrewarm = bridge.prewarmThreadStart;
|
|
386
393
|
const originalOnNotification = manager.onNotification;
|
|
387
394
|
const originalDispatchAppServerResponse = manager.dispatchAppServerResponse;
|
|
388
395
|
let selectedModel = null;
|
|
389
|
-
|
|
396
|
+
let prewarmGeneration = 0;
|
|
397
|
+
const isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
390
398
|
const isUnsupportedPosixBridgeSpawn = (value) => {
|
|
391
399
|
const marker = "AbsolutePathBuf deserialized without a base path";
|
|
392
400
|
if (typeof value === "string") {
|
|
393
401
|
return value.startsWith("Invalid request:") && value.includes(marker);
|
|
394
402
|
}
|
|
395
|
-
if (!
|
|
403
|
+
if (!isRecord3(value)) return false;
|
|
396
404
|
if (typeof value.message === "string" && value.message.includes(marker)) {
|
|
397
405
|
if (value.code === -32600 || value.message.startsWith("Invalid request:")) return true;
|
|
398
406
|
}
|
|
@@ -483,14 +491,14 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
483
491
|
bridgeState = "idle";
|
|
484
492
|
};
|
|
485
493
|
const rememberExternalThread = (value) => {
|
|
486
|
-
if (!
|
|
494
|
+
if (!isRecord3(value) || typeof value.id !== "string") return;
|
|
487
495
|
if (value.modelProvider === "codexhost" || value.cliVersion === "codexhost") {
|
|
488
496
|
knownExternalThreadIds.add(value.id);
|
|
489
497
|
knownOfficialThreadIds.delete(value.id);
|
|
490
498
|
}
|
|
491
499
|
};
|
|
492
500
|
const observeBridgeResult = (request, result) => {
|
|
493
|
-
if (!request || !
|
|
501
|
+
if (!request || !isRecord3(result)) return;
|
|
494
502
|
if (request.method === "thread/list" && Array.isArray(result.data)) {
|
|
495
503
|
for (const thread of result.data) rememberExternalThread(thread);
|
|
496
504
|
return;
|
|
@@ -499,7 +507,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
499
507
|
rememberExternalThread(result.thread);
|
|
500
508
|
return;
|
|
501
509
|
}
|
|
502
|
-
if (request.method === "codexhost/thread/inspect" &&
|
|
510
|
+
if (request.method === "codexhost/thread/inspect" && isRecord3(request.parameters) && typeof request.parameters.threadId === "string") {
|
|
503
511
|
if (result.owner === "external") {
|
|
504
512
|
knownExternalThreadIds.add(request.parameters.threadId);
|
|
505
513
|
knownOfficialThreadIds.delete(request.parameters.threadId);
|
|
@@ -509,18 +517,18 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
509
517
|
}
|
|
510
518
|
return;
|
|
511
519
|
}
|
|
512
|
-
if (request.method === "thread/delete" &&
|
|
520
|
+
if (request.method === "thread/delete" && isRecord3(request.parameters) && typeof request.parameters.threadId === "string") {
|
|
513
521
|
knownExternalThreadIds.delete(request.parameters.threadId);
|
|
514
522
|
knownOfficialThreadIds.delete(request.parameters.threadId);
|
|
515
523
|
}
|
|
516
524
|
};
|
|
517
525
|
const handleBridgeFrame = (value) => {
|
|
518
|
-
if (!
|
|
526
|
+
if (!isRecord3(value)) {
|
|
519
527
|
failBridge("received a non-object app-server frame");
|
|
520
528
|
return;
|
|
521
529
|
}
|
|
522
530
|
if (value.method === bridgeReadyMethod && value.id === void 0) {
|
|
523
|
-
if (
|
|
531
|
+
if (isRecord3(value.params) && value.params.protocolVersion === 1) {
|
|
524
532
|
bridgeState = "ready";
|
|
525
533
|
if (bridgeReadyTimeout !== null) globalThis.clearTimeout(bridgeReadyTimeout);
|
|
526
534
|
bridgeReadyTimeout = null;
|
|
@@ -533,7 +541,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
533
541
|
return;
|
|
534
542
|
}
|
|
535
543
|
if (typeof value.method === "string" && value.id === void 0) {
|
|
536
|
-
if (value.method === "thread/started" &&
|
|
544
|
+
if (value.method === "thread/started" && isRecord3(value.params)) {
|
|
537
545
|
rememberExternalThread(value.params.thread);
|
|
538
546
|
}
|
|
539
547
|
originalOnNotification.call(manager, value.method, value.params);
|
|
@@ -584,7 +592,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
584
592
|
}
|
|
585
593
|
};
|
|
586
594
|
const handleOuterNotification = (method, parameters) => {
|
|
587
|
-
if (method === "process/exited" &&
|
|
595
|
+
if (method === "process/exited" && isRecord3(parameters) && parameters.processHandle === bridgeProcessHandle) {
|
|
588
596
|
const exitCode = typeof parameters.exitCode === "number" ? parameters.exitCode : "unknown";
|
|
589
597
|
const stderr = typeof parameters.stderr === "string" ? parameters.stderr.trim() : "";
|
|
590
598
|
failBridge(
|
|
@@ -593,7 +601,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
593
601
|
);
|
|
594
602
|
return true;
|
|
595
603
|
}
|
|
596
|
-
if (method !== "process/outputDelta" || !
|
|
604
|
+
if (method !== "process/outputDelta" || !isRecord3(parameters) || parameters.processHandle !== bridgeProcessHandle || parameters.stream !== "stdout" && parameters.stream !== "stderr" || typeof parameters.deltaBase64 !== "string") {
|
|
597
605
|
return false;
|
|
598
606
|
}
|
|
599
607
|
if (parameters.capReached === true) {
|
|
@@ -698,7 +706,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
698
706
|
return bridgeInitialization;
|
|
699
707
|
};
|
|
700
708
|
const threadIdFromParameters = (parameters) => {
|
|
701
|
-
if (!
|
|
709
|
+
if (!isRecord3(parameters)) return null;
|
|
702
710
|
const value = parameters.threadId ?? parameters.conversationId;
|
|
703
711
|
return typeof value === "string" ? value : null;
|
|
704
712
|
};
|
|
@@ -713,9 +721,9 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
713
721
|
threadIds: [threadId]
|
|
714
722
|
})
|
|
715
723
|
).then((value) => {
|
|
716
|
-
const ownerships =
|
|
724
|
+
const ownerships = isRecord3(value) && Array.isArray(value.threads) ? value.threads : null;
|
|
717
725
|
const ownership = ownerships?.[0];
|
|
718
|
-
if (!ownerships || !
|
|
726
|
+
if (!ownerships || !isRecord3(ownership) || ownerships.length !== 1 || ownership.threadId !== threadId || ownership.owner !== "external" && ownership.owner !== "codex") {
|
|
719
727
|
throw transportError("Thread ownership lookup returned an invalid result");
|
|
720
728
|
}
|
|
721
729
|
if (ownership.owner === "external") {
|
|
@@ -751,7 +759,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
751
759
|
if (method.startsWith("codexhost/")) return true;
|
|
752
760
|
if (method === "thread/list") return true;
|
|
753
761
|
if (method === "thread/start") {
|
|
754
|
-
return
|
|
762
|
+
return isRecord3(parameters) && typeof parameters.model === "string" && parameters.model.startsWith("codexhost/");
|
|
755
763
|
}
|
|
756
764
|
const threadId = threadIdFromParameters(parameters);
|
|
757
765
|
if (threadId && knownExternalThreadIds.has(threadId)) return true;
|
|
@@ -759,7 +767,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
759
767
|
return selectedModel !== null && (method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("review/"));
|
|
760
768
|
};
|
|
761
769
|
const routeThreadStart = (parameters) => {
|
|
762
|
-
if (!
|
|
770
|
+
if (!isRecord3(parameters) || parameters.ephemeral === true) {
|
|
763
771
|
return parameters;
|
|
764
772
|
}
|
|
765
773
|
return {
|
|
@@ -791,18 +799,43 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
791
799
|
}
|
|
792
800
|
return shouldUseBridge(method, routedParameters) ? sendBridged() : sendDirect();
|
|
793
801
|
};
|
|
802
|
+
const publishDraftWorkspace = (parameters) => {
|
|
803
|
+
if (!isRecord3(parameters) || parameters.ephemeral === true) return;
|
|
804
|
+
const cwd = parameters.cwd;
|
|
805
|
+
if (typeof cwd !== "string" || cwd.length === 0) return;
|
|
806
|
+
const drafts = isRecord3(target.__codexhostDraftWorkspacesV1) ? target.__codexhostDraftWorkspacesV1 : {};
|
|
807
|
+
drafts[hostId] = cwd;
|
|
808
|
+
Object.defineProperty(target, "__codexhostDraftWorkspacesV1", {
|
|
809
|
+
configurable: true,
|
|
810
|
+
value: drafts
|
|
811
|
+
});
|
|
812
|
+
if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function") {
|
|
813
|
+
target.dispatchEvent(
|
|
814
|
+
new CustomEvent("codexhost:draft-workspace", { detail: { hostId, cwd } })
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
794
818
|
const routedPrewarm = (parameters, options) => {
|
|
795
819
|
const routedParameters = routeThreadStart(parameters);
|
|
796
|
-
|
|
797
|
-
|
|
820
|
+
const generation = prewarmGeneration;
|
|
821
|
+
publishDraftWorkspace(routedParameters);
|
|
822
|
+
const pending = shouldUseBridge("thread/start", routedParameters) ? routedSend("thread/start", routedParameters, options) : options === void 0 ? originalPrewarm.call(bridge, routedParameters) : originalPrewarm.call(bridge, routedParameters, options);
|
|
823
|
+
if (isRecord3(parameters) && parameters.ephemeral === true || typeof pending !== "object" && typeof pending !== "function" || pending === null || typeof Reflect.get(pending, "then") !== "function") {
|
|
824
|
+
return pending;
|
|
798
825
|
}
|
|
799
|
-
return
|
|
826
|
+
return Promise.resolve(pending).then((result) => {
|
|
827
|
+
if (disposed || generation !== prewarmGeneration) {
|
|
828
|
+
throw new Error("Renderer draft prewarm was invalidated by a configuration change");
|
|
829
|
+
}
|
|
830
|
+
publishDraftWorkspace(routedParameters);
|
|
831
|
+
return result;
|
|
832
|
+
});
|
|
800
833
|
};
|
|
801
834
|
bridge.sendRequest = routedSend;
|
|
802
835
|
bridge.prewarmThreadStart = routedPrewarm;
|
|
803
836
|
const routedWindowMessage = (event) => {
|
|
804
837
|
const message = event.data;
|
|
805
|
-
if (!
|
|
838
|
+
if (!isRecord3(message) || message.type !== "mcp-notification" || message.hostId !== hostId || typeof message.method !== "string") {
|
|
806
839
|
return;
|
|
807
840
|
}
|
|
808
841
|
handleOuterNotification(message.method, message.params);
|
|
@@ -834,26 +867,35 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
834
867
|
state: "ready",
|
|
835
868
|
hostId,
|
|
836
869
|
owns(candidateManager, candidate, candidateHostId, candidatePrewarmedThreadManager, requiresCurrentManager) {
|
|
837
|
-
return candidateManager === manager && candidate === bridge && candidateHostId === hostId && candidatePrewarmedThreadManager === prewarmedThreadManager && requiresCurrentManager === !!isCurrentManager;
|
|
870
|
+
return !disposed && candidateManager === manager && candidate === bridge && candidateHostId === hostId && candidatePrewarmedThreadManager === prewarmedThreadManager && requiresCurrentManager === !!isCurrentManager;
|
|
838
871
|
},
|
|
839
872
|
requestTarget() {
|
|
840
|
-
if (isCurrentManager && !isCurrentManager())
|
|
873
|
+
if (disposed || isCurrentManager && !isCurrentManager())
|
|
841
874
|
throw new Error("Renderer request manager is retired");
|
|
842
875
|
return manager;
|
|
843
876
|
},
|
|
844
877
|
select(model) {
|
|
878
|
+
if (disposed || isCurrentManager && !isCurrentManager())
|
|
879
|
+
throw new Error("Renderer request manager is retired");
|
|
845
880
|
if (model !== null && (typeof model !== "string" || !model.startsWith("codexhost/"))) {
|
|
846
881
|
throw new Error("Draft route Model must be a codexhost transport carrier");
|
|
847
882
|
}
|
|
848
883
|
if (selectedModel === model) return false;
|
|
849
884
|
selectedModel = model;
|
|
885
|
+
prewarmGeneration += 1;
|
|
850
886
|
return true;
|
|
851
887
|
},
|
|
852
888
|
clear() {
|
|
889
|
+
if (disposed || isCurrentManager && !isCurrentManager())
|
|
890
|
+
return Promise.reject(new Error("Renderer request manager is retired"));
|
|
891
|
+
prewarmGeneration += 1;
|
|
853
892
|
prewarmedThreadManager.discardAllPrewarmedThreads();
|
|
854
893
|
return Promise.resolve();
|
|
855
894
|
},
|
|
856
895
|
dispose() {
|
|
896
|
+
if (disposed) return;
|
|
897
|
+
disposed = true;
|
|
898
|
+
prewarmGeneration += 1;
|
|
857
899
|
retireResponses();
|
|
858
900
|
if (bridge.sendRequest === routedSend) bridge.sendRequest = originalSend;
|
|
859
901
|
if (bridge.prewarmThreadStart === routedPrewarm) {
|
|
@@ -886,167 +928,231 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
886
928
|
selectedModel = null;
|
|
887
929
|
}
|
|
888
930
|
});
|
|
889
|
-
|
|
890
|
-
configurable: true,
|
|
891
|
-
value: policy
|
|
892
|
-
});
|
|
893
|
-
if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function") {
|
|
894
|
-
target.dispatchEvent(new CustomEvent("codexhost:draft-prewarm-policy-changed"));
|
|
895
|
-
}
|
|
896
|
-
return { state: "ready", reason: "owned-request-bridge" };
|
|
931
|
+
return policy;
|
|
897
932
|
}
|
|
898
933
|
|
|
899
|
-
// packages/desktop-control/src/renderer-
|
|
900
|
-
function
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const activeHostId = hosts.values().next().value;
|
|
908
|
-
const eligible = [...unique.values()].filter(
|
|
909
|
-
(candidate) => activeHostId === void 0 || candidate.hostId === activeHostId
|
|
910
|
-
);
|
|
911
|
-
return eligible.length === 1 ? eligible[0] ?? null : null;
|
|
912
|
-
}
|
|
913
|
-
function requestManagerFromHookState(value, activeHostId) {
|
|
914
|
-
const matchesRequestManager = (candidate) => {
|
|
915
|
-
if (candidate == null || typeof candidate !== "object" || !("requestClient" in candidate) || !("prewarmedThreadManager" in candidate) || !("sendRequest" in candidate)) {
|
|
916
|
-
return false;
|
|
917
|
-
}
|
|
918
|
-
const requestClient = candidate.requestClient;
|
|
919
|
-
const prewarmedThreadManager = candidate.prewarmedThreadManager;
|
|
920
|
-
return requestClient != null && typeof requestClient === "object" && "prewarmThreadStart" in requestClient && typeof requestClient.prewarmThreadStart === "function" && "sendRequest" in requestClient && typeof requestClient.sendRequest === "function" && "enqueueRequest" in requestClient && typeof requestClient.enqueueRequest === "function" && prewarmedThreadManager != null && typeof prewarmedThreadManager === "object" && "discardAllPrewarmedThreads" in prewarmedThreadManager && typeof prewarmedThreadManager.discardAllPrewarmedThreads === "function" && typeof candidate.sendRequest === "function";
|
|
934
|
+
// packages/desktop-control/src/renderer-host-discovery.ts
|
|
935
|
+
function requestManagerFromHookState(value, hostId) {
|
|
936
|
+
const record = (candidate) => typeof candidate === "object" && candidate !== null;
|
|
937
|
+
const manager = (candidate) => {
|
|
938
|
+
if (!record(candidate) || !record(candidate.requestClient) || !record(candidate.prewarmedThreadManager))
|
|
939
|
+
return null;
|
|
940
|
+
const bridge = candidate.requestClient;
|
|
941
|
+
return typeof candidate.sendRequest === "function" && typeof bridge.sendRequest === "function" && typeof bridge.prewarmThreadStart === "function" && typeof bridge.enqueueRequest === "function" && typeof candidate.prewarmedThreadManager.discardAllPrewarmedThreads === "function" ? candidate : null;
|
|
921
942
|
};
|
|
922
|
-
if (
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
if (typeof activeHostId !== "string" || activeHostId.length === 0) return null;
|
|
927
|
-
if (value == null || typeof value !== "object" || !("addManager" in value) || typeof value.addManager !== "function" || !("getForHostId" in value) || typeof value.getForHostId !== "function" || !("waitForManagerForHostId" in value) || typeof value.waitForManagerForHostId !== "function") {
|
|
943
|
+
if (!record(value)) return null;
|
|
944
|
+
const direct = manager(value) ?? manager(value.manager);
|
|
945
|
+
if (direct) return direct;
|
|
946
|
+
if (!hostId || typeof value.addManager !== "function" || typeof value.getForHostId !== "function" || typeof value.waitForManagerForHostId !== "function")
|
|
928
947
|
return null;
|
|
929
|
-
|
|
930
|
-
const manager = value.getForHostId.call(value, activeHostId);
|
|
931
|
-
return matchesRequestManager(manager) ? manager : null;
|
|
948
|
+
return manager(value.getForHostId(hostId));
|
|
932
949
|
}
|
|
933
|
-
function
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
)];
|
|
942
|
-
if (editors.length === 0) {
|
|
943
|
-
return { candidateCount: 0, editorCount: editors.length, hostId: null, sendRequest: null };
|
|
944
|
-
}
|
|
945
|
-
// Main and side chat can expose multiple editors backed by the same manager.
|
|
946
|
-
// Resolve their combined Host ownership before consulting any Host registry.
|
|
947
|
-
const composerAncestors = new Set();
|
|
948
|
-
const activeHostIds = new Set();
|
|
950
|
+
function discoverRendererHosts(root, ancestors = committedReactAncestors, managerFrom = requestManagerFromHookState) {
|
|
951
|
+
const editors = [
|
|
952
|
+
...root.querySelectorAll('[data-codex-composer], [contenteditable="true"][role="textbox"]')
|
|
953
|
+
];
|
|
954
|
+
const hostIds = /* @__PURE__ */ new Set();
|
|
955
|
+
const managers = /* @__PURE__ */ new Set();
|
|
956
|
+
const registries = /* @__PURE__ */ new Set();
|
|
957
|
+
const fibers = /* @__PURE__ */ new Set();
|
|
949
958
|
for (const editor of editors) {
|
|
950
959
|
let element = editor;
|
|
951
|
-
let fiber
|
|
952
|
-
while (element
|
|
953
|
-
const key = Object.getOwnPropertyNames(element).find(
|
|
954
|
-
name.startsWith(
|
|
960
|
+
let fiber;
|
|
961
|
+
while (element && !fiber) {
|
|
962
|
+
const key = Object.getOwnPropertyNames(element).find(
|
|
963
|
+
(name) => name.startsWith("__reactFiber$")
|
|
955
964
|
);
|
|
956
|
-
if (key
|
|
957
|
-
element = element.parentElement;
|
|
965
|
+
if (key) fiber = Object.getOwnPropertyDescriptor(element, key)?.value;
|
|
966
|
+
element = element.parentElement ?? null;
|
|
958
967
|
}
|
|
959
|
-
for (const current of
|
|
960
|
-
|
|
968
|
+
for (const current of ancestors(fiber)) {
|
|
969
|
+
fibers.add(current);
|
|
961
970
|
const props = current.memoizedProps;
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
if (typeof value === 'string' && value.length > 0) activeHostIds.add(value);
|
|
966
|
-
}
|
|
971
|
+
for (const key of ["executionTargetHostId", "permissionsHostId"]) {
|
|
972
|
+
const hostId = props?.[key];
|
|
973
|
+
if (typeof hostId === "string" && hostId) hostIds.add(hostId);
|
|
967
974
|
}
|
|
968
975
|
}
|
|
969
976
|
}
|
|
970
|
-
const
|
|
971
|
-
activeHostIds.size === 1 ? activeHostIds.values().next().value : undefined;
|
|
972
|
-
const managers = new Set();
|
|
973
|
-
for (const fiber of composerAncestors) {
|
|
977
|
+
for (const fiber of fibers) {
|
|
974
978
|
let hook = fiber.memoizedState;
|
|
975
|
-
for (let index = 0; hook
|
|
976
|
-
const
|
|
977
|
-
|
|
979
|
+
for (let index = 0; hook && index < 120; index += 1) {
|
|
980
|
+
const value = hook.memoizedState;
|
|
981
|
+
const manager = managerFrom(value);
|
|
982
|
+
if (manager) managers.add(manager);
|
|
983
|
+
if (value && typeof value === "object" && "addManager" in value && typeof value.addManager === "function" && "getForHostId" in value && typeof value.getForHostId === "function" && "waitForManagerForHostId" in value && typeof value.waitForManagerForHostId === "function") {
|
|
984
|
+
registries.add(value);
|
|
985
|
+
}
|
|
986
|
+
hook = hook.next && typeof hook.next === "object" ? hook.next : null;
|
|
978
987
|
}
|
|
979
988
|
}
|
|
980
|
-
const candidates = [...managers].map((manager) => {
|
|
981
|
-
const requestClient =
|
|
982
|
-
typeof manager.requestClient?.sendRequest === 'function' &&
|
|
983
|
-
typeof manager.requestClient?.prewarmThreadStart === 'function' &&
|
|
984
|
-
typeof manager.requestClient?.enqueueRequest === 'function'
|
|
985
|
-
? manager.requestClient
|
|
986
|
-
: manager;
|
|
987
|
-
return {
|
|
988
|
-
manager,
|
|
989
|
-
requestClient,
|
|
990
|
-
hostId: manager?.getHostId?.() ?? requestClient?.hostId ?? null,
|
|
991
|
-
prewarmedThreadManager: manager?.prewarmedThreadManager ?? null,
|
|
992
|
-
};
|
|
993
|
-
});
|
|
994
|
-
const selected = (${selectRendererRequestManager.toString()})(candidates, [...activeHostIds]);
|
|
995
989
|
return {
|
|
996
|
-
candidateCount: selected == null ? candidates.length : 1,
|
|
997
990
|
editorCount: editors.length,
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
prewarmedThreadManager: selected?.prewarmedThreadManager ?? null,
|
|
991
|
+
hostIds: [...hostIds],
|
|
992
|
+
managers: [...managers],
|
|
993
|
+
registries: [...registries]
|
|
1002
994
|
};
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
var INSTALL_RENDERER_POLICY_FUNCTION = `function(requestClient, hostId, prewarmedThreadManager) {
|
|
1012
|
-
return (${installDraftPrewarmPolicyBridge.toString()})(
|
|
1013
|
-
this,
|
|
1014
|
-
requestClient,
|
|
1015
|
-
hostId,
|
|
1016
|
-
window,
|
|
1017
|
-
prewarmedThreadManager,
|
|
1018
|
-
() => (${IS_CURRENT_REQUEST_MANAGER})(this, requestClient, hostId, prewarmedThreadManager),
|
|
1019
|
-
(${retainRendererHostResponses.toString()}),
|
|
995
|
+
}
|
|
996
|
+
function resolveRendererHostManager(discovery, hostId, managerFrom = requestManagerFromHookState) {
|
|
997
|
+
if (!hostId) return null;
|
|
998
|
+
const candidates = discovery.registries.length ? discovery.registries.map((registry) => managerFrom(registry.getForHostId(hostId))) : discovery.managers;
|
|
999
|
+
const matching = new Set(
|
|
1000
|
+
candidates.filter(
|
|
1001
|
+
(manager) => manager && (manager.getHostId?.() ?? manager.requestClient.hostId) === hostId && (manager.requestClient.hostId === void 0 || manager.requestClient.hostId === hostId)
|
|
1002
|
+
)
|
|
1020
1003
|
);
|
|
1021
|
-
|
|
1004
|
+
return matching.size === 1 ? matching.values().next().value ?? null : null;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// packages/desktop-control/src/renderer-host-routing.ts
|
|
1008
|
+
function installRendererHostRouting(root, target, discover, resolve, createPolicy) {
|
|
1009
|
+
const existing = target.__codexhostHostRoutingV1;
|
|
1010
|
+
if (existing) return existing;
|
|
1011
|
+
target.__codexhostDraftPrewarmPolicyV1?.dispose?.();
|
|
1012
|
+
let disposed = false;
|
|
1013
|
+
let lastDiscovery = null;
|
|
1014
|
+
const routes = /* @__PURE__ */ new Map();
|
|
1015
|
+
const read = (composer) => {
|
|
1016
|
+
const source = composer?.matches?.(
|
|
1017
|
+
'[data-codex-composer], [contenteditable="true"][role="textbox"]'
|
|
1018
|
+
) ? { querySelectorAll: () => [composer] } : composer ?? root;
|
|
1019
|
+
const discovery = discover(source);
|
|
1020
|
+
if (composer) return discovery;
|
|
1021
|
+
if (discovery.editorCount === 0 && lastDiscovery) return lastDiscovery;
|
|
1022
|
+
lastDiscovery = discovery;
|
|
1023
|
+
return discovery;
|
|
1024
|
+
};
|
|
1025
|
+
const lookup = (hostId, discovery) => {
|
|
1026
|
+
if (disposed) return null;
|
|
1027
|
+
try {
|
|
1028
|
+
return resolve(discovery ?? read(), hostId);
|
|
1029
|
+
} catch {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
const retire = (hostId) => {
|
|
1034
|
+
const entry = routes.get(hostId);
|
|
1035
|
+
routes.delete(hostId);
|
|
1036
|
+
entry?.route.policy.dispose();
|
|
1037
|
+
};
|
|
1038
|
+
const routeFor = (hostId, discovery) => {
|
|
1039
|
+
const manager = lookup(hostId, discovery);
|
|
1040
|
+
const previous = routes.get(hostId);
|
|
1041
|
+
if (manager && previous?.route.manager === manager && previous.bridge === manager.requestClient && previous.prewarmed === manager.prewarmedThreadManager && previous.route.policy.owns(
|
|
1042
|
+
manager,
|
|
1043
|
+
manager.requestClient,
|
|
1044
|
+
hostId,
|
|
1045
|
+
manager.prewarmedThreadManager,
|
|
1046
|
+
true
|
|
1047
|
+
)) {
|
|
1048
|
+
return previous.route;
|
|
1049
|
+
}
|
|
1050
|
+
retire(hostId);
|
|
1051
|
+
if (!manager) return null;
|
|
1052
|
+
const bridge = manager.requestClient;
|
|
1053
|
+
const prewarmed = manager.prewarmedThreadManager;
|
|
1054
|
+
const policy = createPolicy(
|
|
1055
|
+
manager,
|
|
1056
|
+
bridge,
|
|
1057
|
+
hostId,
|
|
1058
|
+
target,
|
|
1059
|
+
prewarmed,
|
|
1060
|
+
() => lookup(hostId) === manager && manager.requestClient === bridge && manager.prewarmedThreadManager === prewarmed
|
|
1061
|
+
);
|
|
1062
|
+
const route = { hostId, manager, policy };
|
|
1063
|
+
routes.set(hostId, { route, bridge, prewarmed });
|
|
1064
|
+
return route;
|
|
1065
|
+
};
|
|
1066
|
+
const publish = (route) => {
|
|
1067
|
+
const policy = route?.policy;
|
|
1068
|
+
if (target.__codexhostDraftPrewarmPolicyV1 === policy) return;
|
|
1069
|
+
Object.defineProperty(target, "__codexhostDraftPrewarmPolicyV1", {
|
|
1070
|
+
configurable: true,
|
|
1071
|
+
value: policy
|
|
1072
|
+
});
|
|
1073
|
+
if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function") {
|
|
1074
|
+
target.dispatchEvent(new CustomEvent("codexhost:draft-prewarm-policy-changed"));
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
const composerHostId = (discovery) => {
|
|
1078
|
+
if (discovery.hostIds.length === 0 && discovery.registries.length > 0) return null;
|
|
1079
|
+
const hostIds = new Set(
|
|
1080
|
+
discovery.hostIds.length ? discovery.hostIds : discovery.managers.map(
|
|
1081
|
+
(manager) => manager.getHostId?.() ?? manager.requestClient.hostId
|
|
1082
|
+
)
|
|
1083
|
+
);
|
|
1084
|
+
const hostId = hostIds.size === 1 ? hostIds.values().next().value : null;
|
|
1085
|
+
return typeof hostId === "string" && hostId ? hostId : null;
|
|
1086
|
+
};
|
|
1087
|
+
const routing = {
|
|
1088
|
+
forHost(hostId) {
|
|
1089
|
+
return hostId ? routeFor(hostId) : null;
|
|
1090
|
+
},
|
|
1091
|
+
hostIdForComposer(composer) {
|
|
1092
|
+
if (disposed) return null;
|
|
1093
|
+
try {
|
|
1094
|
+
return composerHostId(read(composer));
|
|
1095
|
+
} catch {
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
},
|
|
1099
|
+
forComposer(composer) {
|
|
1100
|
+
if (disposed) return null;
|
|
1101
|
+
let discovery;
|
|
1102
|
+
try {
|
|
1103
|
+
discovery = read(composer);
|
|
1104
|
+
} catch {
|
|
1105
|
+
publish(null);
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
if (!composer) {
|
|
1109
|
+
for (const [hostId2, entry] of routes) {
|
|
1110
|
+
const manager = lookup(hostId2, discovery);
|
|
1111
|
+
if (manager !== entry.route.manager || manager.requestClient !== entry.bridge || manager.prewarmedThreadManager !== entry.prewarmed)
|
|
1112
|
+
retire(hostId2);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
const hostId = composerHostId(discovery);
|
|
1116
|
+
const route = hostId ? routeFor(hostId, discovery) : null;
|
|
1117
|
+
if (!composer) publish(route);
|
|
1118
|
+
return route;
|
|
1119
|
+
},
|
|
1120
|
+
dispose() {
|
|
1121
|
+
if (disposed) return;
|
|
1122
|
+
disposed = true;
|
|
1123
|
+
for (const hostId of routes.keys()) retire(hostId);
|
|
1124
|
+
lastDiscovery = null;
|
|
1125
|
+
if (target.__codexhostHostRoutingV1 === routing) {
|
|
1126
|
+
delete target.__codexhostHostRoutingV1;
|
|
1127
|
+
publish(null);
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
Object.defineProperty(target, "__codexhostHostRoutingV1", { configurable: true, value: routing });
|
|
1132
|
+
return routing;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// packages/desktop-control/src/renderer-draft-prewarm-policy.ts
|
|
1022
1136
|
var REQUEST_MANAGER_WAIT_TIMEOUT_MS = 6e4;
|
|
1023
1137
|
var REQUEST_MANAGER_POLL_INTERVAL_MS = 25;
|
|
1024
1138
|
function directRendererInstaller() {
|
|
1025
|
-
return `(
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
}
|
|
1039
|
-
return (${installDraftPrewarmPolicyBridge.toString()})(
|
|
1040
|
-
selected.manager,
|
|
1041
|
-
selected.requestClient,
|
|
1042
|
-
selected.hostId,
|
|
1043
|
-
window,
|
|
1044
|
-
selected.prewarmedThreadManager,
|
|
1045
|
-
() => (${IS_CURRENT_REQUEST_MANAGER})(
|
|
1046
|
-
selected.manager, selected.requestClient, selected.hostId, selected.prewarmedThreadManager,
|
|
1139
|
+
return `(() => {
|
|
1140
|
+
const committedReactAncestors = ${committedReactAncestors.toString()};
|
|
1141
|
+
const requestManagerFromHookState = ${requestManagerFromHookState.toString()};
|
|
1142
|
+
const discoverRendererHosts = ${discoverRendererHosts.toString()};
|
|
1143
|
+
const resolveRendererHostManager = ${resolveRendererHostManager.toString()};
|
|
1144
|
+
const retainRendererHostResponses = ${retainRendererHostResponses.toString()};
|
|
1145
|
+
const createDraftPrewarmPolicyBridge = ${createDraftPrewarmPolicyBridge.toString()};
|
|
1146
|
+
const routing = (${installRendererHostRouting.toString()})(
|
|
1147
|
+
document, window,
|
|
1148
|
+
(root) => discoverRendererHosts(root, committedReactAncestors, requestManagerFromHookState),
|
|
1149
|
+
(discovery, hostId) => resolveRendererHostManager(discovery, hostId, requestManagerFromHookState),
|
|
1150
|
+
(manager, bridge, hostId, target, prewarmed, isCurrent) => createDraftPrewarmPolicyBridge(
|
|
1151
|
+
manager, bridge, hostId, target, prewarmed, isCurrent, retainRendererHostResponses,
|
|
1047
1152
|
),
|
|
1048
|
-
(${retainRendererHostResponses.toString()}),
|
|
1049
1153
|
);
|
|
1154
|
+
if (!routing.forComposer()) throw new Error('Renderer request manager is ambiguous');
|
|
1155
|
+
return { state: 'ready', reason: 'owned-request-bridge' };
|
|
1050
1156
|
})()`;
|
|
1051
1157
|
}
|
|
1052
1158
|
async function waitForDraftPrewarmPolicy(evaluate, expression) {
|
|
@@ -1054,17 +1160,17 @@ async function waitForDraftPrewarmPolicy(evaluate, expression) {
|
|
|
1054
1160
|
while (true) {
|
|
1055
1161
|
try {
|
|
1056
1162
|
const value = await evaluate(expression);
|
|
1057
|
-
if (!
|
|
1163
|
+
if (typeof value !== "object" || value === null || !("state" in value) || value.state !== "ready" || !("reason" in value) || value.reason !== "owned-request-bridge") {
|
|
1058
1164
|
throw new Error("Renderer draft prewarm policy returned an invalid status");
|
|
1059
1165
|
}
|
|
1060
|
-
return
|
|
1166
|
+
return { state: "ready", reason: "owned-request-bridge" };
|
|
1061
1167
|
} catch (error) {
|
|
1062
1168
|
const message = error instanceof Error ? error.message : String(error);
|
|
1063
1169
|
const remaining = deadline - Date.now();
|
|
1064
1170
|
if (!message.includes("Renderer request manager is ambiguous") || remaining <= 0) throw error;
|
|
1065
|
-
await new Promise(
|
|
1066
|
-
setTimeout(resolve, Math.min(REQUEST_MANAGER_POLL_INTERVAL_MS, remaining))
|
|
1067
|
-
|
|
1171
|
+
await new Promise(
|
|
1172
|
+
(resolve) => setTimeout(resolve, Math.min(REQUEST_MANAGER_POLL_INTERVAL_MS, remaining))
|
|
1173
|
+
);
|
|
1068
1174
|
}
|
|
1069
1175
|
}
|
|
1070
1176
|
}
|
|
@@ -1076,14 +1182,15 @@ function installRendererDraftPrewarmPolicyDirect(renderer) {
|
|
|
1076
1182
|
}
|
|
1077
1183
|
|
|
1078
1184
|
// packages/desktop-control/src/renderer-cdp-control-session.ts
|
|
1079
|
-
function
|
|
1185
|
+
function isRecord2(value) {
|
|
1080
1186
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1081
1187
|
}
|
|
1082
1188
|
function sleep(milliseconds) {
|
|
1083
1189
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
1084
1190
|
}
|
|
1085
1191
|
function sameAgents(actual, expected) {
|
|
1086
|
-
|
|
1192
|
+
const expectedSet = new Set(expected);
|
|
1193
|
+
return actual.length === expected.length && new Set(actual).size === actual.length && actual.every((agent) => expectedSet.has(agent));
|
|
1087
1194
|
}
|
|
1088
1195
|
function isPrimaryRendererUrl(value) {
|
|
1089
1196
|
try {
|
|
@@ -1110,7 +1217,7 @@ var RendererAdapterReadinessError = class extends Error {
|
|
|
1110
1217
|
reason;
|
|
1111
1218
|
};
|
|
1112
1219
|
function validateBindingStatus(value, expectedAgents) {
|
|
1113
|
-
if (!
|
|
1220
|
+
if (!isRecord2(value) || value.version !== 2 || !Array.isArray(value.enabledAgents) || value.enabledAgents.some((agent) => typeof agent !== "string") || !sameAgents(value.enabledAgents, expectedAgents) || !isRecord2(value.adapter)) {
|
|
1114
1221
|
throw new Error("Production Renderer binding returned an invalid status");
|
|
1115
1222
|
}
|
|
1116
1223
|
if (value.adapter.state !== "ready" || typeof value.adapter.reason !== "string") {
|
|
@@ -1144,8 +1251,8 @@ async function evaluateSource(renderer, source) {
|
|
|
1144
1251
|
expression: source,
|
|
1145
1252
|
awaitPromise: true
|
|
1146
1253
|
});
|
|
1147
|
-
if (!
|
|
1148
|
-
if (
|
|
1254
|
+
if (!isRecord2(response)) throw new Error("Renderer source evaluation returned an invalid result");
|
|
1255
|
+
if (isRecord2(response.exceptionDetails)) {
|
|
1149
1256
|
const text = typeof response.exceptionDetails.text === "string" ? response.exceptionDetails.text : "Renderer source evaluation failed";
|
|
1150
1257
|
throw new Error(text);
|
|
1151
1258
|
}
|
|
@@ -1235,7 +1342,6 @@ var InstalledRendererCdpControlSession = class {
|
|
|
1235
1342
|
try {
|
|
1236
1343
|
const existing = await readBinding(this.renderer);
|
|
1237
1344
|
if (existing === null) await evaluateSource(this.renderer, this.rendererSource);
|
|
1238
|
-
else validateBindingStatus(existing, this.enabledAgents);
|
|
1239
1345
|
const draftPrewarmPolicy = await this.operations.installDraftPrewarmPolicy(this.renderer);
|
|
1240
1346
|
const binding = await waitForBinding(
|
|
1241
1347
|
this.renderer,
|
|
@@ -1494,9 +1600,10 @@ ${rendererSource}`,
|
|
|
1494
1600
|
"codebuddy",
|
|
1495
1601
|
"workbuddy",
|
|
1496
1602
|
"cursor-cli",
|
|
1603
|
+
"hermes",
|
|
1497
1604
|
"qoder",
|
|
1498
1605
|
"qoder-cn",
|
|
1499
|
-
"
|
|
1606
|
+
"kimi-code"
|
|
1500
1607
|
],
|
|
1501
1608
|
timeoutMs: PRODUCTION_INSTALL_TIMEOUT_MS
|
|
1502
1609
|
},
|