@codexhost/cli-win32-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.
@@ -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
- void options.attach().then(
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 target = {
103
- id: nonEmptyString(value.id, "id"),
104
- type: nonEmptyString(value.type, "type"),
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: nonEmptyString(value.url, "url"),
107
- webSocketDebuggerUrl: nonEmptyString(value.webSocketDebuggerUrl, "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 isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
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 (!isRecord4(data) || data.type !== "mcp-response" || data.hostId !== hostId) return;
357
+ if (!isRecord3(data) || data.type !== "mcp-response" || data.hostId !== hostId) return;
347
358
  const message = data.message;
348
- if (!isRecord4(message)) return;
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 = isRecord4(message.error);
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 (!isRecord4(event) || event.hostId !== hostId) return;
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 installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewarmedThreadManager, isCurrentManager, retainResponses = retainRendererHostResponses) {
379
- const existing = target.__codexhostDraftPrewarmPolicyV1;
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
- const isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
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 (!isRecord4(value)) return false;
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 (!isRecord4(value) || typeof value.id !== "string") return;
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 || !isRecord4(result)) return;
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" && isRecord4(request.parameters) && typeof request.parameters.threadId === "string") {
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" && isRecord4(request.parameters) && typeof request.parameters.threadId === "string") {
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 (!isRecord4(value)) {
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 (isRecord4(value.params) && value.params.protocolVersion === 1) {
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" && isRecord4(value.params)) {
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" && isRecord4(parameters) && parameters.processHandle === bridgeProcessHandle) {
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" || !isRecord4(parameters) || parameters.processHandle !== bridgeProcessHandle || parameters.stream !== "stdout" && parameters.stream !== "stderr" || typeof parameters.deltaBase64 !== "string") {
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 (!isRecord4(parameters)) return null;
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 = isRecord4(value) && Array.isArray(value.threads) ? value.threads : null;
724
+ const ownerships = isRecord3(value) && Array.isArray(value.threads) ? value.threads : null;
717
725
  const ownership = ownerships?.[0];
718
- if (!ownerships || !isRecord4(ownership) || ownerships.length !== 1 || ownership.threadId !== threadId || ownership.owner !== "external" && ownership.owner !== "codex") {
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 isRecord4(parameters) && typeof parameters.model === "string" && parameters.model.startsWith("codexhost/");
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 (!isRecord4(parameters) || parameters.ephemeral === true) {
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
- if (shouldUseBridge("thread/start", routedParameters)) {
797
- return routedSend("thread/start", routedParameters, options);
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 options === void 0 ? originalPrewarm.call(bridge, routedParameters) : originalPrewarm.call(bridge, routedParameters, options);
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 (!isRecord4(message) || message.type !== "mcp-notification" || message.hostId !== hostId || typeof message.method !== "string") {
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
- Object.defineProperty(target, "__codexhostDraftPrewarmPolicyV1", {
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-draft-prewarm-policy.ts
900
- function selectRendererRequestManager(candidates, activeHostIds) {
901
- const unique = /* @__PURE__ */ new Map();
902
- for (const candidate of candidates) unique.set(candidate.manager, candidate);
903
- const hosts = new Set(
904
- activeHostIds.filter((value) => typeof value === "string" && value.length > 0)
905
- );
906
- if (hosts.size > 1) return null;
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 (matchesRequestManager(value)) return value;
923
- if (value != null && typeof value === "object" && "manager" in value && matchesRequestManager(value.manager)) {
924
- return value.manager;
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 isRecord2(value) {
934
- return typeof value === "object" && value !== null && !Array.isArray(value);
935
- }
936
- var FIND_REQUEST_MANAGER_EXPRESSION = `(() => {
937
- const requestManagerFromHookState = ${requestManagerFromHookState.toString()};
938
- const committedReactAncestors = ${committedReactAncestors.toString()};
939
- const editors = [...document.querySelectorAll(
940
- '[data-codex-composer], [contenteditable="true"][role="textbox"]',
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 = null;
952
- while (element != null && fiber == null) {
953
- const key = Object.getOwnPropertyNames(element).find((name) =>
954
- name.startsWith('__reactFiber$'),
960
+ let fiber;
961
+ while (element && !fiber) {
962
+ const key = Object.getOwnPropertyNames(element).find(
963
+ (name) => name.startsWith("__reactFiber$")
955
964
  );
956
- if (key != null) fiber = element[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 committedReactAncestors(fiber)) {
960
- composerAncestors.add(current);
968
+ for (const current of ancestors(fiber)) {
969
+ fibers.add(current);
961
970
  const props = current.memoizedProps;
962
- if (props != null && typeof props === 'object') {
963
- for (const name of ['executionTargetHostId', 'permissionsHostId']) {
964
- const value = props[name];
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 activeHostId =
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 != null && index < 120; index += 1, hook = hook.next) {
976
- const manager = requestManagerFromHookState(hook.memoizedState, activeHostId);
977
- if (manager != null) managers.add(manager);
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
- hostId: selected?.hostId ?? null,
999
- manager: selected?.manager ?? null,
1000
- requestClient: selected?.requestClient ?? null,
1001
- prewarmedThreadManager: selected?.prewarmedThreadManager ?? null,
991
+ hostIds: [...hostIds],
992
+ managers: [...managers],
993
+ registries: [...registries]
1002
994
  };
1003
- })()`;
1004
- var IS_CURRENT_REQUEST_MANAGER = `function(manager, requestClient, hostId, prewarmedThreadManager) {
1005
- const current = ${FIND_REQUEST_MANAGER_EXPRESSION};
1006
- return current.editorCount === 0 || (
1007
- current.manager === manager && current.requestClient === requestClient &&
1008
- current.hostId === hostId && current.prewarmedThreadManager === prewarmedThreadManager
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 `(async () => {
1026
- const selected = ${FIND_REQUEST_MANAGER_EXPRESSION};
1027
- if (
1028
- selected.candidateCount !== 1 ||
1029
- typeof selected.hostId !== 'string' ||
1030
- selected.hostId.length === 0 ||
1031
- selected.manager == null ||
1032
- selected.requestClient == null
1033
- ) {
1034
- throw new Error('Renderer request manager is ambiguous');
1035
- }
1036
- if (selected.prewarmedThreadManager == null) {
1037
- throw new Error('Renderer prewarmed Thread manager is unavailable');
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 (!isRecord2(value) || value.state !== "ready" || value.reason !== "owned-request-bridge") {
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 value;
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((resolve) => {
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 isRecord3(value) {
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
- return actual.length === expected.length && actual.every((agent, index) => agent === expected[index]);
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 (!isRecord3(value) || value.version !== 2 || !Array.isArray(value.enabledAgents) || value.enabledAgents.some((agent) => typeof agent !== "string") || !sameAgents(value.enabledAgents, expectedAgents) || !isRecord3(value.adapter)) {
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 (!isRecord3(response)) throw new Error("Renderer source evaluation returned an invalid result");
1148
- if (isRecord3(response.exceptionDetails)) {
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
- "hermes"
1606
+ "kimi-code"
1500
1607
  ],
1501
1608
  timeoutMs: PRODUCTION_INSTALL_TIMEOUT_MS
1502
1609
  },