@karlorz/codexhost-cli-darwin-x64 0.13.3-6 → 0.13.3-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/app/codexhost-distribution.json +1 -1
- package/app/console-server.mjs +484 -91
- package/app/console-web.js +553 -37
- package/app/cpa-live-voice-hook.js +550 -33
- package/app/desktop-controller.mjs +25 -1
- package/app/host-runtime.mjs +985 -478
- package/app/plugins/antigravity/plugin.mjs +25 -1
- package/app/plugins/claude-code/plugin.mjs +32 -5
- package/app/plugins/codebuddy/plugin.mjs +32 -5
- package/app/plugins/codex-usage/plugin.mjs +131 -67
- package/app/plugins/cursor-cli/plugin.mjs +20737 -44915
- package/app/plugins/deepseek-harness/plugin.mjs +32 -5
- package/app/plugins/grok/plugin.mjs +802 -155
- package/app/plugins/hermes/plugin.mjs +32 -5
- package/app/plugins/kimi-code/plugin.mjs +25 -1
- package/app/plugins/kiro-cli/plugin.mjs +25 -1
- package/app/plugins/omp/plugin.mjs +2288 -2072
- package/app/plugins/opencode/plugin.mjs +32 -5
- package/app/plugins/pi/plugin.mjs +2373 -2264
- package/app/plugins/qoder/plugin.mjs +32 -5
- package/app/plugins/qoder-cn/plugin.mjs +32 -5
- package/app/plugins/workbuddy/plugin.mjs +32 -5
- package/app/plugins/zcode/plugin.mjs +32 -5
- package/app/renderer-extension.js +1973 -1085
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
|
@@ -6,104 +6,6 @@
|
|
|
6
6
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
// ../desktop-control/dist/renderer-react-ownership.js
|
|
10
|
-
var REACT_FIBER_WALK_LIMIT_EVENT = "codexhost:react-fiber-walk-limit";
|
|
11
|
-
function committedReactAncestors(value) {
|
|
12
|
-
const MAX_VISITED_FIBERS = 2e5;
|
|
13
|
-
const fiber = (value2) => typeof value2 === "object" && value2 !== null ? value2 : null;
|
|
14
|
-
const exhausted = () => {
|
|
15
|
-
const target = globalThis;
|
|
16
|
-
if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function")
|
|
17
|
-
target.dispatchEvent(new CustomEvent("codexhost:react-fiber-walk-limit", {
|
|
18
|
-
detail: { limit: MAX_VISITED_FIBERS }
|
|
19
|
-
}));
|
|
20
|
-
return [];
|
|
21
|
-
};
|
|
22
|
-
const first = fiber(value);
|
|
23
|
-
if (!first)
|
|
24
|
-
return [];
|
|
25
|
-
const previous = [];
|
|
26
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27
|
-
for (let node = first; node; node = fiber(node.return)) {
|
|
28
|
-
if (seen.has(node))
|
|
29
|
-
return [];
|
|
30
|
-
if (seen.size >= MAX_VISITED_FIBERS)
|
|
31
|
-
return exhausted();
|
|
32
|
-
seen.add(node);
|
|
33
|
-
previous.push(node);
|
|
34
|
-
}
|
|
35
|
-
const rootState = fiber(previous.at(-1)?.stateNode);
|
|
36
|
-
if (!rootState || !("current" in rootState))
|
|
37
|
-
return previous;
|
|
38
|
-
const current = fiber(rootState.current);
|
|
39
|
-
if (!current)
|
|
40
|
-
return [];
|
|
41
|
-
const alternate = fiber(first.alternate);
|
|
42
|
-
const path = [current];
|
|
43
|
-
seen.clear();
|
|
44
|
-
seen.add(current);
|
|
45
|
-
for (let index = previous.length - 2; index >= 0; index -= 1) {
|
|
46
|
-
const expected = previous[index];
|
|
47
|
-
const expectedAlternate = fiber(expected?.alternate);
|
|
48
|
-
let child = fiber(path.at(-1)?.child);
|
|
49
|
-
let matched = false;
|
|
50
|
-
while (child && !seen.has(child) && seen.size < MAX_VISITED_FIBERS) {
|
|
51
|
-
seen.add(child);
|
|
52
|
-
if (child === expected || child === expectedAlternate) {
|
|
53
|
-
matched = true;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
child = fiber(child.sibling);
|
|
57
|
-
}
|
|
58
|
-
if (!matched || !child)
|
|
59
|
-
break;
|
|
60
|
-
path.push(child);
|
|
61
|
-
}
|
|
62
|
-
if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
|
|
63
|
-
return path.reverse();
|
|
64
|
-
}
|
|
65
|
-
const stack = [{ node: current, parent: null }];
|
|
66
|
-
seen.clear();
|
|
67
|
-
while (stack.length > 0 && seen.size < MAX_VISITED_FIBERS) {
|
|
68
|
-
const entry = stack.pop();
|
|
69
|
-
if (!entry)
|
|
70
|
-
break;
|
|
71
|
-
if (seen.has(entry.node))
|
|
72
|
-
return [];
|
|
73
|
-
seen.add(entry.node);
|
|
74
|
-
if (entry.node === first || entry.node === alternate) {
|
|
75
|
-
const ancestors = [];
|
|
76
|
-
for (let cursor = entry; cursor; cursor = cursor.parent)
|
|
77
|
-
ancestors.push(cursor.node);
|
|
78
|
-
return ancestors;
|
|
79
|
-
}
|
|
80
|
-
const sibling = entry.parent && fiber(entry.node.sibling);
|
|
81
|
-
if (sibling)
|
|
82
|
-
stack.push({ node: sibling, parent: entry.parent });
|
|
83
|
-
const child = fiber(entry.node.child);
|
|
84
|
-
if (child)
|
|
85
|
-
stack.push({ node: child, parent: entry });
|
|
86
|
-
}
|
|
87
|
-
return stack.length > 0 ? exhausted() : [];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// src/renderer-chat-voice-debug.ts
|
|
91
|
-
var CHAT_VOICE_DEBUG_GLOBAL = "__codexhostChatVoiceDebug";
|
|
92
|
-
var CHAT_VOICE_DEBUG_STORAGE_KEY = "codexhost.chat-voice-debug.v1";
|
|
93
|
-
function chatVoiceDebug(event, detail = {}) {
|
|
94
|
-
const entry = { t: Date.now(), event, ...detail };
|
|
95
|
-
const owner = globalThis;
|
|
96
|
-
const log = Array.isArray(owner[CHAT_VOICE_DEBUG_GLOBAL]) ? owner[CHAT_VOICE_DEBUG_GLOBAL] : [];
|
|
97
|
-
log.push(entry);
|
|
98
|
-
while (log.length > 40) log.shift();
|
|
99
|
-
owner[CHAT_VOICE_DEBUG_GLOBAL] = log;
|
|
100
|
-
try {
|
|
101
|
-
owner.localStorage?.setItem(CHAT_VOICE_DEBUG_STORAGE_KEY, JSON.stringify(log));
|
|
102
|
-
} catch {
|
|
103
|
-
}
|
|
104
|
-
owner.console?.info?.("[codexhost-chat-voice]", event, detail);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
9
|
// ../../node_modules/zod/v4/classic/external.js
|
|
108
10
|
var external_exports = {};
|
|
109
11
|
__export(external_exports, {
|
|
@@ -14990,6 +14892,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
14990
14892
|
"codexhost/harness/installation",
|
|
14991
14893
|
"codexhost/harness/launch-settings/get",
|
|
14992
14894
|
"codexhost/harness/launch-settings/set",
|
|
14895
|
+
"codexhost/harness/grok-computer-use/get",
|
|
14896
|
+
"codexhost/harness/grok-computer-use/set",
|
|
14993
14897
|
"codexhost/harness/web-ui/open",
|
|
14994
14898
|
"codexhost/harness/accounts/sources",
|
|
14995
14899
|
"codexhost/harness/accounts/list",
|
|
@@ -15530,7 +15434,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15530
15434
|
var harnessInspectParamsSchema = external_exports.object({
|
|
15531
15435
|
harnessId: harnessIdSchema,
|
|
15532
15436
|
cwd: nonBlankTextSchema2.max(16384).optional(),
|
|
15533
|
-
refresh: external_exports.boolean().optional()
|
|
15437
|
+
refresh: external_exports.boolean().optional(),
|
|
15438
|
+
/** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
|
|
15439
|
+
purpose: external_exports.literal("availability").optional()
|
|
15534
15440
|
}).strict();
|
|
15535
15441
|
var harnessWebUiOpenParamsSchema = external_exports.object({
|
|
15536
15442
|
harnessId: harnessIdSchema
|
|
@@ -15730,6 +15636,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15730
15636
|
restartRequired: external_exports.boolean()
|
|
15731
15637
|
}).strict();
|
|
15732
15638
|
|
|
15639
|
+
// ../shared-contracts/dist/grok-computer-use.js
|
|
15640
|
+
var GROK_COMPUTER_USE_GET_METHOD = "codexhost/harness/grok-computer-use/get";
|
|
15641
|
+
var GROK_COMPUTER_USE_SET_METHOD = "codexhost/harness/grok-computer-use/set";
|
|
15642
|
+
var grokComputerUseGetSchema = external_exports.object({}).strict();
|
|
15643
|
+
var grokComputerUseSetSchema = external_exports.object({
|
|
15644
|
+
enabled: external_exports.boolean().optional(),
|
|
15645
|
+
browser: external_exports.boolean().optional()
|
|
15646
|
+
}).strict().refine((value) => value.enabled !== void 0 || value.browser !== void 0, {
|
|
15647
|
+
message: "Expected enabled or browser"
|
|
15648
|
+
});
|
|
15649
|
+
var grokComputerUseSettingsSchema = external_exports.object({
|
|
15650
|
+
enabled: external_exports.boolean(),
|
|
15651
|
+
available: external_exports.boolean(),
|
|
15652
|
+
unavailableReason: external_exports.string().min(1).max(500).optional(),
|
|
15653
|
+
browser: external_exports.boolean().optional(),
|
|
15654
|
+
browserFilesPresent: external_exports.boolean().optional(),
|
|
15655
|
+
browserAvailable: external_exports.boolean().optional(),
|
|
15656
|
+
browserUnavailableReason: external_exports.string().min(1).max(500).optional(),
|
|
15657
|
+
applyFailed: external_exports.boolean().optional(),
|
|
15658
|
+
applyError: external_exports.string().min(1).max(500).optional()
|
|
15659
|
+
}).strict();
|
|
15660
|
+
|
|
15733
15661
|
// ../shared-contracts/dist/harness-installation.js
|
|
15734
15662
|
var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
|
|
15735
15663
|
var harnessInstallationParamsSchema = external_exports.object({
|
|
@@ -16157,6 +16085,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16157
16085
|
|
|
16158
16086
|
// ../shared-contracts/dist/voice-settings.js
|
|
16159
16087
|
var VOICE_SETTINGS_METHOD = "codexhost/voice/settings";
|
|
16088
|
+
var VOICE_GATEWAY_STATUS_METHOD = "codexhost/voice/gateway-status";
|
|
16160
16089
|
var voiceRoutesSchema = external_exports.strictObject({
|
|
16161
16090
|
chatExperience: external_exports.enum(["chatgpt", "codex"]),
|
|
16162
16091
|
chatConnection: external_exports.enum(["desktop", "gateway"]),
|
|
@@ -16206,7 +16135,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16206
16135
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
16207
16136
|
|
|
16208
16137
|
// src/renderer-cpa-live-voice-preference.ts
|
|
16209
|
-
var
|
|
16138
|
+
var voiceStateOwner = globalThis;
|
|
16139
|
+
var { sharedRoutes, gatewayReady } = voiceStateOwner.__codexhostVoicePreferenceStateV1 ??= {
|
|
16140
|
+
sharedRoutes: /* @__PURE__ */ new WeakMap(),
|
|
16141
|
+
gatewayReady: /* @__PURE__ */ new WeakMap()
|
|
16142
|
+
};
|
|
16143
|
+
function applyVoiceGatewayReadiness(owner, ready) {
|
|
16144
|
+
gatewayReady.set(owner, ready);
|
|
16145
|
+
}
|
|
16146
|
+
function voiceGatewayIsReady(owner) {
|
|
16147
|
+
return gatewayReady.get(owner) === true;
|
|
16148
|
+
}
|
|
16210
16149
|
var SHARED_VOICE_CACHE = "codexhost.voice-routes-cache.v1";
|
|
16211
16150
|
function cachedRoutes(owner) {
|
|
16212
16151
|
const memory = sharedRoutes.get(owner);
|
|
@@ -16242,9 +16181,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16242
16181
|
return routes ? routes.chatExperience === "chatgpt" : !readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false);
|
|
16243
16182
|
}
|
|
16244
16183
|
function legacyVoiceRoutes(owner) {
|
|
16184
|
+
const chatLegacy = readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false);
|
|
16245
16185
|
return {
|
|
16246
|
-
chatExperience:
|
|
16247
|
-
chatConnection:
|
|
16186
|
+
chatExperience: chatLegacy ? "codex" : "chatgpt",
|
|
16187
|
+
chatConnection: chatLegacy ? "gateway" : "desktop",
|
|
16248
16188
|
workConnection: readFlag(owner, CPA_LIVE_VOICE_STORAGE_KEY, true) ? "gateway" : "desktop"
|
|
16249
16189
|
};
|
|
16250
16190
|
}
|
|
@@ -16406,265 +16346,885 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16406
16346
|
return handle;
|
|
16407
16347
|
}
|
|
16408
16348
|
|
|
16409
|
-
// src/
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
return `codexhost-composer-${Date.now().toString(36)}-${sequence.toString(36)}`;
|
|
16413
|
-
}
|
|
16414
|
-
function isDefaultTarget(target) {
|
|
16415
|
-
return target?.[0] === "default";
|
|
16349
|
+
// src/renderer-voice-assets.ts
|
|
16350
|
+
function supportsVoiceVersion(profiles, version2) {
|
|
16351
|
+
return version2 === void 0 || profiles.some((profile) => profile.version === version2);
|
|
16416
16352
|
}
|
|
16417
|
-
function
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
function sameTarget(left, right) {
|
|
16424
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
16353
|
+
function selectVoiceAssets(profiles, names, version2) {
|
|
16354
|
+
const present = profiles.filter(
|
|
16355
|
+
(profile2) => [profile2.initial, profile2.shared].some((asset) => auditedAppInitialAssetPresent(names, asset))
|
|
16356
|
+
);
|
|
16357
|
+
const profile = present.length === 1 ? present[0] : void 0;
|
|
16358
|
+
return profile && (version2 === void 0 || profile.version === version2) && [profile.initial, profile.shared].every((asset) => auditedAppInitialAssetPresent(names, asset)) ? profile : void 0;
|
|
16425
16359
|
}
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
|
|
16441
|
-
|
|
16442
|
-
|
|
16443
|
-
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
return this.#state(composer);
|
|
16453
|
-
}
|
|
16454
|
-
detach(composer, preservePendingSubmission = false) {
|
|
16455
|
-
const state = this.#states.get(composer);
|
|
16456
|
-
if (state && !preservePendingSubmission) this.#pendingSubmissions.delete(state);
|
|
16457
|
-
this.#states.delete(composer);
|
|
16360
|
+
|
|
16361
|
+
// ../desktop-control/dist/renderer-react-ownership.js
|
|
16362
|
+
var REACT_FIBER_WALK_LIMIT_EVENT = "codexhost:react-fiber-walk-limit";
|
|
16363
|
+
function committedReactAncestors(value) {
|
|
16364
|
+
const MAX_VISITED_FIBERS = 2e5;
|
|
16365
|
+
const fiber = (value2) => typeof value2 === "object" && value2 !== null ? value2 : null;
|
|
16366
|
+
const exhausted = () => {
|
|
16367
|
+
const target = globalThis;
|
|
16368
|
+
if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function")
|
|
16369
|
+
target.dispatchEvent(new CustomEvent("codexhost:react-fiber-walk-limit", {
|
|
16370
|
+
detail: { limit: MAX_VISITED_FIBERS }
|
|
16371
|
+
}));
|
|
16372
|
+
return [];
|
|
16373
|
+
};
|
|
16374
|
+
const first = fiber(value);
|
|
16375
|
+
if (!first)
|
|
16376
|
+
return [];
|
|
16377
|
+
const previous = [];
|
|
16378
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16379
|
+
for (let node = first; node; node = fiber(node.return)) {
|
|
16380
|
+
if (seen.has(node))
|
|
16381
|
+
return [];
|
|
16382
|
+
if (seen.size >= MAX_VISITED_FIBERS)
|
|
16383
|
+
return exhausted();
|
|
16384
|
+
seen.add(node);
|
|
16385
|
+
previous.push(node);
|
|
16458
16386
|
}
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16387
|
+
const rootState = fiber(previous.at(-1)?.stateNode);
|
|
16388
|
+
if (!rootState || !("current" in rootState))
|
|
16389
|
+
return previous;
|
|
16390
|
+
const current = fiber(rootState.current);
|
|
16391
|
+
if (!current)
|
|
16392
|
+
return [];
|
|
16393
|
+
const alternate = fiber(first.alternate);
|
|
16394
|
+
const path = [current];
|
|
16395
|
+
seen.clear();
|
|
16396
|
+
seen.add(current);
|
|
16397
|
+
for (let index = previous.length - 2; index >= 0; index -= 1) {
|
|
16398
|
+
const expected = previous[index];
|
|
16399
|
+
const expectedAlternate = fiber(expected?.alternate);
|
|
16400
|
+
let child = fiber(path.at(-1)?.child);
|
|
16401
|
+
let matched = false;
|
|
16402
|
+
while (child && !seen.has(child) && seen.size < MAX_VISITED_FIBERS) {
|
|
16403
|
+
seen.add(child);
|
|
16404
|
+
if (child === expected || child === expectedAlternate) {
|
|
16405
|
+
matched = true;
|
|
16406
|
+
break;
|
|
16407
|
+
}
|
|
16408
|
+
child = fiber(child.sibling);
|
|
16464
16409
|
}
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
return state;
|
|
16469
|
-
}
|
|
16470
|
-
isSwitching(composer) {
|
|
16471
|
-
return this.#switching.has(this.#state(composer));
|
|
16472
|
-
}
|
|
16473
|
-
beginModelRequest(composer) {
|
|
16474
|
-
const state = this.#state(composer);
|
|
16475
|
-
const generation = ++this.#modelRequestSequence;
|
|
16476
|
-
this.#modelRequestGenerations.set(state, generation);
|
|
16477
|
-
return generation;
|
|
16478
|
-
}
|
|
16479
|
-
invalidateModelRequests(composer) {
|
|
16480
|
-
this.beginModelRequest(composer);
|
|
16481
|
-
}
|
|
16482
|
-
isCurrentModelRequest(composer, generation) {
|
|
16483
|
-
return (this.#modelRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
|
|
16484
|
-
}
|
|
16485
|
-
beginOwnershipRequest(composer) {
|
|
16486
|
-
const generation = ++this.#ownershipRequestSequence;
|
|
16487
|
-
this.#ownershipRequestGenerations.set(this.#state(composer), generation);
|
|
16488
|
-
return generation;
|
|
16489
|
-
}
|
|
16490
|
-
isCurrentOwnershipRequest(composer, generation) {
|
|
16491
|
-
return (this.#ownershipRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
|
|
16410
|
+
if (!matched || !child)
|
|
16411
|
+
break;
|
|
16412
|
+
path.push(child);
|
|
16492
16413
|
}
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
const previous = this.#state(composer);
|
|
16496
|
-
this.#pendingSubmissions.delete(previous);
|
|
16497
|
-
this.#modelRequestGenerations.set(previous, ++this.#modelRequestSequence);
|
|
16498
|
-
this.#ownershipRequestGenerations.set(previous, ++this.#ownershipRequestSequence);
|
|
16499
|
-
let state = this.#targetState(target);
|
|
16500
|
-
if (!state) {
|
|
16501
|
-
state = {
|
|
16502
|
-
agent: "codex",
|
|
16503
|
-
phase: "draft",
|
|
16504
|
-
composerId: this.#idFactory(++this.#composerSequence)
|
|
16505
|
-
};
|
|
16506
|
-
this.#targetStates.push({ target, state });
|
|
16507
|
-
}
|
|
16508
|
-
this.#states.set(composer, state);
|
|
16509
|
-
this.#modelRequestGenerations.set(state, ++this.#modelRequestSequence);
|
|
16510
|
-
this.#ownershipRequestGenerations.set(state, ++this.#ownershipRequestSequence);
|
|
16511
|
-
return state;
|
|
16414
|
+
if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
|
|
16415
|
+
return path.reverse();
|
|
16512
16416
|
}
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16417
|
+
const stack = [{ node: current, parent: null }];
|
|
16418
|
+
seen.clear();
|
|
16419
|
+
while (stack.length > 0 && seen.size < MAX_VISITED_FIBERS) {
|
|
16420
|
+
const entry = stack.pop();
|
|
16421
|
+
if (!entry)
|
|
16422
|
+
break;
|
|
16423
|
+
if (seen.has(entry.node))
|
|
16424
|
+
return [];
|
|
16425
|
+
seen.add(entry.node);
|
|
16426
|
+
if (entry.node === first || entry.node === alternate) {
|
|
16427
|
+
const ancestors = [];
|
|
16428
|
+
for (let cursor = entry; cursor; cursor = cursor.parent)
|
|
16429
|
+
ancestors.push(cursor.node);
|
|
16430
|
+
return ancestors;
|
|
16527
16431
|
}
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
return this.#state(composer).configurationByAgent?.[agent]?.model;
|
|
16535
|
-
}
|
|
16536
|
-
thinkingOptionForAgent(composer, agent) {
|
|
16537
|
-
return this.#state(composer).configurationByAgent?.[agent]?.thinkingOptionId;
|
|
16538
|
-
}
|
|
16539
|
-
permissionModeForAgent(composer, agent) {
|
|
16540
|
-
return this.#state(composer).configurationByAgent?.[agent]?.permissionModeId;
|
|
16541
|
-
}
|
|
16542
|
-
setExternalPermissionMode(composer, agent, permissionModeId) {
|
|
16543
|
-
return this.#configure(composer, agent, { permissionModeId });
|
|
16544
|
-
}
|
|
16545
|
-
setExternalModel(composer, agent, model2) {
|
|
16546
|
-
return this.#configure(composer, agent, { model: model2 });
|
|
16432
|
+
const sibling = entry.parent && fiber(entry.node.sibling);
|
|
16433
|
+
if (sibling)
|
|
16434
|
+
stack.push({ node: sibling, parent: entry.parent });
|
|
16435
|
+
const child = fiber(entry.node.child);
|
|
16436
|
+
if (child)
|
|
16437
|
+
stack.push({ node: child, parent: entry });
|
|
16547
16438
|
}
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16439
|
+
return stack.length > 0 ? exhausted() : [];
|
|
16440
|
+
}
|
|
16441
|
+
|
|
16442
|
+
// src/renderer-chat-voice-debug.ts
|
|
16443
|
+
var CHAT_VOICE_DEBUG_GLOBAL = "__codexhostChatVoiceDebug";
|
|
16444
|
+
var CHAT_VOICE_DEBUG_STORAGE_KEY = "codexhost.chat-voice-debug.v1";
|
|
16445
|
+
function chatVoiceDebug(event, detail = {}) {
|
|
16446
|
+
const entry = { t: Date.now(), event, ...detail };
|
|
16447
|
+
const owner = globalThis;
|
|
16448
|
+
const log = Array.isArray(owner[CHAT_VOICE_DEBUG_GLOBAL]) ? owner[CHAT_VOICE_DEBUG_GLOBAL] : [];
|
|
16449
|
+
log.push(entry);
|
|
16450
|
+
while (log.length > 40) log.shift();
|
|
16451
|
+
owner[CHAT_VOICE_DEBUG_GLOBAL] = log;
|
|
16452
|
+
try {
|
|
16453
|
+
owner.localStorage?.setItem(CHAT_VOICE_DEBUG_STORAGE_KEY, JSON.stringify(log));
|
|
16454
|
+
} catch {
|
|
16555
16455
|
}
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16456
|
+
owner.console?.info?.("[codexhost-chat-voice]", event, detail);
|
|
16457
|
+
}
|
|
16458
|
+
|
|
16459
|
+
// src/renderer-native-chat-voice-state.ts
|
|
16460
|
+
function observeNativeChatVoiceState(scope, initial) {
|
|
16461
|
+
const store = Reflect.apply(initial.SPn, void 0, [
|
|
16462
|
+
scope
|
|
16463
|
+
]);
|
|
16464
|
+
let last = "";
|
|
16465
|
+
const report = () => {
|
|
16466
|
+
const state = store.getState();
|
|
16467
|
+
const connection = state.server?.connectionState;
|
|
16468
|
+
const detail = {
|
|
16469
|
+
active: state.isVoiceModeActive === true,
|
|
16470
|
+
connectedOnce: state.hasConnectedOnce === true,
|
|
16471
|
+
sessionStarted: state.hasVoiceSessionStarted === true,
|
|
16472
|
+
serverConversationReady: typeof state.earlyServerThreadId === "string" && /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i.test(state.earlyServerThreadId),
|
|
16473
|
+
connection: typeof connection === "string" && ["disconnected", "connecting", "connected", "reconnecting", "signalReconnecting"].includes(
|
|
16474
|
+
connection
|
|
16475
|
+
) ? connection : "unknown"
|
|
16561
16476
|
};
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16567
|
-
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
}
|
|
16595
|
-
if (isIdentifiedTarget(target) && !bound) this.#targetStates.push({ target, state });
|
|
16596
|
-
if (isConversationTarget(target) && this.#pendingSubmissions.delete(state))
|
|
16597
|
-
state.phase = "locked";
|
|
16598
|
-
return true;
|
|
16599
|
-
}
|
|
16600
|
-
async switchAgent(composer, nextAgent, operations) {
|
|
16601
|
-
const state = this.#state(composer);
|
|
16602
|
-
if (!this.#enabledAgents.has(nextAgent)) return false;
|
|
16603
|
-
if (state.phase !== "draft" || this.#switching.has(state)) return false;
|
|
16604
|
-
if (state.agent === nextAgent) return true;
|
|
16605
|
-
this.#pendingSubmissions.delete(state);
|
|
16606
|
-
this.#switching.add(state);
|
|
16477
|
+
const next = JSON.stringify(detail);
|
|
16478
|
+
if (next === last) return;
|
|
16479
|
+
last = next;
|
|
16480
|
+
chatVoiceDebug("native-chat-state", detail);
|
|
16481
|
+
};
|
|
16482
|
+
const unsubscribe = store.subscribe(report);
|
|
16483
|
+
report();
|
|
16484
|
+
return unsubscribe;
|
|
16485
|
+
}
|
|
16486
|
+
|
|
16487
|
+
// src/renderer-native-chat-voice-selection.ts
|
|
16488
|
+
var UUID = /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i;
|
|
16489
|
+
function nativeChatVoiceDraftSelection(binding, initial, shared, origin, signal) {
|
|
16490
|
+
const draft = binding.props.conversationId;
|
|
16491
|
+
const navigate = initial.Nir;
|
|
16492
|
+
const conversationPath = shared.Vot;
|
|
16493
|
+
if (binding.backendConversationId !== void 0 || !draft.startsWith("local-chatgpt:") || !UUID.test(draft.slice("local-chatgpt:".length)) || origin == null || initial.Ycr == null || initial.n0n == null || initial.Y1n == null || typeof navigate !== "function" || typeof conversationPath !== "function")
|
|
16494
|
+
return () => {
|
|
16495
|
+
};
|
|
16496
|
+
const store = Reflect.apply(initial.SPn, void 0, [
|
|
16497
|
+
binding.scope
|
|
16498
|
+
]);
|
|
16499
|
+
const stateAtStart = store.getState();
|
|
16500
|
+
const readIntentVersion = typeof initial.HJt === "function" ? () => Reflect.apply(initial.HJt, void 0, [binding.scope]) : void 0;
|
|
16501
|
+
const version2 = readIntentVersion?.();
|
|
16502
|
+
const intentVersion = typeof version2 === "number" && Number.isSafeInteger(version2) && version2 > 0 ? version2 : void 0;
|
|
16503
|
+
let session = stateAtStart.voiceSessionId;
|
|
16504
|
+
let activeSeen = stateAtStart.isVoiceModeActive;
|
|
16505
|
+
let sessionStartedSeen = stateAtStart.hasVoiceSessionStarted;
|
|
16506
|
+
let finished = false;
|
|
16507
|
+
return () => {
|
|
16508
|
+
if (finished) return;
|
|
16607
16509
|
try {
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
if (!operations.applyAgent(state.agent))
|
|
16613
|
-
throw new Error("Draft Agent switch could not restore the prior Agent", { cause: error51 });
|
|
16614
|
-
return false;
|
|
16510
|
+
const state = store.getState();
|
|
16511
|
+
if (signal.aborted || binding.scope.get(initial.Ycr) !== origin || intentVersion !== void 0 && readIntentVersion?.() !== intentVersion || activeSeen && (!state.isVoiceModeActive || state.voiceSessionId !== session && (sessionStartedSeen || intentVersion === void 0))) {
|
|
16512
|
+
finished = true;
|
|
16513
|
+
return;
|
|
16615
16514
|
}
|
|
16616
|
-
state.
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16515
|
+
if (!state.isVoiceModeActive) return;
|
|
16516
|
+
if (!activeSeen) {
|
|
16517
|
+
session = state.voiceSessionId;
|
|
16518
|
+
activeSeen = true;
|
|
16519
|
+
}
|
|
16520
|
+
if (session !== state.voiceSessionId) {
|
|
16521
|
+
session = state.voiceSessionId;
|
|
16522
|
+
chatVoiceDebug("native-chat-selection-startup-id-adopted");
|
|
16523
|
+
}
|
|
16524
|
+
sessionStartedSeen ||= state.hasVoiceSessionStarted;
|
|
16525
|
+
if (state.isWorkMode !== false || state.conversationId !== draft) {
|
|
16526
|
+
finished = true;
|
|
16527
|
+
return;
|
|
16528
|
+
}
|
|
16529
|
+
if (!state.hasVoiceSessionStarted || state.server.connectionState !== "connected") return;
|
|
16530
|
+
const backend = binding.scope.get(initial.B1n, draft);
|
|
16531
|
+
if (typeof backend !== "string" || !UUID.test(backend)) return;
|
|
16532
|
+
const mapping = binding.scope.get(initial.n0n, draft);
|
|
16533
|
+
const currentNode = binding.scope.get(initial.Y1n, draft);
|
|
16534
|
+
if (mapping == null || typeof mapping !== "object" || typeof currentNode !== "string" || !mapping[currentNode]?.message)
|
|
16535
|
+
return;
|
|
16536
|
+
finished = true;
|
|
16537
|
+
const path = Reflect.apply(conversationPath, void 0, [draft]);
|
|
16538
|
+
const accepted = Reflect.apply(navigate, void 0, [binding.scope, path]);
|
|
16539
|
+
void Promise.resolve(accepted).then(
|
|
16540
|
+
(result) => chatVoiceDebug(
|
|
16541
|
+
result === false ? "native-chat-selection-declined" : "native-chat-draft-selection-requested"
|
|
16542
|
+
),
|
|
16543
|
+
() => chatVoiceDebug("native-chat-selection-failed")
|
|
16544
|
+
);
|
|
16545
|
+
} catch {
|
|
16546
|
+
finished = true;
|
|
16547
|
+
chatVoiceDebug("native-chat-selection-failed");
|
|
16620
16548
|
}
|
|
16621
|
-
}
|
|
16622
|
-
#targetState(target) {
|
|
16623
|
-
if (!isIdentifiedTarget(target)) return null;
|
|
16624
|
-
return this.#targetStates.find((candidate) => sameTarget(candidate.target, target))?.state ?? null;
|
|
16625
|
-
}
|
|
16626
|
-
#state(composer, initialAgent) {
|
|
16627
|
-
const existing = this.#states.get(composer);
|
|
16628
|
-
if (existing) return existing;
|
|
16629
|
-
const created = {
|
|
16630
|
-
agent: initialAgent ?? this.#defaultAgent,
|
|
16631
|
-
phase: "draft",
|
|
16632
|
-
composerId: this.#idFactory(++this.#composerSequence)
|
|
16633
|
-
};
|
|
16634
|
-
this.#states.set(composer, created);
|
|
16635
|
-
return created;
|
|
16636
|
-
}
|
|
16637
|
-
};
|
|
16638
|
-
|
|
16639
|
-
// src/renderer-new-thread-preference.ts
|
|
16640
|
-
var RENDERER_NEW_THREAD_PREFERENCE_KEY = "codexhost.new-thread-preference.v1";
|
|
16641
|
-
function rendererNewThreadPreferenceStorage(hostId2 = "local") {
|
|
16642
|
-
if (!hostId2) return null;
|
|
16643
|
-
try {
|
|
16644
|
-
const storage = window.localStorage;
|
|
16645
|
-
if (hostId2 === "local") return storage;
|
|
16646
|
-
const scopedKey = (key) => `${key}.host.${encodeURIComponent(hostId2)}`;
|
|
16647
|
-
return {
|
|
16648
|
-
getItem: (key) => storage.getItem(scopedKey(key)),
|
|
16649
|
-
setItem: (key, value) => storage.setItem(scopedKey(key), value)
|
|
16650
|
-
};
|
|
16651
|
-
} catch {
|
|
16652
|
-
return null;
|
|
16653
|
-
}
|
|
16549
|
+
};
|
|
16654
16550
|
}
|
|
16655
|
-
|
|
16656
|
-
|
|
16551
|
+
|
|
16552
|
+
// src/renderer-native-chat-voice-presentation.ts
|
|
16553
|
+
function alignNativeChatVoiceButton(button2, send, doc) {
|
|
16554
|
+
const parent = send.parentElement;
|
|
16555
|
+
if (!parent) return;
|
|
16556
|
+
const layout = doc.defaultView?.getComputedStyle(parent);
|
|
16557
|
+
const gap = layout && /flex|grid/.test(layout.display) ? Number.parseFloat(layout.columnGap) || 0 : 0;
|
|
16558
|
+
const margin = `max(0px, calc(var(--spacing, 0.25rem) * 2 - ${gap}px))`;
|
|
16559
|
+
if (button2.style.marginInlineEnd !== margin) button2.style.marginInlineEnd = margin;
|
|
16560
|
+
if (button2.style.alignSelf !== "center") button2.style.alignSelf = "center";
|
|
16657
16561
|
}
|
|
16658
|
-
function
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
return
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
|
|
16562
|
+
function hideNativeChatVoiceHomeHeadline(doc) {
|
|
16563
|
+
const headlines = [
|
|
16564
|
+
...doc.querySelectorAll('[style*="--vt-splash-screen-headline"]')
|
|
16565
|
+
].filter(
|
|
16566
|
+
(element) => element.querySelector("h1 [data-headline]") && element.getBoundingClientRect().width > 0 && !element.closest("[hidden], [inert]")
|
|
16567
|
+
);
|
|
16568
|
+
if (headlines.length !== 1) return;
|
|
16569
|
+
const headline = headlines[0];
|
|
16570
|
+
if (!headline) return;
|
|
16571
|
+
const previous = headline.style.getPropertyValue("visibility");
|
|
16572
|
+
const priority = headline.style.getPropertyPriority("visibility");
|
|
16573
|
+
headline.style.setProperty("visibility", "hidden", "important");
|
|
16574
|
+
return () => {
|
|
16575
|
+
if (headline.style.getPropertyValue("visibility") === "hidden" && headline.style.getPropertyPriority("visibility") === "important")
|
|
16576
|
+
headline.style.setProperty("visibility", previous, priority);
|
|
16577
|
+
};
|
|
16578
|
+
}
|
|
16579
|
+
|
|
16580
|
+
// src/renderer-native-chat-voice.ts
|
|
16581
|
+
var HOOK_GLOBAL = "__codexhostNativeChatVoiceV1";
|
|
16582
|
+
var NATIVE_CHAT_VOICE_VERSION = "26.1016.62342";
|
|
16583
|
+
var NATIVE_CHAT_INITIAL_ASSET = "app-initial-dddef47d6ef6.js";
|
|
16584
|
+
var NATIVE_CHAT_SHARED_ASSET = "app-shared-fc3316d48427.js";
|
|
16585
|
+
var START_ASSET = "start-voice-7cbf0a39d53b.js";
|
|
16586
|
+
var PREWARM_ASSET = "voice-prewarm-5d107129ac1c.js";
|
|
16587
|
+
var NATIVE_CHAT_VOICE_ASSETS = [
|
|
16588
|
+
{
|
|
16589
|
+
version: NATIVE_CHAT_VOICE_VERSION,
|
|
16590
|
+
initial: NATIVE_CHAT_INITIAL_ASSET,
|
|
16591
|
+
shared: NATIVE_CHAT_SHARED_ASSET,
|
|
16592
|
+
start: START_ASSET,
|
|
16593
|
+
prewarm: PREWARM_ASSET
|
|
16594
|
+
},
|
|
16595
|
+
{
|
|
16596
|
+
version: "26.1016.61520",
|
|
16597
|
+
initial: "app-initial-c95ddb62696e.js",
|
|
16598
|
+
shared: "app-shared-2eda13eb7044.js",
|
|
16599
|
+
start: "start-voice-18b08f0acdd7.js",
|
|
16600
|
+
prewarm: "voice-prewarm-94271e581c1b.js"
|
|
16601
|
+
}
|
|
16602
|
+
];
|
|
16603
|
+
var BUTTON = "data-codexhost-chat-voice-start";
|
|
16604
|
+
var CONVERSATION_UUID = /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i;
|
|
16605
|
+
var record2 = (value) => value !== null && typeof value === "object";
|
|
16606
|
+
function scopeRefs(owner, definition) {
|
|
16607
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
16608
|
+
let hook = owner.memoizedState;
|
|
16609
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16610
|
+
while (record2(hook) && seen.size < 4096 && !seen.has(hook)) {
|
|
16611
|
+
seen.add(hook);
|
|
16612
|
+
const state = hook.memoizedState;
|
|
16613
|
+
const scope = record2(state) ? state.current : void 0;
|
|
16614
|
+
if (record2(scope) && scope.scope === definition && typeof scope.get === "function" && typeof scope.set === "function" && scope.chain instanceof Map && scope.chain.get(definition.id) === scope.node)
|
|
16615
|
+
scopes.set(scope.node, scope);
|
|
16616
|
+
hook = hook.next;
|
|
16617
|
+
}
|
|
16618
|
+
return hook == null ? scopes : /* @__PURE__ */ new Map();
|
|
16619
|
+
}
|
|
16620
|
+
function detectNativeChatVoiceBinding(composer, native) {
|
|
16621
|
+
const key = Object.getOwnPropertyNames(composer).find((key2) => key2.startsWith("__reactFiber$"));
|
|
16622
|
+
if (!key) return;
|
|
16623
|
+
const ancestors = committedReactAncestors(Object.getOwnPropertyDescriptor(composer, key)?.value);
|
|
16624
|
+
for (const owner of ancestors) {
|
|
16625
|
+
const props = owner.memoizedProps;
|
|
16626
|
+
if (!record2(props) || typeof props.isWorkConversation !== "boolean" || typeof props.isTemporaryChat !== "boolean" || typeof props.conversationId !== "string")
|
|
16627
|
+
continue;
|
|
16628
|
+
if (props.isWorkConversation || props.isTemporaryChat || props.shouldBlockExternalEgress !== false || props.readOnly === true || !record2(props.composerSelectionContext) || props.composerSelectionContext.conversationId !== props.conversationId)
|
|
16629
|
+
return;
|
|
16630
|
+
const scopes = scopeRefs(owner, native.ownerScopeDefinition);
|
|
16631
|
+
if (scopes.size !== 1) return;
|
|
16632
|
+
const scope = [...scopes.values()][0];
|
|
16633
|
+
if (!scope) return;
|
|
16634
|
+
const appNode = scope.chain.get(native.scopeDefinition.id);
|
|
16635
|
+
if (!record2(appNode)) return;
|
|
16636
|
+
const backendId = scope.get(native.backendConversationId, props.conversationId);
|
|
16637
|
+
const hasBackendId = typeof backendId === "string" && CONVERSATION_UUID.test(backendId);
|
|
16638
|
+
const isDraft = backendId == null && props.conversationId.startsWith("local-chatgpt:") && CONVERSATION_UUID.test(props.conversationId.slice("local-chatgpt:".length));
|
|
16639
|
+
if (!hasBackendId && !isDraft) return;
|
|
16640
|
+
const provider = ancestors.slice(0, ancestors.indexOf(owner)).find(
|
|
16641
|
+
(fiber) => fiber.tag === 10 && record2(fiber.type) && fiber.type.displayName === native.composerScopeDefinition.__scopeBrand
|
|
16642
|
+
);
|
|
16643
|
+
if (!provider) return;
|
|
16644
|
+
const composerChain = record2(provider.memoizedProps) ? provider.memoizedProps.value : void 0;
|
|
16645
|
+
const composerNode = composerChain instanceof Map ? composerChain.get(native.composerScopeDefinition.id) : void 0;
|
|
16646
|
+
if (!(composerChain instanceof Map) || composerChain.get(native.scopeDefinition.id) !== appNode || composerChain.get(native.ownerScopeDefinition.id) !== scope.node || !record2(composerNode) || composerNode.token !== native.composerScopeDefinition || !record2(composerNode.value) || composerNode.value.kind !== "chatgpt" || !record2(composerNode.value.chatGptSelectionContext) || composerNode.value.chatGptSelectionContext.conversationId !== props.conversationId)
|
|
16647
|
+
return;
|
|
16648
|
+
const composerContext = { context: provider.type, chain: composerChain };
|
|
16649
|
+
const contexts = /* @__PURE__ */ new Set();
|
|
16650
|
+
for (const fiber of ancestors) {
|
|
16651
|
+
let dependency = record2(fiber.dependencies) ? fiber.dependencies.firstContext : void 0;
|
|
16652
|
+
const seenDependencies = /* @__PURE__ */ new Set();
|
|
16653
|
+
while (record2(dependency) && seenDependencies.size < 4096 && !seenDependencies.has(dependency)) {
|
|
16654
|
+
seenDependencies.add(dependency);
|
|
16655
|
+
const context = dependency.context;
|
|
16656
|
+
const chain = dependency.memoizedValue;
|
|
16657
|
+
if (record2(context) && context.displayName === native.scopeDefinition.__scopeBrand && chain instanceof Map && chain.get(native.scopeDefinition.id) === appNode)
|
|
16658
|
+
contexts.add(context);
|
|
16659
|
+
dependency = dependency.next;
|
|
16660
|
+
}
|
|
16661
|
+
}
|
|
16662
|
+
if (contexts.size !== 1) return;
|
|
16663
|
+
return {
|
|
16664
|
+
composer,
|
|
16665
|
+
appNode,
|
|
16666
|
+
props,
|
|
16667
|
+
scope,
|
|
16668
|
+
context: [...contexts][0],
|
|
16669
|
+
composerContext,
|
|
16670
|
+
backendConversationId: hasBackendId ? backendId : void 0
|
|
16671
|
+
};
|
|
16672
|
+
}
|
|
16673
|
+
}
|
|
16674
|
+
function startNativeChatVoiceForRequest(request, target = globalThis) {
|
|
16675
|
+
if (!record2(request) || request.productExperience !== "chat" || !nativeChatVoicePreferenceAllowsStart(target))
|
|
16676
|
+
return;
|
|
16677
|
+
const hook = target[HOOK_GLOBAL];
|
|
16678
|
+
if (!hook || hook.status === "disabled" || hook.status === "unsupported")
|
|
16679
|
+
return Promise.reject(new Error("Native Chat voice is unavailable"));
|
|
16680
|
+
return hook.start();
|
|
16681
|
+
}
|
|
16682
|
+
function installNativeChatVoiceHook(options = {}) {
|
|
16683
|
+
const target = options.target ?? globalThis;
|
|
16684
|
+
const existing = target[HOOK_GLOBAL];
|
|
16685
|
+
if (existing) return existing;
|
|
16686
|
+
const config2 = readCpaLiveVoiceHookConfig(target);
|
|
16687
|
+
const unavailable = (status) => ({
|
|
16688
|
+
status,
|
|
16689
|
+
dispose() {
|
|
16690
|
+
},
|
|
16691
|
+
start: async () => {
|
|
16692
|
+
throw new Error("Native Chat voice is unavailable");
|
|
16693
|
+
}
|
|
16694
|
+
});
|
|
16695
|
+
if (!config2) return unavailable("disabled");
|
|
16696
|
+
if (!supportsVoiceVersion(NATIVE_CHAT_VOICE_ASSETS, config2.desktopVersion))
|
|
16697
|
+
return unavailable("unsupported");
|
|
16698
|
+
const doc = target.document;
|
|
16699
|
+
if (!doc) return unavailable("unsupported");
|
|
16700
|
+
const importModule = options.importModule ?? ((url2) => import(url2));
|
|
16701
|
+
let disposed = false;
|
|
16702
|
+
let timer;
|
|
16703
|
+
let modules;
|
|
16704
|
+
let boundScope;
|
|
16705
|
+
let mounted;
|
|
16706
|
+
let button2;
|
|
16707
|
+
const overlayButtons = /* @__PURE__ */ new Map();
|
|
16708
|
+
let controller;
|
|
16709
|
+
let starting = false;
|
|
16710
|
+
let selectDraft;
|
|
16711
|
+
let restoreHeadline;
|
|
16712
|
+
let renderFailed = false;
|
|
16713
|
+
const started = Date.now();
|
|
16714
|
+
const showHeadline = () => {
|
|
16715
|
+
restoreHeadline?.();
|
|
16716
|
+
restoreHeadline = void 0;
|
|
16717
|
+
};
|
|
16718
|
+
const removeButton = () => {
|
|
16719
|
+
button2?.remove();
|
|
16720
|
+
button2 = void 0;
|
|
16721
|
+
for (const [control, [display, priority]] of overlayButtons)
|
|
16722
|
+
if (control.style.getPropertyValue("display") === "none" && control.style.getPropertyPriority("display") === "important")
|
|
16723
|
+
control.style.setProperty("display", display, priority);
|
|
16724
|
+
overlayButtons.clear();
|
|
16725
|
+
};
|
|
16726
|
+
const release = () => {
|
|
16727
|
+
showHeadline();
|
|
16728
|
+
selectDraft = void 0;
|
|
16729
|
+
controller?.abort();
|
|
16730
|
+
controller = void 0;
|
|
16731
|
+
removeButton();
|
|
16732
|
+
mounted?.dispose();
|
|
16733
|
+
mounted = void 0;
|
|
16734
|
+
boundScope = void 0;
|
|
16735
|
+
};
|
|
16736
|
+
const findBinding = () => {
|
|
16737
|
+
if (!modules || !nativeChatVoicePreferenceAllowsStart(target)) return;
|
|
16738
|
+
const forms = [...doc.querySelectorAll("[data-chatgpt-composer]")].filter(
|
|
16739
|
+
(form2) => form2.getBoundingClientRect().width > 0 && !form2.closest("[hidden], [inert]")
|
|
16740
|
+
);
|
|
16741
|
+
if (forms.length !== 1) return;
|
|
16742
|
+
const form = forms[0];
|
|
16743
|
+
if (!form) return;
|
|
16744
|
+
return detectNativeChatVoiceBinding(form, {
|
|
16745
|
+
scopeDefinition: modules.shared.Qst,
|
|
16746
|
+
ownerScopeDefinition: modules.initial.MOr,
|
|
16747
|
+
backendConversationId: modules.initial.B1n,
|
|
16748
|
+
composerScopeDefinition: modules.initial.CDr
|
|
16749
|
+
});
|
|
16750
|
+
};
|
|
16751
|
+
const handle = {
|
|
16752
|
+
get activeCall() {
|
|
16753
|
+
if (starting) return true;
|
|
16754
|
+
if (!boundScope || !modules || typeof modules.initial.SPn !== "function") return false;
|
|
16755
|
+
try {
|
|
16756
|
+
return modules.initial.SPn(boundScope).getState().isVoiceModeActive;
|
|
16757
|
+
} catch {
|
|
16758
|
+
return false;
|
|
16759
|
+
}
|
|
16760
|
+
},
|
|
16761
|
+
status: "pending",
|
|
16762
|
+
async start() {
|
|
16763
|
+
if (disposed || starting) return;
|
|
16764
|
+
const current = findBinding();
|
|
16765
|
+
if (!current || !modules || current.appNode !== mounted?.node)
|
|
16766
|
+
throw new Error("Select a ChatGPT conversation to start Chat voice");
|
|
16767
|
+
starting = true;
|
|
16768
|
+
controller = new AbortController();
|
|
16769
|
+
const signal = controller.signal;
|
|
16770
|
+
let origin;
|
|
16771
|
+
try {
|
|
16772
|
+
if (modules.initial.Ycr != null) origin = current.scope.get(modules.initial.Ycr);
|
|
16773
|
+
} catch {
|
|
16774
|
+
chatVoiceDebug("native-chat-selection-failed");
|
|
16775
|
+
}
|
|
16776
|
+
selectDraft = void 0;
|
|
16777
|
+
chatVoiceDebug("native-chat-start", {
|
|
16778
|
+
hasConversationId: current.backendConversationId !== void 0
|
|
16779
|
+
});
|
|
16780
|
+
try {
|
|
16781
|
+
await Reflect.apply(modules.start.n, void 0, [
|
|
16782
|
+
current.scope,
|
|
16783
|
+
current.props,
|
|
16784
|
+
{ event_source: "composer" },
|
|
16785
|
+
signal
|
|
16786
|
+
]);
|
|
16787
|
+
chatVoiceDebug("native-chat-start-returned");
|
|
16788
|
+
try {
|
|
16789
|
+
selectDraft = nativeChatVoiceDraftSelection(
|
|
16790
|
+
current,
|
|
16791
|
+
modules.initial,
|
|
16792
|
+
modules.shared,
|
|
16793
|
+
origin,
|
|
16794
|
+
signal
|
|
16795
|
+
);
|
|
16796
|
+
selectDraft();
|
|
16797
|
+
} catch {
|
|
16798
|
+
chatVoiceDebug("native-chat-selection-failed");
|
|
16799
|
+
}
|
|
16800
|
+
} catch {
|
|
16801
|
+
chatVoiceDebug("native-chat-start-failed");
|
|
16802
|
+
throw new Error("Native Chat voice could not start");
|
|
16803
|
+
} finally {
|
|
16804
|
+
starting = false;
|
|
16805
|
+
}
|
|
16806
|
+
},
|
|
16807
|
+
dispose() {
|
|
16808
|
+
disposed = true;
|
|
16809
|
+
if (timer !== void 0) target.clearTimeout(timer);
|
|
16810
|
+
release();
|
|
16811
|
+
if (target[HOOK_GLOBAL] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL);
|
|
16812
|
+
}
|
|
16813
|
+
};
|
|
16814
|
+
target[HOOK_GLOBAL] = handle;
|
|
16815
|
+
const refresh = async () => {
|
|
16816
|
+
if (disposed) return;
|
|
16817
|
+
try {
|
|
16818
|
+
if (renderFailed) throw new Error();
|
|
16819
|
+
if (!modules) {
|
|
16820
|
+
const names = loadedAssetNames(doc, target.performance);
|
|
16821
|
+
const assets = selectVoiceAssets(NATIVE_CHAT_VOICE_ASSETS, names, config2.desktopVersion);
|
|
16822
|
+
if (!assets) {
|
|
16823
|
+
if (Date.now() - started >= 6e4) {
|
|
16824
|
+
handle.status = "unsupported";
|
|
16825
|
+
return;
|
|
16826
|
+
}
|
|
16827
|
+
return;
|
|
16828
|
+
}
|
|
16829
|
+
const [shared, initial, start, prewarm] = await Promise.all(
|
|
16830
|
+
[assets.shared, assets.initial, assets.start, assets.prewarm].map(
|
|
16831
|
+
(asset) => importModule(`app://-/assets/${asset}`)
|
|
16832
|
+
)
|
|
16833
|
+
);
|
|
16834
|
+
if (disposed) return;
|
|
16835
|
+
if (!shared || !initial || !start || !prewarm || typeof start.t !== "function" || typeof start.n !== "function" || typeof initial.oT !== "function" || typeof initial.SPn !== "function" || typeof shared.FBt !== "function" || typeof shared.PNt !== "function" || typeof prewarm.VoiceInstantConnectCacheController !== "function")
|
|
16836
|
+
throw new Error();
|
|
16837
|
+
initial.oT();
|
|
16838
|
+
start.t();
|
|
16839
|
+
if (!record2(shared.Qst) || !record2(initial.MOr) || !initial.B1n || !initial.aT || !record2(initial.CDr))
|
|
16840
|
+
throw new Error();
|
|
16841
|
+
modules = { shared, initial, start, prewarm };
|
|
16842
|
+
}
|
|
16843
|
+
const current = findBinding();
|
|
16844
|
+
selectDraft?.();
|
|
16845
|
+
if (!current) {
|
|
16846
|
+
showHeadline();
|
|
16847
|
+
if (handle.activeCall) return;
|
|
16848
|
+
release();
|
|
16849
|
+
handle.status = "pending";
|
|
16850
|
+
return;
|
|
16851
|
+
}
|
|
16852
|
+
if (mounted && current.appNode !== mounted.node) release();
|
|
16853
|
+
boundScope = current.scope;
|
|
16854
|
+
if (!mounted) {
|
|
16855
|
+
const { scope } = current;
|
|
16856
|
+
const initial = modules.initial;
|
|
16857
|
+
const previous = scope.get(initial.aT);
|
|
16858
|
+
const container = doc.createElement("div");
|
|
16859
|
+
container.setAttribute("data-codexhost-chat-voice-prewarm", "");
|
|
16860
|
+
doc.body.append(container);
|
|
16861
|
+
const react = Reflect.apply(modules.shared.FBt, void 0, []);
|
|
16862
|
+
const reactDom = Reflect.apply(modules.shared.PNt, void 0, []);
|
|
16863
|
+
const root = reactDom.createRoot(container, {
|
|
16864
|
+
onUncaughtError() {
|
|
16865
|
+
renderFailed = true;
|
|
16866
|
+
}
|
|
16867
|
+
});
|
|
16868
|
+
const stopObserving = observeNativeChatVoiceState(scope, initial);
|
|
16869
|
+
let appChain;
|
|
16870
|
+
let composerChain;
|
|
16871
|
+
mounted = {
|
|
16872
|
+
node: current.appNode,
|
|
16873
|
+
render(next) {
|
|
16874
|
+
if (appChain === next.scope.chain && composerChain === next.composerContext.chain)
|
|
16875
|
+
return;
|
|
16876
|
+
appChain = next.scope.chain;
|
|
16877
|
+
composerChain = next.composerContext.chain;
|
|
16878
|
+
root.render(
|
|
16879
|
+
react.createElement(
|
|
16880
|
+
next.context,
|
|
16881
|
+
{ value: appChain },
|
|
16882
|
+
react.createElement(
|
|
16883
|
+
next.composerContext.context,
|
|
16884
|
+
{ value: composerChain },
|
|
16885
|
+
react.createElement(modules?.prewarm.VoiceInstantConnectCacheController, null)
|
|
16886
|
+
)
|
|
16887
|
+
)
|
|
16888
|
+
);
|
|
16889
|
+
},
|
|
16890
|
+
dispose() {
|
|
16891
|
+
stopObserving();
|
|
16892
|
+
root.unmount();
|
|
16893
|
+
container.remove();
|
|
16894
|
+
if (scope.get(initial.aT) === true) scope.set(initial.aT, previous);
|
|
16895
|
+
chatVoiceDebug("native-chat-unbound");
|
|
16896
|
+
}
|
|
16897
|
+
};
|
|
16898
|
+
scope.set(initial.aT, true);
|
|
16899
|
+
chatVoiceDebug("native-chat-bound", {
|
|
16900
|
+
hasConversationId: current.backendConversationId !== void 0
|
|
16901
|
+
});
|
|
16902
|
+
}
|
|
16903
|
+
mounted.render(current);
|
|
16904
|
+
const voiceState = Reflect.apply(modules.initial.SPn, void 0, [
|
|
16905
|
+
current.scope
|
|
16906
|
+
]).getState();
|
|
16907
|
+
if (current.props.conversationId.startsWith("local-chatgpt:") && voiceState.isVoiceModeActive && voiceState.isWorkMode === false && voiceState.conversationId === current.props.conversationId)
|
|
16908
|
+
restoreHeadline ??= hideNativeChatVoiceHomeHeadline(doc);
|
|
16909
|
+
else showHeadline();
|
|
16910
|
+
const sends = [
|
|
16911
|
+
...current.composer.querySelectorAll('button[type="submit"]')
|
|
16912
|
+
].filter(
|
|
16913
|
+
(control) => control.getBoundingClientRect().width > 0 && !control.closest("[hidden], [inert]")
|
|
16914
|
+
);
|
|
16915
|
+
const send = sends.length === 1 ? sends[0] : void 0;
|
|
16916
|
+
if (!send?.parentElement) removeButton();
|
|
16917
|
+
else {
|
|
16918
|
+
if (!button2 || !current.composer.contains(button2)) {
|
|
16919
|
+
removeButton();
|
|
16920
|
+
button2 = doc.createElement("button");
|
|
16921
|
+
button2.type = "button";
|
|
16922
|
+
button2.setAttribute(BUTTON, "");
|
|
16923
|
+
button2.setAttribute("aria-label", "Start Voice");
|
|
16924
|
+
button2.title = "Start Voice";
|
|
16925
|
+
button2.innerHTML = '<svg class="icon-primary-action text-composer-primary" width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M3 8v4m4-7v10m6-12v14m4-9v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>';
|
|
16926
|
+
button2.addEventListener("click", () => {
|
|
16927
|
+
void handle.start().catch(() => {
|
|
16928
|
+
if (button2) button2.title = "Chat voice could not start. Try again.";
|
|
16929
|
+
});
|
|
16930
|
+
});
|
|
16931
|
+
}
|
|
16932
|
+
if (button2.nextElementSibling !== send) send.parentElement.insertBefore(button2, send);
|
|
16933
|
+
alignNativeChatVoiceButton(button2, send, doc);
|
|
16934
|
+
}
|
|
16935
|
+
if (button2)
|
|
16936
|
+
for (const control of current.composer.querySelectorAll(
|
|
16937
|
+
'button[aria-label="Start new voice chat"], button[aria-label="Start voice chat"]'
|
|
16938
|
+
)) {
|
|
16939
|
+
if (!overlayButtons.has(control))
|
|
16940
|
+
overlayButtons.set(control, [
|
|
16941
|
+
control.style.getPropertyValue("display"),
|
|
16942
|
+
control.style.getPropertyPriority("display")
|
|
16943
|
+
]);
|
|
16944
|
+
control.style.setProperty("display", "none", "important");
|
|
16945
|
+
}
|
|
16946
|
+
if (button2 && send) {
|
|
16947
|
+
button2.disabled = starting || current.props.isStreaming === true || voiceState.isVoiceModeActive;
|
|
16948
|
+
const className = [
|
|
16949
|
+
...send.className.split(/\s+/).filter((name) => name !== "opacity-50" && name !== "cursor-default"),
|
|
16950
|
+
...button2.disabled ? ["opacity-50", "cursor-default"] : []
|
|
16951
|
+
].join(" ");
|
|
16952
|
+
if (button2.className !== className) button2.className = className;
|
|
16953
|
+
}
|
|
16954
|
+
handle.status = "active";
|
|
16955
|
+
} catch {
|
|
16956
|
+
release();
|
|
16957
|
+
handle.status = "unsupported";
|
|
16958
|
+
chatVoiceDebug("native-chat-binding-failed");
|
|
16959
|
+
return;
|
|
16960
|
+
} finally {
|
|
16961
|
+
if (!disposed && handle.status !== "unsupported")
|
|
16962
|
+
timer = target.setTimeout(() => void refresh(), 500);
|
|
16963
|
+
}
|
|
16964
|
+
};
|
|
16965
|
+
void refresh();
|
|
16966
|
+
return handle;
|
|
16967
|
+
}
|
|
16968
|
+
|
|
16969
|
+
// src/agent-selection-state.ts
|
|
16970
|
+
var DEFAULT_RENDERER_AGENTS = ["codex"];
|
|
16971
|
+
function defaultIdFactory(sequence) {
|
|
16972
|
+
return `codexhost-composer-${Date.now().toString(36)}-${sequence.toString(36)}`;
|
|
16973
|
+
}
|
|
16974
|
+
function isDefaultTarget(target) {
|
|
16975
|
+
return target?.[0] === "default";
|
|
16976
|
+
}
|
|
16977
|
+
function isConversationTarget(target) {
|
|
16978
|
+
return target?.[0] === "conversation";
|
|
16979
|
+
}
|
|
16980
|
+
function isIdentifiedTarget(target) {
|
|
16981
|
+
return target?.[0] === "conversation" || target?.[0] === "default" && typeof target[1] === "string" && target[1].startsWith("client-new-thread:");
|
|
16982
|
+
}
|
|
16983
|
+
function sameTarget(left, right) {
|
|
16984
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
16985
|
+
}
|
|
16986
|
+
var DraftAgentController = class {
|
|
16987
|
+
#idFactory;
|
|
16988
|
+
#defaultAgent;
|
|
16989
|
+
#enabledAgents;
|
|
16990
|
+
#targetStates = [];
|
|
16991
|
+
#modelRequestGenerations = /* @__PURE__ */ new WeakMap();
|
|
16992
|
+
#ownershipRequestGenerations = /* @__PURE__ */ new WeakMap();
|
|
16993
|
+
#states = /* @__PURE__ */ new WeakMap();
|
|
16994
|
+
#switching = /* @__PURE__ */ new Set();
|
|
16995
|
+
#pendingSubmissions = /* @__PURE__ */ new Set();
|
|
16996
|
+
#composerSequence = 0;
|
|
16997
|
+
#modelRequestSequence = 0;
|
|
16998
|
+
#ownershipRequestSequence = 0;
|
|
16999
|
+
#lastSubmittedAgent;
|
|
17000
|
+
constructor(options = {}) {
|
|
17001
|
+
this.#idFactory = options.idFactory ?? defaultIdFactory;
|
|
17002
|
+
this.#enabledAgents = new Set(options.enabledAgents ?? DEFAULT_RENDERER_AGENTS);
|
|
17003
|
+
if (!this.#enabledAgents.has("codex"))
|
|
17004
|
+
throw new Error("Renderer enabled Agents must include Codex");
|
|
17005
|
+
this.#defaultAgent = options.defaultAgent ?? "codex";
|
|
17006
|
+
this.#lastSubmittedAgent = this.#defaultAgent;
|
|
17007
|
+
}
|
|
17008
|
+
setEnabledAgents(agents) {
|
|
17009
|
+
this.#enabledAgents = /* @__PURE__ */ new Set(["codex", ...agents]);
|
|
17010
|
+
}
|
|
17011
|
+
get(composer) {
|
|
17012
|
+
return this.#state(composer);
|
|
17013
|
+
}
|
|
17014
|
+
detach(composer, preservePendingSubmission = false) {
|
|
17015
|
+
const state = this.#states.get(composer);
|
|
17016
|
+
if (state && !preservePendingSubmission) this.#pendingSubmissions.delete(state);
|
|
17017
|
+
this.#states.delete(composer);
|
|
17018
|
+
}
|
|
17019
|
+
mount(composer, target, preferredNewThreadAgent) {
|
|
17020
|
+
const bound = this.#targetState(target);
|
|
17021
|
+
if (bound) {
|
|
17022
|
+
this.#states.set(composer, bound);
|
|
17023
|
+
return bound;
|
|
17024
|
+
}
|
|
17025
|
+
const preferredAgent = preferredNewThreadAgent ?? this.#lastSubmittedAgent;
|
|
17026
|
+
const state = this.#state(composer, isDefaultTarget(target) ? preferredAgent : "codex");
|
|
17027
|
+
if (isIdentifiedTarget(target)) this.#targetStates.push({ target, state });
|
|
17028
|
+
return state;
|
|
17029
|
+
}
|
|
17030
|
+
isSwitching(composer) {
|
|
17031
|
+
return this.#switching.has(this.#state(composer));
|
|
17032
|
+
}
|
|
17033
|
+
beginModelRequest(composer) {
|
|
17034
|
+
const state = this.#state(composer);
|
|
17035
|
+
const generation = ++this.#modelRequestSequence;
|
|
17036
|
+
this.#modelRequestGenerations.set(state, generation);
|
|
17037
|
+
return generation;
|
|
17038
|
+
}
|
|
17039
|
+
invalidateModelRequests(composer) {
|
|
17040
|
+
this.beginModelRequest(composer);
|
|
17041
|
+
}
|
|
17042
|
+
isCurrentModelRequest(composer, generation) {
|
|
17043
|
+
return (this.#modelRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
|
|
17044
|
+
}
|
|
17045
|
+
beginOwnershipRequest(composer) {
|
|
17046
|
+
const generation = ++this.#ownershipRequestSequence;
|
|
17047
|
+
this.#ownershipRequestGenerations.set(this.#state(composer), generation);
|
|
17048
|
+
return generation;
|
|
17049
|
+
}
|
|
17050
|
+
isCurrentOwnershipRequest(composer, generation) {
|
|
17051
|
+
return (this.#ownershipRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
|
|
17052
|
+
}
|
|
17053
|
+
rebindConversation(composer, target) {
|
|
17054
|
+
if (!isConversationTarget(target)) return null;
|
|
17055
|
+
const previous = this.#state(composer);
|
|
17056
|
+
this.#pendingSubmissions.delete(previous);
|
|
17057
|
+
this.#modelRequestGenerations.set(previous, ++this.#modelRequestSequence);
|
|
17058
|
+
this.#ownershipRequestGenerations.set(previous, ++this.#ownershipRequestSequence);
|
|
17059
|
+
let state = this.#targetState(target);
|
|
17060
|
+
if (!state) {
|
|
17061
|
+
state = {
|
|
17062
|
+
agent: "codex",
|
|
17063
|
+
phase: "draft",
|
|
17064
|
+
composerId: this.#idFactory(++this.#composerSequence)
|
|
17065
|
+
};
|
|
17066
|
+
this.#targetStates.push({ target, state });
|
|
17067
|
+
}
|
|
17068
|
+
this.#states.set(composer, state);
|
|
17069
|
+
this.#modelRequestGenerations.set(state, ++this.#modelRequestSequence);
|
|
17070
|
+
this.#ownershipRequestGenerations.set(state, ++this.#ownershipRequestSequence);
|
|
17071
|
+
return state;
|
|
17072
|
+
}
|
|
17073
|
+
restore(composer, agent, model2, thinkingOptionId, permissionModeId) {
|
|
17074
|
+
const state = this.#state(composer);
|
|
17075
|
+
this.#pendingSubmissions.delete(state);
|
|
17076
|
+
state.agent = agent;
|
|
17077
|
+
state.phase = "locked";
|
|
17078
|
+
if (agent !== "codex") {
|
|
17079
|
+
state.configurationByAgent = {
|
|
17080
|
+
...state.configurationByAgent,
|
|
17081
|
+
[agent]: {
|
|
17082
|
+
...model2 ? { model: model2 } : {},
|
|
17083
|
+
...thinkingOptionId ? { thinkingOptionId } : {},
|
|
17084
|
+
...permissionModeId ? { permissionModeId } : {}
|
|
17085
|
+
}
|
|
17086
|
+
};
|
|
17087
|
+
}
|
|
17088
|
+
return state;
|
|
17089
|
+
}
|
|
17090
|
+
clearConfiguration(composer) {
|
|
17091
|
+
delete this.#state(composer).configurationByAgent;
|
|
17092
|
+
}
|
|
17093
|
+
modelForAgent(composer, agent) {
|
|
17094
|
+
return this.#state(composer).configurationByAgent?.[agent]?.model;
|
|
17095
|
+
}
|
|
17096
|
+
thinkingOptionForAgent(composer, agent) {
|
|
17097
|
+
return this.#state(composer).configurationByAgent?.[agent]?.thinkingOptionId;
|
|
17098
|
+
}
|
|
17099
|
+
permissionModeForAgent(composer, agent) {
|
|
17100
|
+
return this.#state(composer).configurationByAgent?.[agent]?.permissionModeId;
|
|
17101
|
+
}
|
|
17102
|
+
setExternalPermissionMode(composer, agent, permissionModeId) {
|
|
17103
|
+
return this.#configure(composer, agent, { permissionModeId });
|
|
17104
|
+
}
|
|
17105
|
+
setExternalModel(composer, agent, model2) {
|
|
17106
|
+
return this.#configure(composer, agent, { model: model2 });
|
|
17107
|
+
}
|
|
17108
|
+
setExternalThinkingOption(composer, agent, thinkingOptionId) {
|
|
17109
|
+
const state = this.#configure(composer, agent, {});
|
|
17110
|
+
const configuration = state.configurationByAgent?.[agent];
|
|
17111
|
+
if (!configuration) return state;
|
|
17112
|
+
if (thinkingOptionId) configuration.thinkingOptionId = thinkingOptionId;
|
|
17113
|
+
else delete configuration.thinkingOptionId;
|
|
17114
|
+
return state;
|
|
17115
|
+
}
|
|
17116
|
+
#configure(composer, agent, patch) {
|
|
17117
|
+
const state = this.#state(composer);
|
|
17118
|
+
state.configurationByAgent = {
|
|
17119
|
+
...state.configurationByAgent,
|
|
17120
|
+
[agent]: { ...state.configurationByAgent?.[agent], ...patch }
|
|
17121
|
+
};
|
|
17122
|
+
return state;
|
|
17123
|
+
}
|
|
17124
|
+
lock(composer) {
|
|
17125
|
+
const state = this.#state(composer);
|
|
17126
|
+
this.#pendingSubmissions.delete(state);
|
|
17127
|
+
state.phase = "locked";
|
|
17128
|
+
return state;
|
|
17129
|
+
}
|
|
17130
|
+
markSubmissionPending(composer) {
|
|
17131
|
+
const state = this.#state(composer);
|
|
17132
|
+
if (state.phase === "draft") this.#pendingSubmissions.add(state);
|
|
17133
|
+
return state;
|
|
17134
|
+
}
|
|
17135
|
+
isSubmissionPending(composer) {
|
|
17136
|
+
return this.#pendingSubmissions.has(this.#state(composer));
|
|
17137
|
+
}
|
|
17138
|
+
clearPendingSubmission(composer) {
|
|
17139
|
+
this.#pendingSubmissions.delete(this.#state(composer));
|
|
17140
|
+
}
|
|
17141
|
+
recordSubmission(composer) {
|
|
17142
|
+
const state = this.#state(composer);
|
|
17143
|
+
this.#lastSubmittedAgent = state.agent;
|
|
17144
|
+
return state;
|
|
17145
|
+
}
|
|
17146
|
+
transfer(source, replacement, target = null) {
|
|
17147
|
+
const state = this.#states.get(source);
|
|
17148
|
+
if (!state) return false;
|
|
17149
|
+
const bound = this.#targetState(target);
|
|
17150
|
+
if (bound && bound !== state) return false;
|
|
17151
|
+
if (source !== replacement) {
|
|
17152
|
+
if (this.#states.has(replacement)) return false;
|
|
17153
|
+
this.#states.set(replacement, state);
|
|
17154
|
+
}
|
|
17155
|
+
if (isIdentifiedTarget(target) && !bound) this.#targetStates.push({ target, state });
|
|
17156
|
+
if (isConversationTarget(target) && this.#pendingSubmissions.delete(state))
|
|
17157
|
+
state.phase = "locked";
|
|
17158
|
+
return true;
|
|
17159
|
+
}
|
|
17160
|
+
async switchAgent(composer, nextAgent, operations) {
|
|
17161
|
+
const state = this.#state(composer);
|
|
17162
|
+
if (!this.#enabledAgents.has(nextAgent)) return false;
|
|
17163
|
+
if (state.phase !== "draft" || this.#switching.has(state)) return false;
|
|
17164
|
+
if (state.agent === nextAgent) return true;
|
|
17165
|
+
this.#pendingSubmissions.delete(state);
|
|
17166
|
+
this.#switching.add(state);
|
|
17167
|
+
try {
|
|
17168
|
+
if (!operations.applyAgent(nextAgent)) return false;
|
|
17169
|
+
try {
|
|
17170
|
+
await operations.clearPrewarm();
|
|
17171
|
+
} catch (error51) {
|
|
17172
|
+
if (!operations.applyAgent(state.agent))
|
|
17173
|
+
throw new Error("Draft Agent switch could not restore the prior Agent", { cause: error51 });
|
|
17174
|
+
return false;
|
|
17175
|
+
}
|
|
17176
|
+
state.agent = nextAgent;
|
|
17177
|
+
return true;
|
|
17178
|
+
} finally {
|
|
17179
|
+
this.#switching.delete(state);
|
|
17180
|
+
}
|
|
17181
|
+
}
|
|
17182
|
+
#targetState(target) {
|
|
17183
|
+
if (!isIdentifiedTarget(target)) return null;
|
|
17184
|
+
return this.#targetStates.find((candidate) => sameTarget(candidate.target, target))?.state ?? null;
|
|
17185
|
+
}
|
|
17186
|
+
#state(composer, initialAgent) {
|
|
17187
|
+
const existing = this.#states.get(composer);
|
|
17188
|
+
if (existing) return existing;
|
|
17189
|
+
const created = {
|
|
17190
|
+
agent: initialAgent ?? this.#defaultAgent,
|
|
17191
|
+
phase: "draft",
|
|
17192
|
+
composerId: this.#idFactory(++this.#composerSequence)
|
|
17193
|
+
};
|
|
17194
|
+
this.#states.set(composer, created);
|
|
17195
|
+
return created;
|
|
17196
|
+
}
|
|
17197
|
+
};
|
|
17198
|
+
|
|
17199
|
+
// src/renderer-new-thread-preference.ts
|
|
17200
|
+
var RENDERER_NEW_THREAD_PREFERENCE_KEY = "codexhost.new-thread-preference.v1";
|
|
17201
|
+
function rendererNewThreadPreferenceStorage(hostId2 = "local") {
|
|
17202
|
+
if (!hostId2) return null;
|
|
17203
|
+
try {
|
|
17204
|
+
const storage = window.localStorage;
|
|
17205
|
+
if (hostId2 === "local") return storage;
|
|
17206
|
+
const scopedKey = (key) => `${key}.host.${encodeURIComponent(hostId2)}`;
|
|
17207
|
+
return {
|
|
17208
|
+
getItem: (key) => storage.getItem(scopedKey(key)),
|
|
17209
|
+
setItem: (key, value) => storage.setItem(scopedKey(key), value)
|
|
17210
|
+
};
|
|
17211
|
+
} catch {
|
|
17212
|
+
return null;
|
|
17213
|
+
}
|
|
17214
|
+
}
|
|
17215
|
+
function isRecord2(value) {
|
|
17216
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17217
|
+
}
|
|
17218
|
+
function parseExternalConfiguration(value) {
|
|
17219
|
+
if (!isRecord2(value)) return void 0;
|
|
17220
|
+
const model2 = harnessModelRefSchema.safeParse(value.model);
|
|
17221
|
+
if (!model2.success) return void 0;
|
|
17222
|
+
const thinkingOptionId = harnessThinkingOptionIdSchema.safeParse(value.thinkingOptionId);
|
|
17223
|
+
const permissionModeId = harnessPermissionModeIdSchema.safeParse(value.permissionModeId);
|
|
17224
|
+
return {
|
|
17225
|
+
model: model2.data,
|
|
17226
|
+
...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {},
|
|
17227
|
+
...permissionModeId.success ? { permissionModeId: permissionModeId.data } : {}
|
|
16668
17228
|
};
|
|
16669
17229
|
}
|
|
16670
17230
|
function readPreference(storage) {
|
|
@@ -16747,14 +17307,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16747
17307
|
}
|
|
16748
17308
|
|
|
16749
17309
|
// src/renderer-client-owned-voice.ts
|
|
16750
|
-
var CLIENT_OWNED_VOICE_VERSION = "26.
|
|
16751
|
-
var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-
|
|
16752
|
-
var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-
|
|
16753
|
-
var
|
|
17310
|
+
var CLIENT_OWNED_VOICE_VERSION = "26.1016.62342";
|
|
17311
|
+
var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-dddef47d6ef6.js";
|
|
17312
|
+
var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-fc3316d48427.js";
|
|
17313
|
+
var CLIENT_OWNED_VOICE_SERVICES = "ist";
|
|
17314
|
+
var CLIENT_OWNED_VOICE_OVERLAY_ASSET = "avatar-overlay-native-page-ef8332c6a2fb.js";
|
|
17315
|
+
var CLIENT_OWNED_VOICE_ASSETS = [
|
|
17316
|
+
{
|
|
17317
|
+
version: CLIENT_OWNED_VOICE_VERSION,
|
|
17318
|
+
initial: CLIENT_OWNED_VOICE_INITIAL_ASSET,
|
|
17319
|
+
shared: CLIENT_OWNED_VOICE_SHARED_ASSET,
|
|
17320
|
+
overlay: CLIENT_OWNED_VOICE_OVERLAY_ASSET
|
|
17321
|
+
},
|
|
17322
|
+
{
|
|
17323
|
+
version: "26.1016.61520",
|
|
17324
|
+
initial: "app-initial-c95ddb62696e.js",
|
|
17325
|
+
shared: "app-shared-2eda13eb7044.js",
|
|
17326
|
+
overlay: "avatar-overlay-native-page-fcc17283519a.js"
|
|
17327
|
+
}
|
|
17328
|
+
];
|
|
17329
|
+
var SHARED_INIT = "Oit";
|
|
17330
|
+
var SHARED_FETCH = "Eit";
|
|
17331
|
+
var SHARED_BRIDGE = "AFt";
|
|
17332
|
+
var SHARED_RESPONSE_ERROR = "Mit";
|
|
17333
|
+
var HOOK_GLOBAL2 = "__codexhostClientOwnedVoiceV1";
|
|
16754
17334
|
function object2(value) {
|
|
16755
17335
|
return value !== null && typeof value === "object";
|
|
16756
17336
|
}
|
|
16757
|
-
function
|
|
17337
|
+
function requestVoiceHost(bridge, params, method = REALTIME_CALL_METHOD) {
|
|
16758
17338
|
const id = `codexhost-voice:${crypto.randomUUID()}`;
|
|
16759
17339
|
return new Promise((resolve, reject) => {
|
|
16760
17340
|
let unsubscribe = () => {
|
|
@@ -16777,7 +17357,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16777
17357
|
try {
|
|
16778
17358
|
bridge.dispatchMessage("mcp-request", {
|
|
16779
17359
|
hostId: "local",
|
|
16780
|
-
request: { id, method
|
|
17360
|
+
request: { id, method, params }
|
|
16781
17361
|
});
|
|
16782
17362
|
} catch {
|
|
16783
17363
|
done();
|
|
@@ -16802,24 +17382,50 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16802
17382
|
if (model2.startsWith("codexhost/")) return true;
|
|
16803
17383
|
return model2.includes("codex") && !model2.includes("gpt-live");
|
|
16804
17384
|
}
|
|
17385
|
+
function visibleWorkComposer(owner) {
|
|
17386
|
+
const document2 = owner.document;
|
|
17387
|
+
if (!document2?.querySelectorAll) return false;
|
|
17388
|
+
const work = [...document2.querySelectorAll("[data-codex-composer-root]")].some((element) => {
|
|
17389
|
+
const box = element.getBoundingClientRect?.() ?? { width: 0 };
|
|
17390
|
+
return box.width > 0 && !element.closest?.("[hidden], [inert]");
|
|
17391
|
+
});
|
|
17392
|
+
return work && document2.querySelectorAll("[data-chatgpt-composer]").length === 0;
|
|
17393
|
+
}
|
|
17394
|
+
function selectedWorkTab(owner) {
|
|
17395
|
+
const document2 = owner.document;
|
|
17396
|
+
if (!document2?.querySelectorAll) return false;
|
|
17397
|
+
const controls = document2.querySelectorAll("button, [role='tab'], a");
|
|
17398
|
+
let workSelected = false;
|
|
17399
|
+
let chatSelected = false;
|
|
17400
|
+
for (const element of controls) {
|
|
17401
|
+
const name = (element.textContent ?? "").replace(/\s+/gu, " ").trim();
|
|
17402
|
+
if (name !== "Chat" && name !== "Work") continue;
|
|
17403
|
+
const selected = element.getAttribute("aria-selected") === "true" || element.getAttribute("aria-pressed") === "true" || element.getAttribute("data-state") === "active" || element.getAttribute("data-state") === "on";
|
|
17404
|
+
if (!selected) continue;
|
|
17405
|
+
if (name === "Work") workSelected = true;
|
|
17406
|
+
if (name === "Chat") chatSelected = true;
|
|
17407
|
+
}
|
|
17408
|
+
return workSelected && !chatSelected;
|
|
17409
|
+
}
|
|
16805
17410
|
function isWorkComposerSurface(owner = globalThis) {
|
|
16806
17411
|
const storage = owner.localStorage;
|
|
16807
|
-
if (!storage) return false;
|
|
16808
17412
|
try {
|
|
16809
|
-
const raw = storage
|
|
16810
|
-
if (raw
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
17413
|
+
const raw = storage?.getItem(HOME_COMPOSER_MODE_STORAGE_KEY);
|
|
17414
|
+
if (raw != null && raw !== "") {
|
|
17415
|
+
let value = raw;
|
|
17416
|
+
if (raw.startsWith("{") || raw.startsWith('"') || raw.startsWith("[")) {
|
|
17417
|
+
try {
|
|
17418
|
+
value = JSON.parse(raw);
|
|
17419
|
+
} catch {
|
|
17420
|
+
value = raw;
|
|
17421
|
+
}
|
|
16817
17422
|
}
|
|
17423
|
+
if (value === "work") return true;
|
|
17424
|
+
if (value === "chat") return false;
|
|
16818
17425
|
}
|
|
16819
|
-
return value === "work";
|
|
16820
17426
|
} catch {
|
|
16821
|
-
return false;
|
|
16822
17427
|
}
|
|
17428
|
+
return selectedWorkTab(owner) || visibleWorkComposer(owner);
|
|
16823
17429
|
}
|
|
16824
17430
|
function selectedComposerModel(owner) {
|
|
16825
17431
|
const routing = owner.__codexhostHostRoutingV1;
|
|
@@ -16844,579 +17450,147 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16844
17450
|
if (lastVoiceProductExperience !== "work") return false;
|
|
16845
17451
|
const storage = owner.localStorage;
|
|
16846
17452
|
if (!storage) return false;
|
|
16847
|
-
try {
|
|
16848
|
-
const parsed = JSON.parse(storage.getItem(RENDERER_NEW_THREAD_PREFERENCE_KEY) ?? "");
|
|
16849
|
-
return typeof parsed.lastAgent === "string" && parsed.lastAgent !== "" && parsed.lastAgent !== "codex";
|
|
16850
|
-
} catch {
|
|
16851
|
-
return false;
|
|
16852
|
-
}
|
|
16853
|
-
}
|
|
16854
|
-
function wrapClientOwnedVoiceFetch(client, bridge, workOverride, responseError, chatOverride = () => false, workSurface = () => isWorkComposerSurface(), externalHarness = () => isExternalHarnessComposer()) {
|
|
16855
|
-
const original = client.fetch;
|
|
16856
|
-
const wrapped = async function(url2, options) {
|
|
16857
|
-
if (typeof url2 !== "string" || url2.split("?")[0] !== "/wham/realtime/calls" || options?.method !== "POST")
|
|
16858
|
-
return original.call(this, url2, options);
|
|
16859
|
-
const
|
|
16860
|
-
const
|
|
16861
|
-
const
|
|
16862
|
-
const
|
|
16863
|
-
const
|
|
16864
|
-
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
if (typeof options.body !== "string") throw new Error("Unsupported native voice call request");
|
|
16878
|
-
options.signal?.throwIfAborted();
|
|
16879
|
-
const requestId2 = crypto.randomUUID();
|
|
16880
|
-
let cancelled = false;
|
|
16881
|
-
const cancel = () => {
|
|
16882
|
-
if (cancelled) return;
|
|
16883
|
-
cancelled = true;
|
|
16884
|
-
void requestHost(bridge, { operation: "cancel", requestId: requestId2 }).catch(() => void 0);
|
|
16885
|
-
};
|
|
16886
|
-
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
16887
|
-
try {
|
|
16888
|
-
const result = realtimeCallResponseSchema.parse(
|
|
16889
|
-
await requestHost(bridge, {
|
|
16890
|
-
operation: "create",
|
|
16891
|
-
requestId: requestId2,
|
|
16892
|
-
body: options.body,
|
|
16893
|
-
// Drop Desktop OAuth, ChatGPT account identity and cookies at the bridge
|
|
16894
|
-
// boundary; the Host allowlist repeats this check before sending.
|
|
16895
|
-
headers: filterRealtimeCallHeaders(Object.fromEntries(new Headers(options.headers)))
|
|
16896
|
-
})
|
|
16897
|
-
);
|
|
16898
|
-
if (options.signal?.aborted) {
|
|
16899
|
-
const callId = realtimeCallIdFromLocation(result.headers.location ?? "");
|
|
16900
|
-
if (result.status >= 200 && result.status < 300 && isRealtimeCallId(callId))
|
|
16901
|
-
await requestHost(bridge, { operation: "hangup", callId });
|
|
16902
|
-
options.signal.throwIfAborted();
|
|
16903
|
-
}
|
|
16904
|
-
const response = new Response(result.status === 204 ? null : result.body, {
|
|
16905
|
-
status: result.status,
|
|
16906
|
-
headers: result.headers
|
|
16907
|
-
});
|
|
16908
|
-
if (!response.ok) throw await responseError(response, url2);
|
|
16909
|
-
return response;
|
|
16910
|
-
} catch (error51) {
|
|
16911
|
-
cancel();
|
|
16912
|
-
throw error51;
|
|
16913
|
-
} finally {
|
|
16914
|
-
options.signal?.removeEventListener("abort", cancel);
|
|
16915
|
-
}
|
|
16916
|
-
};
|
|
16917
|
-
client.fetch = wrapped;
|
|
16918
|
-
return () => {
|
|
16919
|
-
if (client.fetch === wrapped) client.fetch = original;
|
|
16920
|
-
};
|
|
16921
|
-
}
|
|
16922
|
-
function installClientOwnedVoiceHook(options = {}) {
|
|
16923
|
-
const target = options.target ?? globalThis;
|
|
16924
|
-
const existing = target[HOOK_GLOBAL];
|
|
16925
|
-
if (existing) return existing;
|
|
16926
|
-
const config2 = readCpaLiveVoiceHookConfig(target);
|
|
16927
|
-
if (!config2) return { status: "disabled", dispose() {
|
|
16928
|
-
} };
|
|
16929
|
-
if (config2.desktopVersion !== void 0 && config2.desktopVersion !== CLIENT_OWNED_VOICE_VERSION)
|
|
16930
|
-
return { status: "unsupported", dispose() {
|
|
16931
|
-
} };
|
|
16932
|
-
const importModule = options.importModule ?? ((url2) => import(url2));
|
|
16933
|
-
let disposed = false;
|
|
16934
|
-
let timer;
|
|
16935
|
-
let restore;
|
|
16936
|
-
const started = Date.now();
|
|
16937
|
-
const handle = {
|
|
16938
|
-
status: "pending",
|
|
16939
|
-
dispose() {
|
|
16940
|
-
disposed = true;
|
|
16941
|
-
if (timer !== void 0) target.clearTimeout(timer);
|
|
16942
|
-
restore?.();
|
|
16943
|
-
if (target[HOOK_GLOBAL] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL);
|
|
16944
|
-
}
|
|
16945
|
-
};
|
|
16946
|
-
target[HOOK_GLOBAL] = handle;
|
|
16947
|
-
const attempt = async () => {
|
|
16948
|
-
if (disposed) return;
|
|
16949
|
-
const names = loadedAssetNames(target.document, target.performance);
|
|
16950
|
-
if (auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_INITIAL_ASSET) && auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_SHARED_ASSET)) {
|
|
16951
|
-
try {
|
|
16952
|
-
const module = await importModule(`app://-/assets/${CLIENT_OWNED_VOICE_SHARED_ASSET}`);
|
|
16953
|
-
if (disposed) return;
|
|
16954
|
-
if (typeof module.frt !== "function") throw new Error();
|
|
16955
|
-
module.frt();
|
|
16956
|
-
const fetchClass = module.urt;
|
|
16957
|
-
const bridgeClass = module.mPt;
|
|
16958
|
-
if (!object2(fetchClass) && typeof fetchClass !== "function") throw new Error();
|
|
16959
|
-
if (!object2(bridgeClass) && typeof bridgeClass !== "function") throw new Error();
|
|
16960
|
-
const client = Reflect.get(fetchClass, "getInstance").call(fetchClass);
|
|
16961
|
-
const bridge = Reflect.get(bridgeClass, "getInstance").call(bridgeClass);
|
|
16962
|
-
if (typeof client?.fetch !== "function" || typeof bridge?.dispatchMessage !== "function" || typeof bridge?.subscribe !== "function" || typeof module.grt !== "function")
|
|
16963
|
-
throw new Error();
|
|
16964
|
-
restore = wrapClientOwnedVoiceFetch(
|
|
16965
|
-
client,
|
|
16966
|
-
bridge,
|
|
16967
|
-
() => cpaLiveVoicePreferenceAllowsInstall(target),
|
|
16968
|
-
module.grt,
|
|
16969
|
-
() => chatLiveVoicePreferenceAllowsOverride(target),
|
|
16970
|
-
() => isWorkComposerSurface(target),
|
|
16971
|
-
() => isExternalHarnessComposer(target)
|
|
16972
|
-
);
|
|
16973
|
-
handle.status = "active";
|
|
16974
|
-
} catch {
|
|
16975
|
-
handle.status = "unsupported";
|
|
16976
|
-
}
|
|
16977
|
-
return;
|
|
16978
|
-
}
|
|
16979
|
-
if (Date.now() - started >= 6e4) {
|
|
16980
|
-
handle.status = "unsupported";
|
|
16981
|
-
return;
|
|
16982
|
-
}
|
|
16983
|
-
timer = target.setTimeout(() => void attempt(), 250);
|
|
16984
|
-
};
|
|
16985
|
-
void attempt();
|
|
16986
|
-
return handle;
|
|
16987
|
-
}
|
|
16988
|
-
|
|
16989
|
-
// src/renderer-native-chat-voice-state.ts
|
|
16990
|
-
function observeNativeChatVoiceState(scope, initial) {
|
|
16991
|
-
const store = Reflect.apply(initial.ejn, void 0, [
|
|
16992
|
-
scope
|
|
16993
|
-
]);
|
|
16994
|
-
let last = "";
|
|
16995
|
-
const report = () => {
|
|
16996
|
-
const state = store.getState();
|
|
16997
|
-
const connection = state.server?.connectionState;
|
|
16998
|
-
const microphone = initial.sUn == null ? void 0 : scope.get(initial.sUn);
|
|
16999
|
-
const detail = {
|
|
17000
|
-
active: state.isVoiceModeActive === true,
|
|
17001
|
-
connectedOnce: state.hasConnectedOnce === true,
|
|
17002
|
-
sessionStarted: state.hasVoiceSessionStarted === true,
|
|
17003
|
-
serverConversationReady: typeof state.earlyServerThreadId === "string" && /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i.test(state.earlyServerThreadId),
|
|
17004
|
-
connection: typeof connection === "string" && ["disconnected", "connecting", "connected", "reconnecting", "signalReconnecting"].includes(
|
|
17005
|
-
connection
|
|
17006
|
-
) ? connection : "unknown",
|
|
17007
|
-
microphone: typeof microphone === "string" && ["unknown", "pending", "granted", "denied"].includes(microphone) ? microphone : "unknown"
|
|
17008
|
-
};
|
|
17009
|
-
const next = JSON.stringify(detail);
|
|
17010
|
-
if (next === last) return;
|
|
17011
|
-
last = next;
|
|
17012
|
-
chatVoiceDebug("native-chat-state", detail);
|
|
17013
|
-
};
|
|
17014
|
-
const unsubscribe = store.subscribe(report);
|
|
17015
|
-
report();
|
|
17016
|
-
return unsubscribe;
|
|
17017
|
-
}
|
|
17018
|
-
|
|
17019
|
-
// src/renderer-native-chat-voice-selection.ts
|
|
17020
|
-
var UUID = /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i;
|
|
17021
|
-
function nativeChatVoiceDraftSelection(binding, initial, shared, origin, signal) {
|
|
17022
|
-
const draft = binding.props.conversationId;
|
|
17023
|
-
const navigate = initial.uIr;
|
|
17024
|
-
const conversationPath = shared.xat;
|
|
17025
|
-
if (binding.backendConversationId !== void 0 || !draft.startsWith("local-chatgpt:") || !UUID.test(draft.slice("local-chatgpt:".length)) || origin == null || initial.FFr == null || initial.kZn == null || initial.SZn == null || typeof navigate !== "function" || typeof conversationPath !== "function")
|
|
17026
|
-
return () => {
|
|
17027
|
-
};
|
|
17028
|
-
const store = Reflect.apply(initial.ejn, void 0, [
|
|
17029
|
-
binding.scope
|
|
17030
|
-
]);
|
|
17031
|
-
let session = store.getState().voiceSessionId;
|
|
17032
|
-
let activeSeen = store.getState().isVoiceModeActive;
|
|
17033
|
-
let finished = false;
|
|
17034
|
-
return () => {
|
|
17035
|
-
if (finished) return;
|
|
17036
|
-
try {
|
|
17037
|
-
const state = store.getState();
|
|
17038
|
-
if (signal.aborted || binding.scope.get(initial.FFr) !== origin || activeSeen && (!state.isVoiceModeActive || state.voiceSessionId !== session)) {
|
|
17039
|
-
finished = true;
|
|
17040
|
-
return;
|
|
17041
|
-
}
|
|
17042
|
-
if (!state.isVoiceModeActive) return;
|
|
17043
|
-
if (!activeSeen) {
|
|
17044
|
-
session = state.voiceSessionId;
|
|
17045
|
-
activeSeen = true;
|
|
17046
|
-
}
|
|
17047
|
-
if (state.isWorkMode !== false || state.conversationId !== draft) {
|
|
17048
|
-
finished = true;
|
|
17049
|
-
return;
|
|
17050
|
-
}
|
|
17051
|
-
if (!state.hasVoiceSessionStarted || state.server.connectionState !== "connected") return;
|
|
17052
|
-
const backend = binding.scope.get(initial.pZn, draft);
|
|
17053
|
-
if (typeof backend !== "string" || !UUID.test(backend)) return;
|
|
17054
|
-
const mapping = binding.scope.get(initial.kZn, draft);
|
|
17055
|
-
const currentNode = binding.scope.get(initial.SZn, draft);
|
|
17056
|
-
if (mapping == null || typeof mapping !== "object" || typeof currentNode !== "string" || !mapping[currentNode]?.message)
|
|
17057
|
-
return;
|
|
17058
|
-
finished = true;
|
|
17059
|
-
const path = Reflect.apply(conversationPath, void 0, [draft]);
|
|
17060
|
-
const accepted = Reflect.apply(navigate, void 0, [binding.scope, path]);
|
|
17061
|
-
void Promise.resolve(accepted).then(
|
|
17062
|
-
(result) => chatVoiceDebug(
|
|
17063
|
-
result === false ? "native-chat-selection-declined" : "native-chat-draft-selection-requested"
|
|
17064
|
-
),
|
|
17065
|
-
() => chatVoiceDebug("native-chat-selection-failed")
|
|
17066
|
-
);
|
|
17067
|
-
} catch {
|
|
17068
|
-
finished = true;
|
|
17069
|
-
chatVoiceDebug("native-chat-selection-failed");
|
|
17070
|
-
}
|
|
17071
|
-
};
|
|
17072
|
-
}
|
|
17073
|
-
|
|
17074
|
-
// src/renderer-native-chat-voice.ts
|
|
17075
|
-
var HOOK_GLOBAL2 = "__codexhostNativeChatVoiceV1";
|
|
17076
|
-
var START_ASSET = "start-voice-954090654801.js";
|
|
17077
|
-
var PREWARM_ASSET = "voice-prewarm-fb2c91219553.js";
|
|
17078
|
-
var BUTTON = "data-codexhost-chat-voice-start";
|
|
17079
|
-
var CONVERSATION_UUID = /^[a-f\d]{8}(?:-[a-f\d]{4}){3}-[a-f\d]{12}$/i;
|
|
17080
|
-
var record2 = (value) => value !== null && typeof value === "object";
|
|
17081
|
-
function scopeRefs(owner, definition) {
|
|
17082
|
-
const scopes = /* @__PURE__ */ new Map();
|
|
17083
|
-
let hook = owner.memoizedState;
|
|
17084
|
-
const seen = /* @__PURE__ */ new Set();
|
|
17085
|
-
while (record2(hook) && seen.size < 4096 && !seen.has(hook)) {
|
|
17086
|
-
seen.add(hook);
|
|
17087
|
-
const state = hook.memoizedState;
|
|
17088
|
-
const scope = record2(state) ? state.current : void 0;
|
|
17089
|
-
if (record2(scope) && scope.scope === definition && typeof scope.get === "function" && typeof scope.set === "function" && scope.chain instanceof Map && scope.chain.get(definition.id) === scope.node)
|
|
17090
|
-
scopes.set(scope.node, scope);
|
|
17091
|
-
hook = hook.next;
|
|
17092
|
-
}
|
|
17093
|
-
return hook == null ? scopes : /* @__PURE__ */ new Map();
|
|
17094
|
-
}
|
|
17095
|
-
function detectNativeChatVoiceBinding(composer, native) {
|
|
17096
|
-
const key = Object.getOwnPropertyNames(composer).find((key2) => key2.startsWith("__reactFiber$"));
|
|
17097
|
-
if (!key) return;
|
|
17098
|
-
const ancestors = committedReactAncestors(Object.getOwnPropertyDescriptor(composer, key)?.value);
|
|
17099
|
-
for (const owner of ancestors) {
|
|
17100
|
-
const props = owner.memoizedProps;
|
|
17101
|
-
if (!record2(props) || typeof props.isWorkConversation !== "boolean" || typeof props.isTemporaryChat !== "boolean" || typeof props.conversationId !== "string")
|
|
17102
|
-
continue;
|
|
17103
|
-
if (props.isWorkConversation || props.isTemporaryChat || props.shouldBlockExternalEgress !== false || props.readOnly === true || !record2(props.composerSelectionContext) || props.composerSelectionContext.conversationId !== props.conversationId)
|
|
17104
|
-
return;
|
|
17105
|
-
const scopes = scopeRefs(owner, native.scopeDefinition);
|
|
17106
|
-
if (scopes.size !== 1) return;
|
|
17107
|
-
const scope = [...scopes.values()][0];
|
|
17108
|
-
if (!scope) return;
|
|
17109
|
-
const backendId = scope.get(native.backendConversationId, props.conversationId);
|
|
17110
|
-
const hasBackendId = typeof backendId === "string" && CONVERSATION_UUID.test(backendId);
|
|
17111
|
-
const isDraft = backendId == null && props.conversationId.startsWith("local-chatgpt:") && CONVERSATION_UUID.test(props.conversationId.slice("local-chatgpt:".length));
|
|
17112
|
-
if (!hasBackendId && !isDraft) return;
|
|
17113
|
-
const draftScopes = /* @__PURE__ */ new Map();
|
|
17114
|
-
if (isDraft) {
|
|
17115
|
-
for (const fiber of ancestors)
|
|
17116
|
-
for (const [node, ref] of scopeRefs(fiber, native.composerScopeDefinition))
|
|
17117
|
-
if (ref.chain.get(native.scopeDefinition.id) === scope.node) draftScopes.set(node, ref);
|
|
17453
|
+
try {
|
|
17454
|
+
const parsed = JSON.parse(storage.getItem(RENDERER_NEW_THREAD_PREFERENCE_KEY) ?? "");
|
|
17455
|
+
return typeof parsed.lastAgent === "string" && parsed.lastAgent !== "" && parsed.lastAgent !== "codex";
|
|
17456
|
+
} catch {
|
|
17457
|
+
return false;
|
|
17458
|
+
}
|
|
17459
|
+
}
|
|
17460
|
+
function wrapClientOwnedVoiceFetch(client, bridge, workOverride, responseError, chatOverride = () => false, workSurface = () => isWorkComposerSurface(), externalHarness = () => isExternalHarnessComposer()) {
|
|
17461
|
+
const original = client.fetch;
|
|
17462
|
+
const wrapped = async function(url2, options) {
|
|
17463
|
+
if (typeof url2 !== "string" || url2.split("?")[0] !== "/wham/realtime/calls" || options?.method !== "POST")
|
|
17464
|
+
return original.call(this, url2, options);
|
|
17465
|
+
const experience = lastVoiceLaunchProductExperience();
|
|
17466
|
+
const chat = experience === "chat";
|
|
17467
|
+
const model2 = backendModelName(options.headers);
|
|
17468
|
+
const work = !chat && (experience === "work" || isWorkBackendModel(model2) || workSurface());
|
|
17469
|
+
const external = !chat && (model2.startsWith("codexhost/") || externalHarness());
|
|
17470
|
+
const gateway = external || (work ? workOverride() : chatOverride());
|
|
17471
|
+
chatVoiceDebug("wham-create", {
|
|
17472
|
+
work,
|
|
17473
|
+
external,
|
|
17474
|
+
route: gateway ? "gateway" : "desktop",
|
|
17475
|
+
productExperience: experience ?? "unset"
|
|
17476
|
+
});
|
|
17477
|
+
if (!gateway) {
|
|
17478
|
+
if (!external && !work)
|
|
17479
|
+
chatVoiceDebug("chat-native-passthrough", {
|
|
17480
|
+
hasThreadId: new Headers(options.headers).has("Thread-Id")
|
|
17481
|
+
});
|
|
17482
|
+
return original.call(this, url2, options);
|
|
17118
17483
|
}
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17484
|
+
if (typeof options.body !== "string") throw new Error("Unsupported native voice call request");
|
|
17485
|
+
options.signal?.throwIfAborted();
|
|
17486
|
+
const requestId2 = crypto.randomUUID();
|
|
17487
|
+
let cancelled = false;
|
|
17488
|
+
const cancel = () => {
|
|
17489
|
+
if (cancelled) return;
|
|
17490
|
+
cancelled = true;
|
|
17491
|
+
void requestVoiceHost(bridge, { operation: "cancel", requestId: requestId2 }).catch(() => void 0);
|
|
17492
|
+
};
|
|
17493
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
17494
|
+
try {
|
|
17495
|
+
const result = realtimeCallResponseSchema.parse(
|
|
17496
|
+
await requestVoiceHost(bridge, {
|
|
17497
|
+
operation: "create",
|
|
17498
|
+
requestId: requestId2,
|
|
17499
|
+
body: options.body,
|
|
17500
|
+
// Drop Desktop OAuth, ChatGPT account identity and cookies at the bridge
|
|
17501
|
+
// boundary; the Host allowlist repeats this check before sending.
|
|
17502
|
+
headers: filterRealtimeCallHeaders(Object.fromEntries(new Headers(options.headers)))
|
|
17503
|
+
})
|
|
17504
|
+
);
|
|
17505
|
+
if (options.signal?.aborted) {
|
|
17506
|
+
const callId = realtimeCallIdFromLocation(result.headers.location ?? "");
|
|
17507
|
+
if (result.status >= 200 && result.status < 300 && isRealtimeCallId(callId))
|
|
17508
|
+
await requestVoiceHost(bridge, { operation: "hangup", callId });
|
|
17509
|
+
options.signal.throwIfAborted();
|
|
17137
17510
|
}
|
|
17511
|
+
const response = new Response(result.status === 204 ? null : result.body, {
|
|
17512
|
+
status: result.status,
|
|
17513
|
+
headers: result.headers
|
|
17514
|
+
});
|
|
17515
|
+
if (!response.ok) throw await responseError(response, url2);
|
|
17516
|
+
return response;
|
|
17517
|
+
} catch (error51) {
|
|
17518
|
+
cancel();
|
|
17519
|
+
throw error51;
|
|
17520
|
+
} finally {
|
|
17521
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
17138
17522
|
}
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
context: [...contexts][0],
|
|
17145
|
-
composerContext,
|
|
17146
|
-
backendConversationId: hasBackendId ? backendId : void 0
|
|
17147
|
-
};
|
|
17148
|
-
}
|
|
17149
|
-
}
|
|
17150
|
-
function startNativeChatVoiceForRequest(request, target = globalThis) {
|
|
17151
|
-
if (!record2(request) || request.productExperience !== "chat" || !nativeChatVoicePreferenceAllowsStart(target))
|
|
17152
|
-
return;
|
|
17153
|
-
const hook = target[HOOK_GLOBAL2];
|
|
17154
|
-
if (!hook || hook.status === "disabled") return;
|
|
17155
|
-
return hook.start();
|
|
17523
|
+
};
|
|
17524
|
+
client.fetch = wrapped;
|
|
17525
|
+
return () => {
|
|
17526
|
+
if (client.fetch === wrapped) client.fetch = original;
|
|
17527
|
+
};
|
|
17156
17528
|
}
|
|
17157
|
-
function
|
|
17529
|
+
function installClientOwnedVoiceHook(options = {}) {
|
|
17158
17530
|
const target = options.target ?? globalThis;
|
|
17159
17531
|
const existing = target[HOOK_GLOBAL2];
|
|
17160
17532
|
if (existing) return existing;
|
|
17161
17533
|
const config2 = readCpaLiveVoiceHookConfig(target);
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
throw new Error("Native Chat voice is unavailable");
|
|
17168
|
-
}
|
|
17169
|
-
});
|
|
17170
|
-
if (!config2) return unavailable("disabled");
|
|
17171
|
-
if (config2.desktopVersion !== void 0 && config2.desktopVersion !== CLIENT_OWNED_VOICE_VERSION)
|
|
17172
|
-
return unavailable("unsupported");
|
|
17173
|
-
const doc = target.document;
|
|
17174
|
-
if (!doc) return unavailable("unsupported");
|
|
17534
|
+
if (!config2) return { status: "disabled", dispose() {
|
|
17535
|
+
} };
|
|
17536
|
+
if (!supportsVoiceVersion(CLIENT_OWNED_VOICE_ASSETS, config2.desktopVersion))
|
|
17537
|
+
return { status: "unsupported", dispose() {
|
|
17538
|
+
} };
|
|
17175
17539
|
const importModule = options.importModule ?? ((url2) => import(url2));
|
|
17176
17540
|
let disposed = false;
|
|
17177
17541
|
let timer;
|
|
17178
|
-
let
|
|
17179
|
-
let boundScope;
|
|
17180
|
-
let mounted;
|
|
17181
|
-
let button2;
|
|
17182
|
-
const overlayButtons = /* @__PURE__ */ new Map();
|
|
17183
|
-
let controller;
|
|
17184
|
-
let starting = false;
|
|
17185
|
-
let selectDraft;
|
|
17186
|
-
let renderFailed = false;
|
|
17542
|
+
let restore;
|
|
17187
17543
|
const started = Date.now();
|
|
17188
|
-
const removeButton = () => {
|
|
17189
|
-
button2?.remove();
|
|
17190
|
-
button2 = void 0;
|
|
17191
|
-
};
|
|
17192
|
-
const release = () => {
|
|
17193
|
-
selectDraft = void 0;
|
|
17194
|
-
controller?.abort();
|
|
17195
|
-
controller = void 0;
|
|
17196
|
-
removeButton();
|
|
17197
|
-
for (const [control, [display, priority]] of overlayButtons)
|
|
17198
|
-
if (control.style.getPropertyValue("display") === "none" && control.style.getPropertyPriority("display") === "important")
|
|
17199
|
-
control.style.setProperty("display", display, priority);
|
|
17200
|
-
overlayButtons.clear();
|
|
17201
|
-
mounted?.dispose();
|
|
17202
|
-
mounted = void 0;
|
|
17203
|
-
boundScope = void 0;
|
|
17204
|
-
};
|
|
17205
|
-
const findBinding = () => {
|
|
17206
|
-
if (!modules || !nativeChatVoicePreferenceAllowsStart(target)) return;
|
|
17207
|
-
const forms = [...doc.querySelectorAll("[data-chatgpt-composer]")].filter(
|
|
17208
|
-
(form2) => form2.getBoundingClientRect().width > 0 && !form2.closest("[hidden], [inert]")
|
|
17209
|
-
);
|
|
17210
|
-
if (forms.length !== 1) return;
|
|
17211
|
-
const form = forms[0];
|
|
17212
|
-
if (!form) return;
|
|
17213
|
-
return detectNativeChatVoiceBinding(form, {
|
|
17214
|
-
scopeDefinition: modules.shared.Cot,
|
|
17215
|
-
backendConversationId: modules.initial.pZn,
|
|
17216
|
-
draftConversationId: modules.initial.lXt,
|
|
17217
|
-
composerScopeDefinition: modules.initial.xAt.scope
|
|
17218
|
-
});
|
|
17219
|
-
};
|
|
17220
17544
|
const handle = {
|
|
17221
|
-
get activeCall() {
|
|
17222
|
-
if (starting) return true;
|
|
17223
|
-
if (!boundScope || !modules || typeof modules.initial.ejn !== "function") return false;
|
|
17224
|
-
try {
|
|
17225
|
-
return modules.initial.ejn(boundScope).getState().isVoiceModeActive;
|
|
17226
|
-
} catch {
|
|
17227
|
-
return false;
|
|
17228
|
-
}
|
|
17229
|
-
},
|
|
17230
17545
|
status: "pending",
|
|
17231
|
-
async start() {
|
|
17232
|
-
if (disposed || starting) return;
|
|
17233
|
-
const current = findBinding();
|
|
17234
|
-
if (!current || !modules || current.scope.node !== mounted?.node)
|
|
17235
|
-
throw new Error("Select a ChatGPT conversation to start Chat voice");
|
|
17236
|
-
starting = true;
|
|
17237
|
-
controller = new AbortController();
|
|
17238
|
-
const signal = controller.signal;
|
|
17239
|
-
let origin;
|
|
17240
|
-
try {
|
|
17241
|
-
if (modules.initial.FFr != null) origin = current.scope.get(modules.initial.FFr);
|
|
17242
|
-
} catch {
|
|
17243
|
-
chatVoiceDebug("native-chat-selection-failed");
|
|
17244
|
-
}
|
|
17245
|
-
selectDraft = void 0;
|
|
17246
|
-
chatVoiceDebug("native-chat-start", {
|
|
17247
|
-
hasConversationId: current.backendConversationId !== void 0
|
|
17248
|
-
});
|
|
17249
|
-
try {
|
|
17250
|
-
await Reflect.apply(modules.start.n, void 0, [
|
|
17251
|
-
current.scope,
|
|
17252
|
-
current.props,
|
|
17253
|
-
{ event_source: "composer" },
|
|
17254
|
-
signal
|
|
17255
|
-
]);
|
|
17256
|
-
chatVoiceDebug("native-chat-start-returned");
|
|
17257
|
-
try {
|
|
17258
|
-
selectDraft = nativeChatVoiceDraftSelection(
|
|
17259
|
-
current,
|
|
17260
|
-
modules.initial,
|
|
17261
|
-
modules.shared,
|
|
17262
|
-
origin,
|
|
17263
|
-
signal
|
|
17264
|
-
);
|
|
17265
|
-
selectDraft();
|
|
17266
|
-
} catch {
|
|
17267
|
-
chatVoiceDebug("native-chat-selection-failed");
|
|
17268
|
-
}
|
|
17269
|
-
} catch {
|
|
17270
|
-
chatVoiceDebug("native-chat-start-failed");
|
|
17271
|
-
throw new Error("Native Chat voice could not start");
|
|
17272
|
-
} finally {
|
|
17273
|
-
starting = false;
|
|
17274
|
-
}
|
|
17275
|
-
},
|
|
17276
17546
|
dispose() {
|
|
17277
17547
|
disposed = true;
|
|
17278
17548
|
if (timer !== void 0) target.clearTimeout(timer);
|
|
17279
|
-
|
|
17549
|
+
restore?.();
|
|
17280
17550
|
if (target[HOOK_GLOBAL2] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL2);
|
|
17281
17551
|
}
|
|
17282
17552
|
};
|
|
17283
17553
|
target[HOOK_GLOBAL2] = handle;
|
|
17284
|
-
const
|
|
17554
|
+
const attempt = async () => {
|
|
17285
17555
|
if (disposed) return;
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17289
|
-
|
|
17290
|
-
|
|
17291
|
-
if (Date.now() - started >= 6e4) {
|
|
17292
|
-
handle.status = "unsupported";
|
|
17293
|
-
return;
|
|
17294
|
-
}
|
|
17295
|
-
return;
|
|
17296
|
-
}
|
|
17297
|
-
const [shared, initial, start, prewarm] = await Promise.all(
|
|
17298
|
-
[
|
|
17299
|
-
CLIENT_OWNED_VOICE_SHARED_ASSET,
|
|
17300
|
-
CLIENT_OWNED_VOICE_INITIAL_ASSET,
|
|
17301
|
-
START_ASSET,
|
|
17302
|
-
PREWARM_ASSET
|
|
17303
|
-
].map((asset) => importModule(`app://-/assets/${asset}`))
|
|
17304
|
-
);
|
|
17556
|
+
const names = loadedAssetNames(target.document, target.performance);
|
|
17557
|
+
const assets = selectVoiceAssets(CLIENT_OWNED_VOICE_ASSETS, names, config2.desktopVersion);
|
|
17558
|
+
if (assets) {
|
|
17559
|
+
try {
|
|
17560
|
+
const module = await importModule(`app://-/assets/${assets.shared}`);
|
|
17305
17561
|
if (disposed) return;
|
|
17306
|
-
if (
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
if (!
|
|
17562
|
+
if (typeof module[SHARED_INIT] !== "function") throw new Error();
|
|
17563
|
+
module[SHARED_INIT]();
|
|
17564
|
+
const fetchClass = module[SHARED_FETCH];
|
|
17565
|
+
const bridgeClass = module[SHARED_BRIDGE];
|
|
17566
|
+
if (!object2(fetchClass) && typeof fetchClass !== "function") throw new Error();
|
|
17567
|
+
if (!object2(bridgeClass) && typeof bridgeClass !== "function") throw new Error();
|
|
17568
|
+
const client = Reflect.get(fetchClass, "getInstance").call(fetchClass);
|
|
17569
|
+
const bridge = Reflect.get(bridgeClass, "getInstance").call(bridgeClass);
|
|
17570
|
+
if (typeof client?.fetch !== "function" || typeof bridge?.dispatchMessage !== "function" || typeof bridge?.subscribe !== "function" || typeof module[SHARED_RESPONSE_ERROR] !== "function")
|
|
17311
17571
|
throw new Error();
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
return;
|
|
17321
|
-
}
|
|
17322
|
-
if (mounted && current.scope.node !== mounted.node) release();
|
|
17323
|
-
boundScope = current.scope;
|
|
17324
|
-
if (!mounted) {
|
|
17325
|
-
const { scope } = current;
|
|
17326
|
-
const initial = modules.initial;
|
|
17327
|
-
const previous = scope.get(initial.Aw);
|
|
17328
|
-
const container = doc.createElement("div");
|
|
17329
|
-
container.setAttribute("data-codexhost-chat-voice-prewarm", "");
|
|
17330
|
-
doc.body.append(container);
|
|
17331
|
-
const react = Reflect.apply(modules.shared.yzt, void 0, []);
|
|
17332
|
-
const reactDom = Reflect.apply(modules.shared.vMt, void 0, []);
|
|
17333
|
-
const root = reactDom.createRoot(container, {
|
|
17334
|
-
onUncaughtError() {
|
|
17335
|
-
renderFailed = true;
|
|
17336
|
-
}
|
|
17337
|
-
});
|
|
17338
|
-
const stopObserving = observeNativeChatVoiceState(scope, initial);
|
|
17339
|
-
let appChain;
|
|
17340
|
-
let composerChain;
|
|
17341
|
-
mounted = {
|
|
17342
|
-
node: scope.node,
|
|
17343
|
-
render(next) {
|
|
17344
|
-
if (appChain === next.scope.chain && composerChain === next.composerContext.chain)
|
|
17345
|
-
return;
|
|
17346
|
-
appChain = next.scope.chain;
|
|
17347
|
-
composerChain = next.composerContext.chain;
|
|
17348
|
-
root.render(
|
|
17349
|
-
react.createElement(
|
|
17350
|
-
next.context,
|
|
17351
|
-
{ value: appChain },
|
|
17352
|
-
react.createElement(
|
|
17353
|
-
next.composerContext.context,
|
|
17354
|
-
{ value: composerChain },
|
|
17355
|
-
react.createElement(modules?.prewarm.VoiceInstantConnectCacheController, null)
|
|
17356
|
-
)
|
|
17357
|
-
)
|
|
17358
|
-
);
|
|
17359
|
-
},
|
|
17360
|
-
dispose() {
|
|
17361
|
-
stopObserving();
|
|
17362
|
-
root.unmount();
|
|
17363
|
-
container.remove();
|
|
17364
|
-
if (scope.get(initial.Aw) === true) scope.set(initial.Aw, previous);
|
|
17365
|
-
chatVoiceDebug("native-chat-unbound");
|
|
17366
|
-
}
|
|
17367
|
-
};
|
|
17368
|
-
scope.set(initial.Aw, true);
|
|
17369
|
-
chatVoiceDebug("native-chat-bound", {
|
|
17370
|
-
hasConversationId: current.backendConversationId !== void 0
|
|
17371
|
-
});
|
|
17372
|
-
}
|
|
17373
|
-
mounted.render(current);
|
|
17374
|
-
if (!button2 || !current.composer.contains(button2)) {
|
|
17375
|
-
removeButton();
|
|
17376
|
-
const dictate = current.composer.querySelector(
|
|
17377
|
-
'button[aria-label="Dictate"]'
|
|
17572
|
+
restore = wrapClientOwnedVoiceFetch(
|
|
17573
|
+
client,
|
|
17574
|
+
bridge,
|
|
17575
|
+
() => cpaLiveVoicePreferenceAllowsInstall(target),
|
|
17576
|
+
module[SHARED_RESPONSE_ERROR],
|
|
17577
|
+
() => chatLiveVoicePreferenceAllowsOverride(target),
|
|
17578
|
+
() => isWorkComposerSurface(target),
|
|
17579
|
+
() => isExternalHarnessComposer(target)
|
|
17378
17580
|
);
|
|
17379
|
-
|
|
17380
|
-
|
|
17381
|
-
|
|
17382
|
-
button2.className = dictate.className;
|
|
17383
|
-
button2.setAttribute(BUTTON, "");
|
|
17384
|
-
button2.setAttribute("aria-label", "Start Voice");
|
|
17385
|
-
button2.title = "Start Voice";
|
|
17386
|
-
button2.innerHTML = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true"><path d="M3 8v4m4-7v10m6-12v14m4-9v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>';
|
|
17387
|
-
button2.addEventListener("click", () => {
|
|
17388
|
-
void handle.start().catch(() => {
|
|
17389
|
-
if (button2) button2.title = "Chat voice could not start. Try again.";
|
|
17390
|
-
});
|
|
17391
|
-
});
|
|
17392
|
-
dictate.parentElement.append(button2);
|
|
17393
|
-
}
|
|
17581
|
+
handle.status = "active";
|
|
17582
|
+
} catch {
|
|
17583
|
+
handle.status = "unsupported";
|
|
17394
17584
|
}
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
)) {
|
|
17399
|
-
if (!overlayButtons.has(control))
|
|
17400
|
-
overlayButtons.set(control, [
|
|
17401
|
-
control.style.getPropertyValue("display"),
|
|
17402
|
-
control.style.getPropertyPriority("display")
|
|
17403
|
-
]);
|
|
17404
|
-
control.style.setProperty("display", "none", "important");
|
|
17405
|
-
}
|
|
17406
|
-
if (button2)
|
|
17407
|
-
button2.disabled = starting || current.props.isStreaming === true || modules.initial.ejn instanceof Function && modules.initial.ejn(current.scope).getState().isVoiceModeActive;
|
|
17408
|
-
handle.status = "active";
|
|
17409
|
-
} catch {
|
|
17410
|
-
release();
|
|
17585
|
+
return;
|
|
17586
|
+
}
|
|
17587
|
+
if (Date.now() - started >= 6e4) {
|
|
17411
17588
|
handle.status = "unsupported";
|
|
17412
|
-
chatVoiceDebug("native-chat-binding-failed");
|
|
17413
17589
|
return;
|
|
17414
|
-
} finally {
|
|
17415
|
-
if (!disposed && handle.status !== "unsupported")
|
|
17416
|
-
timer = target.setTimeout(() => void refresh(), 500);
|
|
17417
17590
|
}
|
|
17591
|
+
timer = target.setTimeout(() => void attempt(), 250);
|
|
17418
17592
|
};
|
|
17419
|
-
void
|
|
17593
|
+
void attempt();
|
|
17420
17594
|
return handle;
|
|
17421
17595
|
}
|
|
17422
17596
|
|
|
@@ -17439,13 +17613,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
17439
17613
|
if (busy || disposed) return;
|
|
17440
17614
|
busy = true;
|
|
17441
17615
|
try {
|
|
17616
|
+
const activeCall = desktopVoiceCallActive(owner);
|
|
17442
17617
|
let state = voiceSettingsStateSchema.parse(
|
|
17443
17618
|
await request(VOICE_SETTINGS_METHOD, {
|
|
17444
17619
|
operation: "get",
|
|
17445
|
-
runtime: { id, revision, activeCall
|
|
17620
|
+
runtime: { id, revision, activeCall }
|
|
17446
17621
|
})
|
|
17447
17622
|
);
|
|
17448
17623
|
if (disposed) return;
|
|
17624
|
+
const ready = state.gatewayReady ?? await request(VOICE_GATEWAY_STATUS_METHOD, {});
|
|
17625
|
+
if (disposed) return;
|
|
17626
|
+
applyVoiceGatewayReadiness(owner, ready === true);
|
|
17449
17627
|
if (!state.initialized)
|
|
17450
17628
|
state = voiceSettingsStateSchema.parse(
|
|
17451
17629
|
await request(VOICE_SETTINGS_METHOD, {
|
|
@@ -17453,7 +17631,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
17453
17631
|
routes: legacyVoiceRoutes(owner)
|
|
17454
17632
|
})
|
|
17455
17633
|
);
|
|
17456
|
-
if (!disposed && !
|
|
17634
|
+
if (!disposed && !activeCall && state.revision !== revision) {
|
|
17457
17635
|
applySharedVoiceRoutes(owner, state.settings);
|
|
17458
17636
|
revision = state.revision;
|
|
17459
17637
|
}
|
|
@@ -17466,6 +17644,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
17466
17644
|
const timer = owner.setInterval(() => void refresh(), intervalMs);
|
|
17467
17645
|
return () => {
|
|
17468
17646
|
disposed = true;
|
|
17647
|
+
applyVoiceGatewayReadiness(owner, false);
|
|
17469
17648
|
owner.clearInterval(timer);
|
|
17470
17649
|
};
|
|
17471
17650
|
}
|
|
@@ -18520,6 +18699,242 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18520
18699
|
return section;
|
|
18521
18700
|
}
|
|
18522
18701
|
|
|
18702
|
+
// src/settings/preference-ui.ts
|
|
18703
|
+
var nextPreferenceId = 0;
|
|
18704
|
+
function preferenceId(prefix) {
|
|
18705
|
+
nextPreferenceId += 1;
|
|
18706
|
+
return `codexhost-${prefix}-${nextPreferenceId}`;
|
|
18707
|
+
}
|
|
18708
|
+
function createPreferenceGroup(document2, title) {
|
|
18709
|
+
const group = document2.createElement("section");
|
|
18710
|
+
group.className = "mt-7 first-of-type:mt-0";
|
|
18711
|
+
const header = document2.createElement("div");
|
|
18712
|
+
header.className = "mb-2 flex min-h-6 items-center gap-2 px-1";
|
|
18713
|
+
const heading = document2.createElement("h3");
|
|
18714
|
+
heading.id = preferenceId("preference-group");
|
|
18715
|
+
heading.className = "m-0 text-[13px] leading-5 font-semibold text-settings-text";
|
|
18716
|
+
heading.textContent = title;
|
|
18717
|
+
header.append(heading);
|
|
18718
|
+
const card = document2.createElement("div");
|
|
18719
|
+
card.className = "rounded-[10px] border border-settings-border bg-settings-panel";
|
|
18720
|
+
group.setAttribute("aria-labelledby", heading.id);
|
|
18721
|
+
group.append(header, card);
|
|
18722
|
+
return { group, header, card };
|
|
18723
|
+
}
|
|
18724
|
+
function createPreferenceItem(document2, input) {
|
|
18725
|
+
const item = document2.createElement("div");
|
|
18726
|
+
item.className = "flex min-h-[60px] items-center justify-between gap-6 border-t border-settings-divider px-4 py-3 first:border-t-0";
|
|
18727
|
+
const copy = document2.createElement("div");
|
|
18728
|
+
copy.className = "flex min-w-0 flex-col gap-0.5";
|
|
18729
|
+
const heading = document2.createElement("div");
|
|
18730
|
+
heading.className = "flex items-center gap-1.5";
|
|
18731
|
+
const title = document2.createElement("label");
|
|
18732
|
+
title.htmlFor = input.controlId;
|
|
18733
|
+
title.className = "cursor-pointer text-[13px] leading-5 font-medium text-settings-text";
|
|
18734
|
+
title.textContent = input.title;
|
|
18735
|
+
heading.append(title);
|
|
18736
|
+
if (input.help) heading.append(createHelpTooltip(document2, input.help.label, input.help.lines));
|
|
18737
|
+
const description = document2.createElement("div");
|
|
18738
|
+
description.id = preferenceId("preference-description");
|
|
18739
|
+
description.className = "text-xs leading-[18px] text-settings-muted data-[invalid=true]:text-settings-danger";
|
|
18740
|
+
description.textContent = input.description;
|
|
18741
|
+
copy.append(heading, description);
|
|
18742
|
+
item.append(copy);
|
|
18743
|
+
return { item, description };
|
|
18744
|
+
}
|
|
18745
|
+
function createHelpTooltip(document2, label, lines) {
|
|
18746
|
+
const wrapper = document2.createElement("span");
|
|
18747
|
+
wrapper.className = "group relative inline-flex";
|
|
18748
|
+
const button2 = document2.createElement("button");
|
|
18749
|
+
button2.type = "button";
|
|
18750
|
+
button2.className = "inline-flex size-4 cursor-help items-center justify-center rounded-full border-0 bg-transparent p-0 text-settings-subtle transition-colors hover:text-settings-text focus-visible:text-settings-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-settings-focus";
|
|
18751
|
+
button2.setAttribute("aria-label", label);
|
|
18752
|
+
button2.append(createRendererSettingsIcon("help", 14));
|
|
18753
|
+
const tooltip = document2.createElement("div");
|
|
18754
|
+
tooltip.id = preferenceId("preference-tooltip");
|
|
18755
|
+
tooltip.setAttribute("role", "tooltip");
|
|
18756
|
+
tooltip.className = "pointer-events-none invisible absolute top-full left-0 z-20 mt-2 w-80 rounded-lg border border-settings-border bg-settings-panel px-3 py-2.5 text-xs leading-[18px] font-normal text-settings-text opacity-0 shadow-[0_10px_30px_rgb(0_0_0/0.22)] transition-opacity duration-150 group-hover:visible group-hover:opacity-100 group-focus-within:visible group-focus-within:opacity-100";
|
|
18757
|
+
const list = document2.createElement("ul");
|
|
18758
|
+
list.className = "m-0 grid list-disc gap-1 pl-4 marker:text-settings-subtle";
|
|
18759
|
+
for (const line of lines) {
|
|
18760
|
+
const item = document2.createElement("li");
|
|
18761
|
+
item.textContent = line;
|
|
18762
|
+
list.append(item);
|
|
18763
|
+
}
|
|
18764
|
+
tooltip.append(list);
|
|
18765
|
+
button2.setAttribute("aria-describedby", tooltip.id);
|
|
18766
|
+
button2.addEventListener("keydown", (event) => {
|
|
18767
|
+
if (event.key === "Escape") button2.blur();
|
|
18768
|
+
});
|
|
18769
|
+
wrapper.append(button2, tooltip);
|
|
18770
|
+
return wrapper;
|
|
18771
|
+
}
|
|
18772
|
+
function createPreferenceSwitch(document2, id, describedBy) {
|
|
18773
|
+
const input = document2.createElement("input");
|
|
18774
|
+
input.type = "checkbox";
|
|
18775
|
+
input.id = id;
|
|
18776
|
+
input.setAttribute("role", "switch");
|
|
18777
|
+
input.setAttribute("aria-describedby", describedBy);
|
|
18778
|
+
input.className = "relative m-0 h-5 w-9 shrink-0 cursor-pointer appearance-none rounded-full bg-settings-surface-hover ring-1 ring-settings-border transition-colors ring-inset before:absolute before:top-0.5 before:left-0.5 before:size-4 before:rounded-full before:bg-white before:shadow-[0_1px_2px_rgb(0_0_0/0.3)] before:transition-transform checked:bg-settings-focus checked:ring-transparent checked:before:translate-x-4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-settings-focus";
|
|
18779
|
+
return input;
|
|
18780
|
+
}
|
|
18781
|
+
function createNumberField(document2, input) {
|
|
18782
|
+
const field = document2.createElement("div");
|
|
18783
|
+
field.className = "flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-settings-border bg-settings-surface px-2.5 transition-colors focus-within:border-settings-focus data-[invalid=true]:border-settings-danger";
|
|
18784
|
+
const control = document2.createElement("input");
|
|
18785
|
+
control.type = "number";
|
|
18786
|
+
control.id = input.id;
|
|
18787
|
+
control.min = String(input.min);
|
|
18788
|
+
control.max = String(input.max);
|
|
18789
|
+
control.step = "1";
|
|
18790
|
+
control.setAttribute("aria-describedby", input.describedBy);
|
|
18791
|
+
control.className = "w-14 border-0 bg-transparent p-0 text-right text-[13px] leading-5 text-settings-text tabular-nums outline-none";
|
|
18792
|
+
const unit = document2.createElement("span");
|
|
18793
|
+
unit.className = "text-xs text-settings-muted";
|
|
18794
|
+
unit.setAttribute("aria-hidden", "true");
|
|
18795
|
+
unit.textContent = input.unit;
|
|
18796
|
+
field.append(control, unit);
|
|
18797
|
+
return { field, control };
|
|
18798
|
+
}
|
|
18799
|
+
|
|
18800
|
+
// src/settings/grok-computer-use-controls.ts
|
|
18801
|
+
function createGrokComputerUseControls(document2, messages, settings) {
|
|
18802
|
+
const section = document2.createElement("section");
|
|
18803
|
+
section.className = "settings-grok-computer-use";
|
|
18804
|
+
section.dataset.grokComputerUse = "true";
|
|
18805
|
+
const header = document2.createElement("div");
|
|
18806
|
+
header.className = "settings-grok-computer-use__header";
|
|
18807
|
+
const copy = document2.createElement("div");
|
|
18808
|
+
copy.className = "settings-grok-computer-use__copy";
|
|
18809
|
+
const title = document2.createElement("h3");
|
|
18810
|
+
title.className = "settings-grok-computer-use__title";
|
|
18811
|
+
title.id = "grok-computer-use-title";
|
|
18812
|
+
title.textContent = messages.grokComputerUseTitle;
|
|
18813
|
+
const description = document2.createElement("p");
|
|
18814
|
+
description.className = "settings-grok-computer-use__description";
|
|
18815
|
+
description.id = "grok-computer-use-description";
|
|
18816
|
+
description.textContent = messages.grokComputerUseDescription;
|
|
18817
|
+
copy.append(title, description);
|
|
18818
|
+
const input = createPreferenceSwitch(
|
|
18819
|
+
document2,
|
|
18820
|
+
"grok-computer-use-enabled",
|
|
18821
|
+
"grok-computer-use-description grok-computer-use-help grok-computer-use-status"
|
|
18822
|
+
);
|
|
18823
|
+
input.setAttribute("aria-labelledby", title.id);
|
|
18824
|
+
input.setAttribute("aria-label", messages.grokComputerUseLabel);
|
|
18825
|
+
header.append(copy, input);
|
|
18826
|
+
const help = document2.createElement("p");
|
|
18827
|
+
help.className = "settings-grok-computer-use__help";
|
|
18828
|
+
help.id = "grok-computer-use-help";
|
|
18829
|
+
help.textContent = messages.grokComputerUseHelp;
|
|
18830
|
+
const status = document2.createElement("p");
|
|
18831
|
+
status.className = "settings-grok-computer-use__status";
|
|
18832
|
+
status.id = "grok-computer-use-status";
|
|
18833
|
+
status.setAttribute("role", "status");
|
|
18834
|
+
status.setAttribute("aria-live", "polite");
|
|
18835
|
+
const browserHeader = document2.createElement("div");
|
|
18836
|
+
browserHeader.className = "settings-grok-computer-use__header settings-grok-computer-use__browser";
|
|
18837
|
+
const browserCopy = document2.createElement("div");
|
|
18838
|
+
browserCopy.className = "settings-grok-computer-use__copy";
|
|
18839
|
+
const browserTitle = document2.createElement("h3");
|
|
18840
|
+
browserTitle.className = "settings-grok-computer-use__title";
|
|
18841
|
+
browserTitle.id = "grok-browser-title";
|
|
18842
|
+
browserTitle.textContent = messages.grokBrowserTitle;
|
|
18843
|
+
const browserDescription = document2.createElement("p");
|
|
18844
|
+
browserDescription.className = "settings-grok-computer-use__description";
|
|
18845
|
+
browserDescription.id = "grok-browser-description";
|
|
18846
|
+
browserDescription.textContent = messages.grokBrowserDescription;
|
|
18847
|
+
browserCopy.append(browserTitle, browserDescription);
|
|
18848
|
+
const browserInput = createPreferenceSwitch(
|
|
18849
|
+
document2,
|
|
18850
|
+
"grok-browser-enabled",
|
|
18851
|
+
"grok-browser-description grok-browser-help grok-browser-status"
|
|
18852
|
+
);
|
|
18853
|
+
browserInput.setAttribute("aria-labelledby", browserTitle.id);
|
|
18854
|
+
browserInput.setAttribute("aria-label", messages.grokBrowserLabel);
|
|
18855
|
+
browserHeader.append(browserCopy, browserInput);
|
|
18856
|
+
const browserHelp = document2.createElement("p");
|
|
18857
|
+
browserHelp.className = "settings-grok-computer-use__help";
|
|
18858
|
+
browserHelp.id = "grok-browser-help";
|
|
18859
|
+
browserHelp.textContent = messages.grokBrowserHelp;
|
|
18860
|
+
const browserStatus = document2.createElement("p");
|
|
18861
|
+
browserStatus.className = "settings-grok-computer-use__status";
|
|
18862
|
+
browserStatus.id = "grok-browser-status";
|
|
18863
|
+
browserStatus.setAttribute("role", "status");
|
|
18864
|
+
browserStatus.setAttribute("aria-live", "polite");
|
|
18865
|
+
section.append(header, help, status, browserHeader, browserHelp, browserStatus);
|
|
18866
|
+
let busy = true;
|
|
18867
|
+
let loaded = false;
|
|
18868
|
+
let last;
|
|
18869
|
+
const show = (value) => {
|
|
18870
|
+
last = value;
|
|
18871
|
+
input.checked = value.enabled;
|
|
18872
|
+
input.disabled = busy || !loaded || !value.available && !value.enabled;
|
|
18873
|
+
const browserOn = value.browser === true;
|
|
18874
|
+
const browserFiles = value.browserFilesPresent === true;
|
|
18875
|
+
browserInput.checked = browserOn;
|
|
18876
|
+
browserInput.disabled = busy || !loaded || !browserFiles && !browserOn;
|
|
18877
|
+
if (!browserFiles) {
|
|
18878
|
+
browserStatus.dataset.state = "unavailable";
|
|
18879
|
+
browserStatus.textContent = value.browserUnavailableReason ?? messages.grokBrowserUnavailable;
|
|
18880
|
+
} else if (value.browserAvailable !== true) {
|
|
18881
|
+
browserStatus.dataset.state = browserOn ? "unavailable" : "off";
|
|
18882
|
+
browserStatus.textContent = browserOn ? value.browserUnavailableReason ?? messages.grokBrowserBlocked : messages.grokBrowserOff;
|
|
18883
|
+
} else {
|
|
18884
|
+
browserStatus.dataset.state = browserOn ? "on" : "off";
|
|
18885
|
+
browserStatus.textContent = browserOn ? messages.grokBrowserOn : messages.grokBrowserOff;
|
|
18886
|
+
}
|
|
18887
|
+
if (value.applyFailed) {
|
|
18888
|
+
status.dataset.state = "unavailable";
|
|
18889
|
+
status.textContent = value.applyError ?? messages.grokComputerUseApplyFailed;
|
|
18890
|
+
return;
|
|
18891
|
+
}
|
|
18892
|
+
if (!value.available) {
|
|
18893
|
+
status.dataset.state = "unavailable";
|
|
18894
|
+
status.textContent = value.unavailableReason ?? messages.grokComputerUseUnavailable;
|
|
18895
|
+
return;
|
|
18896
|
+
}
|
|
18897
|
+
status.dataset.state = value.enabled ? "on" : "off";
|
|
18898
|
+
status.textContent = value.enabled ? messages.grokComputerUseOn : messages.grokComputerUseOff;
|
|
18899
|
+
};
|
|
18900
|
+
const save = (update, target) => {
|
|
18901
|
+
if (busy || !loaded) return;
|
|
18902
|
+
busy = true;
|
|
18903
|
+
input.disabled = true;
|
|
18904
|
+
browserInput.disabled = true;
|
|
18905
|
+
target.textContent = messages.grokComputerUseSaving;
|
|
18906
|
+
void settings.set(update).then((value) => {
|
|
18907
|
+
busy = false;
|
|
18908
|
+
show(value);
|
|
18909
|
+
}).catch(() => {
|
|
18910
|
+
busy = false;
|
|
18911
|
+
if (last) show(last);
|
|
18912
|
+
else {
|
|
18913
|
+
input.disabled = false;
|
|
18914
|
+
browserInput.disabled = false;
|
|
18915
|
+
}
|
|
18916
|
+
target.textContent = messages.grokComputerUseSaveError;
|
|
18917
|
+
});
|
|
18918
|
+
};
|
|
18919
|
+
input.addEventListener("change", () => save({ enabled: input.checked }, status));
|
|
18920
|
+
browserInput.addEventListener(
|
|
18921
|
+
"change",
|
|
18922
|
+
() => save({ browser: browserInput.checked }, browserStatus)
|
|
18923
|
+
);
|
|
18924
|
+
status.textContent = messages.grokComputerUseLoading;
|
|
18925
|
+
browserStatus.textContent = messages.grokBrowserOff;
|
|
18926
|
+
void settings.get().then((value) => {
|
|
18927
|
+
loaded = true;
|
|
18928
|
+
busy = false;
|
|
18929
|
+
show(value);
|
|
18930
|
+
}).catch(() => {
|
|
18931
|
+
busy = false;
|
|
18932
|
+
status.textContent = messages.grokComputerUseLoadError;
|
|
18933
|
+
browserStatus.textContent = messages.grokComputerUseLoadError;
|
|
18934
|
+
});
|
|
18935
|
+
return section;
|
|
18936
|
+
}
|
|
18937
|
+
|
|
18523
18938
|
// src/settings/harness-installation-guides.ts
|
|
18524
18939
|
function harnessHasInstallCommands(plugin) {
|
|
18525
18940
|
return (plugin?.installation?.commands.length ?? 0) > 0;
|
|
@@ -18702,7 +19117,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18702
19117
|
}
|
|
18703
19118
|
|
|
18704
19119
|
// src/settings/harness-version-panel.ts
|
|
18705
|
-
function createHarnessVersionPanel(document2, messages, signal, agent, client) {
|
|
19120
|
+
function createHarnessVersionPanel(document2, messages, signal, agent, client, onChange = () => void 0) {
|
|
18706
19121
|
const panel = document2.createElement("section");
|
|
18707
19122
|
panel.className = "settings-harness-version";
|
|
18708
19123
|
panel.dataset.harnessVersion = agent;
|
|
@@ -18728,6 +19143,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18728
19143
|
panel.append(heading, versions, status, actions, note);
|
|
18729
19144
|
let state;
|
|
18730
19145
|
let busy = false;
|
|
19146
|
+
let updating = false;
|
|
18731
19147
|
let unsupported = false;
|
|
18732
19148
|
const render = () => {
|
|
18733
19149
|
current.textContent = `${messages.harnessVersionCurrent}: ${state?.currentVersion ?? "\u2014"}`;
|
|
@@ -18741,6 +19157,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18741
19157
|
if (busy || unsupported || signal.aborted) return;
|
|
18742
19158
|
if (action === "update" && (!state?.canUpdate || !state.updateAvailable)) return;
|
|
18743
19159
|
busy = true;
|
|
19160
|
+
updating = action === "update";
|
|
19161
|
+
onChange();
|
|
18744
19162
|
status.textContent = action === "check" ? messages.harnessVersionChecking : messages.harnessVersionUpdating;
|
|
18745
19163
|
render();
|
|
18746
19164
|
try {
|
|
@@ -18755,7 +19173,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18755
19173
|
if (state) state = { ...state, canUpdate: false };
|
|
18756
19174
|
} finally {
|
|
18757
19175
|
busy = false;
|
|
18758
|
-
|
|
19176
|
+
updating = false;
|
|
19177
|
+
if (!signal.aborted) {
|
|
19178
|
+
render();
|
|
19179
|
+
onChange();
|
|
19180
|
+
}
|
|
18759
19181
|
}
|
|
18760
19182
|
};
|
|
18761
19183
|
update.addEventListener("click", () => void run("update"));
|
|
@@ -18785,7 +19207,43 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
18785
19207
|
} else {
|
|
18786
19208
|
void run("check");
|
|
18787
19209
|
}
|
|
18788
|
-
return
|
|
19210
|
+
return {
|
|
19211
|
+
element: panel,
|
|
19212
|
+
get state() {
|
|
19213
|
+
return state;
|
|
19214
|
+
},
|
|
19215
|
+
get updating() {
|
|
19216
|
+
return updating;
|
|
19217
|
+
},
|
|
19218
|
+
update: () => void run("update")
|
|
19219
|
+
};
|
|
19220
|
+
}
|
|
19221
|
+
|
|
19222
|
+
// src/settings/connection-versions.ts
|
|
19223
|
+
function createConnectionVersions(document2, messages, signal, diagnostics, onChange) {
|
|
19224
|
+
const panels = /* @__PURE__ */ new Map();
|
|
19225
|
+
const installation = diagnostics?.installation?.bind(diagnostics);
|
|
19226
|
+
return {
|
|
19227
|
+
get(hostId2, agent) {
|
|
19228
|
+
if (!installation || signal.aborted) return void 0;
|
|
19229
|
+
const key = JSON.stringify([hostId2, agent]);
|
|
19230
|
+
let panel = panels.get(key);
|
|
19231
|
+
if (!panel) {
|
|
19232
|
+
panel = createHarnessVersionPanel(
|
|
19233
|
+
document2,
|
|
19234
|
+
messages,
|
|
19235
|
+
signal,
|
|
19236
|
+
agent,
|
|
19237
|
+
{
|
|
19238
|
+
run: (action) => installation(hostId2, agent, action)
|
|
19239
|
+
},
|
|
19240
|
+
onChange
|
|
19241
|
+
);
|
|
19242
|
+
panels.set(key, panel);
|
|
19243
|
+
}
|
|
19244
|
+
return panel;
|
|
19245
|
+
}
|
|
19246
|
+
};
|
|
18789
19247
|
}
|
|
18790
19248
|
|
|
18791
19249
|
// src/settings/connections-page.ts
|
|
@@ -18953,6 +19411,14 @@ ${error51.stderrTail}`] : []
|
|
|
18953
19411
|
status.dataset.connectionTone = connectionStatusTone(item.availability, item.error !== null);
|
|
18954
19412
|
status.setAttribute("role", "cell");
|
|
18955
19413
|
status.textContent = item.error?.code === "authenticationRequired" ? messages.connectionLoginRequired : item.error?.code === "configurationRequired" ? messages.connectionConfigurationRequired : connectionStatusLabel(item.availability, messages, item.error !== null);
|
|
19414
|
+
const version2 = item.version;
|
|
19415
|
+
if (version2?.state?.updateAvailable && !version2.updating) {
|
|
19416
|
+
const available = document2.createElement("span");
|
|
19417
|
+
available.className = "settings-connection-version-available";
|
|
19418
|
+
available.textContent = `${messages.harnessVersionAvailable}: ${harnessVersionLabel(version2.state, messages.harnessVersion)}`;
|
|
19419
|
+
available.title = `${messages.harnessVersionCurrent}: ${version2.state.currentVersion ?? "\u2014"}`;
|
|
19420
|
+
status.append(available);
|
|
19421
|
+
}
|
|
18956
19422
|
const action = document2.createElement("div");
|
|
18957
19423
|
action.className = "settings-connection-row__action";
|
|
18958
19424
|
action.setAttribute("role", "cell");
|
|
@@ -18982,6 +19448,23 @@ ${error51.stderrTail}`] : []
|
|
|
18982
19448
|
});
|
|
18983
19449
|
action.append(viewError);
|
|
18984
19450
|
}
|
|
19451
|
+
if (version2?.state?.updateAvailable && version2.state.canUpdate) {
|
|
19452
|
+
const update = document2.createElement("button");
|
|
19453
|
+
update.type = "button";
|
|
19454
|
+
update.className = "settings-connection-install-link";
|
|
19455
|
+
update.dataset.connectionAction = "update";
|
|
19456
|
+
update.disabled = version2.updating;
|
|
19457
|
+
update.title = messages.harnessVersionUpdate;
|
|
19458
|
+
update.setAttribute("aria-label", `${messages.harnessVersionUpdate}: ${item.name}`);
|
|
19459
|
+
update.append(createRendererSettingsIcon("download", 17));
|
|
19460
|
+
update.addEventListener("click", (event) => {
|
|
19461
|
+
event.stopPropagation();
|
|
19462
|
+
if (update.disabled) return;
|
|
19463
|
+
version2.update();
|
|
19464
|
+
select();
|
|
19465
|
+
});
|
|
19466
|
+
action.append(update);
|
|
19467
|
+
}
|
|
18985
19468
|
if (group) {
|
|
18986
19469
|
const toggle = document2.createElement("button");
|
|
18987
19470
|
toggle.type = "button";
|
|
@@ -19179,6 +19662,16 @@ ${error51.stderrTail}`] : []
|
|
|
19179
19662
|
});
|
|
19180
19663
|
body.append(launchControls);
|
|
19181
19664
|
}
|
|
19665
|
+
const getGrokComputerUse = diagnostics?.getGrokComputerUse?.bind(diagnostics);
|
|
19666
|
+
const setGrokComputerUse = diagnostics?.setGrokComputerUse?.bind(diagnostics);
|
|
19667
|
+
if (hostId2 === "local" && agent === "grok" && getGrokComputerUse && setGrokComputerUse) {
|
|
19668
|
+
body.append(
|
|
19669
|
+
createGrokComputerUseControls(document2, messages, {
|
|
19670
|
+
get: () => getGrokComputerUse(hostId2),
|
|
19671
|
+
set: (update) => setGrokComputerUse(hostId2, update)
|
|
19672
|
+
})
|
|
19673
|
+
);
|
|
19674
|
+
}
|
|
19182
19675
|
inspector.append(body);
|
|
19183
19676
|
return launchControls;
|
|
19184
19677
|
}
|
|
@@ -19273,8 +19766,6 @@ ${error51.stderrTail}`] : []
|
|
|
19273
19766
|
let selectedHostId = null;
|
|
19274
19767
|
let selectedItemKey = null;
|
|
19275
19768
|
let launchControls = null;
|
|
19276
|
-
const versionPanels = /* @__PURE__ */ new Map();
|
|
19277
|
-
const updatingVersions = /* @__PURE__ */ new Set();
|
|
19278
19769
|
const hostNames = /* @__PURE__ */ new Map();
|
|
19279
19770
|
let latestSnapshot = null;
|
|
19280
19771
|
let disposeHostScroller = () => void 0;
|
|
@@ -19303,6 +19794,13 @@ ${error51.stderrTail}`] : []
|
|
|
19303
19794
|
renderFrame = null;
|
|
19304
19795
|
};
|
|
19305
19796
|
const diagnostics = getDiagnostics();
|
|
19797
|
+
const versions = createConnectionVersions(
|
|
19798
|
+
document2,
|
|
19799
|
+
messages,
|
|
19800
|
+
context.signal,
|
|
19801
|
+
diagnostics,
|
|
19802
|
+
scheduleRender
|
|
19803
|
+
);
|
|
19306
19804
|
const installs = diagnostics ? harnessInstallStore(diagnostics) : null;
|
|
19307
19805
|
const runRefresh = () => {
|
|
19308
19806
|
if (pending || !diagnostics) return;
|
|
@@ -19439,10 +19937,13 @@ ${error51.stderrTail}`] : []
|
|
|
19439
19937
|
const agent = item.agentSnapshot?.agent;
|
|
19440
19938
|
if (!agent) return item;
|
|
19441
19939
|
const state = installs?.get(selectedHost.hostId, agent);
|
|
19940
|
+
const availability = state?.status ?? item.availability;
|
|
19941
|
+
const version2 = item.agentSnapshot?.availability !== "notInstalled" && availability !== "installing" && availability !== "checking" ? versions.get(selectedHost.hostId, agent) : void 0;
|
|
19442
19942
|
return {
|
|
19443
19943
|
...item,
|
|
19444
19944
|
...state ? { availability: state.status } : {},
|
|
19445
|
-
...
|
|
19945
|
+
...version2 ? { version: version2 } : {},
|
|
19946
|
+
...version2?.updating ? { availability: "updating" } : {},
|
|
19446
19947
|
...state?.error ? { installError: state.error } : {},
|
|
19447
19948
|
...diagnostics?.installation && harnessHasInstallCommands(item.agentSnapshot?.plugin) ? {
|
|
19448
19949
|
install: () => {
|
|
@@ -19479,30 +19980,7 @@ ${error51.stderrTail}`] : []
|
|
|
19479
19980
|
runRefresh
|
|
19480
19981
|
);
|
|
19481
19982
|
launchControls = { hostId: selectedHost.hostId, itemKey: item.key, element };
|
|
19482
|
-
|
|
19483
|
-
const installation = diagnostics?.installation?.bind(diagnostics);
|
|
19484
|
-
if (agent && item.agentSnapshot?.availability !== "notInstalled" && item.availability !== "installing" && item.availability !== "checking" && installation) {
|
|
19485
|
-
const key = JSON.stringify([selectedHost.hostId, agent]);
|
|
19486
|
-
let panel = versionPanels.get(key);
|
|
19487
|
-
if (!panel) {
|
|
19488
|
-
const hostId2 = selectedHost.hostId;
|
|
19489
|
-
panel = createHarnessVersionPanel(document2, messages, context.signal, agent, {
|
|
19490
|
-
async run(action) {
|
|
19491
|
-
if (action !== "update") return installation(hostId2, agent, action);
|
|
19492
|
-
updatingVersions.add(key);
|
|
19493
|
-
if (diagnostics) render(diagnostics.snapshot());
|
|
19494
|
-
try {
|
|
19495
|
-
return await installation(hostId2, agent, action);
|
|
19496
|
-
} finally {
|
|
19497
|
-
updatingVersions.delete(key);
|
|
19498
|
-
if (!context.signal.aborted && diagnostics) render(diagnostics.snapshot());
|
|
19499
|
-
}
|
|
19500
|
-
}
|
|
19501
|
-
});
|
|
19502
|
-
versionPanels.set(key, panel);
|
|
19503
|
-
}
|
|
19504
|
-
inspector.append(panel);
|
|
19505
|
-
}
|
|
19983
|
+
if (item.version) inspector.append(item.version.element);
|
|
19506
19984
|
};
|
|
19507
19985
|
const pinnedItem = items.find((item) => item.key === "renderer-adapter");
|
|
19508
19986
|
if (pinnedItem) {
|
|
@@ -19963,6 +20441,26 @@ ${error51.stderrTail}`] : []
|
|
|
19963
20441
|
launchPathLoading: "Loading launch settings\u2026",
|
|
19964
20442
|
launchPathLoadError: "Could not load launch settings. Reopen this detail panel to retry.",
|
|
19965
20443
|
launchPathSaveError: "Could not save. Enter an existing absolute installation folder on this Host and check configuration permissions.",
|
|
20444
|
+
grokComputerUseLabel: "Grok Computer Use",
|
|
20445
|
+
grokComputerUseTitle: "Computer Use",
|
|
20446
|
+
grokComputerUseDescription: "Let Grok control Mac apps via ChatGPT Computer Use (cua_repl).",
|
|
20447
|
+
grokComputerUseHelp: "ChatGPT Settings \u2192 Computer use still applies to official Codex threads. Always-allowed apps stay in that list. New Grok threads pick up this switch.",
|
|
20448
|
+
grokComputerUseOn: "On \xB7 available",
|
|
20449
|
+
grokComputerUseOff: "Off",
|
|
20450
|
+
grokComputerUseSaving: "Saving\u2026",
|
|
20451
|
+
grokComputerUseLoading: "Loading Grok Computer Use\u2026",
|
|
20452
|
+
grokComputerUseLoadError: "Could not load Grok Computer Use. Reopen this panel to retry.",
|
|
20453
|
+
grokComputerUseSaveError: "Could not save. Install ChatGPT.app with Computer Use, then try again.",
|
|
20454
|
+
grokComputerUseUnavailable: "ChatGPT Desktop Computer Use files were not found on this Mac.",
|
|
20455
|
+
grokBrowserLabel: "Grok in-app browser",
|
|
20456
|
+
grokBrowserTitle: "In-app browser",
|
|
20457
|
+
grokBrowserDescription: "Let Grok use ChatGPT's built-in browser (Browser Use) through cua_repl. Independent of Computer Use.",
|
|
20458
|
+
grokBrowserHelp: "Official Codex Browser Use is unchanged. Grok fails closed when ChatGPT does not authorize the connection or no in-app browser tab can be bound. The Chrome extension is a separate path.",
|
|
20459
|
+
grokBrowserOn: "On \xB7 browser surface enabled",
|
|
20460
|
+
grokBrowserOff: "Off",
|
|
20461
|
+
grokBrowserUnavailable: "ChatGPT Desktop in-app browser files were not found on this Mac.",
|
|
20462
|
+
grokBrowserBlocked: "Saved as intent. ChatGPT Desktop does not authorize Grok to use the in-app browser.",
|
|
20463
|
+
grokComputerUseApplyFailed: "Could not apply the saved setting to Grok config.",
|
|
19966
20464
|
connectionOfficialWebsite: "Visit official website",
|
|
19967
20465
|
connectionOpenHarnessWeb: "Open DeepSeek Harness Web",
|
|
19968
20466
|
connectionDeepSeekTestedVersions: "Supported DSH versions: 0.1.7-rc.1, 0.1.7-rc.2, 0.2.0-rc.1, 0.2.0-rc.2, 0.2.1-rc.1 and 0.2.1-rc.2. Versions newer than 0.2.1-rc.2 can be tried, but compatibility may be limited; versions older than 0.1.7-rc.1 must be upgraded first.",
|
|
@@ -19974,6 +20472,7 @@ ${error51.stderrTail}`] : []
|
|
|
19974
20472
|
harnessVersionCurrent: "Current version",
|
|
19975
20473
|
harnessVersionLatest: "Latest version",
|
|
19976
20474
|
harnessVersionChecking: "Checking versions\u2026",
|
|
20475
|
+
harnessVersionAvailable: "Update available",
|
|
19977
20476
|
harnessVersionUpdate: "Update",
|
|
19978
20477
|
harnessVersionUpdating: "Updating\u2026",
|
|
19979
20478
|
harnessVersionUpToDate: "Up to date",
|
|
@@ -20245,6 +20744,26 @@ ${error51.stderrTail}`] : []
|
|
|
20245
20744
|
launchPathLoading: "\u6B63\u5728\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\u2026",
|
|
20246
20745
|
launchPathLoadError: "\u65E0\u6CD5\u8BFB\u53D6\u542F\u52A8\u8BBE\u7F6E\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6B64\u8BE6\u60C5\u9762\u677F\u91CD\u8BD5\u3002",
|
|
20247
20746
|
launchPathSaveError: "\u4FDD\u5B58\u5931\u8D25\u3002\u8BF7\u586B\u5199\u6B64 Host \u4E0A\u5B9E\u9645\u5B58\u5728\u7684\u5B89\u88C5\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u5E76\u786E\u8BA4\u914D\u7F6E\u76EE\u5F55\u53EF\u5199\u3002",
|
|
20747
|
+
grokComputerUseLabel: "Grok Computer Use",
|
|
20748
|
+
grokComputerUseTitle: "Computer Use",
|
|
20749
|
+
grokComputerUseDescription: "\u8BA9 Grok \u901A\u8FC7 ChatGPT Computer Use\uFF08cua_repl\uFF09\u63A7\u5236 Mac \u5E94\u7528\u3002",
|
|
20750
|
+
grokComputerUseHelp: "ChatGPT \u8BBE\u7F6E \u2192 Computer use \u4ECD\u53EA\u4F5C\u7528\u4E8E\u5B98\u65B9 Codex \u7EBF\u7A0B\u3002Always-allowed \u5E94\u7528\u4ECD\u4FDD\u5B58\u5728\u8BE5\u5217\u8868\u3002\u65B0\u7684 Grok \u7EBF\u7A0B\u4F1A\u8BFB\u53D6\u6B64\u5F00\u5173\u3002",
|
|
20751
|
+
grokComputerUseOn: "\u5DF2\u5F00\u542F \xB7 \u53EF\u7528",
|
|
20752
|
+
grokComputerUseOff: "\u5DF2\u5173\u95ED",
|
|
20753
|
+
grokComputerUseSaving: "\u6B63\u5728\u4FDD\u5B58\u2026",
|
|
20754
|
+
grokComputerUseLoading: "\u6B63\u5728\u8BFB\u53D6 Grok Computer Use\u2026",
|
|
20755
|
+
grokComputerUseLoadError: "\u65E0\u6CD5\u8BFB\u53D6 Grok Computer Use\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6B64\u9762\u677F\u91CD\u8BD5\u3002",
|
|
20756
|
+
grokComputerUseSaveError: "\u4FDD\u5B58\u5931\u8D25\u3002\u8BF7\u5148\u5B89\u88C5\u5E26 Computer Use \u7684 ChatGPT.app\u3002",
|
|
20757
|
+
grokComputerUseUnavailable: "\u672C\u673A\u672A\u627E\u5230 ChatGPT Desktop \u7684 Computer Use \u6587\u4EF6\u3002",
|
|
20758
|
+
grokBrowserLabel: "Grok \u5185\u7F6E\u6D4F\u89C8\u5668",
|
|
20759
|
+
grokBrowserTitle: "\u5185\u7F6E\u6D4F\u89C8\u5668",
|
|
20760
|
+
grokBrowserDescription: "\u8BA9 Grok \u901A\u8FC7 cua_repl \u4F7F\u7528 ChatGPT \u5185\u7F6E\u6D4F\u89C8\u5668\uFF08Browser Use\uFF09\u3002\u4E0E Computer Use \u76F8\u4E92\u72EC\u7ACB\u3002",
|
|
20761
|
+
grokBrowserHelp: "\u5B98\u65B9 Codex Browser Use \u4E0D\u53D7\u5F71\u54CD\u3002ChatGPT \u4E0D\u6388\u6743\u8FDE\u63A5\u6216\u65E0\u6CD5\u7ED1\u5B9A\u5185\u7F6E\u6D4F\u89C8\u5668\u6807\u7B7E\u9875\u65F6\uFF0CGrok \u4F1A\u76F4\u63A5\u5931\u8D25\u3002Chrome \u6269\u5C55\u662F\u53E6\u4E00\u6761\u8DEF\u5F84\u3002",
|
|
20762
|
+
grokBrowserOn: "\u5DF2\u5F00\u542F \xB7 \u6D4F\u89C8\u5668\u80FD\u529B\u5DF2\u542F\u7528",
|
|
20763
|
+
grokBrowserOff: "\u5DF2\u5173\u95ED",
|
|
20764
|
+
grokBrowserUnavailable: "\u672C\u673A\u672A\u627E\u5230 ChatGPT Desktop \u7684\u5185\u7F6E\u6D4F\u89C8\u5668\u6587\u4EF6\u3002",
|
|
20765
|
+
grokBrowserBlocked: "\u5DF2\u4FDD\u5B58\u4E3A\u610F\u5411\u3002ChatGPT Desktop \u5C1A\u672A\u6388\u6743 Grok \u4F7F\u7528\u5185\u7F6E\u6D4F\u89C8\u5668\u3002",
|
|
20766
|
+
grokComputerUseApplyFailed: "\u65E0\u6CD5\u5C06\u5DF2\u4FDD\u5B58\u7684\u8BBE\u7F6E\u5199\u5165 Grok \u914D\u7F6E\u3002",
|
|
20248
20767
|
connectionOfficialWebsite: "\u8BBF\u95EE\u5B98\u7F51",
|
|
20249
20768
|
connectionOpenHarnessWeb: "\u6253\u5F00 DeepSeek Harness Web",
|
|
20250
20769
|
connectionDeepSeekTestedVersions: "\u652F\u6301 DSH \u7248\u672C\uFF1A0.1.7-rc.1\u30010.1.7-rc.2\u30010.2.0-rc.1\u30010.2.0-rc.2\u30010.2.1-rc.1 \u548C 0.2.1-rc.2\u3002\u9AD8\u4E8E 0.2.1-rc.2 \u7684\u7248\u672C\u53EF\u4EE5\u5C1D\u8BD5\u8FDE\u63A5\uFF0C\u4F46\u9002\u914D\u5EA6\u53EF\u80FD\u6709\u9650\uFF1B\u4F4E\u4E8E 0.1.7-rc.1 \u7684\u7248\u672C\u9700\u8981\u5148\u5347\u7EA7\u3002",
|
|
@@ -20256,6 +20775,7 @@ ${error51.stderrTail}`] : []
|
|
|
20256
20775
|
harnessVersionCurrent: "\u5F53\u524D\u7248\u672C",
|
|
20257
20776
|
harnessVersionLatest: "\u6700\u65B0\u7248\u672C",
|
|
20258
20777
|
harnessVersionChecking: "\u6B63\u5728\u68C0\u67E5\u7248\u672C\u2026",
|
|
20778
|
+
harnessVersionAvailable: "\u6709\u65B0\u7248\u672C",
|
|
20259
20779
|
harnessVersionUpdate: "\u66F4\u65B0",
|
|
20260
20780
|
harnessVersionUpdating: "\u6B63\u5728\u66F4\u65B0\u2026",
|
|
20261
20781
|
harnessVersionUpToDate: "\u5DF2\u662F\u6700\u65B0",
|
|
@@ -24791,7 +25311,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
|
|
|
24791
25311
|
};
|
|
24792
25312
|
const inspectHarness = async (input, options) => {
|
|
24793
25313
|
const params = harnessInspectParamsSchema.parse(input);
|
|
24794
|
-
|
|
25314
|
+
let result;
|
|
25315
|
+
try {
|
|
25316
|
+
result = await manager.sendRequest(HARNESS_INSPECT_METHOD, params, options);
|
|
25317
|
+
} catch (error51) {
|
|
25318
|
+
if (!params.purpose || !isInvalidParams(error51)) throw error51;
|
|
25319
|
+
const full = { ...params };
|
|
25320
|
+
delete full.purpose;
|
|
25321
|
+
result = await manager.sendRequest(HARNESS_INSPECT_METHOD, full, options);
|
|
25322
|
+
}
|
|
24795
25323
|
return harnessInspectionSchema.parse(result);
|
|
24796
25324
|
};
|
|
24797
25325
|
const inspectHarnessCommands = async (input) => {
|
|
@@ -24865,6 +25393,19 @@ Codex Fast mode prioritizes requests and may increase usage.`
|
|
|
24865
25393
|
)
|
|
24866
25394
|
);
|
|
24867
25395
|
},
|
|
25396
|
+
async getGrokComputerUse() {
|
|
25397
|
+
return grokComputerUseSettingsSchema.parse(
|
|
25398
|
+
await manager.sendRequest(GROK_COMPUTER_USE_GET_METHOD, {})
|
|
25399
|
+
);
|
|
25400
|
+
},
|
|
25401
|
+
async setGrokComputerUse(update) {
|
|
25402
|
+
return grokComputerUseSettingsSchema.parse(
|
|
25403
|
+
await manager.sendRequest(
|
|
25404
|
+
GROK_COMPUTER_USE_SET_METHOD,
|
|
25405
|
+
grokComputerUseSetSchema.parse(update)
|
|
25406
|
+
)
|
|
25407
|
+
);
|
|
25408
|
+
},
|
|
24868
25409
|
async listLoadedSessions() {
|
|
24869
25410
|
return loadedSessionsSchema.parse(await manager.sendRequest(LOADED_SESSIONS_METHOD, {}));
|
|
24870
25411
|
},
|
|
@@ -25053,6 +25594,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
|
|
|
25053
25594
|
}
|
|
25054
25595
|
});
|
|
25055
25596
|
}
|
|
25597
|
+
function isInvalidParams(error51) {
|
|
25598
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === -32602;
|
|
25599
|
+
}
|
|
25056
25600
|
|
|
25057
25601
|
// src/renderer-external-queue.ts
|
|
25058
25602
|
function isRecord8(value) {
|
|
@@ -27164,104 +27708,6 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
|
|
|
27164
27708
|
return element;
|
|
27165
27709
|
}
|
|
27166
27710
|
|
|
27167
|
-
// src/settings/preference-ui.ts
|
|
27168
|
-
var nextPreferenceId = 0;
|
|
27169
|
-
function preferenceId(prefix) {
|
|
27170
|
-
nextPreferenceId += 1;
|
|
27171
|
-
return `codexhost-${prefix}-${nextPreferenceId}`;
|
|
27172
|
-
}
|
|
27173
|
-
function createPreferenceGroup(document2, title) {
|
|
27174
|
-
const group = document2.createElement("section");
|
|
27175
|
-
group.className = "mt-7 first-of-type:mt-0";
|
|
27176
|
-
const header = document2.createElement("div");
|
|
27177
|
-
header.className = "mb-2 flex min-h-6 items-center gap-2 px-1";
|
|
27178
|
-
const heading = document2.createElement("h3");
|
|
27179
|
-
heading.id = preferenceId("preference-group");
|
|
27180
|
-
heading.className = "m-0 text-[13px] leading-5 font-semibold text-settings-text";
|
|
27181
|
-
heading.textContent = title;
|
|
27182
|
-
header.append(heading);
|
|
27183
|
-
const card = document2.createElement("div");
|
|
27184
|
-
card.className = "rounded-[10px] border border-settings-border bg-settings-panel";
|
|
27185
|
-
group.setAttribute("aria-labelledby", heading.id);
|
|
27186
|
-
group.append(header, card);
|
|
27187
|
-
return { group, header, card };
|
|
27188
|
-
}
|
|
27189
|
-
function createPreferenceItem(document2, input) {
|
|
27190
|
-
const item = document2.createElement("div");
|
|
27191
|
-
item.className = "flex min-h-[60px] items-center justify-between gap-6 border-t border-settings-divider px-4 py-3 first:border-t-0";
|
|
27192
|
-
const copy = document2.createElement("div");
|
|
27193
|
-
copy.className = "flex min-w-0 flex-col gap-0.5";
|
|
27194
|
-
const heading = document2.createElement("div");
|
|
27195
|
-
heading.className = "flex items-center gap-1.5";
|
|
27196
|
-
const title = document2.createElement("label");
|
|
27197
|
-
title.htmlFor = input.controlId;
|
|
27198
|
-
title.className = "cursor-pointer text-[13px] leading-5 font-medium text-settings-text";
|
|
27199
|
-
title.textContent = input.title;
|
|
27200
|
-
heading.append(title);
|
|
27201
|
-
if (input.help) heading.append(createHelpTooltip(document2, input.help.label, input.help.lines));
|
|
27202
|
-
const description = document2.createElement("div");
|
|
27203
|
-
description.id = preferenceId("preference-description");
|
|
27204
|
-
description.className = "text-xs leading-[18px] text-settings-muted data-[invalid=true]:text-settings-danger";
|
|
27205
|
-
description.textContent = input.description;
|
|
27206
|
-
copy.append(heading, description);
|
|
27207
|
-
item.append(copy);
|
|
27208
|
-
return { item, description };
|
|
27209
|
-
}
|
|
27210
|
-
function createHelpTooltip(document2, label, lines) {
|
|
27211
|
-
const wrapper = document2.createElement("span");
|
|
27212
|
-
wrapper.className = "group relative inline-flex";
|
|
27213
|
-
const button2 = document2.createElement("button");
|
|
27214
|
-
button2.type = "button";
|
|
27215
|
-
button2.className = "inline-flex size-4 cursor-help items-center justify-center rounded-full border-0 bg-transparent p-0 text-settings-subtle transition-colors hover:text-settings-text focus-visible:text-settings-text focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-settings-focus";
|
|
27216
|
-
button2.setAttribute("aria-label", label);
|
|
27217
|
-
button2.append(createRendererSettingsIcon("help", 14));
|
|
27218
|
-
const tooltip = document2.createElement("div");
|
|
27219
|
-
tooltip.id = preferenceId("preference-tooltip");
|
|
27220
|
-
tooltip.setAttribute("role", "tooltip");
|
|
27221
|
-
tooltip.className = "pointer-events-none invisible absolute top-full left-0 z-20 mt-2 w-80 rounded-lg border border-settings-border bg-settings-panel px-3 py-2.5 text-xs leading-[18px] font-normal text-settings-text opacity-0 shadow-[0_10px_30px_rgb(0_0_0/0.22)] transition-opacity duration-150 group-hover:visible group-hover:opacity-100 group-focus-within:visible group-focus-within:opacity-100";
|
|
27222
|
-
const list = document2.createElement("ul");
|
|
27223
|
-
list.className = "m-0 grid list-disc gap-1 pl-4 marker:text-settings-subtle";
|
|
27224
|
-
for (const line of lines) {
|
|
27225
|
-
const item = document2.createElement("li");
|
|
27226
|
-
item.textContent = line;
|
|
27227
|
-
list.append(item);
|
|
27228
|
-
}
|
|
27229
|
-
tooltip.append(list);
|
|
27230
|
-
button2.setAttribute("aria-describedby", tooltip.id);
|
|
27231
|
-
button2.addEventListener("keydown", (event) => {
|
|
27232
|
-
if (event.key === "Escape") button2.blur();
|
|
27233
|
-
});
|
|
27234
|
-
wrapper.append(button2, tooltip);
|
|
27235
|
-
return wrapper;
|
|
27236
|
-
}
|
|
27237
|
-
function createPreferenceSwitch(document2, id, describedBy) {
|
|
27238
|
-
const input = document2.createElement("input");
|
|
27239
|
-
input.type = "checkbox";
|
|
27240
|
-
input.id = id;
|
|
27241
|
-
input.setAttribute("role", "switch");
|
|
27242
|
-
input.setAttribute("aria-describedby", describedBy);
|
|
27243
|
-
input.className = "relative m-0 h-5 w-9 shrink-0 cursor-pointer appearance-none rounded-full bg-settings-surface-hover ring-1 ring-settings-border transition-colors ring-inset before:absolute before:top-0.5 before:left-0.5 before:size-4 before:rounded-full before:bg-white before:shadow-[0_1px_2px_rgb(0_0_0/0.3)] before:transition-transform checked:bg-settings-focus checked:ring-transparent checked:before:translate-x-4 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-settings-focus";
|
|
27244
|
-
return input;
|
|
27245
|
-
}
|
|
27246
|
-
function createNumberField(document2, input) {
|
|
27247
|
-
const field = document2.createElement("div");
|
|
27248
|
-
field.className = "flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-settings-border bg-settings-surface px-2.5 transition-colors focus-within:border-settings-focus data-[invalid=true]:border-settings-danger";
|
|
27249
|
-
const control = document2.createElement("input");
|
|
27250
|
-
control.type = "number";
|
|
27251
|
-
control.id = input.id;
|
|
27252
|
-
control.min = String(input.min);
|
|
27253
|
-
control.max = String(input.max);
|
|
27254
|
-
control.step = "1";
|
|
27255
|
-
control.setAttribute("aria-describedby", input.describedBy);
|
|
27256
|
-
control.className = "w-14 border-0 bg-transparent p-0 text-right text-[13px] leading-5 text-settings-text tabular-nums outline-none";
|
|
27257
|
-
const unit = document2.createElement("span");
|
|
27258
|
-
unit.className = "text-xs text-settings-muted";
|
|
27259
|
-
unit.setAttribute("aria-hidden", "true");
|
|
27260
|
-
unit.textContent = input.unit;
|
|
27261
|
-
field.append(control, unit);
|
|
27262
|
-
return { field, control };
|
|
27263
|
-
}
|
|
27264
|
-
|
|
27265
27711
|
// src/settings/voice-messages.ts
|
|
27266
27712
|
function voiceMessages(locale) {
|
|
27267
27713
|
const en = {
|
|
@@ -27283,6 +27729,15 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
|
|
|
27283
27729
|
configured: "Configured",
|
|
27284
27730
|
needsSetup: "Needs setup",
|
|
27285
27731
|
unknown: "Not checked",
|
|
27732
|
+
gatewayStatus: "Gateway configuration",
|
|
27733
|
+
preferencesStatus: "Preferences applied",
|
|
27734
|
+
hookStatus: "Desktop gateway voice integration",
|
|
27735
|
+
preferencesOn: "Applied",
|
|
27736
|
+
preferencesOff: "Not applied yet",
|
|
27737
|
+
hookSupported: "Supported",
|
|
27738
|
+
hookUnsupported: "This Desktop build is not supported for gateway voice",
|
|
27739
|
+
hookPending: "Attaching\u2026",
|
|
27740
|
+
hookDisabled: "Off",
|
|
27286
27741
|
configure: "Configure",
|
|
27287
27742
|
setup: "Gateway setup",
|
|
27288
27743
|
setupHint: "Gateway settings use your local Codex configuration and the selected provider\u2019s credential. End voice before editing configuration. Never paste credentials here.",
|
|
@@ -27333,6 +27788,15 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
|
|
|
27333
27788
|
configured: "\u5DF2\u914D\u7F6E",
|
|
27334
27789
|
needsSetup: "\u9700\u8981\u914D\u7F6E",
|
|
27335
27790
|
unknown: "\u672A\u68C0\u67E5",
|
|
27791
|
+
gatewayStatus: "\u7F51\u5173\u914D\u7F6E",
|
|
27792
|
+
preferencesStatus: "\u504F\u597D\u662F\u5426\u5DF2\u5E94\u7528",
|
|
27793
|
+
hookStatus: "Desktop \u7F51\u5173\u8BED\u97F3\u96C6\u6210",
|
|
27794
|
+
preferencesOn: "\u5DF2\u5E94\u7528",
|
|
27795
|
+
preferencesOff: "\u5C1A\u672A\u5E94\u7528",
|
|
27796
|
+
hookSupported: "\u652F\u6301",
|
|
27797
|
+
hookUnsupported: "\u5F53\u524D Desktop \u7248\u672C\u4E0D\u652F\u6301\u7F51\u5173\u8BED\u97F3",
|
|
27798
|
+
hookPending: "\u6B63\u5728\u63A5\u5165\u2026",
|
|
27799
|
+
hookDisabled: "\u5DF2\u5173\u95ED",
|
|
27336
27800
|
configure: "\u914D\u7F6E",
|
|
27337
27801
|
setup: "\u7F51\u5173\u914D\u7F6E",
|
|
27338
27802
|
setupHint: "\u7F51\u5173\u4F7F\u7528\u672C\u5730 Codex \u914D\u7F6E\u53CA\u6240\u9009 Provider \u7684\u51ED\u636E\u3002\u7F16\u8F91\u524D\u8BF7\u7ED3\u675F\u8BED\u97F3\u3002\u8BF7\u52FF\u5728\u6B64\u7C98\u8D34\u51ED\u636E\u3002",
|
|
@@ -27532,20 +27996,30 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
|
|
|
27532
27996
|
});
|
|
27533
27997
|
configure.id = gateway.item.querySelector("label")?.htmlFor ?? "";
|
|
27534
27998
|
configure.setAttribute("aria-expanded", String(setup));
|
|
27999
|
+
const gatewayReadyLabel = state.gatewayReady === null ? m.unknown : state.gatewayReady ? m.configured : m.needsSetup;
|
|
27535
28000
|
const gatewayActions = h(
|
|
27536
28001
|
doc,
|
|
27537
28002
|
"div",
|
|
27538
28003
|
{ className: "settings-voice__gateway-actions" },
|
|
28004
|
+
h(doc, "span", {}, gatewayReadyLabel),
|
|
28005
|
+
configure
|
|
28006
|
+
);
|
|
28007
|
+
gateway.item.append(gatewayActions);
|
|
28008
|
+
config2.card.append(gateway.item);
|
|
28009
|
+
const hook = options.desktop ? desktopVoiceHookStatus(doc.defaultView) : "unknown";
|
|
28010
|
+
const hookLabel = hook === "active" ? m.hookSupported : hook === "pending" ? m.hookPending : hook === "unsupported" ? m.hookUnsupported : hook === "disabled" ? m.hookDisabled : m.unknown;
|
|
28011
|
+
const health = h(doc, "div", { className: "settings-voice__health" });
|
|
28012
|
+
health.append(
|
|
28013
|
+
h(doc, "p", {}, `${m.gatewayStatus}: ${gatewayReadyLabel}`),
|
|
27539
28014
|
h(
|
|
27540
28015
|
doc,
|
|
27541
|
-
"
|
|
28016
|
+
"p",
|
|
27542
28017
|
{},
|
|
27543
|
-
state.
|
|
28018
|
+
`${m.preferencesStatus}: ${state.routesActive === true ? m.preferencesOn : state.routesActive === false ? m.preferencesOff : m.unknown}`
|
|
27544
28019
|
),
|
|
27545
|
-
|
|
28020
|
+
h(doc, "p", {}, `${m.hookStatus}: ${hookLabel}`)
|
|
27546
28021
|
);
|
|
27547
|
-
|
|
27548
|
-
config2.card.append(gateway.item);
|
|
28022
|
+
config2.card.append(health);
|
|
27549
28023
|
if (setup) {
|
|
27550
28024
|
const details = h(
|
|
27551
28025
|
doc,
|
|
@@ -27675,6 +28149,15 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
|
|
|
27675
28149
|
}
|
|
27676
28150
|
});
|
|
27677
28151
|
}
|
|
28152
|
+
function desktopVoiceHookStatus(win) {
|
|
28153
|
+
if (!win) return "unknown";
|
|
28154
|
+
const value = win.__codexhostClientOwnedVoiceV1;
|
|
28155
|
+
if (!value || typeof value !== "object") return "unknown";
|
|
28156
|
+
const status = value.status;
|
|
28157
|
+
if (status === "active" || status === "pending" || status === "unsupported" || status === "disabled")
|
|
28158
|
+
return status;
|
|
28159
|
+
return "unknown";
|
|
28160
|
+
}
|
|
27678
28161
|
|
|
27679
28162
|
// src/console/usage/model-labels.ts
|
|
27680
28163
|
function usageModelLabel(model2, labels, harness2) {
|
|
@@ -30061,6 +30544,13 @@ ${detail}` : ""}`
|
|
|
30061
30544
|
save: "Save",
|
|
30062
30545
|
useAutomatic: "Use automatic",
|
|
30063
30546
|
saved: "Saved",
|
|
30547
|
+
grokComputerUse: "Grok Computer Use",
|
|
30548
|
+
grokComputerUseHelp: "Lets Grok control Mac apps through ChatGPT\u2019s Computer Use helper. ChatGPT Settings \u2192 Computer use still applies only to official Codex. New Grok threads pick up this switch.",
|
|
30549
|
+
grokComputerUseUnavailable: "ChatGPT Desktop Computer Use files were not found.",
|
|
30550
|
+
grokBrowser: "Grok in-app browser",
|
|
30551
|
+
grokBrowserHelp: "Lets Grok use ChatGPT\u2019s built-in browser (Browser Use) through cua_repl. Independent of Computer Use; official Codex Browser Use is unchanged. Grok fails closed when the in-app tab cannot be bound.",
|
|
30552
|
+
grokBrowserUnavailable: "ChatGPT Desktop in-app browser files were not found.",
|
|
30553
|
+
grokBrowserBlocked: "Saved as intent. ChatGPT Desktop does not authorize Grok to use the in-app browser.",
|
|
30064
30554
|
installGuide: "Install guide",
|
|
30065
30555
|
noHarness: "No Harness plugins are installed.",
|
|
30066
30556
|
consoleOffline: "The console is not running",
|
|
@@ -30250,6 +30740,13 @@ ${detail}` : ""}`
|
|
|
30250
30740
|
save: "\u4FDD\u5B58",
|
|
30251
30741
|
useAutomatic: "\u6062\u590D\u81EA\u52A8\u67E5\u627E",
|
|
30252
30742
|
saved: "\u5DF2\u4FDD\u5B58",
|
|
30743
|
+
grokComputerUse: "Grok Computer Use",
|
|
30744
|
+
grokComputerUseHelp: "\u8BA9 Grok \u901A\u8FC7 ChatGPT \u7684 Computer Use \u52A9\u624B\u63A7\u5236 Mac \u5E94\u7528\u3002ChatGPT \u8BBE\u7F6E \u2192 Computer use \u4ECD\u53EA\u4F5C\u7528\u4E8E\u5B98\u65B9 Codex\u3002\u65B0\u7684 Grok \u7EBF\u7A0B\u4F1A\u8BFB\u53D6\u6B64\u5F00\u5173\u3002",
|
|
30745
|
+
grokComputerUseUnavailable: "\u672A\u627E\u5230 ChatGPT Desktop \u7684 Computer Use \u6587\u4EF6\u3002",
|
|
30746
|
+
grokBrowser: "Grok \u5185\u7F6E\u6D4F\u89C8\u5668",
|
|
30747
|
+
grokBrowserHelp: "\u8BA9 Grok \u901A\u8FC7 cua_repl \u4F7F\u7528 ChatGPT \u5185\u7F6E\u6D4F\u89C8\u5668\uFF08Browser Use\uFF09\u3002\u4E0E Computer Use \u76F8\u4E92\u72EC\u7ACB\uFF0C\u5B98\u65B9 Codex Browser Use \u4E0D\u53D7\u5F71\u54CD\u3002\u65E0\u6CD5\u7ED1\u5B9A\u5185\u7F6E\u6807\u7B7E\u9875\u65F6 Grok \u4F1A\u76F4\u63A5\u5931\u8D25\u3002",
|
|
30748
|
+
grokBrowserUnavailable: "\u672A\u627E\u5230 ChatGPT Desktop \u7684\u5185\u7F6E\u6D4F\u89C8\u5668\u6587\u4EF6\u3002",
|
|
30749
|
+
grokBrowserBlocked: "\u5DF2\u4FDD\u5B58\u4E3A\u610F\u5411\u3002ChatGPT Desktop \u5C1A\u672A\u6388\u6743 Grok \u4F7F\u7528\u5185\u7F6E\u6D4F\u89C8\u5668\u3002",
|
|
30253
30750
|
installGuide: "\u5B89\u88C5\u8BF4\u660E",
|
|
30254
30751
|
noHarness: "\u6CA1\u6709\u5DF2\u5B89\u88C5\u7684 Harness \u63D2\u4EF6\u3002",
|
|
30255
30752
|
consoleOffline: "\u63A7\u5236\u53F0\u672A\u8FD0\u884C",
|
|
@@ -32663,7 +33160,7 @@ ${detail}` : ""}`
|
|
|
32663
33160
|
}
|
|
32664
33161
|
function defaultImportName(source, existing) {
|
|
32665
33162
|
const base = source.provider === "openai-codex" ? "codex" : "grok";
|
|
32666
|
-
const used = new Set(existing.map((
|
|
33163
|
+
const used = new Set(existing.map((record7) => record7.name));
|
|
32667
33164
|
const valid = (name) => credentialImportNameSchema.safeParse(name).success;
|
|
32668
33165
|
if (!used.has(base)) return base;
|
|
32669
33166
|
const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
|
|
@@ -32686,7 +33183,7 @@ ${detail}` : ""}`
|
|
|
32686
33183
|
const shown = (text) => accountDisplayText(text, hideEmails);
|
|
32687
33184
|
const targetButtons = /* @__PURE__ */ new Map();
|
|
32688
33185
|
const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
|
|
32689
|
-
const sourceOf = (
|
|
33186
|
+
const sourceOf = (record7) => snapshot.sources.find((source) => source.id === record7.source.id);
|
|
32690
33187
|
const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
|
|
32691
33188
|
const compatibleSources = () => {
|
|
32692
33189
|
const target = piTarget();
|
|
@@ -32724,7 +33221,7 @@ ${detail}` : ""}`
|
|
|
32724
33221
|
sectionImport.addEventListener("click", () => {
|
|
32725
33222
|
const sources = compatibleSources();
|
|
32726
33223
|
const free = sources.find(
|
|
32727
|
-
(source2) => !importedRecords().some((
|
|
33224
|
+
(source2) => !importedRecords().some((record7) => record7.source.id === source2.id)
|
|
32728
33225
|
);
|
|
32729
33226
|
const source = free ?? sources[0];
|
|
32730
33227
|
if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
|
|
@@ -32774,30 +33271,30 @@ ${detail}` : ""}`
|
|
|
32774
33271
|
mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
|
|
32775
33272
|
return mark;
|
|
32776
33273
|
};
|
|
32777
|
-
const renderRow = (
|
|
33274
|
+
const renderRow = (record7) => {
|
|
32778
33275
|
const row = document2.createElement("div");
|
|
32779
33276
|
row.className = "settings-pi-accounts__row";
|
|
32780
33277
|
row.tabIndex = -1;
|
|
32781
|
-
row.dataset.importName =
|
|
32782
|
-
row.setAttribute("aria-label", shown(
|
|
32783
|
-
const agent =
|
|
33278
|
+
row.dataset.importName = record7.name;
|
|
33279
|
+
row.setAttribute("aria-label", shown(record7.source.label));
|
|
33280
|
+
const agent = record7.source.harnessId;
|
|
32784
33281
|
const mark = createMark(agent);
|
|
32785
33282
|
const identity = document2.createElement("div");
|
|
32786
33283
|
identity.className = "settings-pi-accounts__identity";
|
|
32787
33284
|
const label = document2.createElement("strong");
|
|
32788
33285
|
label.className = "settings-account-email";
|
|
32789
|
-
label.textContent = shown(
|
|
33286
|
+
label.textContent = shown(record7.source.label);
|
|
32790
33287
|
label.title = label.textContent;
|
|
32791
33288
|
label.translate = false;
|
|
32792
33289
|
const meta3 = document2.createElement("div");
|
|
32793
33290
|
meta3.className = "settings-account-metadata";
|
|
32794
|
-
const source = sourceOf(
|
|
33291
|
+
const source = sourceOf(record7);
|
|
32795
33292
|
const parts = [
|
|
32796
33293
|
metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
|
|
32797
|
-
metaPart(`${
|
|
33294
|
+
metaPart(`${record7.name}/\u2026`, void 0, true),
|
|
32798
33295
|
metaPart(messages.copied)
|
|
32799
33296
|
];
|
|
32800
|
-
const time3 = formatImportedAt(
|
|
33297
|
+
const time3 = formatImportedAt(record7.importedAt);
|
|
32801
33298
|
if (time3) parts.push(metaPart(time3));
|
|
32802
33299
|
parts.forEach((part, index) => {
|
|
32803
33300
|
if (index > 0) {
|
|
@@ -32814,23 +33311,23 @@ ${detail}` : ""}`
|
|
|
32814
33311
|
reimport.type = "button";
|
|
32815
33312
|
reimport.className = "settings-account-action";
|
|
32816
33313
|
reimport.textContent = messages.rowReimport;
|
|
32817
|
-
reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(
|
|
33314
|
+
reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record7.source.label)}`);
|
|
32818
33315
|
reimport.disabled = busy || !source;
|
|
32819
33316
|
reimport.title = messages.reimport;
|
|
32820
33317
|
reimport.addEventListener("click", () => {
|
|
32821
|
-
if (source) openDialog("reimport", { source, record:
|
|
33318
|
+
if (source) openDialog("reimport", { source, record: record7 }, `row:${record7.name}`);
|
|
32822
33319
|
});
|
|
32823
33320
|
const remove = document2.createElement("button");
|
|
32824
33321
|
remove.type = "button";
|
|
32825
33322
|
remove.className = "settings-account-action settings-pi-accounts__remove";
|
|
32826
33323
|
remove.textContent = messages.rowRemove;
|
|
32827
|
-
remove.setAttribute("aria-label", `${messages.remove}: ${shown(
|
|
33324
|
+
remove.setAttribute("aria-label", `${messages.remove}: ${shown(record7.source.label)}`);
|
|
32828
33325
|
remove.disabled = busy;
|
|
32829
|
-
remove.addEventListener("click", () => openDialog("remove", { record:
|
|
33326
|
+
remove.addEventListener("click", () => openDialog("remove", { record: record7 }, `row:${record7.name}`));
|
|
32830
33327
|
if (source) actions.append(reimport);
|
|
32831
33328
|
actions.append(remove);
|
|
32832
33329
|
row.append(mark, identity, actions);
|
|
32833
|
-
rows.set(
|
|
33330
|
+
rows.set(record7.name, row);
|
|
32834
33331
|
return row;
|
|
32835
33332
|
};
|
|
32836
33333
|
const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
|
|
@@ -32983,7 +33480,7 @@ ${detail}` : ""}`
|
|
|
32983
33480
|
const label = document2.createElement("strong");
|
|
32984
33481
|
label.textContent = shown(choice.label);
|
|
32985
33482
|
label.translate = false;
|
|
32986
|
-
const existing = importedRecords().find((
|
|
33483
|
+
const existing = importedRecords().find((record7) => record7.source.id === choice.id);
|
|
32987
33484
|
const agent = choice.harnessId;
|
|
32988
33485
|
const detail = document2.createElement("span");
|
|
32989
33486
|
detail.textContent = [
|
|
@@ -33024,7 +33521,7 @@ ${detail}` : ""}`
|
|
|
33024
33521
|
const name = request.action === "list" ? void 0 : request.name;
|
|
33025
33522
|
state = {
|
|
33026
33523
|
source: state.source,
|
|
33027
|
-
record: importedRecords().find((
|
|
33524
|
+
record: importedRecords().find((record7) => record7.name === name) ?? state.record
|
|
33028
33525
|
};
|
|
33029
33526
|
show(next);
|
|
33030
33527
|
} else {
|
|
@@ -33038,12 +33535,12 @@ ${detail}` : ""}`
|
|
|
33038
33535
|
sourceRadios = [];
|
|
33039
33536
|
body.replaceChildren();
|
|
33040
33537
|
controls.replaceChildren();
|
|
33041
|
-
const { source, record:
|
|
33538
|
+
const { source, record: record7 } = state;
|
|
33042
33539
|
const close = () => modal.close();
|
|
33043
33540
|
if (mode === "add" || mode === "reimport") {
|
|
33044
33541
|
title.textContent = mode === "add" ? messages.add : messages.reimport;
|
|
33045
33542
|
modal.setAttribute("aria-label", title.textContent);
|
|
33046
|
-
const active = source ??
|
|
33543
|
+
const active = source ?? record7?.source;
|
|
33047
33544
|
const choices = mode === "add" && state.choose ? compatibleSources() : [];
|
|
33048
33545
|
if (choices.length > 1) body.append(sourcePicker(choices));
|
|
33049
33546
|
else if (active) body.append(line(messages.source, shown(active.label)));
|
|
@@ -33052,8 +33549,8 @@ ${detail}` : ""}`
|
|
|
33052
33549
|
input.maxLength = 48;
|
|
33053
33550
|
input.autocomplete = "off";
|
|
33054
33551
|
input.spellcheck = false;
|
|
33055
|
-
input.value =
|
|
33056
|
-
input.readOnly = Boolean(
|
|
33552
|
+
input.value = record7?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
|
|
33553
|
+
input.readOnly = Boolean(record7);
|
|
33057
33554
|
input.addEventListener("input", () => {
|
|
33058
33555
|
nameEdited = true;
|
|
33059
33556
|
});
|
|
@@ -33087,7 +33584,7 @@ ${detail}` : ""}`
|
|
|
33087
33584
|
{
|
|
33088
33585
|
action: mode === "reimport" ? "reimport" : "import",
|
|
33089
33586
|
sourceId: source2.id,
|
|
33090
|
-
name:
|
|
33587
|
+
name: record7?.name ?? input.value,
|
|
33091
33588
|
confirmed: true
|
|
33092
33589
|
},
|
|
33093
33590
|
"done"
|
|
@@ -33097,16 +33594,16 @@ ${detail}` : ""}`
|
|
|
33097
33594
|
)
|
|
33098
33595
|
);
|
|
33099
33596
|
(mode === "add" ? input : controls.children[0]).focus();
|
|
33100
|
-
} else if (mode === "remove" &&
|
|
33597
|
+
} else if (mode === "remove" && record7) {
|
|
33101
33598
|
title.textContent = messages.remove;
|
|
33102
33599
|
modal.setAttribute("aria-label", title.textContent);
|
|
33103
|
-
body.append(note(messages.removeWarning.replace("{name}",
|
|
33600
|
+
body.append(note(messages.removeWarning.replace("{name}", record7.name)));
|
|
33104
33601
|
const cancel = command(messages.cancel, close);
|
|
33105
33602
|
controls.append(
|
|
33106
33603
|
cancel,
|
|
33107
33604
|
command(
|
|
33108
33605
|
messages.remove,
|
|
33109
|
-
() => submit({ action: "remove", name:
|
|
33606
|
+
() => submit({ action: "remove", name: record7.name, confirmed: true }, null),
|
|
33110
33607
|
"danger"
|
|
33111
33608
|
)
|
|
33112
33609
|
);
|
|
@@ -33114,7 +33611,7 @@ ${detail}` : ""}`
|
|
|
33114
33611
|
} else {
|
|
33115
33612
|
title.textContent = messages.doneTitle;
|
|
33116
33613
|
modal.setAttribute("aria-label", title.textContent);
|
|
33117
|
-
const name =
|
|
33614
|
+
const name = record7?.name;
|
|
33118
33615
|
if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
|
|
33119
33616
|
body.append(note(messages.done));
|
|
33120
33617
|
const done = command(messages.close, close, "primary");
|
|
@@ -33161,21 +33658,21 @@ ${detail}` : ""}`
|
|
|
33161
33658
|
(candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
|
|
33162
33659
|
);
|
|
33163
33660
|
if (!source || !target) return null;
|
|
33164
|
-
const
|
|
33661
|
+
const record7 = target.imports.find((candidate) => candidate.source.id === source.id);
|
|
33165
33662
|
const key = `${harnessId}:${accountLabel}:import`;
|
|
33166
33663
|
const button2 = document2.createElement("button");
|
|
33167
33664
|
button2.type = "button";
|
|
33168
33665
|
button2.className = "settings-account-pi-import";
|
|
33169
33666
|
button2.dataset.accountFocus = key;
|
|
33170
33667
|
button2.disabled = busy;
|
|
33171
|
-
const hint =
|
|
33668
|
+
const hint = record7 ? messages.importedHint.replace("{name}", record7.name) : messages.add;
|
|
33172
33669
|
button2.title = hint;
|
|
33173
33670
|
button2.setAttribute("aria-label", hint);
|
|
33174
33671
|
button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
|
|
33175
|
-
if (
|
|
33672
|
+
if (record7) {
|
|
33176
33673
|
button2.dataset.state = "imported";
|
|
33177
33674
|
const name = document2.createElement("code");
|
|
33178
|
-
name.textContent = `${
|
|
33675
|
+
name.textContent = `${record7.name}/\u2026`;
|
|
33179
33676
|
name.translate = false;
|
|
33180
33677
|
button2.append(name, createRendererSettingsIcon("check", 12));
|
|
33181
33678
|
} else {
|
|
@@ -33183,7 +33680,7 @@ ${detail}` : ""}`
|
|
|
33183
33680
|
button2.append(messages.add);
|
|
33184
33681
|
}
|
|
33185
33682
|
button2.addEventListener("click", () => {
|
|
33186
|
-
if (!
|
|
33683
|
+
if (!record7) {
|
|
33187
33684
|
openDialog("add", { source }, key);
|
|
33188
33685
|
return;
|
|
33189
33686
|
}
|
|
@@ -33192,7 +33689,7 @@ ${detail}` : ""}`
|
|
|
33192
33689
|
renderSection();
|
|
33193
33690
|
sectionToggle.setAttribute("aria-expanded", "true");
|
|
33194
33691
|
}
|
|
33195
|
-
const row = rows.get(
|
|
33692
|
+
const row = rows.get(record7.name);
|
|
33196
33693
|
row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
33197
33694
|
row?.focus();
|
|
33198
33695
|
});
|
|
@@ -35749,6 +36246,17 @@ ${detail}` : ""}`
|
|
|
35749
36246
|
line-height: 18px;
|
|
35750
36247
|
}
|
|
35751
36248
|
|
|
36249
|
+
.settings-connection-row__status:has(.settings-connection-version-available) {
|
|
36250
|
+
flex-wrap: wrap;
|
|
36251
|
+
max-width: 160px;
|
|
36252
|
+
}
|
|
36253
|
+
|
|
36254
|
+
.settings-connection-version-available {
|
|
36255
|
+
flex-basis: 100%;
|
|
36256
|
+
color: var(--settings-focus);
|
|
36257
|
+
overflow-wrap: anywhere;
|
|
36258
|
+
}
|
|
36259
|
+
|
|
35752
36260
|
.settings-connection-row__status::before {
|
|
35753
36261
|
width: 6px;
|
|
35754
36262
|
height: 6px;
|
|
@@ -36092,6 +36600,69 @@ ${detail}` : ""}`
|
|
|
36092
36600
|
gap: 8px;
|
|
36093
36601
|
}
|
|
36094
36602
|
|
|
36603
|
+
.settings-grok-computer-use {
|
|
36604
|
+
display: grid;
|
|
36605
|
+
gap: 10px;
|
|
36606
|
+
min-width: 0;
|
|
36607
|
+
margin-top: 4px;
|
|
36608
|
+
padding: 12px;
|
|
36609
|
+
background: var(--settings-surface);
|
|
36610
|
+
border: 1px solid var(--settings-divider);
|
|
36611
|
+
border-radius: 12px;
|
|
36612
|
+
}
|
|
36613
|
+
|
|
36614
|
+
.settings-grok-computer-use__header {
|
|
36615
|
+
display: flex;
|
|
36616
|
+
align-items: flex-start;
|
|
36617
|
+
justify-content: space-between;
|
|
36618
|
+
gap: 12px;
|
|
36619
|
+
}
|
|
36620
|
+
|
|
36621
|
+
.settings-grok-computer-use__copy {
|
|
36622
|
+
display: grid;
|
|
36623
|
+
gap: 4px;
|
|
36624
|
+
min-width: 0;
|
|
36625
|
+
}
|
|
36626
|
+
|
|
36627
|
+
.settings-grok-computer-use__title {
|
|
36628
|
+
margin: 0;
|
|
36629
|
+
color: var(--settings-text);
|
|
36630
|
+
font-size: 14px;
|
|
36631
|
+
font-weight: 600;
|
|
36632
|
+
line-height: 20px;
|
|
36633
|
+
}
|
|
36634
|
+
|
|
36635
|
+
.settings-grok-computer-use__description {
|
|
36636
|
+
margin: 0;
|
|
36637
|
+
color: var(--settings-muted);
|
|
36638
|
+
font-size: 13px;
|
|
36639
|
+
line-height: 18px;
|
|
36640
|
+
overflow-wrap: anywhere;
|
|
36641
|
+
}
|
|
36642
|
+
|
|
36643
|
+
.settings-grok-computer-use__help,
|
|
36644
|
+
.settings-grok-computer-use__status {
|
|
36645
|
+
margin: 0;
|
|
36646
|
+
color: var(--settings-subtle);
|
|
36647
|
+
font-size: 12px;
|
|
36648
|
+
line-height: 16px;
|
|
36649
|
+
overflow-wrap: anywhere;
|
|
36650
|
+
}
|
|
36651
|
+
|
|
36652
|
+
.settings-grok-computer-use__help {
|
|
36653
|
+
padding-top: 8px;
|
|
36654
|
+
border-top: 1px solid var(--settings-divider);
|
|
36655
|
+
}
|
|
36656
|
+
|
|
36657
|
+
.settings-grok-computer-use__browser {
|
|
36658
|
+
padding-top: 8px;
|
|
36659
|
+
border-top: 1px solid var(--settings-divider);
|
|
36660
|
+
}
|
|
36661
|
+
|
|
36662
|
+
.settings-grok-computer-use__status[data-state="on"] {
|
|
36663
|
+
color: var(--settings-success);
|
|
36664
|
+
}
|
|
36665
|
+
|
|
36095
36666
|
.settings-connection-install-callout {
|
|
36096
36667
|
display: grid;
|
|
36097
36668
|
grid-template-columns: 28px minmax(0, 1fr);
|
|
@@ -37341,6 +37912,19 @@ ${detail}` : ""}`
|
|
|
37341
37912
|
border-top: 1px solid var(--settings-divider);
|
|
37342
37913
|
font-size: 13px;
|
|
37343
37914
|
}
|
|
37915
|
+
.settings-voice__health {
|
|
37916
|
+
display: grid;
|
|
37917
|
+
gap: 4px;
|
|
37918
|
+
margin: 8px 12px 12px;
|
|
37919
|
+
color: var(--settings-subtle);
|
|
37920
|
+
font-size: 12px;
|
|
37921
|
+
line-height: 16px;
|
|
37922
|
+
}
|
|
37923
|
+
|
|
37924
|
+
.settings-voice__health p {
|
|
37925
|
+
margin: 0;
|
|
37926
|
+
}
|
|
37927
|
+
|
|
37344
37928
|
.settings-voice__footer p,
|
|
37345
37929
|
.settings-voice__hint {
|
|
37346
37930
|
margin: 4px 0 0;
|
|
@@ -39707,7 +40291,7 @@ th[aria-sort] .console-usage-sort__mark {
|
|
|
39707
40291
|
place();
|
|
39708
40292
|
const observer = ownerWindow ? new ownerWindow.MutationObserver((records) => {
|
|
39709
40293
|
const titlebar = source?.closest("[data-app-shell-titlebar]");
|
|
39710
|
-
if (!source?.isConnected || records.some((
|
|
40294
|
+
if (!source?.isConnected || records.some((record7) => titlebar?.contains(record7.target))) {
|
|
39711
40295
|
place();
|
|
39712
40296
|
}
|
|
39713
40297
|
}) : null;
|
|
@@ -42474,7 +43058,7 @@ ${usage_default}`;
|
|
|
42474
43058
|
let webUiAvailable = false;
|
|
42475
43059
|
try {
|
|
42476
43060
|
const inspection = await client.inspectHarness(
|
|
42477
|
-
{ harnessId: harnessIdSchema.parse(agent), refresh },
|
|
43061
|
+
{ harnessId: harnessIdSchema.parse(agent), refresh, purpose: "availability" },
|
|
42478
43062
|
{ priority: "background" }
|
|
42479
43063
|
);
|
|
42480
43064
|
status = inspection.status === "ready" ? "ready" : inspection.status;
|
|
@@ -42693,6 +43277,18 @@ ${usage_default}`;
|
|
|
42693
43277
|
if (!client?.setHarnessLaunchSettings) throw new Error("Launch settings are unavailable");
|
|
42694
43278
|
return client.setHarnessLaunchSettings({ harnessId: harnessIdSchema.parse(agent), path });
|
|
42695
43279
|
},
|
|
43280
|
+
async getGrokComputerUse(hostId2) {
|
|
43281
|
+
const client = hostId2 === "local" ? modelClientForHost(hostId2) : null;
|
|
43282
|
+
if (!client?.getGrokComputerUse)
|
|
43283
|
+
throw new Error("Grok Computer Use settings are unavailable");
|
|
43284
|
+
return client.getGrokComputerUse();
|
|
43285
|
+
},
|
|
43286
|
+
async setGrokComputerUse(hostId2, update) {
|
|
43287
|
+
const client = hostId2 === "local" ? modelClientForHost(hostId2) : null;
|
|
43288
|
+
if (!client?.setGrokComputerUse)
|
|
43289
|
+
throw new Error("Grok Computer Use settings are unavailable");
|
|
43290
|
+
return client.setGrokComputerUse(update);
|
|
43291
|
+
},
|
|
42696
43292
|
async openWebUi(hostId2, agent) {
|
|
42697
43293
|
const state = hostHarnessAvailabilityState(hostId2);
|
|
42698
43294
|
const client = hostId2 === "local" ? modelClientForHost(hostId2) : null;
|
|
@@ -43335,6 +43931,18 @@ ${usage_default}`;
|
|
|
43335
43931
|
// src/renderer-external-voice-launch.ts
|
|
43336
43932
|
var HOOK_GLOBAL3 = "__codexhostExternalVoiceLaunchV1";
|
|
43337
43933
|
var SHARED_ASSET = "app-shared-8bd9d0399038.js";
|
|
43934
|
+
var LAUNCH_ASSETS = [
|
|
43935
|
+
...CLIENT_OWNED_VOICE_ASSETS.map((profile) => ({
|
|
43936
|
+
...profile,
|
|
43937
|
+
services: CLIENT_OWNED_VOICE_SERVICES
|
|
43938
|
+
})),
|
|
43939
|
+
{
|
|
43940
|
+
version: AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION,
|
|
43941
|
+
initial: AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET,
|
|
43942
|
+
shared: SHARED_ASSET,
|
|
43943
|
+
services: "fN"
|
|
43944
|
+
}
|
|
43945
|
+
];
|
|
43338
43946
|
function isRecord16(value) {
|
|
43339
43947
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43340
43948
|
}
|
|
@@ -43373,7 +43981,7 @@ ${usage_default}`;
|
|
|
43373
43981
|
const config2 = readCpaLiveVoiceHookConfig(target);
|
|
43374
43982
|
if (!config2) return { status: "disabled", dispose() {
|
|
43375
43983
|
} };
|
|
43376
|
-
if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION || config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET || config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion && config2.desktopVersion
|
|
43984
|
+
if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION || config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET || config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion && !supportsVoiceVersion(CLIENT_OWNED_VOICE_ASSETS, config2.desktopVersion))
|
|
43377
43985
|
return { status: "unsupported", dispose() {
|
|
43378
43986
|
} };
|
|
43379
43987
|
const importModule = options.importModule ?? ((url2) => import(url2));
|
|
@@ -43396,14 +44004,11 @@ ${usage_default}`;
|
|
|
43396
44004
|
if (disposed) return;
|
|
43397
44005
|
try {
|
|
43398
44006
|
const names = loadedAssetNames(target.document, target.performance);
|
|
43399
|
-
const
|
|
43400
|
-
|
|
43401
|
-
|
|
43402
|
-
module ??= await importModule(
|
|
43403
|
-
`app://-/assets/${clientOwned ? CLIENT_OWNED_VOICE_SHARED_ASSET : SHARED_ASSET}`
|
|
43404
|
-
);
|
|
44007
|
+
const assets = selectVoiceAssets(LAUNCH_ASSETS, names, config2.desktopVersion);
|
|
44008
|
+
if (assets) {
|
|
44009
|
+
module ??= await importModule(`app://-/assets/${assets.shared}`);
|
|
43405
44010
|
if (disposed) return;
|
|
43406
|
-
const services =
|
|
44011
|
+
const services = module?.[assets.services];
|
|
43407
44012
|
if (isRecord16(services)) {
|
|
43408
44013
|
const original = services.realtimeVoiceRuntime;
|
|
43409
44014
|
if (typeof original === "function" || isRecord16(original)) {
|
|
@@ -43454,11 +44059,294 @@ ${usage_default}`;
|
|
|
43454
44059
|
return handle;
|
|
43455
44060
|
}
|
|
43456
44061
|
|
|
44062
|
+
// src/renderer-voice-capability.ts
|
|
44063
|
+
var GLOBAL = "__codexhostVoiceCapabilityV1";
|
|
44064
|
+
var INFERENCE_GATE = "3683713372";
|
|
44065
|
+
var record6 = (value) => value !== null && typeof value === "object";
|
|
44066
|
+
var capable = (value) => record6(value) && typeof value.isLoading === "boolean" && typeof value.isError === "boolean" && typeof value.isCapable === "boolean";
|
|
44067
|
+
var equal = (a, b) => a.isLoading === b.isLoading && a.isError === b.isError && a.isCapable === b.isCapable;
|
|
44068
|
+
function replayVoiceCapability(store, atom, gate) {
|
|
44069
|
+
const evaluate = (override) => {
|
|
44070
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
44071
|
+
let remaining = 512;
|
|
44072
|
+
let hits = 0;
|
|
44073
|
+
const read = (dependency) => {
|
|
44074
|
+
if (--remaining < 0) throw new Error("Voice capability dependency limit");
|
|
44075
|
+
const value = store.get(dependency);
|
|
44076
|
+
if (dependency === gate) {
|
|
44077
|
+
hits += 1;
|
|
44078
|
+
if (typeof value !== "boolean") throw new Error("Voice inference gate unavailable");
|
|
44079
|
+
return override ? false : value;
|
|
44080
|
+
}
|
|
44081
|
+
if (dependency.write || visiting.has(dependency)) return value;
|
|
44082
|
+
if (typeof dependency.read !== "function") throw new Error("Voice dependency unavailable");
|
|
44083
|
+
visiting.add(dependency);
|
|
44084
|
+
try {
|
|
44085
|
+
return dependency.read(read);
|
|
44086
|
+
} finally {
|
|
44087
|
+
visiting.delete(dependency);
|
|
44088
|
+
}
|
|
44089
|
+
};
|
|
44090
|
+
return { value: read(atom), hits };
|
|
44091
|
+
};
|
|
44092
|
+
try {
|
|
44093
|
+
const native = store.get(atom);
|
|
44094
|
+
if (!capable(native) || native.isLoading || native.isError) return null;
|
|
44095
|
+
const before = evaluate(false);
|
|
44096
|
+
if (!capable(before.value) || !equal(native, before.value)) return null;
|
|
44097
|
+
const after = evaluate(true);
|
|
44098
|
+
return after.hits > 0 && capable(after.value) && !after.value.isLoading && !after.value.isError ? after.value : null;
|
|
44099
|
+
} catch {
|
|
44100
|
+
return null;
|
|
44101
|
+
}
|
|
44102
|
+
}
|
|
44103
|
+
function hooks(fiber) {
|
|
44104
|
+
const result = [];
|
|
44105
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44106
|
+
let hook = fiber.memoizedState;
|
|
44107
|
+
while (record6(hook) && result.length < 4096 && !seen.has(hook)) {
|
|
44108
|
+
seen.add(hook);
|
|
44109
|
+
result.push(hook);
|
|
44110
|
+
hook = hook.next;
|
|
44111
|
+
}
|
|
44112
|
+
return hook == null ? result : [];
|
|
44113
|
+
}
|
|
44114
|
+
function composerFibers(composer, chat = false) {
|
|
44115
|
+
const fibers = /* @__PURE__ */ new Set();
|
|
44116
|
+
const rootKey = Object.getOwnPropertyNames(composer).find(
|
|
44117
|
+
(key) => key.startsWith("__reactFiber$")
|
|
44118
|
+
);
|
|
44119
|
+
const ancestors = rootKey ? committedReactAncestors(Object.getOwnPropertyDescriptor(composer, rootKey)?.value) : [];
|
|
44120
|
+
let root = ancestors[0];
|
|
44121
|
+
if (chat) {
|
|
44122
|
+
const owners = ancestors.filter(
|
|
44123
|
+
({ memoizedProps: props }) => record6(props) && props.isWorkConversation === false && props.isTemporaryChat === false && props.shouldBlockExternalEgress === false && props.readOnly !== true && typeof props.conversationId === "string" && record6(props.composerSelectionContext) && props.composerSelectionContext.conversationId === props.conversationId
|
|
44124
|
+
);
|
|
44125
|
+
if (owners.length !== 1) return fibers;
|
|
44126
|
+
root = owners[0];
|
|
44127
|
+
}
|
|
44128
|
+
if (!root) return fibers;
|
|
44129
|
+
for (const element of [composer, ...composer.querySelectorAll("*")].slice(0, 2048)) {
|
|
44130
|
+
const key = Object.getOwnPropertyNames(element).find((key2) => key2.startsWith("__reactFiber$"));
|
|
44131
|
+
if (!key) continue;
|
|
44132
|
+
const ancestors2 = committedReactAncestors(Object.getOwnPropertyDescriptor(element, key)?.value);
|
|
44133
|
+
const boundary = ancestors2.indexOf(root);
|
|
44134
|
+
if (boundary < 0) continue;
|
|
44135
|
+
for (const fiber of ancestors2.slice(0, boundary + 1)) if (record6(fiber)) fibers.add(fiber);
|
|
44136
|
+
}
|
|
44137
|
+
return fibers;
|
|
44138
|
+
}
|
|
44139
|
+
function bindComposerVoiceCapability(composer, family, gates, allowed, chat = false) {
|
|
44140
|
+
return bindVoiceCapabilitySubscriptions(
|
|
44141
|
+
() => composerFibers(composer, chat),
|
|
44142
|
+
family,
|
|
44143
|
+
gates,
|
|
44144
|
+
allowed
|
|
44145
|
+
);
|
|
44146
|
+
}
|
|
44147
|
+
function bindVoiceCapabilitySubscriptions(currentFibers, family, gates, allowed, realtimeOnly = false) {
|
|
44148
|
+
const fibers = currentFibers();
|
|
44149
|
+
const restores = [];
|
|
44150
|
+
const bindings = [];
|
|
44151
|
+
try {
|
|
44152
|
+
for (const fiber of fibers) {
|
|
44153
|
+
const list = hooks(fiber);
|
|
44154
|
+
for (const memo of list) {
|
|
44155
|
+
const [signal, deps] = Array.isArray(memo.memoizedState) ? memo.memoizedState : [];
|
|
44156
|
+
if (!record6(signal) || !Array.isArray(deps) || deps.length !== 5 || deps[3] !== family || !(deps[1] instanceof Map) || deps[2] !== void 0)
|
|
44157
|
+
continue;
|
|
44158
|
+
const chain = deps[1];
|
|
44159
|
+
const node = chain.get(family.scope.id);
|
|
44160
|
+
const members = node?.familyBindings?.get(family);
|
|
44161
|
+
if (!node || !(members instanceof Map) || node.store !== signal.store) continue;
|
|
44162
|
+
const matches = [...members].filter(([, member]) => member.cacheKey === deps[0]);
|
|
44163
|
+
if (matches.length !== 1 || typeof matches[0]?.[0] !== "string") continue;
|
|
44164
|
+
const parameter = JSON.parse(matches[0][0]);
|
|
44165
|
+
if (!record6(parameter) || Object.keys(parameter).some((key) => key !== "name" && key !== "hostId") || parameter.name !== "voice.realtime" && parameter.name !== "voice.thread" || realtimeOnly && parameter.name !== "voice.realtime" || parameter.hostId !== void 0 && parameter.hostId !== "local" || parameter.name === "voice.thread" && parameter.hostId !== "local")
|
|
44166
|
+
continue;
|
|
44167
|
+
const subscriptions = list.filter((hook2) => {
|
|
44168
|
+
const state = hook2.memoizedState;
|
|
44169
|
+
return Array.isArray(state) && Array.isArray(state[1]) && state[1].length === 2 && state[1][0] === signal && state[1][1] === void 0 && typeof state[0]?.getSnapshot === "function";
|
|
44170
|
+
});
|
|
44171
|
+
if (subscriptions.length !== 1) throw new Error("Ambiguous voice subscription");
|
|
44172
|
+
const hook = subscriptions[0];
|
|
44173
|
+
const subscriber = hook.memoizedState[0];
|
|
44174
|
+
const instance = hook.next?.queue;
|
|
44175
|
+
const effect = hook.next?.next?.memoizedState;
|
|
44176
|
+
const store = signal.store;
|
|
44177
|
+
const gate = gates.resolve(node, chain, INFERENCE_GATE)?.atom;
|
|
44178
|
+
if (!gate || !instance || !record6(effect) || !Array.isArray(effect.deps) || effect.deps[0] !== subscriber.subscribe || typeof effect.create !== "function" || typeof instance.getSnapshot !== "function" || !capable(store.get(signal.atom)) || !capable(subscriber.getSnapshot()) || !capable(instance.getSnapshot()) || !equal(
|
|
44179
|
+
store.get(signal.atom),
|
|
44180
|
+
subscriber.getSnapshot()
|
|
44181
|
+
) || !equal(subscriber.getSnapshot(), instance.getSnapshot()) || subscriber.createRender?.() != null)
|
|
44182
|
+
throw new Error("Unsupported voice subscription");
|
|
44183
|
+
for (const [object3, key] of [
|
|
44184
|
+
[store, "sub"],
|
|
44185
|
+
[subscriber, "getSnapshot"],
|
|
44186
|
+
[instance, "getSnapshot"]
|
|
44187
|
+
])
|
|
44188
|
+
if (Object.getOwnPropertyDescriptor(object3, key)?.writable !== true)
|
|
44189
|
+
throw new Error("Voice subscription is not writable");
|
|
44190
|
+
let notify;
|
|
44191
|
+
const sub = store.sub;
|
|
44192
|
+
try {
|
|
44193
|
+
store.sub = (atom, listener) => {
|
|
44194
|
+
if (atom !== signal.atom || notify) throw new Error("Unexpected voice subscription");
|
|
44195
|
+
notify = listener;
|
|
44196
|
+
return () => {
|
|
44197
|
+
};
|
|
44198
|
+
};
|
|
44199
|
+
effect.create();
|
|
44200
|
+
} finally {
|
|
44201
|
+
store.sub = sub;
|
|
44202
|
+
}
|
|
44203
|
+
if (!notify) throw new Error("Voice listener unavailable");
|
|
44204
|
+
const original = subscriber.getSnapshot;
|
|
44205
|
+
const originalInstance = instance.getSnapshot;
|
|
44206
|
+
let previous;
|
|
44207
|
+
const snapshot = () => {
|
|
44208
|
+
const native = original.call(subscriber);
|
|
44209
|
+
if (!allowed()) return native;
|
|
44210
|
+
const projected = replayVoiceCapability(store, signal.atom, gate);
|
|
44211
|
+
if (!projected || !projected.isCapable) return native;
|
|
44212
|
+
if (!previous || !equal(previous, projected)) previous = projected;
|
|
44213
|
+
return previous;
|
|
44214
|
+
};
|
|
44215
|
+
subscriber.getSnapshot = snapshot;
|
|
44216
|
+
instance.getSnapshot = snapshot;
|
|
44217
|
+
const onChange = notify;
|
|
44218
|
+
restores.push(() => {
|
|
44219
|
+
if (subscriber.getSnapshot === snapshot) subscriber.getSnapshot = original;
|
|
44220
|
+
if (instance.getSnapshot === snapshot) instance.getSnapshot = originalInstance;
|
|
44221
|
+
onChange();
|
|
44222
|
+
});
|
|
44223
|
+
bindings.push({ subscriber, signal, instance });
|
|
44224
|
+
onChange();
|
|
44225
|
+
}
|
|
44226
|
+
}
|
|
44227
|
+
if (!restores.length) throw new Error("Owned voice capability unavailable");
|
|
44228
|
+
if (realtimeOnly && restores.length !== 1) throw new Error("Ambiguous voice starter");
|
|
44229
|
+
} catch (error51) {
|
|
44230
|
+
for (const restore of restores.reverse()) restore();
|
|
44231
|
+
throw error51;
|
|
44232
|
+
}
|
|
44233
|
+
return {
|
|
44234
|
+
dispose() {
|
|
44235
|
+
for (const restore of restores.splice(0).reverse()) restore();
|
|
44236
|
+
},
|
|
44237
|
+
current() {
|
|
44238
|
+
const current = [...currentFibers()].flatMap(hooks);
|
|
44239
|
+
return bindings.every(
|
|
44240
|
+
({ subscriber, signal, instance }) => current.some(
|
|
44241
|
+
(hook) => Array.isArray(hook.memoizedState) && hook.memoizedState[0] === subscriber && hook.memoizedState[1]?.[0] === signal && hook.next?.queue === instance && (!realtimeOnly || capable(hook.next?.memoizedState) && hook.next.memoizedState.isCapable)
|
|
44242
|
+
)
|
|
44243
|
+
);
|
|
44244
|
+
}
|
|
44245
|
+
};
|
|
44246
|
+
}
|
|
44247
|
+
function installVoiceCapabilityProjection(options = {}) {
|
|
44248
|
+
const target = options.target ?? globalThis;
|
|
44249
|
+
if (target[GLOBAL]) return target[GLOBAL];
|
|
44250
|
+
const config2 = readCpaLiveVoiceHookConfig(target);
|
|
44251
|
+
if (!config2) return { status: "disabled", dispose() {
|
|
44252
|
+
} };
|
|
44253
|
+
if (!supportsVoiceVersion(CLIENT_OWNED_VOICE_ASSETS, config2.desktopVersion))
|
|
44254
|
+
return { status: "unsupported", dispose() {
|
|
44255
|
+
} };
|
|
44256
|
+
let timer;
|
|
44257
|
+
let binding;
|
|
44258
|
+
let composer;
|
|
44259
|
+
let disposed = false;
|
|
44260
|
+
const handle = {
|
|
44261
|
+
status: "pending",
|
|
44262
|
+
dispose() {
|
|
44263
|
+
disposed = true;
|
|
44264
|
+
target.clearTimeout(timer);
|
|
44265
|
+
binding?.dispose();
|
|
44266
|
+
if (target[GLOBAL] === handle) Reflect.deleteProperty(target, GLOBAL);
|
|
44267
|
+
}
|
|
44268
|
+
};
|
|
44269
|
+
target[GLOBAL] = handle;
|
|
44270
|
+
const hookActive = (key) => {
|
|
44271
|
+
const hook = target[key];
|
|
44272
|
+
return record6(hook) && hook.status === "active";
|
|
44273
|
+
};
|
|
44274
|
+
const currentRoute = () => {
|
|
44275
|
+
try {
|
|
44276
|
+
const routing = target.__codexhostHostRoutingV1;
|
|
44277
|
+
const route = routing?.forComposer();
|
|
44278
|
+
return route?.hostId === "local" && routing?.forHost("local") === route ? route : void 0;
|
|
44279
|
+
} catch {
|
|
44280
|
+
return void 0;
|
|
44281
|
+
}
|
|
44282
|
+
};
|
|
44283
|
+
const external = () => {
|
|
44284
|
+
try {
|
|
44285
|
+
return currentRoute()?.policy.selectedModel()?.startsWith("codexhost/") === true;
|
|
44286
|
+
} catch {
|
|
44287
|
+
return false;
|
|
44288
|
+
}
|
|
44289
|
+
};
|
|
44290
|
+
const chatGateway = () => !isWorkComposerSurface(target) && chatLiveVoicePreferenceAllowsOverride(target);
|
|
44291
|
+
const allowed = () => !!readCpaLiveVoiceHookConfig(target) && voiceGatewayIsReady(target) && hookActive("__codexhostClientOwnedVoiceV1") && hookActive("__codexhostExternalVoiceLaunchV1") && (chatGateway() || !!currentRoute() && (isWorkComposerSurface(target) || external() && target.document?.querySelectorAll("[data-chatgpt-composer]").length === 0) && (cpaLiveVoicePreferenceAllowsInstall(target) || external()));
|
|
44292
|
+
const refresh = async () => {
|
|
44293
|
+
if (disposed) return;
|
|
44294
|
+
try {
|
|
44295
|
+
const names = loadedAssetNames(target.document, target.performance);
|
|
44296
|
+
const assets = selectVoiceAssets(CLIENT_OWNED_VOICE_ASSETS, names, config2.desktopVersion);
|
|
44297
|
+
if (!assets) {
|
|
44298
|
+
handle.status = "unsupported";
|
|
44299
|
+
} else if (!allowed()) handle.status = "pending";
|
|
44300
|
+
else {
|
|
44301
|
+
const module = await (options.importModule ?? ((url2) => import(url2)))(
|
|
44302
|
+
`app://-/assets/${assets.initial}`
|
|
44303
|
+
);
|
|
44304
|
+
if (disposed) return;
|
|
44305
|
+
if (typeof module.njr !== "function")
|
|
44306
|
+
throw new Error("Voice capability exports unavailable");
|
|
44307
|
+
const composers = [
|
|
44308
|
+
...target.document?.querySelectorAll(
|
|
44309
|
+
chatGateway() ? "[data-chatgpt-composer]" : "[data-codex-composer-root]"
|
|
44310
|
+
) ?? []
|
|
44311
|
+
].filter(
|
|
44312
|
+
(element) => element.getBoundingClientRect().width > 0 && !element.closest("[hidden], [inert]")
|
|
44313
|
+
);
|
|
44314
|
+
if (composers.length !== 1) throw new Error("Voice composer unavailable");
|
|
44315
|
+
if (composers[0] !== composer || !binding?.current()) {
|
|
44316
|
+
module.njr();
|
|
44317
|
+
binding?.dispose();
|
|
44318
|
+
binding = void 0;
|
|
44319
|
+
composer = composers[0];
|
|
44320
|
+
binding = bindComposerVoiceCapability(
|
|
44321
|
+
composer,
|
|
44322
|
+
module.tjr,
|
|
44323
|
+
module.uBr,
|
|
44324
|
+
allowed,
|
|
44325
|
+
chatGateway()
|
|
44326
|
+
);
|
|
44327
|
+
}
|
|
44328
|
+
handle.status = "active";
|
|
44329
|
+
}
|
|
44330
|
+
} catch {
|
|
44331
|
+
handle.status = "unsupported";
|
|
44332
|
+
}
|
|
44333
|
+
if (handle.status !== "active") {
|
|
44334
|
+
binding?.dispose();
|
|
44335
|
+
binding = void 0;
|
|
44336
|
+
composer = void 0;
|
|
44337
|
+
}
|
|
44338
|
+
if (!disposed) timer = target.setTimeout(() => void refresh(), 1e3);
|
|
44339
|
+
};
|
|
44340
|
+
void refresh();
|
|
44341
|
+
return handle;
|
|
44342
|
+
}
|
|
44343
|
+
|
|
43457
44344
|
// src/production-entry.ts
|
|
43458
44345
|
installCpaLiveVoiceHook();
|
|
43459
44346
|
installClientOwnedVoiceHook();
|
|
43460
44347
|
installExternalVoiceLaunchHook();
|
|
43461
44348
|
installNativeChatVoiceHook();
|
|
44349
|
+
installVoiceCapabilityProjection();
|
|
43462
44350
|
var installBinding = () => {
|
|
43463
44351
|
installRendererBinding();
|
|
43464
44352
|
};
|