@codexhost/cli-darwin-x64 0.4.1 → 0.4.3
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/desktop-controller.mjs +209 -671
- package/app/host-runtime.mjs +3062 -1216
- package/app/renderer-extension.js +137 -42
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
|
@@ -285,270 +285,6 @@ var CdpClient = class _CdpClient {
|
|
|
285
285
|
}
|
|
286
286
|
};
|
|
287
287
|
|
|
288
|
-
// packages/desktop-control/src/main-process-title-policy.ts
|
|
289
|
-
function isRecord2(value) {
|
|
290
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
291
|
-
}
|
|
292
|
-
function resultRecord(value, command) {
|
|
293
|
-
if (!isRecord2(value)) throw new Error(`${command} returned an invalid result`);
|
|
294
|
-
if (isRecord2(value.exceptionDetails)) {
|
|
295
|
-
const exception = value.exceptionDetails.exception;
|
|
296
|
-
const description = isRecord2(exception) ? exception.description : null;
|
|
297
|
-
const text = value.exceptionDetails.text;
|
|
298
|
-
throw new Error(
|
|
299
|
-
typeof description === "string" ? description : typeof text === "string" ? text : `${command} failed`
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
return value;
|
|
303
|
-
}
|
|
304
|
-
function remoteObjectId(value, label) {
|
|
305
|
-
if (!isRecord2(value) || typeof value.objectId !== "string") {
|
|
306
|
-
throw new Error(`${label} is unavailable`);
|
|
307
|
-
}
|
|
308
|
-
return value.objectId;
|
|
309
|
-
}
|
|
310
|
-
function properties(value, command) {
|
|
311
|
-
const result = resultRecord(value, command).result;
|
|
312
|
-
if (!Array.isArray(result)) throw new Error(`${command} returned invalid properties`);
|
|
313
|
-
return result.filter(isRecord2);
|
|
314
|
-
}
|
|
315
|
-
var ELECTRON_MODULE_EXPRESSION = `(() => {
|
|
316
|
-
const mainModule = process.mainModule;
|
|
317
|
-
if (mainModule != null && typeof mainModule.require === 'function') {
|
|
318
|
-
return mainModule.require('electron');
|
|
319
|
-
}
|
|
320
|
-
const { createRequire } = process.getBuiltinModule('module');
|
|
321
|
-
return createRequire(process.execPath)('electron');
|
|
322
|
-
})()`;
|
|
323
|
-
var CONNECT_APP_HOST_CHANNEL = "codex_desktop:connect-app-host";
|
|
324
|
-
var POLICY_STATE_SYMBOL = "codexhost.main-process-title-policy.v1";
|
|
325
|
-
var SERVICE_OWNER_SYMBOL = "codexhost.main-process-title-policy.owner.v1";
|
|
326
|
-
var RENDERER_READY_EXPRESSION = "(() => { Object.defineProperty(window, '__codexhostMainProcessTitlePolicyV1', { configurable: true, value: { state: 'ready' } }); return 'ready'; })()";
|
|
327
|
-
var INSTALL_POLICY_FUNCTION = `async function (rendererWebContentsId) {
|
|
328
|
-
const mainModule = process.mainModule;
|
|
329
|
-
const electron = mainModule != null && typeof mainModule.require === 'function'
|
|
330
|
-
? mainModule.require('electron')
|
|
331
|
-
: process.getBuiltinModule('module').createRequire(process.execPath)('electron');
|
|
332
|
-
const selected = electron.webContents.fromId(rendererWebContentsId);
|
|
333
|
-
if (selected == null || selected.isDestroyed() || selected.getType() !== 'window') {
|
|
334
|
-
throw new Error('Owned Renderer unavailable for title policy');
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
const context = this(selected);
|
|
338
|
-
if (context == null || typeof context.createAppHost !== 'function') {
|
|
339
|
-
throw new Error('WindowContext unavailable for title policy');
|
|
340
|
-
}
|
|
341
|
-
const stateSymbol = Symbol.for(${JSON.stringify(POLICY_STATE_SYMBOL)});
|
|
342
|
-
const ownerSymbol = Symbol.for(${JSON.stringify(SERVICE_OWNER_SYMBOL)});
|
|
343
|
-
globalThis[stateSymbol]?.dispose?.();
|
|
344
|
-
|
|
345
|
-
const originalCreateAppHost = context.createAppHost;
|
|
346
|
-
const sampleHost = originalCreateAppHost.call(context, selected);
|
|
347
|
-
const sampleService = sampleHost?.services?.threadMetadataGeneration;
|
|
348
|
-
const servicePrototype = sampleService == null ? null : Object.getPrototypeOf(sampleService);
|
|
349
|
-
const originalGenerateTitle = servicePrototype?.generateTitle;
|
|
350
|
-
if (
|
|
351
|
-
servicePrototype == null ||
|
|
352
|
-
typeof originalGenerateTitle !== 'function' ||
|
|
353
|
-
!Function.prototype.toString.call(originalGenerateTitle).includes('Failed to generate thread title')
|
|
354
|
-
) {
|
|
355
|
-
throw new Error('ThreadMetadataGenerationService signature mismatch');
|
|
356
|
-
}
|
|
357
|
-
const counters = {
|
|
358
|
-
codexTitleCalls: 0,
|
|
359
|
-
piTitleSkips: 0,
|
|
360
|
-
externalTitleSkips: 0,
|
|
361
|
-
ambiguousTitleSkips: 0,
|
|
362
|
-
};
|
|
363
|
-
const ownedWebContentsIds = new Set();
|
|
364
|
-
const ownService = (service, contents) => {
|
|
365
|
-
const existingOwner = service[ownerSymbol];
|
|
366
|
-
if (existingOwner != null && existingOwner !== contents) {
|
|
367
|
-
throw new Error('Thread metadata service ownership mismatch');
|
|
368
|
-
}
|
|
369
|
-
if (existingOwner == null) {
|
|
370
|
-
Object.defineProperty(service, ownerSymbol, { value: contents });
|
|
371
|
-
}
|
|
372
|
-
ownedWebContentsIds.add(contents.id);
|
|
373
|
-
};
|
|
374
|
-
ownService(sampleService, selected);
|
|
375
|
-
const wrappedCreateAppHost = function (contents) {
|
|
376
|
-
const host = originalCreateAppHost.call(this, contents);
|
|
377
|
-
const service = host?.services?.threadMetadataGeneration;
|
|
378
|
-
if (service != null) ownService(service, contents);
|
|
379
|
-
return host;
|
|
380
|
-
};
|
|
381
|
-
const wrappedGenerateTitle = async function (params) {
|
|
382
|
-
const owner = this[ownerSymbol];
|
|
383
|
-
if (owner == null || owner.isDestroyed()) {
|
|
384
|
-
counters.ambiguousTitleSkips += 1;
|
|
385
|
-
return null;
|
|
386
|
-
}
|
|
387
|
-
let selection = null;
|
|
388
|
-
try {
|
|
389
|
-
selection = await owner.executeJavaScript(
|
|
390
|
-
"window.__codexhostRendererBindingProbeV1?.lockedSelection() ?? null",
|
|
391
|
-
true,
|
|
392
|
-
);
|
|
393
|
-
} catch {}
|
|
394
|
-
if (selection?.phase !== 'locked') {
|
|
395
|
-
counters.ambiguousTitleSkips += 1;
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
if (selection.agent === 'pi') {
|
|
399
|
-
counters.piTitleSkips += 1;
|
|
400
|
-
return null;
|
|
401
|
-
}
|
|
402
|
-
if (selection.agent !== 'codex') {
|
|
403
|
-
counters.externalTitleSkips += 1;
|
|
404
|
-
return null;
|
|
405
|
-
}
|
|
406
|
-
counters.codexTitleCalls += 1;
|
|
407
|
-
return originalGenerateTitle.call(this, params);
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
context.createAppHost = wrappedCreateAppHost;
|
|
411
|
-
servicePrototype.generateTitle = wrappedGenerateTitle;
|
|
412
|
-
const state = {
|
|
413
|
-
counters,
|
|
414
|
-
ownedWebContentsIds,
|
|
415
|
-
dispose() {
|
|
416
|
-
if (context.createAppHost === wrappedCreateAppHost) {
|
|
417
|
-
context.createAppHost = originalCreateAppHost;
|
|
418
|
-
}
|
|
419
|
-
if (servicePrototype.generateTitle === wrappedGenerateTitle) {
|
|
420
|
-
servicePrototype.generateTitle = originalGenerateTitle;
|
|
421
|
-
}
|
|
422
|
-
if (globalThis[stateSymbol] === state) delete globalThis[stateSymbol];
|
|
423
|
-
},
|
|
424
|
-
};
|
|
425
|
-
globalThis[stateSymbol] = state;
|
|
426
|
-
return {
|
|
427
|
-
state: 'ready',
|
|
428
|
-
reason: 'ready',
|
|
429
|
-
requiresRendererReload: true,
|
|
430
|
-
};
|
|
431
|
-
}`;
|
|
432
|
-
async function installMainProcessTitlePolicy(inspector, rendererWebContentsId) {
|
|
433
|
-
if (!Number.isInteger(rendererWebContentsId) || rendererWebContentsId <= 0) {
|
|
434
|
-
throw new Error("Renderer webContents ID must be a positive integer");
|
|
435
|
-
}
|
|
436
|
-
const listenerResponse = resultRecord(
|
|
437
|
-
await inspector.command("Runtime.evaluate", {
|
|
438
|
-
expression: `(${ELECTRON_MODULE_EXPRESSION}).ipcMain.listeners(${JSON.stringify(
|
|
439
|
-
CONNECT_APP_HOST_CHANNEL
|
|
440
|
-
)})[0]`
|
|
441
|
-
}),
|
|
442
|
-
"Runtime.evaluate"
|
|
443
|
-
);
|
|
444
|
-
const listener = listenerResponse.result;
|
|
445
|
-
const listenerId = remoteObjectId(listener, "connect-app-host listener");
|
|
446
|
-
const listenerProperties = resultRecord(
|
|
447
|
-
await inspector.command("Runtime.getProperties", { objectId: listenerId }),
|
|
448
|
-
"Runtime.getProperties"
|
|
449
|
-
);
|
|
450
|
-
const internalProperties = listenerProperties.internalProperties;
|
|
451
|
-
if (!Array.isArray(internalProperties)) {
|
|
452
|
-
throw new Error("connect-app-host listener scopes are unavailable");
|
|
453
|
-
}
|
|
454
|
-
const scopes = internalProperties.find(
|
|
455
|
-
(property) => isRecord2(property) && property.name === "[[Scopes]]"
|
|
456
|
-
);
|
|
457
|
-
const scopesId = remoteObjectId(
|
|
458
|
-
isRecord2(scopes) ? scopes.value : null,
|
|
459
|
-
"connect-app-host listener scopes"
|
|
460
|
-
);
|
|
461
|
-
const scopeProperties = properties(
|
|
462
|
-
await inspector.command("Runtime.getProperties", {
|
|
463
|
-
objectId: scopesId,
|
|
464
|
-
ownProperties: true
|
|
465
|
-
}),
|
|
466
|
-
"Runtime.getProperties"
|
|
467
|
-
);
|
|
468
|
-
const localScope = scopeProperties.find((property) => property.name === "0");
|
|
469
|
-
const localScopeId = remoteObjectId(localScope?.value, "connect-app-host local scope");
|
|
470
|
-
const localProperties = properties(
|
|
471
|
-
await inspector.command("Runtime.getProperties", {
|
|
472
|
-
objectId: localScopeId,
|
|
473
|
-
ownProperties: true
|
|
474
|
-
}),
|
|
475
|
-
"Runtime.getProperties"
|
|
476
|
-
);
|
|
477
|
-
const getContext = localProperties.find(
|
|
478
|
-
(property) => property.name === "f" && typeof property.value?.objectId === "string"
|
|
479
|
-
);
|
|
480
|
-
const getContextId = remoteObjectId(getContext?.value, "getContextForWebContents");
|
|
481
|
-
const installPromise = resultRecord(
|
|
482
|
-
await inspector.command("Runtime.callFunctionOn", {
|
|
483
|
-
objectId: getContextId,
|
|
484
|
-
functionDeclaration: INSTALL_POLICY_FUNCTION,
|
|
485
|
-
arguments: [{ value: rendererWebContentsId }]
|
|
486
|
-
}),
|
|
487
|
-
"Runtime.callFunctionOn"
|
|
488
|
-
);
|
|
489
|
-
const promiseObjectId = remoteObjectId(
|
|
490
|
-
installPromise.result,
|
|
491
|
-
"Main-process title policy installation promise"
|
|
492
|
-
);
|
|
493
|
-
const installResponse = resultRecord(
|
|
494
|
-
await inspector.command("Runtime.awaitPromise", {
|
|
495
|
-
promiseObjectId,
|
|
496
|
-
returnByValue: true
|
|
497
|
-
}),
|
|
498
|
-
"Runtime.awaitPromise"
|
|
499
|
-
);
|
|
500
|
-
const remoteResult = installResponse.result;
|
|
501
|
-
const value = isRecord2(remoteResult) ? remoteResult.value : null;
|
|
502
|
-
if (!isRecord2(value) || value.state !== "ready" || value.reason !== "ready" || value.requiresRendererReload !== true || Object.keys(value).length !== 3) {
|
|
503
|
-
throw new Error("Main-process title policy returned an invalid status");
|
|
504
|
-
}
|
|
505
|
-
return value;
|
|
506
|
-
}
|
|
507
|
-
async function markRendererTitlePolicyReady(inspector, rendererWebContentsId) {
|
|
508
|
-
if (!Number.isInteger(rendererWebContentsId) || rendererWebContentsId <= 0) {
|
|
509
|
-
throw new Error("Renderer webContents ID must be a positive integer");
|
|
510
|
-
}
|
|
511
|
-
const value = await inspector.evaluate(`(async () => {
|
|
512
|
-
const state = globalThis[Symbol.for(${JSON.stringify(POLICY_STATE_SYMBOL)})];
|
|
513
|
-
if (state == null) throw new Error('Main-process title policy is unavailable');
|
|
514
|
-
const mainModule = process.mainModule;
|
|
515
|
-
const electron = mainModule != null && typeof mainModule.require === 'function'
|
|
516
|
-
? mainModule.require('electron')
|
|
517
|
-
: process.getBuiltinModule('module').createRequire(process.execPath)('electron');
|
|
518
|
-
const selected = electron.webContents.fromId(${rendererWebContentsId});
|
|
519
|
-
if (selected == null || selected.isDestroyed() || selected.getType() !== 'window') {
|
|
520
|
-
throw new Error('Owned Renderer unavailable for title policy readiness');
|
|
521
|
-
}
|
|
522
|
-
if (!state.ownedWebContentsIds.has(selected.id)) {
|
|
523
|
-
throw new Error('Renderer metadata service ownership is unavailable');
|
|
524
|
-
}
|
|
525
|
-
const marker = selected.executeJavaScript(
|
|
526
|
-
${JSON.stringify(RENDERER_READY_EXPRESSION)},
|
|
527
|
-
true,
|
|
528
|
-
);
|
|
529
|
-
const markerTimeout = new Promise((_, reject) => {
|
|
530
|
-
setTimeout(() => reject(new Error('Renderer readiness marker timed out')), 2_000);
|
|
531
|
-
});
|
|
532
|
-
await Promise.race([marker, markerTimeout]);
|
|
533
|
-
return { state: 'ready', reason: 'owned-metadata-service' };
|
|
534
|
-
})()`);
|
|
535
|
-
if (!isRecord2(value) || value.state !== "ready" || value.reason !== "owned-metadata-service") {
|
|
536
|
-
throw new Error("Renderer title policy returned an invalid readiness status");
|
|
537
|
-
}
|
|
538
|
-
return value;
|
|
539
|
-
}
|
|
540
|
-
async function readMainProcessTitlePolicyCounters(inspector) {
|
|
541
|
-
const value = await inspector.evaluate(`(() => {
|
|
542
|
-
const state = globalThis[Symbol.for(${JSON.stringify(POLICY_STATE_SYMBOL)})];
|
|
543
|
-
return state == null ? null : { ...state.counters };
|
|
544
|
-
})()`);
|
|
545
|
-
if (value === null) return null;
|
|
546
|
-
if (!isRecord2(value) || !Number.isInteger(value.codexTitleCalls) || !Number.isInteger(value.piTitleSkips) || !Number.isInteger(value.externalTitleSkips) || !Number.isInteger(value.ambiguousTitleSkips)) {
|
|
547
|
-
throw new Error("Main-process title policy returned invalid counters");
|
|
548
|
-
}
|
|
549
|
-
return value;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
288
|
// packages/desktop-control/src/renderer-draft-prewarm-runtime.ts
|
|
553
289
|
function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewarmedThreadManager) {
|
|
554
290
|
const existing = target.__codexhostDraftPrewarmPolicyV1;
|
|
@@ -561,7 +297,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
561
297
|
const originalOnNotification = manager.onNotification;
|
|
562
298
|
const originalDispatchAppServerResponse = manager.dispatchAppServerResponse;
|
|
563
299
|
let selectedModel = null;
|
|
564
|
-
const
|
|
300
|
+
const isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
565
301
|
const isRemoteControlHost = hostId.startsWith("remote-control:");
|
|
566
302
|
const knownExternalThreadIds = /* @__PURE__ */ new Set();
|
|
567
303
|
const knownOfficialThreadIds = /* @__PURE__ */ new Set();
|
|
@@ -645,14 +381,14 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
645
381
|
bridgeState = "idle";
|
|
646
382
|
};
|
|
647
383
|
const rememberExternalThread = (value) => {
|
|
648
|
-
if (!
|
|
384
|
+
if (!isRecord4(value) || typeof value.id !== "string") return;
|
|
649
385
|
if (value.modelProvider === "codexhost" || value.cliVersion === "codexhost") {
|
|
650
386
|
knownExternalThreadIds.add(value.id);
|
|
651
387
|
knownOfficialThreadIds.delete(value.id);
|
|
652
388
|
}
|
|
653
389
|
};
|
|
654
390
|
const observeBridgeResult = (request, result) => {
|
|
655
|
-
if (!request || !
|
|
391
|
+
if (!request || !isRecord4(result)) return;
|
|
656
392
|
if (request.method === "thread/list" && Array.isArray(result.data)) {
|
|
657
393
|
for (const thread of result.data) rememberExternalThread(thread);
|
|
658
394
|
return;
|
|
@@ -661,7 +397,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
661
397
|
rememberExternalThread(result.thread);
|
|
662
398
|
return;
|
|
663
399
|
}
|
|
664
|
-
if (request.method === "codexhost/thread/inspect" &&
|
|
400
|
+
if (request.method === "codexhost/thread/inspect" && isRecord4(request.parameters) && typeof request.parameters.threadId === "string") {
|
|
665
401
|
if (result.owner === "external") {
|
|
666
402
|
knownExternalThreadIds.add(request.parameters.threadId);
|
|
667
403
|
knownOfficialThreadIds.delete(request.parameters.threadId);
|
|
@@ -671,18 +407,18 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
671
407
|
}
|
|
672
408
|
return;
|
|
673
409
|
}
|
|
674
|
-
if (request.method === "thread/delete" &&
|
|
410
|
+
if (request.method === "thread/delete" && isRecord4(request.parameters) && typeof request.parameters.threadId === "string") {
|
|
675
411
|
knownExternalThreadIds.delete(request.parameters.threadId);
|
|
676
412
|
knownOfficialThreadIds.delete(request.parameters.threadId);
|
|
677
413
|
}
|
|
678
414
|
};
|
|
679
415
|
const handleBridgeFrame = (value) => {
|
|
680
|
-
if (!
|
|
416
|
+
if (!isRecord4(value)) {
|
|
681
417
|
failBridge("received a non-object app-server frame");
|
|
682
418
|
return;
|
|
683
419
|
}
|
|
684
420
|
if (value.method === bridgeReadyMethod && value.id === void 0) {
|
|
685
|
-
if (
|
|
421
|
+
if (isRecord4(value.params) && value.params.protocolVersion === 1) {
|
|
686
422
|
bridgeState = "ready";
|
|
687
423
|
if (bridgeReadyTimeout !== null) globalThis.clearTimeout(bridgeReadyTimeout);
|
|
688
424
|
bridgeReadyTimeout = null;
|
|
@@ -695,7 +431,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
695
431
|
return;
|
|
696
432
|
}
|
|
697
433
|
if (typeof value.method === "string" && value.id === void 0) {
|
|
698
|
-
if (value.method === "thread/started" &&
|
|
434
|
+
if (value.method === "thread/started" && isRecord4(value.params)) {
|
|
699
435
|
rememberExternalThread(value.params.thread);
|
|
700
436
|
}
|
|
701
437
|
originalOnNotification.call(manager, value.method, value.params);
|
|
@@ -746,7 +482,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
746
482
|
}
|
|
747
483
|
};
|
|
748
484
|
const handleOuterNotification = (method, parameters) => {
|
|
749
|
-
if (method === "process/exited" &&
|
|
485
|
+
if (method === "process/exited" && isRecord4(parameters) && parameters.processHandle === bridgeProcessHandle) {
|
|
750
486
|
const exitCode = typeof parameters.exitCode === "number" ? parameters.exitCode : "unknown";
|
|
751
487
|
const stderr = typeof parameters.stderr === "string" ? parameters.stderr.trim() : "";
|
|
752
488
|
failBridge(
|
|
@@ -755,7 +491,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
755
491
|
);
|
|
756
492
|
return true;
|
|
757
493
|
}
|
|
758
|
-
if (method !== "process/outputDelta" || !
|
|
494
|
+
if (method !== "process/outputDelta" || !isRecord4(parameters) || parameters.processHandle !== bridgeProcessHandle || parameters.stream !== "stdout" && parameters.stream !== "stderr" || typeof parameters.deltaBase64 !== "string") {
|
|
759
495
|
return false;
|
|
760
496
|
}
|
|
761
497
|
if (parameters.capReached === true) {
|
|
@@ -860,7 +596,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
860
596
|
return bridgeInitialization;
|
|
861
597
|
};
|
|
862
598
|
const threadIdFromParameters = (parameters) => {
|
|
863
|
-
if (!
|
|
599
|
+
if (!isRecord4(parameters)) return null;
|
|
864
600
|
const value = parameters.threadId ?? parameters.conversationId;
|
|
865
601
|
return typeof value === "string" ? value : null;
|
|
866
602
|
};
|
|
@@ -875,9 +611,9 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
875
611
|
threadIds: [threadId]
|
|
876
612
|
})
|
|
877
613
|
).then((value) => {
|
|
878
|
-
const ownerships =
|
|
614
|
+
const ownerships = isRecord4(value) && Array.isArray(value.threads) ? value.threads : null;
|
|
879
615
|
const ownership = ownerships?.[0];
|
|
880
|
-
if (!ownerships || !
|
|
616
|
+
if (!ownerships || !isRecord4(ownership) || ownerships.length !== 1 || ownership.threadId !== threadId || ownership.owner !== "external" && ownership.owner !== "codex") {
|
|
881
617
|
throw transportError("Thread ownership lookup returned an invalid result");
|
|
882
618
|
}
|
|
883
619
|
if (ownership.owner === "external") {
|
|
@@ -913,7 +649,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
913
649
|
if (method.startsWith("codexhost/")) return true;
|
|
914
650
|
if (method === "thread/list") return true;
|
|
915
651
|
if (method === "thread/start") {
|
|
916
|
-
return
|
|
652
|
+
return isRecord4(parameters) && typeof parameters.model === "string" && parameters.model.startsWith("codexhost/");
|
|
917
653
|
}
|
|
918
654
|
const threadId = threadIdFromParameters(parameters);
|
|
919
655
|
if (threadId && knownExternalThreadIds.has(threadId)) return true;
|
|
@@ -921,7 +657,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
921
657
|
return selectedModel !== null && (method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("review/"));
|
|
922
658
|
};
|
|
923
659
|
const routeThreadStart = (parameters) => {
|
|
924
|
-
if (selectedModel === null || !
|
|
660
|
+
if (selectedModel === null || !isRecord4(parameters) || parameters.ephemeral === true) {
|
|
925
661
|
return parameters;
|
|
926
662
|
}
|
|
927
663
|
return { ...parameters, model: selectedModel };
|
|
@@ -951,7 +687,7 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
951
687
|
bridge.prewarmThreadStart = routedPrewarm;
|
|
952
688
|
const routedWindowMessage = (event) => {
|
|
953
689
|
const message = event.data;
|
|
954
|
-
if (!
|
|
690
|
+
if (!isRecord4(message) || message.type !== "mcp-notification" || message.hostId !== hostId || typeof message.method !== "string") {
|
|
955
691
|
return;
|
|
956
692
|
}
|
|
957
693
|
handleOuterNotification(message.method, message.params);
|
|
@@ -1041,63 +777,6 @@ function installDraftPrewarmPolicyBridge(manager, bridge, hostId, target, prewar
|
|
|
1041
777
|
}
|
|
1042
778
|
return { state: "ready", reason: "owned-request-bridge" };
|
|
1043
779
|
}
|
|
1044
|
-
async function installDraftPrewarmPolicyInRenderer(contents, findRequestManagerExpression, installRendererPolicyFunction) {
|
|
1045
|
-
if (contents === null || contents.isDestroyed() || contents.getType() !== "window") {
|
|
1046
|
-
throw new Error("Owned Renderer is unavailable for draft prewarm policy");
|
|
1047
|
-
}
|
|
1048
|
-
let attachedHere = false;
|
|
1049
|
-
try {
|
|
1050
|
-
if (!contents.debugger.isAttached()) {
|
|
1051
|
-
contents.debugger.attach("1.3");
|
|
1052
|
-
attachedHere = true;
|
|
1053
|
-
}
|
|
1054
|
-
await contents.debugger.sendCommand("Runtime.enable");
|
|
1055
|
-
const managerResult = await contents.debugger.sendCommand("Runtime.evaluate", {
|
|
1056
|
-
expression: findRequestManagerExpression
|
|
1057
|
-
});
|
|
1058
|
-
const managerResultId = managerResult.result?.objectId;
|
|
1059
|
-
if (typeof managerResultId !== "string") {
|
|
1060
|
-
throw new Error("Renderer request manager inspection failed");
|
|
1061
|
-
}
|
|
1062
|
-
const managerProperties = await contents.debugger.sendCommand("Runtime.getProperties", {
|
|
1063
|
-
objectId: managerResultId,
|
|
1064
|
-
ownProperties: true
|
|
1065
|
-
});
|
|
1066
|
-
const candidateCount = managerProperties.result?.find(
|
|
1067
|
-
(property) => property.name === "candidateCount"
|
|
1068
|
-
)?.value?.value;
|
|
1069
|
-
const hostId = managerProperties.result?.find((property) => property.name === "hostId")?.value?.value;
|
|
1070
|
-
const manager = managerProperties.result?.find(
|
|
1071
|
-
(property) => property.name === "manager"
|
|
1072
|
-
)?.value;
|
|
1073
|
-
const requestClient = managerProperties.result?.find(
|
|
1074
|
-
(property) => property.name === "requestClient"
|
|
1075
|
-
)?.value;
|
|
1076
|
-
const prewarmedThreadManager = managerProperties.result?.find(
|
|
1077
|
-
(property) => property.name === "prewarmedThreadManager"
|
|
1078
|
-
)?.value;
|
|
1079
|
-
if (candidateCount !== 1 || typeof hostId !== "string" || hostId.length === 0 || typeof manager?.objectId !== "string" || typeof requestClient?.objectId !== "string") {
|
|
1080
|
-
throw new Error("Renderer request manager is ambiguous");
|
|
1081
|
-
}
|
|
1082
|
-
if (typeof prewarmedThreadManager?.objectId !== "string") {
|
|
1083
|
-
throw new Error("Renderer prewarmed Thread manager is unavailable");
|
|
1084
|
-
}
|
|
1085
|
-
const installed = await contents.debugger.sendCommand("Runtime.callFunctionOn", {
|
|
1086
|
-
objectId: manager.objectId,
|
|
1087
|
-
functionDeclaration: installRendererPolicyFunction,
|
|
1088
|
-
arguments: [
|
|
1089
|
-
{ objectId: requestClient.objectId },
|
|
1090
|
-
{ value: hostId },
|
|
1091
|
-
{ objectId: prewarmedThreadManager.objectId }
|
|
1092
|
-
],
|
|
1093
|
-
awaitPromise: true,
|
|
1094
|
-
returnByValue: true
|
|
1095
|
-
});
|
|
1096
|
-
return installed.result?.value;
|
|
1097
|
-
} finally {
|
|
1098
|
-
if (attachedHere && contents.debugger.isAttached()) contents.debugger.detach();
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
780
|
|
|
1102
781
|
// packages/desktop-control/src/renderer-draft-prewarm-policy.ts
|
|
1103
782
|
function selectRendererRequestManager(candidates, activeHostIds) {
|
|
@@ -1113,7 +792,7 @@ function selectRendererRequestManager(candidates, activeHostIds) {
|
|
|
1113
792
|
);
|
|
1114
793
|
return eligible.length === 1 ? eligible[0] ?? null : null;
|
|
1115
794
|
}
|
|
1116
|
-
function
|
|
795
|
+
function isRecord2(value) {
|
|
1117
796
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1118
797
|
}
|
|
1119
798
|
var FIND_REQUEST_MANAGER_EXPRESSION = `(() => {
|
|
@@ -1193,30 +872,36 @@ var INSTALL_RENDERER_POLICY_FUNCTION = `function(requestClient, hostId, prewarme
|
|
|
1193
872
|
}`;
|
|
1194
873
|
var REQUEST_MANAGER_WAIT_TIMEOUT_MS = 6e4;
|
|
1195
874
|
var REQUEST_MANAGER_POLL_INTERVAL_MS = 25;
|
|
1196
|
-
function
|
|
1197
|
-
return `async
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
875
|
+
function directRendererInstaller() {
|
|
876
|
+
return `(async () => {
|
|
877
|
+
const selected = ${FIND_REQUEST_MANAGER_EXPRESSION};
|
|
878
|
+
if (
|
|
879
|
+
selected.candidateCount !== 1 ||
|
|
880
|
+
typeof selected.hostId !== 'string' ||
|
|
881
|
+
selected.hostId.length === 0 ||
|
|
882
|
+
selected.manager == null ||
|
|
883
|
+
selected.requestClient == null
|
|
884
|
+
) {
|
|
885
|
+
throw new Error('Renderer request manager is ambiguous');
|
|
886
|
+
}
|
|
887
|
+
if (selected.prewarmedThreadManager == null) {
|
|
888
|
+
throw new Error('Renderer prewarmed Thread manager is unavailable');
|
|
889
|
+
}
|
|
890
|
+
return (${installDraftPrewarmPolicyBridge.toString()})(
|
|
891
|
+
selected.manager,
|
|
892
|
+
selected.requestClient,
|
|
893
|
+
selected.hostId,
|
|
894
|
+
window,
|
|
895
|
+
selected.prewarmedThreadManager,
|
|
1207
896
|
);
|
|
1208
|
-
}`;
|
|
897
|
+
})()`;
|
|
1209
898
|
}
|
|
1210
|
-
async function
|
|
1211
|
-
if (!Number.isInteger(rendererWebContentsId) || rendererWebContentsId <= 0) {
|
|
1212
|
-
throw new Error("Renderer webContents ID must be a positive integer");
|
|
1213
|
-
}
|
|
1214
|
-
const installer = mainProcessInstaller(rendererWebContentsId);
|
|
899
|
+
async function waitForDraftPrewarmPolicy(evaluate, expression) {
|
|
1215
900
|
const deadline = Date.now() + REQUEST_MANAGER_WAIT_TIMEOUT_MS;
|
|
1216
901
|
while (true) {
|
|
1217
902
|
try {
|
|
1218
|
-
const value = await
|
|
1219
|
-
if (!
|
|
903
|
+
const value = await evaluate(expression);
|
|
904
|
+
if (!isRecord2(value) || value.state !== "ready" || value.reason !== "owned-request-bridge") {
|
|
1220
905
|
throw new Error("Renderer draft prewarm policy returned an invalid status");
|
|
1221
906
|
}
|
|
1222
907
|
return value;
|
|
@@ -1230,9 +915,15 @@ async function installRendererDraftPrewarmPolicy(inspector, rendererWebContentsI
|
|
|
1230
915
|
}
|
|
1231
916
|
}
|
|
1232
917
|
}
|
|
918
|
+
function installRendererDraftPrewarmPolicyDirect(renderer) {
|
|
919
|
+
return waitForDraftPrewarmPolicy(
|
|
920
|
+
(expression) => renderer.evaluate(expression),
|
|
921
|
+
directRendererInstaller()
|
|
922
|
+
);
|
|
923
|
+
}
|
|
1233
924
|
|
|
1234
|
-
// packages/desktop-control/src/renderer-control-session.ts
|
|
1235
|
-
function
|
|
925
|
+
// packages/desktop-control/src/renderer-cdp-control-session.ts
|
|
926
|
+
function isRecord3(value) {
|
|
1236
927
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1237
928
|
}
|
|
1238
929
|
function sleep(milliseconds) {
|
|
@@ -1241,6 +932,20 @@ function sleep(milliseconds) {
|
|
|
1241
932
|
function sameAgents(actual, expected) {
|
|
1242
933
|
return actual.length === expected.length && actual.every((agent, index) => agent === expected[index]);
|
|
1243
934
|
}
|
|
935
|
+
function isPrimaryRendererUrl(value) {
|
|
936
|
+
try {
|
|
937
|
+
const url = new URL(value);
|
|
938
|
+
return url.protocol === "app:" && url.hostname === "-" && url.pathname === "/index.html" && url.search === "" && url.hash === "";
|
|
939
|
+
} catch {
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
function selectPrimaryRendererTarget(targets, preferredTargetId) {
|
|
944
|
+
const candidates = targets.filter(
|
|
945
|
+
(target) => target.type === "page" && isPrimaryRendererUrl(target.url)
|
|
946
|
+
);
|
|
947
|
+
return candidates.find((target) => target.id === preferredTargetId) ?? candidates.at(0) ?? null;
|
|
948
|
+
}
|
|
1244
949
|
var RendererAdapterReadinessError = class extends Error {
|
|
1245
950
|
constructor(state, reason) {
|
|
1246
951
|
super(`Production Renderer Adapter is ${state}: ${reason}`);
|
|
@@ -1252,7 +957,7 @@ var RendererAdapterReadinessError = class extends Error {
|
|
|
1252
957
|
reason;
|
|
1253
958
|
};
|
|
1254
959
|
function validateBindingStatus(value, expectedAgents) {
|
|
1255
|
-
if (!
|
|
960
|
+
if (!isRecord3(value) || value.version !== 2 || !Array.isArray(value.enabledAgents) || value.enabledAgents.some((agent) => typeof agent !== "string") || !sameAgents(value.enabledAgents, expectedAgents) || !isRecord3(value.adapter)) {
|
|
1256
961
|
throw new Error("Production Renderer binding returned an invalid status");
|
|
1257
962
|
}
|
|
1258
963
|
if (value.adapter.state !== "ready" || typeof value.adapter.reason !== "string") {
|
|
@@ -1262,161 +967,45 @@ function validateBindingStatus(value, expectedAgents) {
|
|
|
1262
967
|
}
|
|
1263
968
|
return value;
|
|
1264
969
|
}
|
|
1265
|
-
function
|
|
1266
|
-
const candidates = contents.filter(
|
|
1267
|
-
(item) => item.type === "window" && item.surface === "primary" && item.runtime.available && item.runtime.elementCount !== null
|
|
1268
|
-
).toSorted(
|
|
1269
|
-
(left, right) => (right.runtime.elementCount ?? 0) - (left.runtime.elementCount ?? 0)
|
|
1270
|
-
);
|
|
1271
|
-
const preferred = candidates.find(
|
|
1272
|
-
(candidate) => candidate.id === preferredRendererId && (candidate.runtime.elementCount ?? 0) > 0
|
|
1273
|
-
);
|
|
1274
|
-
if (preferred) return preferred;
|
|
1275
|
-
return candidates.find((candidate) => (candidate.runtime.elementCount ?? 0) > 0) ?? null;
|
|
1276
|
-
}
|
|
1277
|
-
async function waitForRendererTitlePolicyReady(markReadiness, options = {}) {
|
|
1278
|
-
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
1279
|
-
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
1280
|
-
const now = options.now ?? Date.now;
|
|
1281
|
-
const wait = options.sleep ?? sleep;
|
|
1282
|
-
const deadline = now() + timeoutMs;
|
|
1283
|
-
let lastError;
|
|
1284
|
-
while (now() < deadline) {
|
|
1285
|
-
try {
|
|
1286
|
-
return await markReadiness();
|
|
1287
|
-
} catch (error) {
|
|
1288
|
-
lastError = error;
|
|
1289
|
-
}
|
|
1290
|
-
await wait(pollIntervalMs);
|
|
1291
|
-
}
|
|
1292
|
-
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
1293
|
-
throw new Error(`Renderer title policy ownership did not become ready${detail}`);
|
|
1294
|
-
}
|
|
1295
|
-
async function waitForInspectorTarget(endpoint, options = {}) {
|
|
1296
|
-
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
1297
|
-
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
970
|
+
async function waitForPrimaryTarget(endpoint, operations, timeoutMs, pollIntervalMs, preferredTargetId) {
|
|
1298
971
|
const deadline = Date.now() + timeoutMs;
|
|
1299
972
|
let lastError;
|
|
1300
973
|
while (Date.now() < deadline) {
|
|
1301
974
|
try {
|
|
1302
|
-
const
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
975
|
+
const target = selectPrimaryRendererTarget(
|
|
976
|
+
await operations.listTargets(endpoint),
|
|
977
|
+
preferredTargetId
|
|
978
|
+
);
|
|
979
|
+
if (target) return target;
|
|
980
|
+
lastError = new Error("Renderer CDP has no primary app://-/index.html page target");
|
|
1306
981
|
} catch (error) {
|
|
1307
982
|
lastError = error;
|
|
1308
983
|
}
|
|
1309
984
|
await sleep(pollIntervalMs);
|
|
1310
985
|
}
|
|
1311
986
|
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
1312
|
-
throw new Error(`
|
|
987
|
+
throw new Error(`Primary Codex Renderer CDP target did not become ready${detail}`);
|
|
1313
988
|
}
|
|
1314
|
-
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
}
|
|
1319
|
-
const { createRequire } = process.getBuiltinModule('module');
|
|
1320
|
-
return createRequire(process.execPath)('electron');
|
|
1321
|
-
})()`;
|
|
1322
|
-
var webContentsRuntimeExpression = "(() => ({ elementCount: document.querySelectorAll('*').length }))()";
|
|
1323
|
-
async function inspectElectronWebContents(inspector) {
|
|
1324
|
-
const value = await inspector.evaluate(`(async () => {
|
|
1325
|
-
const { webContents } = ${electronModuleExpression};
|
|
1326
|
-
const result = await Promise.all(webContents.getAllWebContents().map(async (contents) => {
|
|
1327
|
-
let runtime = { available: false, elementCount: null };
|
|
1328
|
-
try {
|
|
1329
|
-
const evaluation = contents.executeJavaScript(${JSON.stringify(webContentsRuntimeExpression)}, true);
|
|
1330
|
-
const timeout = new Promise((_, reject) => {
|
|
1331
|
-
setTimeout(() => reject(new Error('Renderer inspection timed out')), 2_000);
|
|
1332
|
-
});
|
|
1333
|
-
runtime = { available: true, ...(await Promise.race([evaluation, timeout])) };
|
|
1334
|
-
} catch {}
|
|
1335
|
-
return {
|
|
1336
|
-
id: contents.id,
|
|
1337
|
-
type: contents.getType(),
|
|
1338
|
-
surface: contents.getURL().includes('avatar-overlay') ? 'overlay' : 'primary',
|
|
1339
|
-
runtime,
|
|
1340
|
-
};
|
|
1341
|
-
}));
|
|
1342
|
-
return result;
|
|
1343
|
-
})()`);
|
|
1344
|
-
if (!Array.isArray(value)) throw new Error("Electron webContents inspection returned an array");
|
|
1345
|
-
return value.map((item) => {
|
|
1346
|
-
if (!isRecord4(item) || !Number.isInteger(item.id) || typeof item.type !== "string" || !["primary", "overlay"].includes(String(item.surface)) || !isRecord4(item.runtime)) {
|
|
1347
|
-
throw new Error("Electron webContents inspection returned an invalid item");
|
|
1348
|
-
}
|
|
1349
|
-
return {
|
|
1350
|
-
id: item.id,
|
|
1351
|
-
type: item.type,
|
|
1352
|
-
surface: item.surface,
|
|
1353
|
-
runtime: {
|
|
1354
|
-
available: item.runtime.available === true,
|
|
1355
|
-
elementCount: Number.isInteger(item.runtime.elementCount) ? item.runtime.elementCount : null
|
|
1356
|
-
}
|
|
1357
|
-
};
|
|
989
|
+
async function evaluateSource(renderer, source) {
|
|
990
|
+
const response = await renderer.command("Runtime.evaluate", {
|
|
991
|
+
expression: source,
|
|
992
|
+
awaitPromise: true
|
|
1358
993
|
});
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
const windows = BrowserWindow.getAllWindows().filter((window) => !window.isDestroyed());
|
|
1364
|
-
for (const window of windows) {
|
|
1365
|
-
if (window.isMinimized()) window.restore();
|
|
1366
|
-
window.show();
|
|
1367
|
-
window.focus();
|
|
1368
|
-
}
|
|
1369
|
-
return windows.length;
|
|
1370
|
-
})()`);
|
|
1371
|
-
if (!Number.isInteger(value) || value < 1) {
|
|
1372
|
-
throw new Error("Electron Desktop activation found no live window");
|
|
994
|
+
if (!isRecord3(response)) throw new Error("Renderer source evaluation returned an invalid result");
|
|
995
|
+
if (isRecord3(response.exceptionDetails)) {
|
|
996
|
+
const text = typeof response.exceptionDetails.text === "string" ? response.exceptionDetails.text : "Renderer source evaluation failed";
|
|
997
|
+
throw new Error(text);
|
|
1373
998
|
}
|
|
1374
|
-
return value;
|
|
1375
|
-
}
|
|
1376
|
-
async function executeInWebContents(inspector, rendererWebContentsId, source) {
|
|
1377
|
-
return inspector.evaluate(`(async () => {
|
|
1378
|
-
const { webContents } = ${electronModuleExpression};
|
|
1379
|
-
const contents = webContents.fromId(${rendererWebContentsId});
|
|
1380
|
-
if (contents == null || contents.isDestroyed()) throw new Error('Renderer webContents is unavailable');
|
|
1381
|
-
const result = await contents.executeJavaScript(${JSON.stringify(source)}, true);
|
|
1382
|
-
return result === undefined ? null : result;
|
|
1383
|
-
})()`);
|
|
1384
999
|
}
|
|
1385
|
-
async function
|
|
1386
|
-
|
|
1387
|
-
}
|
|
1388
|
-
var defaultOperations = {
|
|
1389
|
-
inspect: inspectElectronWebContents,
|
|
1390
|
-
installTitlePolicy: installMainProcessTitlePolicy,
|
|
1391
|
-
markTitlePolicyReady: markRendererTitlePolicyReady,
|
|
1392
|
-
installDraftPrewarmPolicy: installRendererDraftPrewarmPolicy,
|
|
1393
|
-
reload: reloadRenderer,
|
|
1394
|
-
execute: executeInWebContents,
|
|
1395
|
-
readBinding: (inspector, rendererWebContentsId) => executeInWebContents(
|
|
1396
|
-
inspector,
|
|
1397
|
-
rendererWebContentsId,
|
|
1398
|
-
"window.__codexhostRendererBindingProbeV1?.status() ?? null"
|
|
1399
|
-
),
|
|
1400
|
-
readTitlePolicyCounters: readMainProcessTitlePolicyCounters
|
|
1401
|
-
};
|
|
1402
|
-
async function waitForRenderer(inspector, operations, timeoutMs, pollIntervalMs, preferredRendererId) {
|
|
1403
|
-
const deadline = Date.now() + timeoutMs;
|
|
1404
|
-
let candidateCount = 0;
|
|
1405
|
-
while (Date.now() < deadline) {
|
|
1406
|
-
const inventory = await operations.inspect(inspector);
|
|
1407
|
-
candidateCount = inventory.length;
|
|
1408
|
-
const renderer = selectRendererWebContents(inventory, preferredRendererId);
|
|
1409
|
-
if (renderer) return renderer;
|
|
1410
|
-
await sleep(pollIntervalMs);
|
|
1411
|
-
}
|
|
1412
|
-
throw new Error(`Inspector did not find a live Electron Renderer (${candidateCount} seen)`);
|
|
1000
|
+
async function readBinding(renderer) {
|
|
1001
|
+
return renderer.evaluate("window.__codexhostRendererBindingProbeV1?.status() ?? null");
|
|
1413
1002
|
}
|
|
1414
|
-
async function waitForBinding(
|
|
1003
|
+
async function waitForBinding(renderer, enabledAgents, timeoutMs, pollIntervalMs) {
|
|
1415
1004
|
const deadline = Date.now() + timeoutMs;
|
|
1416
1005
|
let lastError;
|
|
1417
1006
|
while (Date.now() < deadline) {
|
|
1418
1007
|
try {
|
|
1419
|
-
const value = await
|
|
1008
|
+
const value = await readBinding(renderer);
|
|
1420
1009
|
if (value !== null) return validateBindingStatus(value, enabledAgents);
|
|
1421
1010
|
} catch (error) {
|
|
1422
1011
|
lastError = error;
|
|
@@ -1429,218 +1018,163 @@ async function waitForBinding(inspector, operations, rendererWebContentsId, enab
|
|
|
1429
1018
|
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
1430
1019
|
throw new Error(`Production Renderer binding did not become ready${detail}`);
|
|
1431
1020
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1021
|
+
async function installTarget(target, rendererSource, enabledAgents, timeoutMs, pollIntervalMs, operations) {
|
|
1022
|
+
const renderer = await operations.connect(target.webSocketDebuggerUrl);
|
|
1023
|
+
try {
|
|
1024
|
+
await renderer.command("Runtime.enable");
|
|
1025
|
+
await renderer.command("Page.enable");
|
|
1026
|
+
await renderer.command("Page.addScriptToEvaluateOnNewDocument", { source: rendererSource });
|
|
1027
|
+
await evaluateSource(renderer, rendererSource);
|
|
1028
|
+
const draftPrewarmPolicy = await operations.installDraftPrewarmPolicy(renderer);
|
|
1029
|
+
const binding = await waitForBinding(renderer, enabledAgents, timeoutMs, pollIntervalMs);
|
|
1030
|
+
return { renderer, snapshot: { target, draftPrewarmPolicy, binding } };
|
|
1031
|
+
} catch (error) {
|
|
1032
|
+
renderer.close();
|
|
1033
|
+
throw error;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
var InstalledRendererCdpControlSession = class {
|
|
1037
|
+
constructor(renderer, rendererCdpEndpoint2, rendererSource, enabledAgents, timeoutMs, pollIntervalMs, operations, currentSnapshot) {
|
|
1038
|
+
this.renderer = renderer;
|
|
1039
|
+
this.rendererCdpEndpoint = rendererCdpEndpoint2;
|
|
1435
1040
|
this.rendererSource = rendererSource;
|
|
1436
1041
|
this.enabledAgents = enabledAgents;
|
|
1437
1042
|
this.timeoutMs = timeoutMs;
|
|
1438
1043
|
this.pollIntervalMs = pollIntervalMs;
|
|
1439
1044
|
this.operations = operations;
|
|
1440
|
-
this
|
|
1045
|
+
this.currentSnapshot = currentSnapshot;
|
|
1441
1046
|
}
|
|
1442
|
-
|
|
1047
|
+
renderer;
|
|
1048
|
+
rendererCdpEndpoint;
|
|
1443
1049
|
rendererSource;
|
|
1444
1050
|
enabledAgents;
|
|
1445
1051
|
timeoutMs;
|
|
1446
1052
|
pollIntervalMs;
|
|
1447
1053
|
operations;
|
|
1054
|
+
currentSnapshot;
|
|
1448
1055
|
#closed = false;
|
|
1449
|
-
#snapshot;
|
|
1450
1056
|
get snapshot() {
|
|
1451
|
-
return this
|
|
1057
|
+
return this.currentSnapshot;
|
|
1452
1058
|
}
|
|
1453
1059
|
async ensureInstalled() {
|
|
1454
|
-
if (this.#closed) throw new Error("Renderer Control Session is closed");
|
|
1455
|
-
const
|
|
1456
|
-
this.
|
|
1060
|
+
if (this.#closed) throw new Error("Renderer CDP Control Session is closed");
|
|
1061
|
+
const target = await waitForPrimaryTarget(
|
|
1062
|
+
this.rendererCdpEndpoint,
|
|
1457
1063
|
this.operations,
|
|
1458
1064
|
this.timeoutMs,
|
|
1459
1065
|
this.pollIntervalMs,
|
|
1460
|
-
this
|
|
1066
|
+
this.currentSnapshot.target.id
|
|
1461
1067
|
);
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
this.
|
|
1466
|
-
|
|
1068
|
+
if (target.id !== this.currentSnapshot.target.id) {
|
|
1069
|
+
const replacement = await installTarget(
|
|
1070
|
+
target,
|
|
1071
|
+
this.rendererSource,
|
|
1072
|
+
this.enabledAgents,
|
|
1073
|
+
this.timeoutMs,
|
|
1074
|
+
this.pollIntervalMs,
|
|
1075
|
+
this.operations
|
|
1467
1076
|
);
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1077
|
+
this.renderer.close();
|
|
1078
|
+
this.renderer = replacement.renderer;
|
|
1079
|
+
this.currentSnapshot = replacement.snapshot;
|
|
1080
|
+
return this.currentSnapshot;
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
const existing = await readBinding(this.renderer);
|
|
1084
|
+
if (existing === null) await evaluateSource(this.renderer, this.rendererSource);
|
|
1085
|
+
else validateBindingStatus(existing, this.enabledAgents);
|
|
1086
|
+
const draftPrewarmPolicy = await this.operations.installDraftPrewarmPolicy(this.renderer);
|
|
1087
|
+
const binding = await waitForBinding(
|
|
1088
|
+
this.renderer,
|
|
1089
|
+
this.enabledAgents,
|
|
1090
|
+
this.timeoutMs,
|
|
1091
|
+
this.pollIntervalMs
|
|
1092
|
+
);
|
|
1093
|
+
this.currentSnapshot = { target, draftPrewarmPolicy, binding };
|
|
1094
|
+
return this.currentSnapshot;
|
|
1095
|
+
} catch {
|
|
1096
|
+
const replacement = await installTarget(
|
|
1097
|
+
target,
|
|
1098
|
+
this.rendererSource,
|
|
1099
|
+
this.enabledAgents,
|
|
1100
|
+
this.timeoutMs,
|
|
1101
|
+
this.pollIntervalMs,
|
|
1102
|
+
this.operations
|
|
1103
|
+
);
|
|
1104
|
+
this.renderer.close();
|
|
1105
|
+
this.renderer = replacement.renderer;
|
|
1106
|
+
this.currentSnapshot = replacement.snapshot;
|
|
1107
|
+
return this.currentSnapshot;
|
|
1490
1108
|
}
|
|
1491
|
-
const titlePolicyReadiness = await waitForRendererTitlePolicyReady(
|
|
1492
|
-
() => this.operations.markTitlePolicyReady(this.inspector, selected.id),
|
|
1493
|
-
{ timeoutMs: this.timeoutMs, pollIntervalMs: this.pollIntervalMs }
|
|
1494
|
-
);
|
|
1495
|
-
await activateElectronDesktop(this.inspector);
|
|
1496
|
-
await this.operations.execute(this.inspector, selected.id, this.rendererSource);
|
|
1497
|
-
const draftPrewarmPolicy = await this.operations.installDraftPrewarmPolicy(
|
|
1498
|
-
this.inspector,
|
|
1499
|
-
selected.id
|
|
1500
|
-
);
|
|
1501
|
-
const binding = await waitForBinding(
|
|
1502
|
-
this.inspector,
|
|
1503
|
-
this.operations,
|
|
1504
|
-
selected.id,
|
|
1505
|
-
this.enabledAgents,
|
|
1506
|
-
this.timeoutMs,
|
|
1507
|
-
this.pollIntervalMs
|
|
1508
|
-
);
|
|
1509
|
-
this.#snapshot = {
|
|
1510
|
-
...this.#snapshot,
|
|
1511
|
-
renderer: selected,
|
|
1512
|
-
titlePolicyReadiness,
|
|
1513
|
-
draftPrewarmPolicy,
|
|
1514
|
-
binding
|
|
1515
|
-
};
|
|
1516
|
-
return this.#snapshot;
|
|
1517
1109
|
}
|
|
1518
|
-
activateDesktop() {
|
|
1519
|
-
if (this.#closed)
|
|
1520
|
-
|
|
1110
|
+
async activateDesktop() {
|
|
1111
|
+
if (this.#closed) throw new Error("Renderer CDP Control Session is closed");
|
|
1112
|
+
await this.renderer.command("Page.bringToFront");
|
|
1113
|
+
return 1;
|
|
1521
1114
|
}
|
|
1522
1115
|
executeRenderer(expression) {
|
|
1523
|
-
if (this.#closed) return Promise.reject(new Error("Renderer Control Session is closed"));
|
|
1524
|
-
return this.
|
|
1525
|
-
this.inspector,
|
|
1526
|
-
this.#snapshot.renderer.id,
|
|
1527
|
-
expression
|
|
1528
|
-
);
|
|
1529
|
-
}
|
|
1530
|
-
readTitlePolicyCounters() {
|
|
1531
|
-
if (this.#closed) return Promise.reject(new Error("Renderer Control Session is closed"));
|
|
1532
|
-
return this.operations.readTitlePolicyCounters(this.inspector);
|
|
1116
|
+
if (this.#closed) return Promise.reject(new Error("Renderer CDP Control Session is closed"));
|
|
1117
|
+
return this.renderer.evaluate(expression);
|
|
1533
1118
|
}
|
|
1534
1119
|
close() {
|
|
1535
1120
|
if (this.#closed) return;
|
|
1536
1121
|
this.#closed = true;
|
|
1537
|
-
this.
|
|
1122
|
+
this.renderer.close();
|
|
1538
1123
|
}
|
|
1539
1124
|
};
|
|
1540
|
-
var
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
}
|
|
1547
|
-
async function createRendererControlSession(options) {
|
|
1125
|
+
var defaultOperations = {
|
|
1126
|
+
listTargets: (endpoint) => listCdpTargets(endpoint),
|
|
1127
|
+
connect: (webSocketDebuggerUrl) => CdpClient.connect(webSocketDebuggerUrl),
|
|
1128
|
+
installDraftPrewarmPolicy: installRendererDraftPrewarmPolicyDirect
|
|
1129
|
+
};
|
|
1130
|
+
async function createRendererCdpControlSession(options) {
|
|
1548
1131
|
const enabledAgents = options.enabledAgents ?? ["codex", "pi"];
|
|
1549
1132
|
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
1550
1133
|
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
1551
1134
|
const operations = options.operations ?? defaultOperations;
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
startupTrace("installing title policy");
|
|
1555
|
-
const titlePolicy = await operations.installTitlePolicy(options.inspector, initial.id);
|
|
1556
|
-
startupTrace("reloading Renderer");
|
|
1557
|
-
await operations.reload(options.inspector, initial.id);
|
|
1558
|
-
startupTrace("waiting for reloaded Renderer");
|
|
1559
|
-
const selected = await waitForRenderer(
|
|
1560
|
-
options.inspector,
|
|
1135
|
+
const target = await waitForPrimaryTarget(
|
|
1136
|
+
options.rendererCdpEndpoint,
|
|
1561
1137
|
operations,
|
|
1562
1138
|
timeoutMs,
|
|
1563
|
-
pollIntervalMs
|
|
1564
|
-
initial.id
|
|
1565
|
-
);
|
|
1566
|
-
startupTrace("waiting for title policy readiness");
|
|
1567
|
-
const titlePolicyReadiness = await waitForRendererTitlePolicyReady(
|
|
1568
|
-
() => operations.markTitlePolicyReady(options.inspector, selected.id),
|
|
1569
|
-
{
|
|
1570
|
-
timeoutMs,
|
|
1571
|
-
pollIntervalMs
|
|
1572
|
-
}
|
|
1573
|
-
);
|
|
1574
|
-
startupTrace("injecting Renderer bundle");
|
|
1575
|
-
await operations.execute(options.inspector, selected.id, options.rendererSource);
|
|
1576
|
-
startupTrace("installing draft routing policy");
|
|
1577
|
-
const draftPrewarmPolicy = await operations.installDraftPrewarmPolicy(
|
|
1578
|
-
options.inspector,
|
|
1579
|
-
selected.id
|
|
1139
|
+
pollIntervalMs
|
|
1580
1140
|
);
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
options.
|
|
1584
|
-
operations,
|
|
1585
|
-
selected.id,
|
|
1141
|
+
const installed = await installTarget(
|
|
1142
|
+
target,
|
|
1143
|
+
options.rendererSource,
|
|
1586
1144
|
enabledAgents,
|
|
1587
1145
|
timeoutMs,
|
|
1588
|
-
pollIntervalMs
|
|
1146
|
+
pollIntervalMs,
|
|
1147
|
+
operations
|
|
1589
1148
|
);
|
|
1590
|
-
return new
|
|
1591
|
-
|
|
1149
|
+
return new InstalledRendererCdpControlSession(
|
|
1150
|
+
installed.renderer,
|
|
1151
|
+
options.rendererCdpEndpoint,
|
|
1592
1152
|
options.rendererSource,
|
|
1593
1153
|
enabledAgents,
|
|
1594
1154
|
timeoutMs,
|
|
1595
1155
|
pollIntervalMs,
|
|
1596
1156
|
operations,
|
|
1597
|
-
|
|
1598
|
-
renderer: selected,
|
|
1599
|
-
titlePolicy,
|
|
1600
|
-
titlePolicyReadiness,
|
|
1601
|
-
draftPrewarmPolicy,
|
|
1602
|
-
binding
|
|
1603
|
-
}
|
|
1157
|
+
installed.snapshot
|
|
1604
1158
|
);
|
|
1605
1159
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
const pollIntervalMs = options.pollIntervalMs ?? 250;
|
|
1609
|
-
startupTrace("waiting for Electron Inspector target");
|
|
1610
|
-
const target = await waitForInspectorTarget(options.inspectorEndpoint, {
|
|
1611
|
-
timeoutMs,
|
|
1612
|
-
pollIntervalMs
|
|
1613
|
-
});
|
|
1614
|
-
startupTrace("connecting to Electron Inspector");
|
|
1615
|
-
const inspector = await CdpClient.connect(target.webSocketDebuggerUrl);
|
|
1616
|
-
try {
|
|
1617
|
-
startupTrace("enabling Inspector Runtime domain");
|
|
1618
|
-
await inspector.command("Runtime.enable");
|
|
1619
|
-
return await createRendererControlSession({
|
|
1620
|
-
...options,
|
|
1621
|
-
inspector,
|
|
1622
|
-
timeoutMs,
|
|
1623
|
-
pollIntervalMs
|
|
1624
|
-
});
|
|
1625
|
-
} catch (error) {
|
|
1626
|
-
inspector.close();
|
|
1627
|
-
throw error;
|
|
1628
|
-
}
|
|
1160
|
+
function installRendererCdpControlSession(options) {
|
|
1161
|
+
return createRendererCdpControlSession(options);
|
|
1629
1162
|
}
|
|
1630
1163
|
|
|
1631
1164
|
// packages/desktop-control/src/production-controller.ts
|
|
1632
1165
|
var PRODUCTION_INSTALL_TIMEOUT_MS = 9e4;
|
|
1166
|
+
var RENDERER_CSP_BOOTSTRAP = "globalThis.__zod_globalConfig ??= {}; globalThis.__zod_globalConfig.jitless = true;";
|
|
1633
1167
|
var DESKTOP_CONTROLLER_READINESS_MAX_BYTES = 512;
|
|
1634
1168
|
var TRANSIENT_INSTALL_ATTEMPTS = 3;
|
|
1635
1169
|
var TRANSIENT_INSTALL_RETRY_MS = 250;
|
|
1636
1170
|
var RECOVERY_RETRY_INITIAL_MS = 3e4;
|
|
1637
1171
|
var RECOVERY_RETRY_MAX_MS = 3e5;
|
|
1638
|
-
var
|
|
1639
|
-
function
|
|
1172
|
+
var startupTraceStartedAt = Date.now();
|
|
1173
|
+
function startupTrace(stage, detail) {
|
|
1640
1174
|
if (process.env.CODEXHOST_STARTUP_TRACE !== "1") return;
|
|
1641
1175
|
const suffix = detail === void 0 ? "" : `: ${detail instanceof Error ? detail.message : String(detail)}`;
|
|
1642
1176
|
console.error(
|
|
1643
|
-
`[codexhost startup +${Date.now() -
|
|
1177
|
+
`[codexhost startup +${Date.now() - startupTraceStartedAt}ms] controller: ${stage}${suffix}`
|
|
1644
1178
|
);
|
|
1645
1179
|
}
|
|
1646
1180
|
function serializeDesktopControllerReadiness(readiness) {
|
|
@@ -1655,7 +1189,7 @@ function serializeDesktopControllerReadiness(readiness) {
|
|
|
1655
1189
|
}
|
|
1656
1190
|
var defaultDependencies = {
|
|
1657
1191
|
readRenderer: (filePath) => readFile(filePath, "utf8"),
|
|
1658
|
-
install:
|
|
1192
|
+
install: installRendererCdpControlSession,
|
|
1659
1193
|
startAttachmentServer: startControllerAttachmentServer,
|
|
1660
1194
|
ready: (readiness) => {
|
|
1661
1195
|
process.stdout.write(`${serializeDesktopControllerReadiness(readiness)}
|
|
@@ -1664,10 +1198,10 @@ var defaultDependencies = {
|
|
|
1664
1198
|
sleep: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
|
|
1665
1199
|
monitorIntervalMs: 500
|
|
1666
1200
|
};
|
|
1667
|
-
function
|
|
1201
|
+
function rendererCdpEndpoint(value) {
|
|
1668
1202
|
const url = new URL(value);
|
|
1669
1203
|
if (url.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) || !url.port || url.username || url.password || url.pathname !== "/" && url.pathname !== "" || url.search || url.hash) {
|
|
1670
|
-
throw new Error("--
|
|
1204
|
+
throw new Error("--renderer-cdp-endpoint must be a loopback HTTP origin with an explicit port");
|
|
1671
1205
|
}
|
|
1672
1206
|
return url.origin;
|
|
1673
1207
|
}
|
|
@@ -1680,10 +1214,12 @@ function parseDesktopControllerArguments(arguments_) {
|
|
|
1680
1214
|
for (let index = 0; index < arguments_.length; index += 1) {
|
|
1681
1215
|
const argument = arguments_[index];
|
|
1682
1216
|
const value = arguments_[index + 1];
|
|
1683
|
-
if (argument === "--
|
|
1684
|
-
if (endpoint !== void 0)
|
|
1685
|
-
|
|
1686
|
-
|
|
1217
|
+
if (argument === "--renderer-cdp-endpoint") {
|
|
1218
|
+
if (endpoint !== void 0) {
|
|
1219
|
+
throw new Error("--renderer-cdp-endpoint may only be provided once");
|
|
1220
|
+
}
|
|
1221
|
+
if (!value) throw new Error("--renderer-cdp-endpoint requires a value");
|
|
1222
|
+
endpoint = rendererCdpEndpoint(value);
|
|
1687
1223
|
index += 1;
|
|
1688
1224
|
continue;
|
|
1689
1225
|
}
|
|
@@ -1729,20 +1265,20 @@ function parseDesktopControllerArguments(arguments_) {
|
|
|
1729
1265
|
}
|
|
1730
1266
|
throw new Error(`unknown Desktop Controller option: ${argument}`);
|
|
1731
1267
|
}
|
|
1732
|
-
if (endpoint === void 0) throw new Error("--
|
|
1268
|
+
if (endpoint === void 0) throw new Error("--renderer-cdp-endpoint is required");
|
|
1733
1269
|
if (rendererPath === void 0) throw new Error("--renderer is required");
|
|
1734
1270
|
if (defaultAgent === void 0) throw new Error("--default-agent is required");
|
|
1735
1271
|
if (attachmentPort === void 0) throw new Error("--attachment-port is required");
|
|
1736
1272
|
if (attachmentNonce === void 0) throw new Error("--attachment-nonce is required");
|
|
1737
1273
|
return {
|
|
1738
|
-
|
|
1274
|
+
rendererCdpEndpoint: endpoint,
|
|
1739
1275
|
rendererPath,
|
|
1740
1276
|
defaultAgent,
|
|
1741
1277
|
attachmentPort,
|
|
1742
1278
|
attachmentNonce
|
|
1743
1279
|
};
|
|
1744
1280
|
}
|
|
1745
|
-
function
|
|
1281
|
+
function isTransientRendererInstallError(error) {
|
|
1746
1282
|
let current = error;
|
|
1747
1283
|
for (let depth = 0; depth < 4; depth += 1) {
|
|
1748
1284
|
const message = current instanceof Error ? current.message : String(current);
|
|
@@ -1759,7 +1295,7 @@ async function installProductionSession(options, dependencies) {
|
|
|
1759
1295
|
try {
|
|
1760
1296
|
return await dependencies.install(options);
|
|
1761
1297
|
} catch (error) {
|
|
1762
|
-
if (attempt === TRANSIENT_INSTALL_ATTEMPTS || !
|
|
1298
|
+
if (attempt === TRANSIENT_INSTALL_ATTEMPTS || !isTransientRendererInstallError(error)) {
|
|
1763
1299
|
throw error;
|
|
1764
1300
|
}
|
|
1765
1301
|
await dependencies.sleep(TRANSIENT_INSTALL_RETRY_MS);
|
|
@@ -1782,14 +1318,15 @@ async function runDesktopController(options, signal, dependencies = defaultDepen
|
|
|
1782
1318
|
recoveryDelayMs = RECOVERY_RETRY_INITIAL_MS;
|
|
1783
1319
|
};
|
|
1784
1320
|
const createSession = async () => {
|
|
1785
|
-
|
|
1321
|
+
startupTrace("reading Renderer bundle");
|
|
1786
1322
|
const rendererSource = await dependencies.readRenderer(options.rendererPath);
|
|
1787
1323
|
if (rendererSource.trim().length === 0) throw new Error("production Renderer Bundle is empty");
|
|
1788
|
-
|
|
1324
|
+
startupTrace("installing Renderer Session");
|
|
1789
1325
|
const installed = await installProductionSession(
|
|
1790
1326
|
{
|
|
1791
|
-
|
|
1792
|
-
rendererSource: `${
|
|
1327
|
+
rendererCdpEndpoint: options.rendererCdpEndpoint,
|
|
1328
|
+
rendererSource: `${RENDERER_CSP_BOOTSTRAP}
|
|
1329
|
+
${configuration}
|
|
1793
1330
|
${rendererSource}`,
|
|
1794
1331
|
enabledAgents: [
|
|
1795
1332
|
"codex",
|
|
@@ -1798,21 +1335,22 @@ ${rendererSource}`,
|
|
|
1798
1335
|
"deepseek-harness",
|
|
1799
1336
|
"opencode",
|
|
1800
1337
|
"grok",
|
|
1801
|
-
"omp"
|
|
1338
|
+
"omp",
|
|
1339
|
+
"antigravity"
|
|
1802
1340
|
],
|
|
1803
1341
|
timeoutMs: PRODUCTION_INSTALL_TIMEOUT_MS
|
|
1804
1342
|
},
|
|
1805
1343
|
dependencies
|
|
1806
1344
|
);
|
|
1807
|
-
|
|
1345
|
+
startupTrace("Renderer Session installed");
|
|
1808
1346
|
return installed;
|
|
1809
1347
|
};
|
|
1810
|
-
|
|
1348
|
+
startupTrace("initialization started");
|
|
1811
1349
|
try {
|
|
1812
1350
|
session = await createSession();
|
|
1813
1351
|
recordRecoverySuccess();
|
|
1814
1352
|
} catch (error) {
|
|
1815
|
-
|
|
1353
|
+
startupTrace("initial Renderer Session unavailable", error);
|
|
1816
1354
|
session = void 0;
|
|
1817
1355
|
recordRecoveryFailure();
|
|
1818
1356
|
}
|
|
@@ -1847,7 +1385,7 @@ ${rendererSource}`,
|
|
|
1847
1385
|
};
|
|
1848
1386
|
let attachmentServer;
|
|
1849
1387
|
try {
|
|
1850
|
-
|
|
1388
|
+
startupTrace("starting attachment server");
|
|
1851
1389
|
attachmentServer = await dependencies.startAttachmentServer({
|
|
1852
1390
|
port: options.attachmentPort,
|
|
1853
1391
|
nonce: options.attachmentNonce,
|
|
@@ -1856,8 +1394,8 @@ ${rendererSource}`,
|
|
|
1856
1394
|
await current.activateDesktop();
|
|
1857
1395
|
})
|
|
1858
1396
|
});
|
|
1859
|
-
|
|
1860
|
-
|
|
1397
|
+
startupTrace("attachment server ready");
|
|
1398
|
+
startupTrace("publishing readiness");
|
|
1861
1399
|
dependencies.ready({
|
|
1862
1400
|
schemaVersion: 2,
|
|
1863
1401
|
state: "compatible",
|