@karlorz/codexhost-cli-darwin-x64 0.13.3-5 → 0.13.3-6

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.
@@ -6,164 +6,102 @@
6
6
  __defProp(target, name, { get: all[name], enumerable: true });
7
7
  };
8
8
 
9
- // src/renderer-cpa-live-voice-preference.ts
10
- var CPA_LIVE_VOICE_STORAGE_KEY = "codexhost.cpa-live-voice.v1";
11
- var CPA_LIVE_VOICE_CHANGE_EVENT = "codexhost:cpa-live-voice-changed";
12
- function readCpaLiveVoicePreference(owner) {
13
- try {
14
- return owner.localStorage.getItem(CPA_LIVE_VOICE_STORAGE_KEY) !== "0";
15
- } catch {
16
- return true;
17
- }
18
- }
19
- function writeCpaLiveVoicePreference(owner, enabled) {
20
- try {
21
- owner.localStorage.setItem(CPA_LIVE_VOICE_STORAGE_KEY, enabled ? "1" : "0");
22
- } catch {
23
- return false;
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);
24
34
  }
25
- owner.dispatchEvent(new Event(CPA_LIVE_VOICE_CHANGE_EVENT));
26
- return true;
27
- }
28
- function cpaLiveVoicePreferenceAllowsInstall(globalObject) {
29
- const storage = globalObject.localStorage;
30
- if (!storage) return true;
31
- try {
32
- return storage.getItem(CPA_LIVE_VOICE_STORAGE_KEY) !== "0";
33
- } catch {
34
- return true;
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);
35
61
  }
36
- }
37
-
38
- // src/renderer-cpa-live-voice-hook.ts
39
- var CPA_LIVE_VOICE_HOOK_GLOBAL = "__codexhostCpaLiveVoiceHookV1";
40
- var AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION = "26.1007.30912";
41
- var AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET = "app-initial-6350d04672d0.js";
42
- var THREAD_REALTIME_EXISTING_CALL_GATE = "206132468";
43
- var originalCheckGate = /* @__PURE__ */ new WeakMap();
44
- var DISCOVERY_TIMEOUT_MS = 6e4;
45
- function isRecord(value) {
46
- return typeof value === "object" && value !== null;
47
- }
48
- function readCpaLiveVoiceHookConfig(globalObject) {
49
- const value = globalObject[CPA_LIVE_VOICE_HOOK_GLOBAL];
50
- if (!isRecord(value) || value.enabled !== true) return null;
51
- if (typeof value.auditedDesktopVersion !== "string" || typeof value.auditedAppInitialAsset !== "string") {
52
- return null;
62
+ if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
63
+ return path.reverse();
53
64
  }
54
- return {
55
- enabled: true,
56
- auditedDesktopVersion: value.auditedDesktopVersion,
57
- auditedAppInitialAsset: value.auditedAppInitialAsset,
58
- ...typeof value.desktopVersion === "string" ? { desktopVersion: value.desktopVersion } : {}
59
- };
60
- }
61
- function auditedAppInitialAssetPresent(resourceNames, asset) {
62
- return resourceNames.some((name) => {
63
- try {
64
- const url2 = new URL(name, "app://-/");
65
- return url2.protocol === "app:" && url2.hostname === "-" && url2.pathname === `/assets/${asset}`;
66
- } catch {
67
- return false;
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;
68
79
  }
69
- });
70
- }
71
- function resourceNamesFromPerformance(source) {
72
- const target = source ?? (typeof performance === "undefined" ? void 0 : performance);
73
- if (!target || typeof target.getEntriesByType !== "function") return [];
74
- return target.getEntriesByType("resource").map((entry) => entry.name).filter((name) => typeof name === "string");
75
- }
76
- function loadedAssetNames(root, performanceSource) {
77
- const names = resourceNamesFromPerformance(performanceSource);
78
- if (!root || !("querySelectorAll" in root)) return names;
79
- for (const element of root.querySelectorAll("script[src], link[href]")) {
80
- const value = element.getAttribute("src") ?? element.getAttribute("href");
81
- if (value) names.push(value);
82
- }
83
- return names;
84
- }
85
- function statsigClients(globalObject) {
86
- const registry2 = globalObject.__STATSIG__;
87
- if (!isRecord(registry2)) return [];
88
- const clients = new Set(
89
- isRecord(registry2.instances) ? Object.values(registry2.instances) : []
90
- );
91
- if (registry2.firstInstance) clients.add(registry2.firstInstance);
92
- return [...clients].filter(
93
- (client) => isRecord(client) && typeof client.checkGate === "function"
94
- );
95
- }
96
- function wrapCheckGate(client) {
97
- if (originalCheckGate.has(client)) return false;
98
- const original = client.checkGate;
99
- originalCheckGate.set(client, original);
100
- client.checkGate = function(name, ...rest) {
101
- return name === THREAD_REALTIME_EXISTING_CALL_GATE ? false : original.call(this, name, ...rest);
102
- };
103
- return true;
104
- }
105
- function restoreCheckGate(client) {
106
- const original = originalCheckGate.get(client);
107
- if (!original) return;
108
- client.checkGate = original;
109
- originalCheckGate.delete(client);
110
- }
111
- function configAllowsInstall(config2, resourceNames) {
112
- if (config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion) {
113
- return false;
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 });
114
86
  }
115
- if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION) return false;
116
- if (config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET) return false;
117
- return auditedAppInitialAssetPresent(resourceNames, config2.auditedAppInitialAsset);
87
+ return stack.length > 0 ? exhausted() : [];
118
88
  }
119
- function installCpaLiveVoiceHook(options = {}) {
120
- const globalObject = options.globalThis ?? globalThis;
121
- const config2 = options.config === void 0 ? readCpaLiveVoiceHookConfig(globalObject) : options.config;
122
- if (!config2?.enabled || !cpaLiveVoicePreferenceAllowsInstall(globalObject)) {
123
- return { status: "disabled", dispose() {
124
- } };
125
- }
126
- const root = options.document ?? globalObject.document;
127
- const wrapped = [];
128
- let disposed = false;
129
- let auditedAssetFound = false;
130
- const handle = {
131
- status: "pending",
132
- dispose() {
133
- disposed = true;
134
- for (const client of wrapped) restoreCheckGate(client);
135
- wrapped.length = 0;
136
- }
137
- };
138
- const attempt = () => {
139
- if (!auditedAssetFound) {
140
- const resourceNames = options.resourceNames ?? loadedAssetNames(root);
141
- auditedAssetFound = configAllowsInstall(config2, resourceNames);
142
- if (!auditedAssetFound) return false;
143
- }
144
- for (const client of statsigClients(globalObject)) {
145
- if (wrapCheckGate(client)) wrapped.push(client);
146
- }
147
- if (wrapped.length === 0) return false;
148
- handle.status = "active";
149
- return true;
150
- };
151
- if (attempt()) return handle;
152
- if (options.resourceNames && !configAllowsInstall(config2, options.resourceNames)) {
153
- handle.status = "unsupported";
154
- return handle;
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 {
155
103
  }
156
- const started = Date.now();
157
- const tick = () => {
158
- if (disposed || attempt()) return;
159
- if (Date.now() - started > DISCOVERY_TIMEOUT_MS) {
160
- handle.status = "unsupported";
161
- return;
162
- }
163
- globalThis.setTimeout(tick, 250);
164
- };
165
- globalThis.setTimeout(tick, 250);
166
- return handle;
104
+ owner.console?.info?.("[codexhost-chat-voice]", event, detail);
167
105
  }
168
106
 
169
107
  // ../../node_modules/zod/v4/classic/external.js
@@ -15041,6 +14979,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15041
14979
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
15042
14980
  });
15043
14981
  var CONSOLE_HOST_METHODS = Object.freeze([
14982
+ "codexhost/voice/gateway-status",
15044
14983
  "codexhost/console/remote-connections",
15045
14984
  "codexhost/runtime/status",
15046
14985
  "codexhost/remote/ssh-setup",
@@ -16216,158 +16155,254 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16216
16155
  external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
16217
16156
  ]);
16218
16157
 
16158
+ // ../shared-contracts/dist/voice-settings.js
16159
+ var VOICE_SETTINGS_METHOD = "codexhost/voice/settings";
16160
+ var voiceRoutesSchema = external_exports.strictObject({
16161
+ chatExperience: external_exports.enum(["chatgpt", "codex"]),
16162
+ chatConnection: external_exports.enum(["desktop", "gateway"]),
16163
+ workConnection: external_exports.enum(["desktop", "gateway"])
16164
+ });
16165
+ var DEFAULT_VOICE_ROUTES = Object.freeze({
16166
+ chatExperience: "chatgpt",
16167
+ chatConnection: "desktop",
16168
+ workConnection: "gateway"
16169
+ });
16170
+ var voiceSettingsSchema = voiceRoutesSchema.extend({ inject: external_exports.boolean() });
16171
+ var voiceSettingsRequestSchema = external_exports.discriminatedUnion("operation", [
16172
+ external_exports.strictObject({
16173
+ operation: external_exports.literal("get"),
16174
+ runtime: external_exports.strictObject({
16175
+ id: external_exports.string().uuid(),
16176
+ revision: external_exports.string().max(64),
16177
+ activeCall: external_exports.boolean()
16178
+ }).optional()
16179
+ }),
16180
+ external_exports.strictObject({ operation: external_exports.literal("migrate"), routes: voiceRoutesSchema }),
16181
+ external_exports.strictObject({
16182
+ operation: external_exports.literal("set"),
16183
+ settings: voiceSettingsSchema,
16184
+ revision: external_exports.string().max(64)
16185
+ }),
16186
+ external_exports.strictObject({ operation: external_exports.literal("restart"), confirm: external_exports.literal(true) })
16187
+ ]);
16188
+ var voiceSettingsStateSchema = external_exports.strictObject({
16189
+ settings: voiceSettingsSchema,
16190
+ initialized: external_exports.boolean(),
16191
+ revision: external_exports.string(),
16192
+ activeInject: external_exports.boolean().nullable(),
16193
+ envOverride: external_exports.enum(["0", "1"]).nullable(),
16194
+ activeEnvOverride: external_exports.enum(["0", "1"]).nullable(),
16195
+ routesActive: external_exports.boolean().nullable(),
16196
+ activeCall: external_exports.boolean().nullable(),
16197
+ gatewayReady: external_exports.boolean().nullable(),
16198
+ restartAvailable: external_exports.boolean(),
16199
+ restart: external_exports.strictObject({
16200
+ phase: external_exports.enum(["idle", "restarting", "succeeded", "failed"]),
16201
+ error: external_exports.string().nullable()
16202
+ })
16203
+ });
16204
+
16219
16205
  // ../shared-contracts/dist/index.js
16220
16206
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
16221
16207
 
16222
- // src/renderer-client-owned-voice.ts
16223
- var CLIENT_OWNED_VOICE_VERSION = "26.1013.40934";
16224
- var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-90eb42395b7d.js";
16225
- var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-52443cbe9ac4.js";
16226
- var HOOK_GLOBAL = "__codexhostClientOwnedVoiceV1";
16227
- function object2(value) {
16228
- return value !== null && typeof value === "object";
16208
+ // src/renderer-cpa-live-voice-preference.ts
16209
+ var sharedRoutes = /* @__PURE__ */ new WeakMap();
16210
+ var SHARED_VOICE_CACHE = "codexhost.voice-routes-cache.v1";
16211
+ function cachedRoutes(owner) {
16212
+ const memory = sharedRoutes.get(owner);
16213
+ if (memory) return memory;
16214
+ try {
16215
+ const storage = owner.localStorage;
16216
+ const parsed = voiceRoutesSchema.safeParse(
16217
+ JSON.parse(storage?.getItem(SHARED_VOICE_CACHE) ?? "null")
16218
+ ).data;
16219
+ if (parsed) sharedRoutes.set(owner, parsed);
16220
+ return parsed;
16221
+ } catch {
16222
+ return void 0;
16223
+ }
16229
16224
  }
16230
- function requestHost(bridge, params) {
16231
- const id = `codexhost-voice:${crypto.randomUUID()}`;
16232
- return new Promise((resolve, reject) => {
16233
- let unsubscribe = () => {
16234
- };
16235
- const timer = setTimeout(() => {
16236
- unsubscribe();
16237
- reject(new Error("Voice gateway did not answer in time"));
16238
- }, 3e4);
16239
- const done = () => {
16240
- clearTimeout(timer);
16241
- unsubscribe();
16242
- };
16243
- unsubscribe = bridge.subscribe("mcp-response", (event) => {
16244
- if (!object2(event) || event.hostId !== "local" || !object2(event.message) || event.message.id !== id)
16245
- return;
16246
- done();
16247
- if (event.message.error) reject(new Error("Configured voice gateway request failed"));
16248
- else resolve(event.message.result);
16249
- });
16225
+ function applySharedVoiceRoutes(owner, routes) {
16226
+ const snapshot = voiceRoutesSchema.parse({
16227
+ chatExperience: routes.chatExperience,
16228
+ chatConnection: routes.chatConnection,
16229
+ workConnection: routes.workConnection
16230
+ });
16231
+ sharedRoutes.set(owner, snapshot);
16232
+ try {
16233
+ owner.localStorage?.setItem(
16234
+ SHARED_VOICE_CACHE,
16235
+ JSON.stringify(snapshot)
16236
+ );
16237
+ } catch {
16238
+ }
16239
+ }
16240
+ function nativeChatVoicePreferenceAllowsStart(owner) {
16241
+ const routes = cachedRoutes(owner);
16242
+ return routes ? routes.chatExperience === "chatgpt" : !readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false);
16243
+ }
16244
+ function legacyVoiceRoutes(owner) {
16245
+ return {
16246
+ chatExperience: readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false) ? "codex" : "chatgpt",
16247
+ chatConnection: readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false) ? "gateway" : "desktop",
16248
+ workConnection: readFlag(owner, CPA_LIVE_VOICE_STORAGE_KEY, true) ? "gateway" : "desktop"
16249
+ };
16250
+ }
16251
+ var CPA_LIVE_VOICE_STORAGE_KEY = "codexhost.cpa-live-voice.v1";
16252
+ var CHAT_LIVE_VOICE_STORAGE_KEY = "codexhost.chat-live-voice.v1";
16253
+ function readFlag(owner, key, enabledWhenUnset) {
16254
+ const storage = owner.localStorage;
16255
+ if (!storage) return enabledWhenUnset;
16256
+ try {
16257
+ const value = storage.getItem(key);
16258
+ return enabledWhenUnset ? value !== "0" : value === "1";
16259
+ } catch {
16260
+ return enabledWhenUnset;
16261
+ }
16262
+ }
16263
+ function readCpaLiveVoicePreference(owner) {
16264
+ const routes = cachedRoutes(owner);
16265
+ return routes ? routes.workConnection === "gateway" : readFlag(owner, CPA_LIVE_VOICE_STORAGE_KEY, true);
16266
+ }
16267
+ function readChatLiveVoicePreference(owner) {
16268
+ const routes = cachedRoutes(owner);
16269
+ return routes ? routes.chatExperience === "codex" && routes.chatConnection === "gateway" : readFlag(owner, CHAT_LIVE_VOICE_STORAGE_KEY, false);
16270
+ }
16271
+ function cpaLiveVoicePreferenceAllowsInstall(globalObject) {
16272
+ return readCpaLiveVoicePreference(globalObject);
16273
+ }
16274
+ function chatLiveVoicePreferenceAllowsOverride(globalObject) {
16275
+ return readChatLiveVoicePreference(globalObject);
16276
+ }
16277
+
16278
+ // src/renderer-cpa-live-voice-hook.ts
16279
+ var CPA_LIVE_VOICE_HOOK_GLOBAL = "__codexhostCpaLiveVoiceHookV1";
16280
+ var AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION = "26.1007.30912";
16281
+ var AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET = "app-initial-6350d04672d0.js";
16282
+ var THREAD_REALTIME_EXISTING_CALL_GATE = "206132468";
16283
+ var originalCheckGate = /* @__PURE__ */ new WeakMap();
16284
+ var DISCOVERY_TIMEOUT_MS = 6e4;
16285
+ function isRecord(value) {
16286
+ return typeof value === "object" && value !== null;
16287
+ }
16288
+ function readCpaLiveVoiceHookConfig(globalObject) {
16289
+ const value = globalObject[CPA_LIVE_VOICE_HOOK_GLOBAL];
16290
+ if (!isRecord(value) || value.enabled !== true) return null;
16291
+ if (typeof value.auditedDesktopVersion !== "string" || typeof value.auditedAppInitialAsset !== "string") {
16292
+ return null;
16293
+ }
16294
+ return {
16295
+ enabled: true,
16296
+ auditedDesktopVersion: value.auditedDesktopVersion,
16297
+ auditedAppInitialAsset: value.auditedAppInitialAsset,
16298
+ ...typeof value.desktopVersion === "string" ? { desktopVersion: value.desktopVersion } : {}
16299
+ };
16300
+ }
16301
+ function auditedAppInitialAssetPresent(resourceNames, asset) {
16302
+ return resourceNames.some((name) => {
16250
16303
  try {
16251
- bridge.dispatchMessage("mcp-request", {
16252
- hostId: "local",
16253
- request: { id, method: REALTIME_CALL_METHOD, params }
16254
- });
16304
+ const url2 = new URL(name, "app://-/");
16305
+ return url2.protocol === "app:" && url2.hostname === "-" && url2.pathname === `/assets/${asset}`;
16255
16306
  } catch {
16256
- done();
16257
- reject(new Error("Voice gateway Host connection is unavailable"));
16307
+ return false;
16258
16308
  }
16259
16309
  });
16260
16310
  }
16261
- function wrapClientOwnedVoiceFetch(client, bridge, enabled, responseError) {
16262
- const original = client.fetch;
16263
- const wrapped = async function(url2, options) {
16264
- if (typeof url2 !== "string" || url2.split("?")[0] !== "/wham/realtime/calls" || options?.method !== "POST" || !enabled())
16265
- return original.call(this, url2, options);
16266
- if (typeof options.body !== "string") throw new Error("Unsupported native voice call request");
16267
- options.signal?.throwIfAborted();
16268
- const requestId2 = crypto.randomUUID();
16269
- let cancelled = false;
16270
- const cancel = () => {
16271
- if (cancelled) return;
16272
- cancelled = true;
16273
- void requestHost(bridge, { operation: "cancel", requestId: requestId2 }).catch(() => void 0);
16274
- };
16275
- options.signal?.addEventListener("abort", cancel, { once: true });
16276
- try {
16277
- const result = realtimeCallResponseSchema.parse(
16278
- await requestHost(bridge, {
16279
- operation: "create",
16280
- requestId: requestId2,
16281
- body: options.body,
16282
- // Drop Desktop OAuth, ChatGPT account identity and cookies at the bridge
16283
- // boundary; the Host allowlist repeats this check before sending.
16284
- headers: filterRealtimeCallHeaders(Object.fromEntries(new Headers(options.headers)))
16285
- })
16286
- );
16287
- if (options.signal?.aborted) {
16288
- const callId = realtimeCallIdFromLocation(result.headers.location ?? "");
16289
- if (result.status >= 200 && result.status < 300 && isRealtimeCallId(callId))
16290
- await requestHost(bridge, { operation: "hangup", callId });
16291
- options.signal.throwIfAborted();
16292
- }
16293
- const response = new Response(result.status === 204 ? null : result.body, {
16294
- status: result.status,
16295
- headers: result.headers
16296
- });
16297
- if (!response.ok) throw await responseError(response, url2);
16298
- return response;
16299
- } catch (error51) {
16300
- cancel();
16301
- throw error51;
16302
- } finally {
16303
- options.signal?.removeEventListener("abort", cancel);
16304
- }
16305
- };
16306
- client.fetch = wrapped;
16307
- return () => {
16308
- if (client.fetch === wrapped) client.fetch = original;
16311
+ function resourceNamesFromPerformance(source) {
16312
+ const target = source ?? (typeof performance === "undefined" ? void 0 : performance);
16313
+ if (!target || typeof target.getEntriesByType !== "function") return [];
16314
+ return target.getEntriesByType("resource").map((entry) => entry.name).filter((name) => typeof name === "string");
16315
+ }
16316
+ function loadedAssetNames(root, performanceSource) {
16317
+ const names = resourceNamesFromPerformance(performanceSource);
16318
+ if (!root || !("querySelectorAll" in root)) return names;
16319
+ for (const element of root.querySelectorAll("script[src], link[href]")) {
16320
+ const value = element.getAttribute("src") ?? element.getAttribute("href");
16321
+ if (value) names.push(value);
16322
+ }
16323
+ return names;
16324
+ }
16325
+ function statsigClients(globalObject) {
16326
+ const registry2 = globalObject.__STATSIG__;
16327
+ if (!isRecord(registry2)) return [];
16328
+ const clients = new Set(
16329
+ isRecord(registry2.instances) ? Object.values(registry2.instances) : []
16330
+ );
16331
+ if (registry2.firstInstance) clients.add(registry2.firstInstance);
16332
+ return [...clients].filter(
16333
+ (client) => isRecord(client) && typeof client.checkGate === "function"
16334
+ );
16335
+ }
16336
+ function wrapCheckGate(client) {
16337
+ if (originalCheckGate.has(client)) return false;
16338
+ const original = client.checkGate;
16339
+ originalCheckGate.set(client, original);
16340
+ client.checkGate = function(name, ...rest) {
16341
+ return name === THREAD_REALTIME_EXISTING_CALL_GATE ? false : original.call(this, name, ...rest);
16309
16342
  };
16343
+ return true;
16310
16344
  }
16311
- function installClientOwnedVoiceHook(options = {}) {
16312
- const target = options.target ?? globalThis;
16313
- const existing = target[HOOK_GLOBAL];
16314
- if (existing) return existing;
16315
- const config2 = readCpaLiveVoiceHookConfig(target);
16316
- if (!config2 || !cpaLiveVoicePreferenceAllowsInstall(target))
16345
+ function restoreCheckGate(client) {
16346
+ const original = originalCheckGate.get(client);
16347
+ if (!original) return;
16348
+ client.checkGate = original;
16349
+ originalCheckGate.delete(client);
16350
+ }
16351
+ function configAllowsInstall(config2, resourceNames) {
16352
+ if (config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion) {
16353
+ return false;
16354
+ }
16355
+ if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION) return false;
16356
+ if (config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET) return false;
16357
+ return auditedAppInitialAssetPresent(resourceNames, config2.auditedAppInitialAsset);
16358
+ }
16359
+ function installCpaLiveVoiceHook(options = {}) {
16360
+ const globalObject = options.globalThis ?? globalThis;
16361
+ const config2 = options.config === void 0 ? readCpaLiveVoiceHookConfig(globalObject) : options.config;
16362
+ if (!config2?.enabled || !cpaLiveVoicePreferenceAllowsInstall(globalObject)) {
16317
16363
  return { status: "disabled", dispose() {
16318
16364
  } };
16319
- if (config2.desktopVersion !== void 0 && config2.desktopVersion !== CLIENT_OWNED_VOICE_VERSION)
16320
- return { status: "unsupported", dispose() {
16321
- } };
16322
- const importModule = options.importModule ?? ((url2) => import(url2));
16365
+ }
16366
+ const root = options.document ?? globalObject.document;
16367
+ const wrapped = [];
16323
16368
  let disposed = false;
16324
- let timer;
16325
- let restore;
16326
- const started = Date.now();
16369
+ let auditedAssetFound = false;
16327
16370
  const handle = {
16328
16371
  status: "pending",
16329
16372
  dispose() {
16330
16373
  disposed = true;
16331
- if (timer !== void 0) target.clearTimeout(timer);
16332
- restore?.();
16333
- if (target[HOOK_GLOBAL] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL);
16374
+ for (const client of wrapped) restoreCheckGate(client);
16375
+ wrapped.length = 0;
16334
16376
  }
16335
16377
  };
16336
- target[HOOK_GLOBAL] = handle;
16337
- const attempt = async () => {
16338
- if (disposed) return;
16339
- const names = loadedAssetNames(target.document, target.performance);
16340
- if (auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_INITIAL_ASSET) && auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_SHARED_ASSET)) {
16341
- try {
16342
- const module = await importModule(`app://-/assets/${CLIENT_OWNED_VOICE_SHARED_ASSET}`);
16343
- if (disposed) return;
16344
- const fetchClass = module.urt;
16345
- const bridgeClass = module.mPt;
16346
- if (!object2(fetchClass) && typeof fetchClass !== "function") throw new Error();
16347
- if (!object2(bridgeClass) && typeof bridgeClass !== "function") throw new Error();
16348
- const client = Reflect.get(fetchClass, "getInstance").call(fetchClass);
16349
- const bridge = Reflect.get(bridgeClass, "getInstance").call(bridgeClass);
16350
- if (typeof client?.fetch !== "function" || typeof bridge?.dispatchMessage !== "function" || typeof bridge?.subscribe !== "function" || typeof module.grt !== "function")
16351
- throw new Error();
16352
- restore = wrapClientOwnedVoiceFetch(
16353
- client,
16354
- bridge,
16355
- () => cpaLiveVoicePreferenceAllowsInstall(target),
16356
- module.grt
16357
- );
16358
- handle.status = "active";
16359
- } catch {
16360
- handle.status = "unsupported";
16361
- }
16362
- return;
16378
+ const attempt = () => {
16379
+ if (!auditedAssetFound) {
16380
+ const resourceNames = options.resourceNames ?? loadedAssetNames(root);
16381
+ auditedAssetFound = configAllowsInstall(config2, resourceNames);
16382
+ if (!auditedAssetFound) return false;
16363
16383
  }
16364
- if (Date.now() - started >= 6e4) {
16384
+ for (const client of statsigClients(globalObject)) {
16385
+ if (wrapCheckGate(client)) wrapped.push(client);
16386
+ }
16387
+ if (wrapped.length === 0) return false;
16388
+ handle.status = "active";
16389
+ return true;
16390
+ };
16391
+ if (attempt()) return handle;
16392
+ if (options.resourceNames && !configAllowsInstall(config2, options.resourceNames)) {
16393
+ handle.status = "unsupported";
16394
+ return handle;
16395
+ }
16396
+ const started = Date.now();
16397
+ const tick = () => {
16398
+ if (disposed || attempt()) return;
16399
+ if (Date.now() - started > DISCOVERY_TIMEOUT_MS) {
16365
16400
  handle.status = "unsupported";
16366
16401
  return;
16367
16402
  }
16368
- timer = target.setTimeout(() => void attempt(), 250);
16403
+ globalThis.setTimeout(tick, 250);
16369
16404
  };
16370
- void attempt();
16405
+ globalThis.setTimeout(tick, 250);
16371
16406
  return handle;
16372
16407
  }
16373
16408
 
@@ -16601,8 +16636,842 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16601
16636
  }
16602
16637
  };
16603
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
+ }
16654
+ }
16655
+ function isRecord2(value) {
16656
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16657
+ }
16658
+ function parseExternalConfiguration(value) {
16659
+ if (!isRecord2(value)) return void 0;
16660
+ const model2 = harnessModelRefSchema.safeParse(value.model);
16661
+ if (!model2.success) return void 0;
16662
+ const thinkingOptionId = harnessThinkingOptionIdSchema.safeParse(value.thinkingOptionId);
16663
+ const permissionModeId = harnessPermissionModeIdSchema.safeParse(value.permissionModeId);
16664
+ return {
16665
+ model: model2.data,
16666
+ ...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {},
16667
+ ...permissionModeId.success ? { permissionModeId: permissionModeId.data } : {}
16668
+ };
16669
+ }
16670
+ function readPreference(storage) {
16671
+ if (!storage) return void 0;
16672
+ try {
16673
+ const raw = storage.getItem(RENDERER_NEW_THREAD_PREFERENCE_KEY);
16674
+ if (!raw) return void 0;
16675
+ const parsed = JSON.parse(raw);
16676
+ if (!isRecord2(parsed) || parsed.version !== 1) return void 0;
16677
+ if (parsed.lastAgent !== "codex" && !harnessPluginIdSchema.safeParse(parsed.lastAgent).success)
16678
+ return void 0;
16679
+ const externalByAgent = isRecord2(parsed.externalByAgent) ? parsed.externalByAgent : {};
16680
+ const parsedExternal = Object.fromEntries(
16681
+ Object.keys(externalByAgent).filter((agent) => harnessPluginIdSchema.safeParse(agent).success).flatMap((agent) => {
16682
+ const configuration = parseExternalConfiguration(externalByAgent[agent]);
16683
+ return configuration ? [[agent, configuration]] : [];
16684
+ })
16685
+ );
16686
+ return {
16687
+ version: 1,
16688
+ lastAgent: parsed.lastAgent,
16689
+ externalByAgent: parsedExternal
16690
+ };
16691
+ } catch {
16692
+ return void 0;
16693
+ }
16694
+ }
16695
+ function writePreference(preference, storage) {
16696
+ if (!storage) return;
16697
+ try {
16698
+ storage.setItem(RENDERER_NEW_THREAD_PREFERENCE_KEY, JSON.stringify(preference));
16699
+ } catch {
16700
+ }
16701
+ }
16702
+ function readNewThreadAgentPreference(enabledAgents, storage = rendererNewThreadPreferenceStorage()) {
16703
+ const agent = readPreference(storage)?.lastAgent;
16704
+ return agent && (!enabledAgents || enabledAgents.has(agent)) ? agent : void 0;
16705
+ }
16706
+ function readNewThreadExternalConfigurationPreference(agent, catalog, permissionModes, storage = rendererNewThreadPreferenceStorage()) {
16707
+ const preference = readPreference(storage)?.externalByAgent[agent];
16708
+ if (!preference) return void 0;
16709
+ const catalogModel = catalogModelForRef(catalog, preference.model);
16710
+ if (!catalogModel) return void 0;
16711
+ const thinkingOptionId = preference.thinkingOptionId && catalogModel.supportedThinkingOptionIds?.includes(preference.thinkingOptionId) ? preference.thinkingOptionId : void 0;
16712
+ const permissionModeId = preference.permissionModeId && permissionModes?.modes.some(({ id }) => id === preference.permissionModeId) ? preference.permissionModeId : void 0;
16713
+ return {
16714
+ model: catalogModel.ref,
16715
+ ...thinkingOptionId ? { thinkingOptionId } : {},
16716
+ ...permissionModeId ? { permissionModeId } : {}
16717
+ };
16718
+ }
16719
+ function writeNewThreadAgentPreference(agent, storage = rendererNewThreadPreferenceStorage()) {
16720
+ const current = readPreference(storage);
16721
+ writePreference(
16722
+ {
16723
+ version: 1,
16724
+ lastAgent: agent,
16725
+ externalByAgent: current?.externalByAgent ?? {}
16726
+ },
16727
+ storage
16728
+ );
16729
+ }
16730
+ function writeNewThreadExternalConfigurationPreference(agent, model2, thinkingOptionId, permissionModeId, storage = rendererNewThreadPreferenceStorage()) {
16731
+ const current = readPreference(storage);
16732
+ writePreference(
16733
+ {
16734
+ version: 1,
16735
+ lastAgent: current?.lastAgent ?? "codex",
16736
+ externalByAgent: {
16737
+ ...current?.externalByAgent,
16738
+ [agent]: {
16739
+ model: harnessModelRefSchema.parse(model2),
16740
+ ...thinkingOptionId ? { thinkingOptionId: harnessThinkingOptionIdSchema.parse(thinkingOptionId) } : {},
16741
+ ...permissionModeId ? { permissionModeId: harnessPermissionModeIdSchema.parse(permissionModeId) } : {}
16742
+ }
16743
+ }
16744
+ },
16745
+ storage
16746
+ );
16747
+ }
16748
+
16749
+ // src/renderer-client-owned-voice.ts
16750
+ var CLIENT_OWNED_VOICE_VERSION = "26.1013.40934";
16751
+ var CLIENT_OWNED_VOICE_INITIAL_ASSET = "app-initial-90eb42395b7d.js";
16752
+ var CLIENT_OWNED_VOICE_SHARED_ASSET = "app-shared-52443cbe9ac4.js";
16753
+ var HOOK_GLOBAL = "__codexhostClientOwnedVoiceV1";
16754
+ function object2(value) {
16755
+ return value !== null && typeof value === "object";
16756
+ }
16757
+ function requestHost(bridge, params) {
16758
+ const id = `codexhost-voice:${crypto.randomUUID()}`;
16759
+ return new Promise((resolve, reject) => {
16760
+ let unsubscribe = () => {
16761
+ };
16762
+ const timer = setTimeout(() => {
16763
+ unsubscribe();
16764
+ reject(new Error("Voice gateway did not answer in time"));
16765
+ }, 3e4);
16766
+ const done = () => {
16767
+ clearTimeout(timer);
16768
+ unsubscribe();
16769
+ };
16770
+ unsubscribe = bridge.subscribe("mcp-response", (event) => {
16771
+ if (!object2(event) || event.hostId !== "local" || !object2(event.message) || event.message.id !== id)
16772
+ return;
16773
+ done();
16774
+ if (event.message.error) reject(new Error("Configured voice gateway request failed"));
16775
+ else resolve(event.message.result);
16776
+ });
16777
+ try {
16778
+ bridge.dispatchMessage("mcp-request", {
16779
+ hostId: "local",
16780
+ request: { id, method: REALTIME_CALL_METHOD, params }
16781
+ });
16782
+ } catch {
16783
+ done();
16784
+ reject(new Error("Voice gateway Host connection is unavailable"));
16785
+ }
16786
+ });
16787
+ }
16788
+ var HOME_COMPOSER_MODE_STORAGE_KEY = "home-composer-mode-v1";
16789
+ function backendModelName(headers) {
16790
+ const raw = new Headers(headers).get("x-codex-turn-metadata");
16791
+ if (!raw) return "";
16792
+ try {
16793
+ const parsed = JSON.parse(raw);
16794
+ return typeof parsed.backend_model_name === "string" ? parsed.backend_model_name : "";
16795
+ } catch {
16796
+ return "";
16797
+ }
16798
+ }
16799
+ function isWorkBackendModel(name) {
16800
+ const model2 = name.toLowerCase();
16801
+ if (!model2) return false;
16802
+ if (model2.startsWith("codexhost/")) return true;
16803
+ return model2.includes("codex") && !model2.includes("gpt-live");
16804
+ }
16805
+ function isWorkComposerSurface(owner = globalThis) {
16806
+ const storage = owner.localStorage;
16807
+ if (!storage) return false;
16808
+ try {
16809
+ const raw = storage.getItem(HOME_COMPOSER_MODE_STORAGE_KEY);
16810
+ if (raw == null || raw === "") return false;
16811
+ let value = raw;
16812
+ if (raw.startsWith("{") || raw.startsWith('"') || raw.startsWith("[")) {
16813
+ try {
16814
+ value = JSON.parse(raw);
16815
+ } catch {
16816
+ value = raw;
16817
+ }
16818
+ }
16819
+ return value === "work";
16820
+ } catch {
16821
+ return false;
16822
+ }
16823
+ }
16824
+ function selectedComposerModel(owner) {
16825
+ const routing = owner.__codexhostHostRoutingV1;
16826
+ try {
16827
+ const model2 = routing?.forComposer()?.policy.selectedModel();
16828
+ return typeof model2 === "string" ? model2 : "";
16829
+ } catch {
16830
+ return "";
16831
+ }
16832
+ }
16833
+ var lastVoiceProductExperience;
16834
+ function rememberVoiceProductExperience(request) {
16835
+ const experience = object2(request) ? request.productExperience : void 0;
16836
+ lastVoiceProductExperience = experience === "chat" || experience === "work" ? experience : void 0;
16837
+ }
16838
+ function lastVoiceLaunchProductExperience() {
16839
+ return lastVoiceProductExperience;
16840
+ }
16841
+ function isExternalHarnessComposer(owner = globalThis) {
16842
+ if (lastVoiceProductExperience === "chat") return false;
16843
+ if (selectedComposerModel(owner).startsWith("codexhost/")) return true;
16844
+ if (lastVoiceProductExperience !== "work") return false;
16845
+ const storage = owner.localStorage;
16846
+ 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 chat = lastVoiceLaunchProductExperience() === "chat";
16860
+ const model2 = backendModelName(options.headers);
16861
+ const work = !chat && (isWorkBackendModel(model2) || workSurface());
16862
+ const external = !chat && (model2.startsWith("codexhost/") || externalHarness());
16863
+ const gateway = external || (work ? workOverride() : chatOverride());
16864
+ chatVoiceDebug("wham-create", {
16865
+ work,
16866
+ external,
16867
+ route: gateway ? "gateway" : "desktop",
16868
+ productExperience: lastVoiceLaunchProductExperience() ?? "unset"
16869
+ });
16870
+ if (!gateway) {
16871
+ if (!external && !work)
16872
+ chatVoiceDebug("chat-native-passthrough", {
16873
+ hasThreadId: new Headers(options.headers).has("Thread-Id")
16874
+ });
16875
+ return original.call(this, url2, options);
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);
17118
+ }
17119
+ const contexts = /* @__PURE__ */ new Set();
17120
+ let composerContext;
17121
+ for (const fiber of ancestors) {
17122
+ let dependency = record2(fiber.dependencies) ? fiber.dependencies.firstContext : void 0;
17123
+ const seenDependencies = /* @__PURE__ */ new Set();
17124
+ while (record2(dependency) && seenDependencies.size < 4096 && !seenDependencies.has(dependency)) {
17125
+ seenDependencies.add(dependency);
17126
+ const context = dependency.context;
17127
+ const chain = dependency.memoizedValue;
17128
+ if (record2(context) && context.displayName === native.scopeDefinition.__scopeBrand && chain instanceof Map && chain.get(native.scopeDefinition.id) === scope.node)
17129
+ contexts.add(context);
17130
+ if (!composerContext && record2(context) && context.displayName === native.composerScopeDefinition.__scopeBrand && chain instanceof Map && chain.get(native.scopeDefinition.id) === scope.node) {
17131
+ const node = chain.get(native.composerScopeDefinition.id);
17132
+ if (record2(node) && record2(node.value) && (node.value.kind === "chatgpt" && record2(node.value.chatGptSelectionContext) && node.value.chatGptSelectionContext.conversationId === props.conversationId || isDraft && node.value.kind === "new" && native.draftConversationId != null && draftScopes.get(node)?.get(native.draftConversationId) === props.conversationId))
17133
+ composerContext = { context, chain };
17134
+ else return;
17135
+ }
17136
+ dependency = dependency.next;
17137
+ }
17138
+ }
17139
+ if (contexts.size !== 1 || !composerContext) return;
17140
+ return {
17141
+ composer,
17142
+ props,
17143
+ scope,
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();
17156
+ }
17157
+ function installNativeChatVoiceHook(options = {}) {
17158
+ const target = options.target ?? globalThis;
17159
+ const existing = target[HOOK_GLOBAL2];
17160
+ if (existing) return existing;
17161
+ const config2 = readCpaLiveVoiceHookConfig(target);
17162
+ const unavailable = (status) => ({
17163
+ status,
17164
+ dispose() {
17165
+ },
17166
+ start: async () => {
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");
17175
+ const importModule = options.importModule ?? ((url2) => import(url2));
17176
+ let disposed = false;
17177
+ let timer;
17178
+ let modules;
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;
17187
+ 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
+ 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
+ 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
+ dispose() {
17277
+ disposed = true;
17278
+ if (timer !== void 0) target.clearTimeout(timer);
17279
+ release();
17280
+ if (target[HOOK_GLOBAL2] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL2);
17281
+ }
17282
+ };
17283
+ target[HOOK_GLOBAL2] = handle;
17284
+ const refresh = async () => {
17285
+ if (disposed) return;
17286
+ try {
17287
+ if (renderFailed) throw new Error();
17288
+ if (!modules) {
17289
+ const names = loadedAssetNames(doc, target.performance);
17290
+ if (!auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_INITIAL_ASSET) || !auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_SHARED_ASSET)) {
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
+ );
17305
+ if (disposed) return;
17306
+ if (!shared || !initial || !start || !prewarm || typeof start.t !== "function" || typeof start.n !== "function" || typeof initial.jw !== "function" || typeof initial.ejn !== "function" || typeof shared.yzt !== "function" || typeof shared.vMt !== "function" || typeof prewarm.VoiceInstantConnectCacheController !== "function")
17307
+ throw new Error();
17308
+ initial.jw();
17309
+ start.t();
17310
+ if (!record2(shared.Cot) || !initial.pZn || !initial.lXt || !initial.Aw || !record2(initial.xAt) || !record2(initial.xAt.scope))
17311
+ throw new Error();
17312
+ modules = { shared, initial, start, prewarm };
17313
+ }
17314
+ const current = findBinding();
17315
+ selectDraft?.();
17316
+ if (!current) {
17317
+ if (handle.activeCall) return;
17318
+ release();
17319
+ handle.status = "pending";
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"]'
17378
+ );
17379
+ if (dictate?.parentElement) {
17380
+ button2 = doc.createElement("button");
17381
+ button2.type = "button";
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
+ }
17394
+ }
17395
+ if (button2)
17396
+ for (const control of current.composer.querySelectorAll(
17397
+ 'button[aria-label="Start new voice chat"], button[aria-label="Start voice chat"]'
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();
17411
+ handle.status = "unsupported";
17412
+ chatVoiceDebug("native-chat-binding-failed");
17413
+ return;
17414
+ } finally {
17415
+ if (!disposed && handle.status !== "unsupported")
17416
+ timer = target.setTimeout(() => void refresh(), 500);
17417
+ }
17418
+ };
17419
+ void refresh();
17420
+ return handle;
17421
+ }
17422
+
17423
+ // src/voice-settings-sync.ts
17424
+ function desktopVoiceCallActive(owner) {
17425
+ const hook = Reflect.get(owner, "__codexhostNativeChatVoiceV1");
17426
+ if (hook?.activeCall) return true;
17427
+ return [
17428
+ ...owner.document.querySelectorAll(
17429
+ 'button[aria-label="End Voice"],button[aria-label="End voice"],button[aria-label="End voice chat"]'
17430
+ )
17431
+ ].some((button2) => button2.getBoundingClientRect().width > 0);
17432
+ }
17433
+ function startVoiceSettingsSync(owner, request, intervalMs = 2e3) {
17434
+ let disposed = false;
17435
+ let busy = false;
17436
+ let revision = "";
17437
+ const id = crypto.randomUUID();
17438
+ const refresh = async () => {
17439
+ if (busy || disposed) return;
17440
+ busy = true;
17441
+ try {
17442
+ let state = voiceSettingsStateSchema.parse(
17443
+ await request(VOICE_SETTINGS_METHOD, {
17444
+ operation: "get",
17445
+ runtime: { id, revision, activeCall: desktopVoiceCallActive(owner) }
17446
+ })
17447
+ );
17448
+ if (disposed) return;
17449
+ if (!state.initialized)
17450
+ state = voiceSettingsStateSchema.parse(
17451
+ await request(VOICE_SETTINGS_METHOD, {
17452
+ operation: "migrate",
17453
+ routes: legacyVoiceRoutes(owner)
17454
+ })
17455
+ );
17456
+ if (!disposed && !desktopVoiceCallActive(owner)) {
17457
+ applySharedVoiceRoutes(owner, state.settings);
17458
+ revision = state.revision;
17459
+ }
17460
+ } catch {
17461
+ } finally {
17462
+ busy = false;
17463
+ }
17464
+ };
17465
+ void refresh();
17466
+ const timer = owner.setInterval(() => void refresh(), intervalMs);
17467
+ return () => {
17468
+ disposed = true;
17469
+ owner.clearInterval(timer);
17470
+ };
17471
+ }
17472
+
16604
17473
  // src/codex-ssh-adapter.ts
16605
- var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17474
+ var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16606
17475
  function createCodexSshClient(ownerWindow) {
16607
17476
  function request(operation, params, signal) {
16608
17477
  const bridge = ownerWindow.electronBridge;
@@ -16621,7 +17490,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16621
17490
  const abort = () => finish(new DOMException("Aborted", "AbortError"));
16622
17491
  const receive = (event) => {
16623
17492
  const message2 = event.data;
16624
- if (!record2(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId2)
17493
+ if (!record3(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId2)
16625
17494
  return;
16626
17495
  if (message2.responseType !== "success" || typeof message2.status !== "number" || message2.status < 200 || message2.status >= 300 || typeof message2.bodyJsonString !== "string") {
16627
17496
  finish(new Error("Codex SSH request failed; check the native Connections settings"));
@@ -16657,12 +17526,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16657
17526
  }
16658
17527
  async function list(signal) {
16659
17528
  const result = await request("refresh-remote-connections", {}, signal);
16660
- if (!record2(result) || !Array.isArray(result.remoteConnections))
17529
+ if (!record3(result) || !Array.isArray(result.remoteConnections))
16661
17530
  throw new Error("Invalid Codex SSH connection list");
16662
17531
  return result.remoteConnections.filter(
16663
- (item) => !(record2(item) && ["wsl", "remote-control"].includes(String(item.source)))
17532
+ (item) => !(record3(item) && ["wsl", "remote-control"].includes(String(item.source)))
16664
17533
  ).map((item) => {
16665
- if (!record2(item) || typeof item.hostId !== "string" || typeof item.displayName !== "string" || !["codex-managed", "discovered"].includes(String(item.source)) || typeof item.sshHost !== "string" || typeof item.autoConnect !== "boolean" || !(item.sshAlias == null || typeof item.sshAlias === "string") || !(item.identity == null || typeof item.identity === "string") || !(item.sshPort == null || Number.isInteger(item.sshPort) && Number(item.sshPort) > 0 && Number(item.sshPort) <= 65535)) {
17534
+ if (!record3(item) || typeof item.hostId !== "string" || typeof item.displayName !== "string" || !["codex-managed", "discovered"].includes(String(item.source)) || typeof item.sshHost !== "string" || typeof item.autoConnect !== "boolean" || !(item.sshAlias == null || typeof item.sshAlias === "string") || !(item.identity == null || typeof item.identity === "string") || !(item.sshPort == null || Number.isInteger(item.sshPort) && Number(item.sshPort) > 0 && Number(item.sshPort) <= 65535)) {
16666
17535
  throw new Error(
16667
17536
  "This Codex version uses an unsupported SSH configuration; open native settings"
16668
17537
  );
@@ -16734,11 +17603,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16734
17603
  },
16735
17604
  async state(hostId2, signal) {
16736
17605
  const result = await request("app-server-connection-state", { hostId: hostId2 }, signal);
16737
- if (!record2(result) || typeof result.state !== "string")
17606
+ if (!record3(result) || typeof result.state !== "string")
16738
17607
  throw new Error("Invalid Codex connection state");
16739
17608
  return {
16740
17609
  state: result.state,
16741
- error: typeof result.error === "string" ? result.error : record2(result.error) && typeof result.error.message === "string" ? result.error.message : null
17610
+ error: typeof result.error === "string" ? result.error : record3(result.error) && typeof result.error.message === "string" ? result.error.message : null
16742
17611
  };
16743
17612
  }
16744
17613
  };
@@ -16816,87 +17685,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16816
17685
  return control;
16817
17686
  }
16818
17687
 
16819
- // ../desktop-control/dist/renderer-react-ownership.js
16820
- var REACT_FIBER_WALK_LIMIT_EVENT = "codexhost:react-fiber-walk-limit";
16821
- function committedReactAncestors(value) {
16822
- const MAX_VISITED_FIBERS = 2e5;
16823
- const fiber = (value2) => typeof value2 === "object" && value2 !== null ? value2 : null;
16824
- const exhausted = () => {
16825
- const target = globalThis;
16826
- if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function")
16827
- target.dispatchEvent(new CustomEvent("codexhost:react-fiber-walk-limit", {
16828
- detail: { limit: MAX_VISITED_FIBERS }
16829
- }));
16830
- return [];
16831
- };
16832
- const first = fiber(value);
16833
- if (!first)
16834
- return [];
16835
- const previous = [];
16836
- const seen = /* @__PURE__ */ new Set();
16837
- for (let node = first; node; node = fiber(node.return)) {
16838
- if (seen.has(node))
16839
- return [];
16840
- if (seen.size >= MAX_VISITED_FIBERS)
16841
- return exhausted();
16842
- seen.add(node);
16843
- previous.push(node);
16844
- }
16845
- const rootState = fiber(previous.at(-1)?.stateNode);
16846
- if (!rootState || !("current" in rootState))
16847
- return previous;
16848
- const current = fiber(rootState.current);
16849
- if (!current)
16850
- return [];
16851
- const alternate = fiber(first.alternate);
16852
- const path = [current];
16853
- seen.clear();
16854
- seen.add(current);
16855
- for (let index = previous.length - 2; index >= 0; index -= 1) {
16856
- const expected = previous[index];
16857
- const expectedAlternate = fiber(expected?.alternate);
16858
- let child = fiber(path.at(-1)?.child);
16859
- let matched = false;
16860
- while (child && !seen.has(child) && seen.size < MAX_VISITED_FIBERS) {
16861
- seen.add(child);
16862
- if (child === expected || child === expectedAlternate) {
16863
- matched = true;
16864
- break;
16865
- }
16866
- child = fiber(child.sibling);
16867
- }
16868
- if (!matched || !child)
16869
- break;
16870
- path.push(child);
16871
- }
16872
- if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
16873
- return path.reverse();
16874
- }
16875
- const stack = [{ node: current, parent: null }];
16876
- seen.clear();
16877
- while (stack.length > 0 && seen.size < MAX_VISITED_FIBERS) {
16878
- const entry = stack.pop();
16879
- if (!entry)
16880
- break;
16881
- if (seen.has(entry.node))
16882
- return [];
16883
- seen.add(entry.node);
16884
- if (entry.node === first || entry.node === alternate) {
16885
- const ancestors = [];
16886
- for (let cursor = entry; cursor; cursor = cursor.parent)
16887
- ancestors.push(cursor.node);
16888
- return ancestors;
16889
- }
16890
- const sibling = entry.parent && fiber(entry.node.sibling);
16891
- if (sibling)
16892
- stack.push({ node: sibling, parent: entry.parent });
16893
- const child = fiber(entry.node.child);
16894
- if (child)
16895
- stack.push({ node: child, parent: entry });
16896
- }
16897
- return stack.length > 0 ? exhausted() : [];
16898
- }
16899
-
16900
17688
  // src/renderer-composer-kind.ts
16901
17689
  function orbitComposerKind(composer) {
16902
17690
  let element = composer.querySelector('[contenteditable="true"], textarea, [role="textbox"]') ?? composer;
@@ -19015,16 +19803,6 @@ ${error51.stderrTail}`] : []
19015
19803
  "When this is on, that card is hidden on every Composer, including Codex threads. Reset usage and Upgrade stay available in Settings.",
19016
19804
  "Turning this off only shows the native card again. Send on this Composer, including Codex threads, is already separated from that quota card."
19017
19805
  ]),
19018
- cpaLiveVoiceTitle: "Override live voice",
19019
- cpaLiveVoiceDescription: "On by default. Host creates the realtime call instead of ChatGPT.",
19020
- cpaLiveVoiceHelpLabel: "About overriding live voice",
19021
- cpaLiveVoiceHelp: Object.freeze([
19022
- "Overrides Desktop's existing-call path on audited 26.1007.30912 so a local host can create the WebRTC call.",
19023
- "This switch applies on the next voice session. No relaunch.",
19024
- "Also set both keys in ~/.codex/config.toml and relaunch Codex: experimental_realtime_ws_base_url and experimental_realtime_webrtc_call_base_url, each pointing at your realtime host /v1.",
19025
- "CODEXHOST_CPA_LIVE_VOICE=0 is not live. Relaunch Codex after changing that environment variable."
19026
- ]),
19027
- cpaLiveVoiceRestartRequired: "This override is not injected. Unset CODEXHOST_CPA_LIVE_VOICE=0 and relaunch Codex. The switch cannot take effect until then.",
19028
19806
  loadedSessions: {
19029
19807
  title: "Loaded sessions",
19030
19808
  description: "Local external Harnesses only. Refreshes every 10 seconds without waking sessions or resetting activity. Released sessions disappear from this list.",
@@ -19280,6 +20058,7 @@ ${error51.stderrTail}`] : []
19280
20058
  connections: "Connections",
19281
20059
  "remote-connections": "Remote connections",
19282
20060
  appearance: "General",
20061
+ voice: "Voice",
19283
20062
  accounts: "Accounts",
19284
20063
  "session-import": "Session Import",
19285
20064
  "usage-statistics": "Usage statistics",
@@ -19306,16 +20085,6 @@ ${error51.stderrTail}`] : []
19306
20085
  "\u5F00\u542F\u540E\uFF0C\u6240\u6709 Composer \u90FD\u9690\u85CF\u8BE5\u5361\u7247\uFF0C\u5305\u62EC Codex \u4F1A\u8BDD\u3002\u300C\u91CD\u7F6E\u7528\u91CF\u300D\u548C\u300C\u5347\u7EA7\u300D\u4ECD\u53EF\u5728\u8BBE\u7F6E\u4E2D\u4F7F\u7528\u3002",
19307
20086
  "\u5173\u95ED\u6B64\u5F00\u5173\u53EA\u4F1A\u91CD\u65B0\u663E\u793A\u539F\u751F\u5361\u7247\u3002\u5F53\u524D Composer \u7684\u53D1\u9001\uFF08\u5305\u62EC Codex \u4F1A\u8BDD\uFF09\u5DF2\u4E0E\u8BE5\u989D\u5EA6\u5361\u7247\u5206\u79BB\u3002"
19308
20087
  ]),
19309
- cpaLiveVoiceTitle: "\u6539\u5199\u5B9E\u65F6\u8BED\u97F3",
19310
- cpaLiveVoiceDescription: "\u9ED8\u8BA4\u5F00\u542F\u3002\u7531 Host \u521B\u5EFA realtime \u901A\u8BDD\uFF0C\u800C\u4E0D\u662F ChatGPT\u3002",
19311
- cpaLiveVoiceHelpLabel: "\u6539\u5199\u5B9E\u65F6\u8BED\u97F3\u8BF4\u660E",
19312
- cpaLiveVoiceHelp: Object.freeze([
19313
- "\u5728\u5DF2\u5BA1\u8BA1\u7684 Desktop 26.1007.30912 \u4E0A\u8986\u76D6 existing-call \u8DEF\u5F84\uFF0C\u8BA9\u672C\u5730 Host \u521B\u5EFA WebRTC \u901A\u8BDD\u3002",
19314
- "\u6B64\u5F00\u5173\u5728\u4E0B\u4E00\u6B21\u8BED\u97F3\u4F1A\u8BDD\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u65B0\u542F\u52A8\u3002",
19315
- "\u8FD8\u9700\u8981\u5728 ~/.codex/config.toml \u8BBE\u7F6E experimental_realtime_ws_base_url \u4E0E experimental_realtime_webrtc_call_base_url\uFF0C\u90FD\u6307\u5411\u4F60\u7684 realtime \u4E3B\u673A /v1\uFF0C\u7136\u540E\u91CD\u65B0\u542F\u52A8 Codex\u3002",
19316
- "CODEXHOST_CPA_LIVE_VOICE=0 \u4E0D\u4F1A\u5373\u65F6\u751F\u6548\u3002\u4FEE\u6539\u8BE5\u73AF\u5883\u53D8\u91CF\u540E\u5FC5\u987B\u91CD\u65B0\u542F\u52A8 Codex\u3002"
19317
- ]),
19318
- cpaLiveVoiceRestartRequired: "\u5F53\u524D\u672A\u6CE8\u5165\u6B64\u6539\u5199\u3002\u8BF7\u53D6\u6D88 CODEXHOST_CPA_LIVE_VOICE=0 \u5E76\u91CD\u65B0\u542F\u52A8 Codex\uFF0C\u672C\u5F00\u5173\u624D\u4F1A\u751F\u6548\u3002",
19319
20088
  loadedSessions: {
19320
20089
  title: "\u5DF2\u52A0\u8F7D\u4F1A\u8BDD",
19321
20090
  description: "\u4EC5\u663E\u793A\u672C\u5730\u5916\u90E8 Harness\u3002\u6BCF 10 \u79D2\u5237\u65B0\uFF0C\u4E0D\u5524\u9192\u4F1A\u8BDD\u3001\u4E0D\u91CD\u7F6E\u6D3B\u52A8\u65F6\u95F4\u3002\u91CA\u653E\u540E\u7684\u4F1A\u8BDD\u4ECE\u5217\u8868\u79FB\u9664\u3002",
@@ -19571,6 +20340,7 @@ ${error51.stderrTail}`] : []
19571
20340
  connections: "\u8FDE\u63A5",
19572
20341
  "remote-connections": "\u8FDC\u7A0B\u8FDE\u63A5",
19573
20342
  appearance: "\u901A\u7528",
20343
+ voice: "\u8BED\u97F3",
19574
20344
  accounts: "\u8D26\u53F7",
19575
20345
  "session-import": "\u4F1A\u8BDD\u5BFC\u5165",
19576
20346
  "usage-statistics": "\u7528\u91CF\u7EDF\u8BA1",
@@ -22871,7 +23641,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22871
23641
  const composer = element.closest(CODEX_COMPOSER_SELECTOR);
22872
23642
  return composer && !isOrbitComposer(composer) ? composer : null;
22873
23643
  }
22874
- function isRecord2(value) {
23644
+ function isRecord3(value) {
22875
23645
  return typeof value === "object" && value !== null && !Array.isArray(value);
22876
23646
  }
22877
23647
  function isNativeModelControlCandidate(element) {
@@ -22887,7 +23657,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22887
23657
  let fiber = fiberName ? Object.getOwnPropertyDescriptor(element, fiberName)?.value : null;
22888
23658
  for (let depth = 0; fiber && depth < 60; depth += 1) {
22889
23659
  const props = fiber.memoizedProps;
22890
- if (isRecord2(props) && typeof props.onSelectModel === "function" && typeof props.onSelectReasoningEffort === "function" && "reasoningEffort" in props && isRecord2(props.fallbackPowerSelection)) {
23660
+ if (isRecord3(props) && typeof props.onSelectModel === "function" && typeof props.onSelectReasoningEffort === "function" && "reasoningEffort" in props && isRecord3(props.fallbackPowerSelection)) {
22891
23661
  return true;
22892
23662
  }
22893
23663
  const parent = fiber.return;
@@ -22907,7 +23677,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22907
23677
  let ownsComposerPermissionState = false;
22908
23678
  for (let depth = 0; fiber && depth < 60; depth += 1) {
22909
23679
  const props = fiber.memoizedProps;
22910
- if (isRecord2(props)) {
23680
+ if (isRecord3(props)) {
22911
23681
  if (props["data-composer-navigation-target"] === "permissions" && props["aria-haspopup"] === "menu") {
22912
23682
  ownsTrigger = true;
22913
23683
  }
@@ -23400,19 +24170,19 @@ Codex Fast mode prioritizes requests and may increase usage.`
23400
24170
 
23401
24171
  // src/renderer-codex-usage-banner.ts
23402
24172
  var MAX_FIBERS = 2e4;
23403
- function isRecord3(value) {
24173
+ function isRecord4(value) {
23404
24174
  return typeof value === "object" && value !== null && !Array.isArray(value);
23405
24175
  }
23406
24176
  function isUsageBanner(props) {
23407
- return isRecord3(props) && "banner" in props && "rateLimitStatus" in props && typeof props.sendBlocked === "boolean";
24177
+ return isRecord4(props) && "banner" in props && "rateLimitStatus" in props && typeof props.sendBlocked === "boolean";
23408
24178
  }
23409
24179
  function isElement(value) {
23410
- return isRecord3(value) && typeof value.setAttribute === "function" && isRecord3(value.style);
24180
+ return isRecord4(value) && typeof value.setAttribute === "function" && isRecord4(value.style);
23411
24181
  }
23412
24182
  function hostElements(fiber, budget) {
23413
24183
  const result = [];
23414
24184
  const visit = (node) => {
23415
- for (let current = node; isRecord3(current); current = current.sibling) {
24185
+ for (let current = node; isRecord4(current); current = current.sibling) {
23416
24186
  if (budget.remaining-- <= 0) return;
23417
24187
  const { stateNode } = current;
23418
24188
  if (isElement(stateNode)) result.push(stateNode);
@@ -23423,13 +24193,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23423
24193
  return result;
23424
24194
  }
23425
24195
  function findCodexUsageBannerElements(owner) {
23426
- if (!isRecord3(owner)) return [];
24196
+ if (!isRecord4(owner)) return [];
23427
24197
  const budget = { remaining: MAX_FIBERS };
23428
24198
  const found = [];
23429
24199
  const stack = [owner.child];
23430
24200
  while (stack.length > 0 && budget.remaining > 0) {
23431
24201
  const node = stack.pop();
23432
- if (!isRecord3(node)) continue;
24202
+ if (!isRecord4(node)) continue;
23433
24203
  budget.remaining -= 1;
23434
24204
  const fiber = node;
23435
24205
  stack.push(fiber.sibling);
@@ -23474,13 +24244,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23474
24244
  var MAX_HOOKS = 4096;
23475
24245
  var MAX_DOM_DEPTH = 12;
23476
24246
  var RETRY_DELAY_MS = 1e3;
23477
- function isRecord4(value) {
24247
+ function isRecord5(value) {
23478
24248
  return typeof value === "object" && value !== null && !Array.isArray(value);
23479
24249
  }
23480
24250
  function hooksOf(fiber) {
23481
24251
  const result = [];
23482
- let hook = isRecord4(fiber) ? fiber.memoizedState : null;
23483
- while (isRecord4(hook) && result.length < MAX_HOOKS) {
24252
+ let hook = isRecord5(fiber) ? fiber.memoizedState : null;
24253
+ while (isRecord5(hook) && result.length < MAX_HOOKS) {
23484
24254
  result.push(hook);
23485
24255
  hook = hook.next;
23486
24256
  }
@@ -23498,7 +24268,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23498
24268
  );
23499
24269
  const scopes = [];
23500
24270
  ancestors.forEach(({ memoizedProps: props }, index) => {
23501
- if (isRecord4(props) && "onLocalSubmitStart" in props && typeof props.submitDisabled === "boolean") {
24271
+ if (isRecord5(props) && "onLocalSubmitStart" in props && typeof props.submitDisabled === "boolean") {
23502
24272
  scopes.push({ owner: ancestors[index], fibers: ancestors.slice(0, index + 1) });
23503
24273
  }
23504
24274
  });
@@ -23524,11 +24294,11 @@ Codex Fast mode prioritizes requests and may increase usage.`
23524
24294
  const [subscriber, dependencies] = memo;
23525
24295
  if (dependencies.length !== 2) return null;
23526
24296
  const signal = dependencies[0];
23527
- const adapted = dependencies[1] === void 0 && isRecord4(signal) && typeof signal.get === "function" && typeof signal.subscribe === "function";
24297
+ const adapted = dependencies[1] === void 0 && isRecord5(signal) && typeof signal.get === "function" && typeof signal.subscribe === "function";
23528
24298
  const [store, atom] = adapted ? [signal.store, signal.atom] : dependencies;
23529
24299
  const instance = hook.next?.queue;
23530
24300
  const effect = hook.next?.next?.memoizedState;
23531
- if (!isRecord4(subscriber) || typeof subscriber.getSnapshot !== "function" || typeof subscriber.subscribe !== "function" || !isRecord4(store) || typeof store.get !== "function" || typeof store.sub !== "function" || !isRecord4(atom) || typeof atom.read !== "function" || "write" in atom || !isRecord4(instance) || typeof instance.value !== "boolean" || typeof instance.getSnapshot !== "function" || !isRecord4(effect) || typeof effect.create !== "function" || !Array.isArray(effect.deps) || effect.deps[0] !== subscriber.subscribe) {
24301
+ if (!isRecord5(subscriber) || typeof subscriber.getSnapshot !== "function" || typeof subscriber.subscribe !== "function" || !isRecord5(store) || typeof store.get !== "function" || typeof store.sub !== "function" || !isRecord5(atom) || typeof atom.read !== "function" || "write" in atom || !isRecord5(instance) || typeof instance.value !== "boolean" || typeof instance.getSnapshot !== "function" || !isRecord5(effect) || typeof effect.create !== "function" || !Array.isArray(effect.deps) || effect.deps[0] !== subscriber.subscribe) {
23532
24302
  return null;
23533
24303
  }
23534
24304
  return {
@@ -23570,10 +24340,10 @@ Codex Fast mode prioritizes requests and may increase usage.`
23570
24340
  visiting.delete(dependency);
23571
24341
  }
23572
24342
  }
23573
- if (!isRecord4(value)) return value;
24343
+ if (!isRecord5(value)) return value;
23574
24344
  if (typeof value.hardBlocked === "boolean") return trace(value, "reserve");
23575
24345
  if ("authMethod" in value) return trace(value, "auth");
23576
- if (isRecord4(value.data) && isRecord4(value.data.rate_limit)) {
24346
+ if (isRecord5(value.data) && isRecord5(value.data.rate_limit)) {
23577
24347
  return {
23578
24348
  ...value,
23579
24349
  data: { ...value.data, rate_limit: trace(value.data.rate_limit, "limit") }
@@ -23685,7 +24455,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23685
24455
  }
23686
24456
  function isBound(projections) {
23687
24457
  return [...projections].every(({ fiber, subscriber, instance }) => {
23688
- const alternate = isRecord4(fiber.alternate) ? fiber.alternate : null;
24458
+ const alternate = isRecord5(fiber.alternate) ? fiber.alternate : null;
23689
24459
  return [fiber, alternate].some(
23690
24460
  (candidate) => hooksOf(candidate).some(
23691
24461
  (hook) => Array.isArray(hook.memoizedState) && hook.memoizedState[0] === subscriber && hook.next?.queue === instance
@@ -23865,13 +24635,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23865
24635
  }
23866
24636
 
23867
24637
  // src/renderer-native-thread.ts
23868
- function isRecord5(value) {
24638
+ function isRecord6(value) {
23869
24639
  return typeof value === "object" && value !== null && !Array.isArray(value);
23870
24640
  }
23871
24641
  async function verifyNativeCodexThread(sendRequest, threadId) {
23872
24642
  const native = await sendRequest("thread/read", { threadId, includeTurns: false });
23873
- const thread = isRecord5(native) ? native.thread : null;
23874
- if (!isRecord5(thread) || thread.id !== threadId || typeof thread.modelProvider !== "string" || !thread.modelProvider || thread.modelProvider === "codexhost" || typeof thread.cliVersion !== "string" || !thread.cliVersion || thread.cliVersion === "codexhost") {
24643
+ const thread = isRecord6(native) ? native.thread : null;
24644
+ if (!isRecord6(thread) || thread.id !== threadId || typeof thread.modelProvider !== "string" || !thread.modelProvider || thread.modelProvider === "codexhost" || typeof thread.cliVersion !== "string" || !thread.cliVersion || thread.cliVersion === "codexhost") {
23875
24645
  throw new Error("Native Thread response cannot establish Codex ownership");
23876
24646
  }
23877
24647
  }
@@ -23950,15 +24720,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
23950
24720
  var CODEX_ACCOUNT_LIST_METHOD = "codexhost/account/list";
23951
24721
  var CODEX_ACCOUNT_REFRESH_METHOD = "codexhost/account/refresh";
23952
24722
  var CODEX_ACCOUNT_CHANGED_METHOD = "codexhost/account/changed";
23953
- function isRecord6(value) {
24723
+ function isRecord7(value) {
23954
24724
  return typeof value === "object" && value !== null && !Array.isArray(value);
23955
24725
  }
23956
24726
  function notifiedThreadId(notification) {
23957
- if (!isRecord6(notification) || !THREAD_USAGE_REFRESH_METHODS.includes(notification.method)) {
24727
+ if (!isRecord7(notification) || !THREAD_USAGE_REFRESH_METHODS.includes(notification.method)) {
23958
24728
  return null;
23959
24729
  }
23960
24730
  const params = notification.params;
23961
- if (!isRecord6(params)) return null;
24731
+ if (!isRecord7(params)) return null;
23962
24732
  const parsed = hostThreadIdSchema.safeParse(params.threadId);
23963
24733
  return parsed.success ? parsed.data : null;
23964
24734
  }
@@ -24276,7 +25046,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24276
25046
  throw new Error("Renderer Account notification callback is unavailable");
24277
25047
  }
24278
25048
  return notifications.addNotificationCallback(CODEX_ACCOUNT_CHANGED_METHOD, (notification) => {
24279
- if (!isRecord6(notification) || notification.method !== CODEX_ACCOUNT_CHANGED_METHOD) return;
25049
+ if (!isRecord7(notification) || notification.method !== CODEX_ACCOUNT_CHANGED_METHOD) return;
24280
25050
  const state = codexAccountChangedSchema.safeParse(notification.params);
24281
25051
  if (state.success) listener(state.data);
24282
25052
  });
@@ -24285,16 +25055,16 @@ Codex Fast mode prioritizes requests and may increase usage.`
24285
25055
  }
24286
25056
 
24287
25057
  // src/renderer-external-queue.ts
24288
- function isRecord7(value) {
25058
+ function isRecord8(value) {
24289
25059
  return value !== null && typeof value === "object" && !Array.isArray(value);
24290
25060
  }
24291
25061
  function installRendererExternalQueue(target) {
24292
- if (!isRecord7(target) || typeof target.getTurnCoordinator !== "function" || typeof target.getConversation !== "function") {
25062
+ if (!isRecord8(target) || typeof target.getTurnCoordinator !== "function" || typeof target.getConversation !== "function") {
24293
25063
  return null;
24294
25064
  }
24295
25065
  const coordinator = target.getTurnCoordinator();
24296
- const queue = isRecord7(coordinator) ? coordinator.serverQueue : null;
24297
- if (!isRecord7(queue) || typeof queue.isEnabled !== "function") return null;
25066
+ const queue = isRecord8(coordinator) ? coordinator.serverQueue : null;
25067
+ if (!isRecord8(queue) || typeof queue.isEnabled !== "function") return null;
24298
25068
  const descriptor = Object.getOwnPropertyDescriptor(queue, "isEnabled");
24299
25069
  if (!descriptor?.writable) return null;
24300
25070
  const original = queue.isEnabled;
@@ -24303,7 +25073,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24303
25073
  const threadId = args[0];
24304
25074
  if (typeof threadId === "string") {
24305
25075
  const conversation = getConversation.call(target, threadId);
24306
- if (isRecord7(conversation) && conversation.id === threadId && // Reserved transport marker from externalThreadValue, retained by
25076
+ if (isRecord8(conversation) && conversation.id === threadId && // Reserved transport marker from externalThreadValue, retained by
24307
25077
  // Desktop in both newly created and hydrated conversation metadata.
24308
25078
  conversation.modelProvider === "codexhost") {
24309
25079
  return false;
@@ -24319,19 +25089,19 @@ Codex Fast mode prioritizes requests and may increase usage.`
24319
25089
 
24320
25090
  // src/renderer-external-steering.ts
24321
25091
  var THREAD_OWNERSHIP_LIST_METHOD2 = "codexhost/thread/ownership/list";
24322
- function isRecord8(value) {
25092
+ function isRecord9(value) {
24323
25093
  return value !== null && typeof value === "object" && !Array.isArray(value);
24324
25094
  }
24325
25095
  function isManager(value) {
24326
- return isRecord8(value) && ["sendRequest", "steerTurn", "startTurn", "getTurnCoordinator"].every(
25096
+ return isRecord9(value) && ["sendRequest", "steerTurn", "startTurn", "getTurnCoordinator"].every(
24327
25097
  (key) => typeof value[key] === "function"
24328
25098
  );
24329
25099
  }
24330
25100
  function submissionHost(manager) {
24331
25101
  const coordinator = manager.getTurnCoordinator();
24332
- const options = isRecord8(coordinator) ? coordinator.options : null;
24333
- const host = isRecord8(options) ? options.submissionHost : null;
24334
- if (!isRecord8(host) || typeof host.getActiveTurnId !== "function" || typeof host.hasPendingTurnStart !== "function") {
25102
+ const options = isRecord9(coordinator) ? coordinator.options : null;
25103
+ const host = isRecord9(options) ? options.submissionHost : null;
25104
+ if (!isRecord9(host) || typeof host.getActiveTurnId !== "function" || typeof host.hasPendingTurnStart !== "function") {
24335
25105
  throw new Error("Desktop turn submission binding is unavailable");
24336
25106
  }
24337
25107
  return {
@@ -24373,20 +25143,20 @@ Codex Fast mode prioritizes requests and may increase usage.`
24373
25143
  var INTERRUPTED_QUEUE_REASON = "Interrupted before the steer was accepted.";
24374
25144
  async function preserveQueuedFollowUps(manager, threadId) {
24375
25145
  const coordinator = manager.getTurnCoordinator();
24376
- if (!isRecord8(coordinator) || typeof coordinator.loadMessages !== "function" || typeof coordinator.readMessages !== "function" || typeof coordinator.mutate !== "function") {
25146
+ if (!isRecord9(coordinator) || typeof coordinator.loadMessages !== "function" || typeof coordinator.readMessages !== "function" || typeof coordinator.mutate !== "function") {
24377
25147
  throw new Error("Desktop follow-up queue binding is unavailable");
24378
25148
  }
24379
25149
  await coordinator.loadMessages.call(coordinator, threadId);
24380
25150
  const messages = coordinator.readMessages.call(coordinator, threadId);
24381
25151
  if (!Array.isArray(messages)) throw new Error("Desktop follow-up queue is unavailable");
24382
25152
  const alreadyPaused = new Set(
24383
- messages.filter((message2) => isRecord8(message2) && message2.pausedReason != null).map((message2) => message2.id)
25153
+ messages.filter((message2) => isRecord9(message2) && message2.pausedReason != null).map((message2) => message2.id)
24384
25154
  );
24385
25155
  return () => {
24386
25156
  coordinator.mutate.call(coordinator, threadId, (current) => {
24387
25157
  if (!Array.isArray(current)) return current;
24388
25158
  return current.map((message2) => {
24389
- if (!isRecord8(message2) || alreadyPaused.has(message2.id) || message2.pausedReason !== INTERRUPTED_QUEUE_REASON)
25159
+ if (!isRecord9(message2) || alreadyPaused.has(message2.id) || message2.pausedReason !== INTERRUPTED_QUEUE_REASON)
24390
25160
  return message2;
24391
25161
  const resumed = { ...message2 };
24392
25162
  delete resumed.pausedReason;
@@ -24407,9 +25177,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
24407
25177
  if ((method === "turn/start" || method === "turn/steer") && prepareTurnInput) {
24408
25178
  params = prepareTurnInput(params);
24409
25179
  }
24410
- const messageId = isRecord8(params) ? params.clientUserMessageId : null;
24411
- const route = typeof messageId === "string" && isRecord8(params) ? routes.get(`${params.threadId}\0${messageId}`) : void 0;
24412
- if (method !== "turn/start" || !isRecord8(params) || !route || route.threadId !== params.threadId) {
25180
+ const messageId = isRecord9(params) ? params.clientUserMessageId : null;
25181
+ const route = typeof messageId === "string" && isRecord9(params) ? routes.get(`${params.threadId}\0${messageId}`) : void 0;
25182
+ if (method !== "turn/start" || !isRecord9(params) || !route || route.threadId !== params.threadId) {
24413
25183
  if (method === "turn/start" && sendTurnStart) {
24414
25184
  return sendTurnStart(params, (input) => {
24415
25185
  if (disposed) throw new Error("External submission binding was disposed");
@@ -24435,7 +25205,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24435
25205
  options
24436
25206
  )
24437
25207
  ).then((response) => {
24438
- if (!isRecord8(response) || typeof response.turnId !== "string" || !response.turnId) {
25208
+ if (!isRecord9(response) || typeof response.turnId !== "string" || !response.turnId) {
24439
25209
  throw new Error("External steering returned no replacement Turn identity");
24440
25210
  }
24441
25211
  return {
@@ -24466,7 +25236,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24466
25236
  ] = args;
24467
25237
  if (typeof threadId !== "string") return originalSteer.apply(manager, args);
24468
25238
  const role = manager.getStreamRole?.(threadId);
24469
- if (isRecord8(role) && role.role === "follower") return originalSteer.apply(manager, args);
25239
+ if (isRecord9(role) && role.role === "follower") return originalSteer.apply(manager, args);
24470
25240
  let host = null;
24471
25241
  let expectedTurnId;
24472
25242
  try {
@@ -24495,15 +25265,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
24495
25265
  if (owner === "codex") return originalSteer.apply(manager, args);
24496
25266
  if (!host) throw new Error("Desktop turn submission binding is unavailable");
24497
25267
  const currentRole = manager.getStreamRole?.(threadId);
24498
- if (isRecord8(currentRole) && currentRole.role === "follower")
25268
+ if (isRecord9(currentRole) && currentRole.role === "follower")
24499
25269
  return originalSteer.apply(manager, args);
24500
25270
  if (!Array.isArray(input) || input.length === 0 || input.some(
24501
- (item) => !isRecord8(item) || item.type !== "text" || typeof item.text !== "string"
24502
- ) || !input.some((item) => isRecord8(item) && typeof item.text === "string" && item.text.trim())) {
25271
+ (item) => !isRecord9(item) || item.type !== "text" || typeof item.text !== "string"
25272
+ ) || !input.some((item) => isRecord9(item) && typeof item.text === "string" && item.text.trim())) {
24503
25273
  throw new Error("External steering requires non-empty text input");
24504
25274
  }
24505
25275
  if (toolOutput != null) throw new Error("External steering cannot replace a tool response");
24506
- if (!isRecord8(restoreMessage) || !isRecord8(restoreMessage.context)) {
25276
+ if (!isRecord9(restoreMessage) || !isRecord9(restoreMessage.context)) {
24507
25277
  throw new Error("Desktop steering message context is unavailable");
24508
25278
  }
24509
25279
  const messageId = typeof clientUserMessageId === "string" && clientUserMessageId ? clientUserMessageId : typeof restoreMessage.id === "string" && restoreMessage.id ? restoreMessage.id : crypto.randomUUID();
@@ -24551,7 +25321,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24551
25321
  },
24552
25322
  onMessageAdded
24553
25323
  );
24554
- if (!isRecord8(response) || !isRecord8(response.turn) || typeof response.turn.id !== "string") {
25324
+ if (!isRecord9(response) || !isRecord9(response.turn) || typeof response.turn.id !== "string") {
24555
25325
  throw new Error("Desktop returned no replacement Turn identity");
24556
25326
  }
24557
25327
  try {
@@ -24582,7 +25352,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24582
25352
  }
24583
25353
 
24584
25354
  // src/renderer-remote-attachments.ts
24585
- function isRecord9(value) {
25355
+ function isRecord10(value) {
24586
25356
  return value !== null && typeof value === "object" && !Array.isArray(value);
24587
25357
  }
24588
25358
  var MAX_IMAGE_BYTES = 20 * 1024 * 1024;
@@ -24634,14 +25404,14 @@ Codex Fast mode prioritizes requests and may increase usage.`
24634
25404
  function createRemoteAttachmentSender(target, hostId2, isCurrent) {
24635
25405
  const prepared = /* @__PURE__ */ new WeakMap();
24636
25406
  return (params, send) => {
24637
- if (hostId2 === "local" || !isRecord9(target) || !isRecord9(params) || typeof params.threadId !== "string" || !Array.isArray(params.input) || typeof target.getConversation !== "function")
25407
+ if (hostId2 === "local" || !isRecord10(target) || !isRecord10(params) || typeof params.threadId !== "string" || !Array.isArray(params.input) || typeof target.getConversation !== "function")
24638
25408
  return send(params);
24639
25409
  const images = params.input.filter(
24640
- (item) => isRecord9(item) && (item.type === "image" || item.type === "localImage")
25410
+ (item) => isRecord10(item) && (item.type === "image" || item.type === "localImage")
24641
25411
  );
24642
25412
  if (images.length === 0) return send(params);
24643
25413
  const conversation = target.getConversation.call(target, params.threadId);
24644
- if (!isRecord9(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25414
+ if (!isRecord10(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
24645
25415
  return send(params);
24646
25416
  const assertCurrent = () => {
24647
25417
  if (!isCurrent()) throw new Error("Remote attachment connection is no longer available");
@@ -24654,7 +25424,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24654
25424
  const cached2 = prepared.get(params);
24655
25425
  if (cached2) return cached2.then(dispatch);
24656
25426
  const input = params.input;
24657
- const text = input.filter((item) => isRecord9(item) && item.type === "text").map((item) => isRecord9(item) && typeof item.text === "string" ? item.text : "").join("\n");
25427
+ const text = input.filter((item) => isRecord10(item) && item.type === "text").map((item) => isRecord10(item) && typeof item.text === "string" ? item.text : "").join("\n");
24658
25428
  const existingPaths = nativeImagePaths(text);
24659
25429
  const prepare = async () => {
24660
25430
  if (existingPaths.length === images.length) return params;
@@ -24686,7 +25456,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24686
25456
  contents: file2.contents,
24687
25457
  label: `image-${index + 1}.${file2.extension}`
24688
25458
  });
24689
- if (!isRecord9(saved) || !filePath(saved.path) || saved.fsPath !== saved.path) {
25459
+ if (!isRecord10(saved) || !filePath(saved.path) || saved.fsPath !== saved.path) {
24690
25460
  throw new Error("Desktop returned an invalid remote attachment path");
24691
25461
  }
24692
25462
  created.push(saved.path);
@@ -24737,9 +25507,9 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24737
25507
  }
24738
25508
 
24739
25509
  // src/renderer-thread-reference-capability.ts
24740
- var record3 = (value) => typeof value === "object" && value !== null;
25510
+ var record4 = (value) => typeof value === "object" && value !== null;
24741
25511
  function restoreThreadReferenceCapability(client, manager, isCurrent) {
24742
- if (!record3(manager) || !record3(manager.storage)) return client;
25512
+ if (!record4(manager) || !record4(manager.storage)) return client;
24743
25513
  const storage = manager.storage;
24744
25514
  const read = storage.readValue;
24745
25515
  const write = storage.writeValue;
@@ -24774,14 +25544,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24774
25544
  }
24775
25545
 
24776
25546
  // src/renderer-thread-reference-context.ts
24777
- var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25547
+ var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
24778
25548
  function createThreadReferenceContext(manager, hostId2, isCurrent) {
24779
25549
  const prepared = /* @__PURE__ */ new WeakMap();
24780
25550
  return (params) => {
24781
- if (hostId2 === "local" || !record4(manager) || typeof manager.getConversation !== "function" || !record4(params) || typeof params.threadId !== "string")
25551
+ if (hostId2 === "local" || !record5(manager) || typeof manager.getConversation !== "function" || !record5(params) || typeof params.threadId !== "string")
24782
25552
  return params;
24783
25553
  const conversation = manager.getConversation.call(manager, params.threadId);
24784
- if (!record4(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25554
+ if (!record5(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
24785
25555
  return params;
24786
25556
  if (!isCurrent()) throw new Error("Thread reference connection is no longer available");
24787
25557
  const cached2 = prepared.get(params);
@@ -24793,11 +25563,11 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24793
25563
  }
24794
25564
 
24795
25565
  // src/renderer-manual-compaction.ts
24796
- function isRecord10(value) {
25566
+ function isRecord11(value) {
24797
25567
  return value !== null && typeof value === "object" && !Array.isArray(value);
24798
25568
  }
24799
25569
  function installRendererManualCompaction(target, hostId2, messages) {
24800
- if (!messages || typeof messages.addEventListener !== "function" || typeof messages.removeEventListener !== "function" || !isRecord10(target) || typeof target.registerPendingManualContextCompaction !== "function" || typeof target.getConversation !== "function") {
25570
+ if (!messages || typeof messages.addEventListener !== "function" || typeof messages.removeEventListener !== "function" || !isRecord11(target) || typeof target.registerPendingManualContextCompaction !== "function" || typeof target.getConversation !== "function") {
24801
25571
  return null;
24802
25572
  }
24803
25573
  const register = target.registerPendingManualContextCompaction;
@@ -24806,18 +25576,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24806
25576
  const listener = (event) => {
24807
25577
  if (event.source != null && event.source !== messages) return;
24808
25578
  const message2 = event.data;
24809
- if (!isRecord10(message2) || message2.type !== "mcp-notification" || message2.hostId !== hostId2 || message2.method !== THREAD_MANUAL_COMPACTION_STARTED_METHOD) {
25579
+ if (!isRecord11(message2) || message2.type !== "mcp-notification" || message2.hostId !== hostId2 || message2.method !== THREAD_MANUAL_COMPACTION_STARTED_METHOD) {
24810
25580
  return;
24811
25581
  }
24812
25582
  const params = threadManualCompactionStartedSchema.safeParse(message2.params);
24813
25583
  if (!params.success) return;
24814
25584
  const { threadId } = params.data;
24815
25585
  const conversation = getConversation.call(target, threadId);
24816
- if (!isRecord10(conversation) || conversation.id !== threadId || conversation.modelProvider !== "codexhost") {
25586
+ if (!isRecord11(conversation) || conversation.id !== threadId || conversation.modelProvider !== "codexhost") {
24817
25587
  return;
24818
25588
  }
24819
25589
  const role = getStreamRole?.call(target, threadId);
24820
- if (isRecord10(role) && role.role === "follower") return;
25590
+ if (isRecord11(role) && role.role === "follower") return;
24821
25591
  register.call(target, threadId);
24822
25592
  };
24823
25593
  messages.addEventListener("message", listener);
@@ -25032,7 +25802,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25032
25802
  var SIDEBAR_THREAD_HOST_ID_ATTRIBUTE = "data-app-action-sidebar-thread-host-id";
25033
25803
  var SIDEBAR_AGENT_ICON_ATTRIBUTE = "data-codexhost-sidebar-agent-icon";
25034
25804
  var OWNERSHIP_RETRY_DELAYS_MS = [100, 300, 800, 1500, 3e3];
25035
- function isRecord11(value) {
25805
+ function isRecord12(value) {
25036
25806
  return typeof value === "object" && value !== null && !Array.isArray(value);
25037
25807
  }
25038
25808
  function sidebarThreadAttributes(element) {
@@ -25059,19 +25829,19 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25059
25829
  const fiberName = fiberNames[0];
25060
25830
  if (fiberNames.length !== 1 || !fiberName) return null;
25061
25831
  const firstFiber2 = Object.getOwnPropertyDescriptor(element, fiberName)?.value;
25062
- if (!isRecord11(firstFiber2)) return null;
25832
+ if (!isRecord12(firstFiber2)) return null;
25063
25833
  const candidates = /* @__PURE__ */ new Set();
25064
25834
  let fiber = firstFiber2;
25065
25835
  for (let depth = 0; fiber && depth < 12; depth += 1) {
25066
25836
  const props = fiber.memoizedProps;
25067
- if (isRecord11(props) && isRecord11(props.dataAttributes)) {
25837
+ if (isRecord12(props) && isRecord12(props.dataAttributes)) {
25068
25838
  const dataAttributes = props.dataAttributes;
25069
25839
  const threadId = hostThreadIdSchema.safeParse(props.conversationId);
25070
25840
  if (threadId.success && dataAttributes[SIDEBAR_THREAD_ROW_ATTRIBUTE] === rowMarker && dataAttributes[SIDEBAR_THREAD_ID_ATTRIBUTE] === taskKey && dataAttributes[SIDEBAR_THREAD_HOST_ID_ATTRIBUTE] === hostId2) {
25071
25841
  candidates.add(threadId.data);
25072
25842
  }
25073
25843
  }
25074
- fiber = isRecord11(fiber.return) ? fiber.return : null;
25844
+ fiber = isRecord12(fiber.return) ? fiber.return : null;
25075
25845
  }
25076
25846
  return candidates.size === 1 ? candidates.values().next().value ?? null : null;
25077
25847
  }
@@ -25481,7 +26251,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25481
26251
  if (row) finish(row);
25482
26252
  });
25483
26253
  }
25484
- function isRecord12(value) {
26254
+ function isRecord13(value) {
25485
26255
  return typeof value === "object" && value !== null && !Array.isArray(value);
25486
26256
  }
25487
26257
  function firstFiber(element) {
@@ -25491,7 +26261,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25491
26261
  const name = names[0];
25492
26262
  if (names.length !== 1 || !name) return null;
25493
26263
  const value = Object.getOwnPropertyDescriptor(element, name)?.value;
25494
- return isRecord12(value) ? value : null;
26264
+ return isRecord13(value) ? value : null;
25495
26265
  }
25496
26266
  function directForkAncestors(first) {
25497
26267
  const ancestors = [];
@@ -25501,7 +26271,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25501
26271
  if (seen.has(fiber)) return [];
25502
26272
  seen.add(fiber);
25503
26273
  ancestors.push(fiber);
25504
- fiber = isRecord12(fiber.return) ? fiber.return : null;
26274
+ fiber = isRecord13(fiber.return) ? fiber.return : null;
25505
26275
  }
25506
26276
  return ancestors;
25507
26277
  }
@@ -25519,7 +26289,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25519
26289
  let hasForkCallback = false;
25520
26290
  for (const fiber of ancestors) {
25521
26291
  const props = fiber.memoizedProps;
25522
- if (!isRecord12(props)) continue;
26292
+ if (!isRecord13(props)) continue;
25523
26293
  if (!hasForkCallback && typeof props.onFork !== "function" && ownsOtherCallback(fiber, props)) {
25524
26294
  return null;
25525
26295
  }
@@ -25551,7 +26321,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25551
26321
  if (!threadId.success || !turnId.success) return null;
25552
26322
  const fiber = firstFiber(button2);
25553
26323
  const buttonProps = fiber?.memoizedProps;
25554
- if (!fiber || !isRecord12(buttonProps) || !Object.hasOwn(buttonProps, "aria-busy")) return null;
26324
+ if (!fiber || !isRecord13(buttonProps) || !Object.hasOwn(buttonProps, "aria-busy")) return null;
25555
26325
  return forkTargetFromAncestors(button2, threadId.data, turnId.data, directForkAncestors(fiber)) ?? forkTargetFromAncestors(button2, threadId.data, turnId.data, committedReactAncestors(fiber));
25556
26326
  }
25557
26327
  var BrowserRendererForkDom = class {
@@ -25641,7 +26411,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25641
26411
  }
25642
26412
  var DRAFT_PREWARM_POLICY_WAIT_TIMEOUT_MS = 1e4;
25643
26413
  var DRAFT_PREWARM_POLICY_POLL_INTERVAL_MS = 25;
25644
- function isRecord13(value) {
26414
+ function isRecord14(value) {
25645
26415
  return typeof value === "object" && value !== null && !Array.isArray(value);
25646
26416
  }
25647
26417
  function decodeOpenCodeTransportModelId(value) {
@@ -25806,7 +26576,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25806
26576
  let fiber = findComposerFiber(composer);
25807
26577
  for (let depth = 0; fiber && depth < 120; depth += 1) {
25808
26578
  const props = fiber.memoizedProps;
25809
- if (isRecord13(props) && "conversationId" in props && props.conversationId != null) {
26579
+ if (isRecord14(props) && "conversationId" in props && props.conversationId != null) {
25810
26580
  const candidate = hostThreadIdSchema.safeParse(props.conversationId);
25811
26581
  if (!candidate.success || threadId !== void 0 && threadId !== candidate.data) {
25812
26582
  return null;
@@ -25819,12 +26589,12 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25819
26589
  return threadId;
25820
26590
  }
25821
26591
  function isLegacySevenSlotDraftWrapper(value) {
25822
- if (!Array.isArray(value) || value.length !== 7 || value[3] !== value[5] || value[3] !== value[6] || !isRecord13(value[3]) || typeof value[3].get !== "function" || typeof value[2] !== "string" && value[2] !== null) {
26592
+ if (!Array.isArray(value) || value.length !== 7 || value[3] !== value[5] || value[3] !== value[6] || !isRecord14(value[3]) || typeof value[3].get !== "function" || typeof value[2] !== "string" && value[2] !== null) {
25823
26593
  return false;
25824
26594
  }
25825
26595
  try {
25826
26596
  const draft = value[3].get();
25827
- return isRecord13(draft) && "modelSettings" in draft && "isManuallyChanged" in draft;
26597
+ return isRecord14(draft) && "modelSettings" in draft && "isManuallyChanged" in draft;
25828
26598
  } catch {
25829
26599
  return false;
25830
26600
  }
@@ -25858,8 +26628,8 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25858
26628
  let fiber = findComposerFiber(composer);
25859
26629
  for (let depth = 0; fiber && depth < 120; depth += 1) {
25860
26630
  const updateQueue = fiber.updateQueue;
25861
- const memoCache = isRecord13(updateQueue) ? updateQueue.memoCache : null;
25862
- const data = isRecord13(memoCache) && Array.isArray(memoCache.data) ? memoCache.data : [];
26631
+ const memoCache = isRecord14(updateQueue) ? updateQueue.memoCache : null;
26632
+ const data = isRecord14(memoCache) && Array.isArray(memoCache.data) ? memoCache.data : [];
25863
26633
  for (const value of data) {
25864
26634
  const draftId = draftIdFromMemoValue(value);
25865
26635
  if (draftId) draftIds.add(draftId);
@@ -25887,7 +26657,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25887
26657
  return ["default", draftIds.values().next().value];
25888
26658
  }
25889
26659
  function isDraftPrewarmPolicyReady(value) {
25890
- return isRecord13(value) && value.state === "ready" && typeof value.hostId === "string" && value.hostId.length > 0 && typeof value.select === "function" && typeof value.clear === "function";
26660
+ return isRecord14(value) && value.state === "ready" && typeof value.hostId === "string" && value.hostId.length > 0 && typeof value.select === "function" && typeof value.clear === "function";
25891
26661
  }
25892
26662
  async function waitForRendererDraftPrewarmPolicy(target, composer) {
25893
26663
  const deadline = Date.now() + DRAFT_PREWARM_POLICY_WAIT_TIMEOUT_MS;
@@ -26137,116 +26907,6 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26137
26907
  }
26138
26908
  }
26139
26909
 
26140
- // src/renderer-new-thread-preference.ts
26141
- var RENDERER_NEW_THREAD_PREFERENCE_KEY = "codexhost.new-thread-preference.v1";
26142
- function rendererNewThreadPreferenceStorage(hostId2 = "local") {
26143
- if (!hostId2) return null;
26144
- try {
26145
- const storage = window.localStorage;
26146
- if (hostId2 === "local") return storage;
26147
- const scopedKey = (key) => `${key}.host.${encodeURIComponent(hostId2)}`;
26148
- return {
26149
- getItem: (key) => storage.getItem(scopedKey(key)),
26150
- setItem: (key, value) => storage.setItem(scopedKey(key), value)
26151
- };
26152
- } catch {
26153
- return null;
26154
- }
26155
- }
26156
- function isRecord14(value) {
26157
- return typeof value === "object" && value !== null && !Array.isArray(value);
26158
- }
26159
- function parseExternalConfiguration(value) {
26160
- if (!isRecord14(value)) return void 0;
26161
- const model2 = harnessModelRefSchema.safeParse(value.model);
26162
- if (!model2.success) return void 0;
26163
- const thinkingOptionId = harnessThinkingOptionIdSchema.safeParse(value.thinkingOptionId);
26164
- const permissionModeId = harnessPermissionModeIdSchema.safeParse(value.permissionModeId);
26165
- return {
26166
- model: model2.data,
26167
- ...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {},
26168
- ...permissionModeId.success ? { permissionModeId: permissionModeId.data } : {}
26169
- };
26170
- }
26171
- function readPreference(storage) {
26172
- if (!storage) return void 0;
26173
- try {
26174
- const raw = storage.getItem(RENDERER_NEW_THREAD_PREFERENCE_KEY);
26175
- if (!raw) return void 0;
26176
- const parsed = JSON.parse(raw);
26177
- if (!isRecord14(parsed) || parsed.version !== 1) return void 0;
26178
- if (parsed.lastAgent !== "codex" && !harnessPluginIdSchema.safeParse(parsed.lastAgent).success)
26179
- return void 0;
26180
- const externalByAgent = isRecord14(parsed.externalByAgent) ? parsed.externalByAgent : {};
26181
- const parsedExternal = Object.fromEntries(
26182
- Object.keys(externalByAgent).filter((agent) => harnessPluginIdSchema.safeParse(agent).success).flatMap((agent) => {
26183
- const configuration = parseExternalConfiguration(externalByAgent[agent]);
26184
- return configuration ? [[agent, configuration]] : [];
26185
- })
26186
- );
26187
- return {
26188
- version: 1,
26189
- lastAgent: parsed.lastAgent,
26190
- externalByAgent: parsedExternal
26191
- };
26192
- } catch {
26193
- return void 0;
26194
- }
26195
- }
26196
- function writePreference(preference, storage) {
26197
- if (!storage) return;
26198
- try {
26199
- storage.setItem(RENDERER_NEW_THREAD_PREFERENCE_KEY, JSON.stringify(preference));
26200
- } catch {
26201
- }
26202
- }
26203
- function readNewThreadAgentPreference(enabledAgents, storage = rendererNewThreadPreferenceStorage()) {
26204
- const agent = readPreference(storage)?.lastAgent;
26205
- return agent && (!enabledAgents || enabledAgents.has(agent)) ? agent : void 0;
26206
- }
26207
- function readNewThreadExternalConfigurationPreference(agent, catalog, permissionModes, storage = rendererNewThreadPreferenceStorage()) {
26208
- const preference = readPreference(storage)?.externalByAgent[agent];
26209
- if (!preference) return void 0;
26210
- const catalogModel = catalogModelForRef(catalog, preference.model);
26211
- if (!catalogModel) return void 0;
26212
- const thinkingOptionId = preference.thinkingOptionId && catalogModel.supportedThinkingOptionIds?.includes(preference.thinkingOptionId) ? preference.thinkingOptionId : void 0;
26213
- const permissionModeId = preference.permissionModeId && permissionModes?.modes.some(({ id }) => id === preference.permissionModeId) ? preference.permissionModeId : void 0;
26214
- return {
26215
- model: catalogModel.ref,
26216
- ...thinkingOptionId ? { thinkingOptionId } : {},
26217
- ...permissionModeId ? { permissionModeId } : {}
26218
- };
26219
- }
26220
- function writeNewThreadAgentPreference(agent, storage = rendererNewThreadPreferenceStorage()) {
26221
- const current = readPreference(storage);
26222
- writePreference(
26223
- {
26224
- version: 1,
26225
- lastAgent: agent,
26226
- externalByAgent: current?.externalByAgent ?? {}
26227
- },
26228
- storage
26229
- );
26230
- }
26231
- function writeNewThreadExternalConfigurationPreference(agent, model2, thinkingOptionId, permissionModeId, storage = rendererNewThreadPreferenceStorage()) {
26232
- const current = readPreference(storage);
26233
- writePreference(
26234
- {
26235
- version: 1,
26236
- lastAgent: current?.lastAgent ?? "codex",
26237
- externalByAgent: {
26238
- ...current?.externalByAgent,
26239
- [agent]: {
26240
- model: harnessModelRefSchema.parse(model2),
26241
- ...thinkingOptionId ? { thinkingOptionId: harnessThinkingOptionIdSchema.parse(thinkingOptionId) } : {},
26242
- ...permissionModeId ? { permissionModeId: harnessPermissionModeIdSchema.parse(permissionModeId) } : {}
26243
- }
26244
- }
26245
- },
26246
- storage
26247
- );
26248
- }
26249
-
26250
26910
  // src/renderer-harness-command-claim.ts
26251
26911
  function inputEvent(editor, text) {
26252
26912
  const view = editor.ownerDocument.defaultView;
@@ -26504,6 +27164,518 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26504
27164
  return element;
26505
27165
  }
26506
27166
 
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
+ // src/settings/voice-messages.ts
27266
+ function voiceMessages(locale) {
27267
+ const en = {
27268
+ title: "Voice",
27269
+ description: "Choose voice for Chat and Work. Shared on this Mac.",
27270
+ chat: "Chat",
27271
+ experience: "Voice experience",
27272
+ chatHint: "ChatGPT stays in your current Chat conversation.",
27273
+ codexConnection: "Codex connection",
27274
+ codexHint: "Available when Codex voice is selected.",
27275
+ work: "Work",
27276
+ connection: "Voice connection",
27277
+ workHint: "Desktop default applies to Codex Work. External Harness voice uses the configured gateway.",
27278
+ desktop: "Desktop default",
27279
+ gateway: "Configured gateway",
27280
+ configuration: "Configuration",
27281
+ gatewayTitle: "Gateway",
27282
+ gatewayHint: "Used only when Configured gateway is selected.",
27283
+ configured: "Configured",
27284
+ needsSetup: "Needs setup",
27285
+ unknown: "Not checked",
27286
+ configure: "Configure",
27287
+ setup: "Gateway setup",
27288
+ setupHint: "Gateway settings use your local Codex configuration and the selected provider\u2019s credential. End voice before editing configuration. Never paste credentials here.",
27289
+ advanced: "Advanced",
27290
+ advancedHint: "Voice integration and diagnostics.",
27291
+ inject: "Enable voice integration",
27292
+ injectHint: "Enables the ChatGPT voice control and gateway routing. Changing this requires restarting codexhost.",
27293
+ environment: "Voice integration is controlled by this launch environment.",
27294
+ loading: "Loading voice settings\u2026",
27295
+ unavailable: "Voice settings are unavailable. Check the local Host connection.",
27296
+ retry: "Reload",
27297
+ cancel: "Cancel",
27298
+ apply: "Apply changes",
27299
+ applyRestart: "Apply and restart codexhost",
27300
+ retryRestart: "Retry restart",
27301
+ saving: "Saving settings\u2026",
27302
+ restarting: "Restarting codexhost\u2026",
27303
+ ready: "No pending changes",
27304
+ edited: "Unsaved changes",
27305
+ nextCall: "Voice choices apply to the next call.",
27306
+ pending: "Saved \u2014 waiting for Desktop to apply voice choices.",
27307
+ restartNeeded: "Saved \u2014 restart required",
27308
+ activeUnknown: "Saved \u2014 active setting is unknown.",
27309
+ activeCall: "End your voice call to apply changes.",
27310
+ integrationOff: "Voice integration is off. Enable it in Advanced to use these choices.",
27311
+ restartWarning: "Restart codexhost to apply voice integration? This may interrupt running tasks. End voice before continuing.",
27312
+ confirm: "Apply and restart",
27313
+ restartFailed: "Settings are saved, but restart failed.",
27314
+ conflict: "Settings changed in another window. Reload before applying.",
27315
+ gatewayWarning: "The selected gateway needs setup before voice can connect."
27316
+ };
27317
+ if (locale !== "zh-CN") return en;
27318
+ return {
27319
+ ...en,
27320
+ title: "\u8BED\u97F3",
27321
+ description: "\u9009\u62E9 Chat \u548C Work \u7684\u8BED\u97F3\u65B9\u5F0F\u3002\u5728\u6B64 Mac \u4E0A\u5171\u4EAB\u3002",
27322
+ experience: "\u8BED\u97F3\u4F53\u9A8C",
27323
+ chatHint: "ChatGPT \u8BED\u97F3\u4FDD\u7559\u5728\u5F53\u524D Chat \u5BF9\u8BDD\u4E2D\u3002",
27324
+ codexConnection: "Codex \u8FDE\u63A5",
27325
+ codexHint: "\u9009\u62E9 Codex \u8BED\u97F3\u540E\u53EF\u7528\u3002",
27326
+ connection: "\u8BED\u97F3\u8FDE\u63A5",
27327
+ workHint: "Desktop \u9ED8\u8BA4\u9002\u7528\u4E8E Codex Work\u3002\u5916\u90E8 Harness \u8BED\u97F3\u4F7F\u7528\u5DF2\u914D\u7F6E\u7684\u7F51\u5173\u3002",
27328
+ desktop: "Desktop \u9ED8\u8BA4",
27329
+ gateway: "\u5DF2\u914D\u7F6E\u7684\u7F51\u5173",
27330
+ configuration: "\u914D\u7F6E",
27331
+ gatewayTitle: "\u7F51\u5173",
27332
+ gatewayHint: "\u4EC5\u5728\u9009\u62E9\u5DF2\u914D\u7F6E\u7684\u7F51\u5173\u65F6\u4F7F\u7528\u3002",
27333
+ configured: "\u5DF2\u914D\u7F6E",
27334
+ needsSetup: "\u9700\u8981\u914D\u7F6E",
27335
+ unknown: "\u672A\u68C0\u67E5",
27336
+ configure: "\u914D\u7F6E",
27337
+ setup: "\u7F51\u5173\u914D\u7F6E",
27338
+ 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",
27339
+ advanced: "\u9AD8\u7EA7",
27340
+ advancedHint: "\u8BED\u97F3\u96C6\u6210\u4E0E\u8BCA\u65AD\u3002",
27341
+ inject: "\u542F\u7528\u8BED\u97F3\u96C6\u6210",
27342
+ injectHint: "\u542F\u7528 ChatGPT \u8BED\u97F3\u6309\u94AE\u4E0E\u7F51\u5173\u8DEF\u7531\u3002\u66F4\u6539\u6B64\u9879\u9700\u8981\u91CD\u542F codexhost\u3002",
27343
+ environment: "\u5F53\u524D\u542F\u52A8\u73AF\u5883\u63A7\u5236\u8BED\u97F3\u96C6\u6210\u3002",
27344
+ loading: "\u6B63\u5728\u52A0\u8F7D\u8BED\u97F3\u8BBE\u7F6E\u2026",
27345
+ unavailable: "\u8BED\u97F3\u8BBE\u7F6E\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730 Host \u8FDE\u63A5\u3002",
27346
+ retry: "\u91CD\u65B0\u52A0\u8F7D",
27347
+ cancel: "\u53D6\u6D88",
27348
+ apply: "\u5E94\u7528\u66F4\u6539",
27349
+ applyRestart: "\u5E94\u7528\u5E76\u91CD\u542F codexhost",
27350
+ retryRestart: "\u91CD\u8BD5\u91CD\u542F",
27351
+ saving: "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E\u2026",
27352
+ restarting: "\u6B63\u5728\u91CD\u542F codexhost\u2026",
27353
+ ready: "\u6CA1\u6709\u5F85\u5E94\u7528\u7684\u66F4\u6539",
27354
+ edited: "\u66F4\u6539\u5C1A\u672A\u4FDD\u5B58",
27355
+ nextCall: "\u8BED\u97F3\u9009\u62E9\u4ECE\u4E0B\u6B21\u901A\u8BDD\u751F\u6548\u3002",
27356
+ pending: "\u5DF2\u4FDD\u5B58\uFF0C\u7B49\u5F85 Desktop \u5E94\u7528\u8BED\u97F3\u9009\u62E9\u3002",
27357
+ restartNeeded: "\u5DF2\u4FDD\u5B58\uFF0C\u9700\u8981\u91CD\u542F",
27358
+ activeUnknown: "\u5DF2\u4FDD\u5B58\uFF0C\u5F53\u524D\u751F\u6548\u72B6\u6001\u672A\u77E5\u3002",
27359
+ activeCall: "\u8BF7\u7ED3\u675F\u8BED\u97F3\u540E\u518D\u5E94\u7528\u66F4\u6539\u3002",
27360
+ integrationOff: "\u8BED\u97F3\u96C6\u6210\u5DF2\u5173\u95ED\uFF0C\u8BF7\u5728\u9AD8\u7EA7\u8BBE\u7F6E\u4E2D\u542F\u7528\u540E\u4F7F\u7528\u8FD9\u4E9B\u9009\u9879\u3002",
27361
+ restartWarning: "\u91CD\u542F codexhost \u4EE5\u5E94\u7528\u8BED\u97F3\u96C6\u6210\uFF1F\u8FD9\u53EF\u80FD\u4E2D\u65AD\u8FD0\u884C\u4E2D\u7684\u4EFB\u52A1\uFF0C\u8BF7\u5148\u7ED3\u675F\u8BED\u97F3\u3002",
27362
+ confirm: "\u5E94\u7528\u5E76\u91CD\u542F",
27363
+ restartFailed: "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u91CD\u542F\u5931\u8D25\u3002",
27364
+ conflict: "\u5176\u4ED6\u7A97\u53E3\u66F4\u6539\u4E86\u8BBE\u7F6E\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u540E\u518D\u5E94\u7528\u3002",
27365
+ gatewayWarning: "\u6240\u9009\u7F51\u5173\u9700\u8981\u914D\u7F6E\u540E\u624D\u80FD\u8FDE\u63A5\u8BED\u97F3\u3002"
27366
+ };
27367
+ }
27368
+
27369
+ // src/settings/voice-page.ts
27370
+ function createVoiceSettingsPage(locale, request, options = {}) {
27371
+ const m = voiceMessages(locale);
27372
+ return Object.freeze({
27373
+ id: options.id ?? "voice",
27374
+ label: m.title,
27375
+ icon: "settings",
27376
+ mount(context) {
27377
+ const doc = context.content.ownerDocument;
27378
+ let state = null;
27379
+ let base = null;
27380
+ let draft = null;
27381
+ let offline = false;
27382
+ let busy = false;
27383
+ let refreshing = false;
27384
+ let generation = 0;
27385
+ let disposed = false;
27386
+ let confirm = false;
27387
+ let advanced = false;
27388
+ let setup = false;
27389
+ let error51 = null;
27390
+ const ids = /* @__PURE__ */ new Map();
27391
+ const controlId = (key) => {
27392
+ const existing = ids.get(key);
27393
+ if (existing) return existing;
27394
+ const id = preferenceId(key);
27395
+ ids.set(key, id);
27396
+ return id;
27397
+ };
27398
+ const dirty = () => !!draft && JSON.stringify(draft) !== JSON.stringify(base?.settings);
27399
+ const isActiveCall = () => state?.activeCall === true || options.desktop && !!doc.defaultView && desktopVoiceCallActive(doc.defaultView);
27400
+ const needsRestart = () => !!draft && !!state && (state.activeInject === null ? draft.inject !== base?.settings.inject : (state.envOverride ? state.envOverride === "1" : draft.inject) !== state.activeInject);
27401
+ const load = async (reset = false) => {
27402
+ if (refreshing || busy || disposed) return;
27403
+ refreshing = true;
27404
+ const currentGeneration = generation;
27405
+ try {
27406
+ const next = voiceSettingsStateSchema.parse(await request({ operation: "get" }));
27407
+ if (disposed || generation !== currentGeneration) return;
27408
+ const changed = JSON.stringify(state) !== JSON.stringify(next) || offline || reset;
27409
+ if (reset || !dirty()) {
27410
+ base = next;
27411
+ draft = { ...next.settings };
27412
+ }
27413
+ state = next;
27414
+ offline = false;
27415
+ if (reset) {
27416
+ error51 = null;
27417
+ confirm = false;
27418
+ }
27419
+ if (changed) render();
27420
+ } catch {
27421
+ if (!disposed && generation === currentGeneration) {
27422
+ offline = true;
27423
+ render();
27424
+ }
27425
+ } finally {
27426
+ refreshing = false;
27427
+ }
27428
+ };
27429
+ const apply = async (restart) => {
27430
+ if (!draft || !base || busy || isActiveCall()) return;
27431
+ busy = true;
27432
+ generation += 1;
27433
+ error51 = null;
27434
+ confirm = false;
27435
+ render();
27436
+ try {
27437
+ const current = voiceSettingsStateSchema.parse(await request({ operation: "get" }));
27438
+ if (disposed) return;
27439
+ if (current.activeCall || isActiveCall()) throw new Error(m.activeCall);
27440
+ if (current.revision !== base.revision) throw new Error(m.conflict);
27441
+ if (dirty()) {
27442
+ const saved = voiceSettingsStateSchema.parse(
27443
+ await request({
27444
+ operation: "set",
27445
+ settings: draft,
27446
+ revision: base.revision
27447
+ })
27448
+ );
27449
+ if (disposed) return;
27450
+ state = saved;
27451
+ base = saved;
27452
+ draft = { ...saved.settings };
27453
+ }
27454
+ if (restart) await request({ operation: "restart", confirm: true });
27455
+ } catch (failure) {
27456
+ if (!disposed) error51 = failure instanceof Error ? failure.message : m.unavailable;
27457
+ } finally {
27458
+ busy = false;
27459
+ if (!disposed) {
27460
+ render();
27461
+ void load();
27462
+ }
27463
+ }
27464
+ };
27465
+ const render = () => {
27466
+ if (disposed) return;
27467
+ const tree = context.content.getRootNode();
27468
+ const focused = tree.activeElement;
27469
+ const focusedId = focused && context.content.contains(focused) ? focused.id : "";
27470
+ const root = h(doc, "div", { className: "settings-voice" });
27471
+ root.append(
27472
+ h(doc, "div", { className: "settings-section-label" }, m.title),
27473
+ h(doc, "p", { className: "settings-page-description" }, m.description)
27474
+ );
27475
+ if (!draft || !state) {
27476
+ root.append(h(doc, "p", { role: "status" }, offline ? m.unavailable : m.loading));
27477
+ if (offline) root.append(button(doc, m.retry, () => void load(true)));
27478
+ context.content.replaceChildren(root);
27479
+ return;
27480
+ }
27481
+ const unavailable = busy || offline || state.restart.phase === "restarting";
27482
+ const row = (card, title, description, key, choices, disabled = false) => {
27483
+ const id = controlId(`voice-${key}`);
27484
+ const item = createPreferenceItem(doc, { title, description, controlId: id });
27485
+ item.item.classList.add("settings-voice__row");
27486
+ const select = h(doc, "select", {
27487
+ id,
27488
+ className: "settings-voice__select",
27489
+ "aria-describedby": item.description.id
27490
+ });
27491
+ for (const [value, label] of choices) select.append(h(doc, "option", { value }, label));
27492
+ select.value = draft?.[key] ?? "";
27493
+ select.disabled = unavailable || disabled;
27494
+ select.addEventListener("change", () => {
27495
+ if (!draft) return;
27496
+ draft = { ...draft, [key]: select.value };
27497
+ confirm = false;
27498
+ render();
27499
+ });
27500
+ item.item.append(select);
27501
+ card.append(item.item);
27502
+ };
27503
+ const connections = [
27504
+ ["desktop", m.desktop],
27505
+ ["gateway", m.gateway]
27506
+ ];
27507
+ const chat = createPreferenceGroup(doc, m.chat);
27508
+ row(chat.card, m.experience, m.chatHint, "chatExperience", [
27509
+ ["chatgpt", "ChatGPT"],
27510
+ ["codex", "Codex"]
27511
+ ]);
27512
+ row(
27513
+ chat.card,
27514
+ m.codexConnection,
27515
+ m.codexHint,
27516
+ "chatConnection",
27517
+ connections,
27518
+ draft.chatExperience !== "codex"
27519
+ );
27520
+ const work = createPreferenceGroup(doc, m.work);
27521
+ row(work.card, m.connection, m.workHint, "workConnection", connections);
27522
+ const config2 = createPreferenceGroup(doc, m.configuration);
27523
+ const gateway = createPreferenceItem(doc, {
27524
+ title: m.gatewayTitle,
27525
+ description: m.gatewayHint,
27526
+ controlId: preferenceId("gateway-config")
27527
+ });
27528
+ gateway.item.classList.add("settings-voice__row");
27529
+ const configure = button(doc, m.configure, () => {
27530
+ setup = !setup;
27531
+ render();
27532
+ });
27533
+ configure.id = gateway.item.querySelector("label")?.htmlFor ?? "";
27534
+ configure.setAttribute("aria-expanded", String(setup));
27535
+ const gatewayActions = h(
27536
+ doc,
27537
+ "div",
27538
+ { className: "settings-voice__gateway-actions" },
27539
+ h(
27540
+ doc,
27541
+ "span",
27542
+ {},
27543
+ state.gatewayReady === null ? m.unknown : state.gatewayReady ? m.configured : m.needsSetup
27544
+ ),
27545
+ configure
27546
+ );
27547
+ gateway.item.append(gatewayActions);
27548
+ config2.card.append(gateway.item);
27549
+ if (setup) {
27550
+ const details = h(
27551
+ doc,
27552
+ "div",
27553
+ { className: "settings-voice__details" },
27554
+ h(doc, "strong", {}, m.setup),
27555
+ h(doc, "p", {}, m.setupHint)
27556
+ );
27557
+ details.append(
27558
+ h(doc, "code", {}, "~/.codex/config.toml"),
27559
+ h(
27560
+ doc,
27561
+ "p",
27562
+ {},
27563
+ "experimental_realtime_webrtc_call_base_url \xB7 experimental_realtime_ws_base_url"
27564
+ )
27565
+ );
27566
+ config2.card.append(details);
27567
+ }
27568
+ const adv = createPreferenceItem(doc, {
27569
+ title: m.advanced,
27570
+ description: m.advancedHint,
27571
+ controlId: preferenceId("voice-advanced")
27572
+ });
27573
+ const expand = button(doc, advanced ? "\u2303" : "\u203A", () => {
27574
+ advanced = !advanced;
27575
+ render();
27576
+ });
27577
+ expand.id = adv.item.querySelector("label")?.htmlFor ?? "";
27578
+ expand.setAttribute("aria-label", m.advanced);
27579
+ expand.setAttribute("aria-expanded", String(advanced));
27580
+ adv.item.append(expand);
27581
+ config2.card.append(adv.item);
27582
+ if (advanced) {
27583
+ const id = controlId("voice-inject");
27584
+ const injection = createPreferenceItem(doc, {
27585
+ title: m.inject,
27586
+ description: m.injectHint,
27587
+ controlId: id
27588
+ });
27589
+ injection.item.classList.add("settings-voice__row");
27590
+ const toggle = createPreferenceSwitch(doc, id, injection.description.id);
27591
+ toggle.checked = draft.inject;
27592
+ toggle.disabled = unavailable || !!state.envOverride;
27593
+ toggle.addEventListener("change", () => {
27594
+ if (draft) draft = { ...draft, inject: toggle.checked };
27595
+ confirm = false;
27596
+ render();
27597
+ });
27598
+ injection.item.append(toggle);
27599
+ config2.card.append(injection.item);
27600
+ if (state.envOverride || state.activeEnvOverride)
27601
+ config2.card.append(
27602
+ h(doc, "p", { className: "settings-voice__details" }, m.environment)
27603
+ );
27604
+ }
27605
+ root.append(chat.group, work.group, config2.group);
27606
+ const restarting = state.restart.phase === "restarting";
27607
+ const failed = state.restart.phase === "failed";
27608
+ const status = busy ? m.saving : restarting ? m.restarting : isActiveCall() ? m.activeCall : offline ? m.unavailable : dirty() ? m.edited : needsRestart() ? m.restartNeeded : state.activeInject === null ? m.activeUnknown : state.routesActive === false ? m.pending : state.routesActive === null ? m.activeUnknown : m.ready;
27609
+ const footer = h(
27610
+ doc,
27611
+ "div",
27612
+ { className: "settings-voice__footer" },
27613
+ h(doc, "div", { role: "status" }, h(doc, "div", {}, status), h(doc, "p", {}, m.nextCall))
27614
+ );
27615
+ const actions = h(doc, "div", { className: "settings-voice__actions" });
27616
+ const cancel = button(doc, m.cancel, () => {
27617
+ draft = base ? { ...base.settings } : null;
27618
+ confirm = false;
27619
+ error51 = null;
27620
+ render();
27621
+ });
27622
+ cancel.disabled = busy || !dirty() && !confirm;
27623
+ const submit = button(
27624
+ doc,
27625
+ failed && needsRestart() && !dirty() ? m.retryRestart : needsRestart() && state.restartAvailable ? m.applyRestart : m.apply,
27626
+ () => {
27627
+ if (needsRestart() && state?.restartAvailable) {
27628
+ confirm = true;
27629
+ render();
27630
+ } else void apply(false);
27631
+ },
27632
+ "primary"
27633
+ );
27634
+ submit.disabled = unavailable || !!isActiveCall() || !dirty() && !(needsRestart() && state.restartAvailable);
27635
+ actions.append(cancel, submit);
27636
+ footer.append(actions);
27637
+ root.append(footer);
27638
+ if (confirm)
27639
+ root.append(
27640
+ h(
27641
+ doc,
27642
+ "div",
27643
+ { className: "settings-voice__confirmation" },
27644
+ h(doc, "p", {}, m.restartWarning),
27645
+ button(doc, m.confirm, () => void apply(true), "primary"),
27646
+ button(doc, m.cancel, () => {
27647
+ confirm = false;
27648
+ render();
27649
+ })
27650
+ )
27651
+ );
27652
+ if (failed)
27653
+ root.append(
27654
+ h(doc, "p", { role: "alert" }, `${m.restartFailed} ${state.restart.error ?? ""}`)
27655
+ );
27656
+ if (error51) root.append(h(doc, "p", { role: "alert" }, error51));
27657
+ const gatewaySelected = draft.workConnection === "gateway" || draft.chatExperience === "codex" && draft.chatConnection === "gateway";
27658
+ if (gatewaySelected && state.gatewayReady === false)
27659
+ root.append(h(doc, "p", { className: "settings-voice__hint" }, m.gatewayWarning));
27660
+ if (!draft.inject)
27661
+ root.append(h(doc, "p", { className: "settings-voice__hint" }, m.integrationOff));
27662
+ if (offline || base?.revision !== state.revision)
27663
+ root.append(button(doc, m.retry, () => void load(true)));
27664
+ context.content.replaceChildren(root);
27665
+ if (focusedId)
27666
+ root.querySelector(`#${focusedId}`)?.focus({ preventScroll: true });
27667
+ };
27668
+ render();
27669
+ void load();
27670
+ const timer = doc.defaultView?.setInterval(() => void load(), 3e3);
27671
+ return () => {
27672
+ disposed = true;
27673
+ if (timer !== void 0) doc.defaultView?.clearInterval(timer);
27674
+ };
27675
+ }
27676
+ });
27677
+ }
27678
+
26507
27679
  // src/console/usage/model-labels.ts
26508
27680
  function usageModelLabel(model2, labels, harness2) {
26509
27681
  const names = new Set(
@@ -28831,6 +30003,12 @@ ${detail}` : ""}`
28831
30003
  stopped: "codexhost is not running",
28832
30004
  stoppedDetail: "Start codexhost to use Codex Desktop with your Harnesses.",
28833
30005
  start: "Start codexhost",
30006
+ restart: "Restart codexhost",
30007
+ restartConfirm: "Restart now",
30008
+ restartCancel: "Cancel",
30009
+ restartWarning: "Restart closes Desktop and may interrupt a voice call or running tasks. Finish or stop them before continuing. Saved chats remain available; Desktop controls which chat reopens.",
30010
+ restarting: "Restarting codexhost\u2026 Waiting for the new Desktop controller.",
30011
+ restarted: "Restart complete. The new Desktop controller is ready.",
28834
30012
  starting: "Starting\u2026",
28835
30013
  startingTitle: "codexhost is starting",
28836
30014
  startingDetail: "Preparing Codex Desktop. Please wait; there is no need to start it again.",
@@ -29014,6 +30192,12 @@ ${detail}` : ""}`
29014
30192
  stopped: "codexhost \u672A\u8FD0\u884C",
29015
30193
  stoppedDetail: "\u542F\u52A8 codexhost \u540E\u5373\u53EF\u5728 Codex Desktop \u4E2D\u4F7F\u7528\u5404\u4E2A Harness\u3002",
29016
30194
  start: "\u542F\u52A8 codexhost",
30195
+ restart: "\u91CD\u65B0\u542F\u52A8 codexhost",
30196
+ restartConfirm: "\u7ACB\u5373\u91CD\u65B0\u542F\u52A8",
30197
+ restartCancel: "\u53D6\u6D88",
30198
+ restartWarning: "\u91CD\u65B0\u542F\u52A8\u4F1A\u5173\u95ED Desktop\uFF0C\u53EF\u80FD\u4E2D\u65AD\u8BED\u97F3\u901A\u8BDD\u6216\u8FD0\u884C\u4E2D\u7684\u4EFB\u52A1\u3002\u8BF7\u5148\u5B8C\u6210\u6216\u505C\u6B62\u5B83\u4EEC\u3002\u5DF2\u4FDD\u5B58\u804A\u5929\u4ECD\u53EF\u4F7F\u7528\uFF1B\u91CD\u65B0\u6253\u5F00\u54EA\u4E2A\u804A\u5929\u7531 Desktop \u51B3\u5B9A\u3002",
30199
+ restarting: "\u6B63\u5728\u91CD\u65B0\u542F\u52A8 codexhost\u2026 \u7B49\u5F85\u65B0\u7684 Desktop \u63A7\u5236\u5668\u3002",
30200
+ restarted: "\u91CD\u65B0\u542F\u52A8\u5B8C\u6210\u3002\u65B0\u7684 Desktop \u63A7\u5236\u5668\u5DF2\u5C31\u7EEA\u3002",
29017
30201
  starting: "\u6B63\u5728\u542F\u52A8\u2026",
29018
30202
  startingTitle: "codexhost \u6B63\u5728\u542F\u52A8",
29019
30203
  startingDetail: "\u6B63\u5728\u51C6\u5907 Codex Desktop\uFF0C\u8BF7\u7A0D\u5019\uFF0C\u65E0\u9700\u91CD\u590D\u542F\u52A8\u3002",
@@ -29543,104 +30727,6 @@ ${detail}` : ""}`
29543
30727
  return card;
29544
30728
  }
29545
30729
 
29546
- // src/settings/preference-ui.ts
29547
- var nextPreferenceId = 0;
29548
- function preferenceId(prefix) {
29549
- nextPreferenceId += 1;
29550
- return `codexhost-${prefix}-${nextPreferenceId}`;
29551
- }
29552
- function createPreferenceGroup(document2, title) {
29553
- const group = document2.createElement("section");
29554
- group.className = "mt-7 first-of-type:mt-0";
29555
- const header = document2.createElement("div");
29556
- header.className = "mb-2 flex min-h-6 items-center gap-2 px-1";
29557
- const heading = document2.createElement("h3");
29558
- heading.id = preferenceId("preference-group");
29559
- heading.className = "m-0 text-[13px] leading-5 font-semibold text-settings-text";
29560
- heading.textContent = title;
29561
- header.append(heading);
29562
- const card = document2.createElement("div");
29563
- card.className = "rounded-[10px] border border-settings-border bg-settings-panel";
29564
- group.setAttribute("aria-labelledby", heading.id);
29565
- group.append(header, card);
29566
- return { group, header, card };
29567
- }
29568
- function createPreferenceItem(document2, input) {
29569
- const item = document2.createElement("div");
29570
- 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";
29571
- const copy = document2.createElement("div");
29572
- copy.className = "flex min-w-0 flex-col gap-0.5";
29573
- const heading = document2.createElement("div");
29574
- heading.className = "flex items-center gap-1.5";
29575
- const title = document2.createElement("label");
29576
- title.htmlFor = input.controlId;
29577
- title.className = "cursor-pointer text-[13px] leading-5 font-medium text-settings-text";
29578
- title.textContent = input.title;
29579
- heading.append(title);
29580
- if (input.help) heading.append(createHelpTooltip(document2, input.help.label, input.help.lines));
29581
- const description = document2.createElement("div");
29582
- description.id = preferenceId("preference-description");
29583
- description.className = "text-xs leading-[18px] text-settings-muted data-[invalid=true]:text-settings-danger";
29584
- description.textContent = input.description;
29585
- copy.append(heading, description);
29586
- item.append(copy);
29587
- return { item, description };
29588
- }
29589
- function createHelpTooltip(document2, label, lines) {
29590
- const wrapper = document2.createElement("span");
29591
- wrapper.className = "group relative inline-flex";
29592
- const button2 = document2.createElement("button");
29593
- button2.type = "button";
29594
- 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";
29595
- button2.setAttribute("aria-label", label);
29596
- button2.append(createRendererSettingsIcon("help", 14));
29597
- const tooltip = document2.createElement("div");
29598
- tooltip.id = preferenceId("preference-tooltip");
29599
- tooltip.setAttribute("role", "tooltip");
29600
- 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";
29601
- const list = document2.createElement("ul");
29602
- list.className = "m-0 grid list-disc gap-1 pl-4 marker:text-settings-subtle";
29603
- for (const line of lines) {
29604
- const item = document2.createElement("li");
29605
- item.textContent = line;
29606
- list.append(item);
29607
- }
29608
- tooltip.append(list);
29609
- button2.setAttribute("aria-describedby", tooltip.id);
29610
- button2.addEventListener("keydown", (event) => {
29611
- if (event.key === "Escape") button2.blur();
29612
- });
29613
- wrapper.append(button2, tooltip);
29614
- return wrapper;
29615
- }
29616
- function createPreferenceSwitch(document2, id, describedBy) {
29617
- const input = document2.createElement("input");
29618
- input.type = "checkbox";
29619
- input.id = id;
29620
- input.setAttribute("role", "switch");
29621
- input.setAttribute("aria-describedby", describedBy);
29622
- 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";
29623
- return input;
29624
- }
29625
- function createNumberField(document2, input) {
29626
- const field = document2.createElement("div");
29627
- 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";
29628
- const control = document2.createElement("input");
29629
- control.type = "number";
29630
- control.id = input.id;
29631
- control.min = String(input.min);
29632
- control.max = String(input.max);
29633
- control.step = "1";
29634
- control.setAttribute("aria-describedby", input.describedBy);
29635
- control.className = "w-14 border-0 bg-transparent p-0 text-right text-[13px] leading-5 text-settings-text tabular-nums outline-none";
29636
- const unit = document2.createElement("span");
29637
- unit.className = "text-xs text-settings-muted";
29638
- unit.setAttribute("aria-hidden", "true");
29639
- unit.textContent = input.unit;
29640
- field.append(control, unit);
29641
- return { field, control };
29642
- }
29643
-
29644
30730
  // src/settings/remote-connections-dialogs.ts
29645
30731
  function createRemoteDialog({ container, signal, t }, title) {
29646
30732
  if (signal.aborted || container.querySelector("dialog")) return null;
@@ -31320,31 +32406,6 @@ ${detail}` : ""}`
31320
32406
  ownerWindow.addEventListener(CODEX_USAGE_BANNER_CHANGE_EVENT, syncUsageBanner);
31321
32407
  usageBannerRow.item.append(usageBanner);
31322
32408
  card.append(usageBannerRow.item);
31323
- const liveVoiceId = preferenceId("cpa-live-voice");
31324
- const liveVoiceRow = createPreferenceItem(document2, {
31325
- title: messages.cpaLiveVoiceTitle,
31326
- description: messages.cpaLiveVoiceDescription,
31327
- controlId: liveVoiceId,
31328
- help: { label: messages.cpaLiveVoiceHelpLabel, lines: messages.cpaLiveVoiceHelp }
31329
- });
31330
- const liveVoice = createPreferenceSwitch(document2, liveVoiceId, liveVoiceRow.description.id);
31331
- liveVoice.checked = readCpaLiveVoicePreference(ownerWindow);
31332
- liveVoice.addEventListener("change", () => {
31333
- writeCpaLiveVoicePreference(ownerWindow, liveVoice.checked);
31334
- });
31335
- const syncLiveVoice = () => {
31336
- liveVoice.checked = readCpaLiveVoicePreference(ownerWindow);
31337
- };
31338
- ownerWindow.addEventListener(CPA_LIVE_VOICE_CHANGE_EVENT, syncLiveVoice);
31339
- liveVoiceRow.item.append(liveVoice);
31340
- if (!readCpaLiveVoiceHookConfig(ownerWindow)) {
31341
- const warning = document2.createElement("div");
31342
- warning.className = "text-xs leading-[18px] text-settings-warning";
31343
- warning.setAttribute("role", "status");
31344
- warning.textContent = messages.cpaLiveVoiceRestartRequired;
31345
- liveVoiceRow.description.after(warning);
31346
- }
31347
- card.append(liveVoiceRow.item);
31348
32409
  const softWrapId = preferenceId("reasoning-soft-wrap");
31349
32410
  const row = createPreferenceItem(document2, {
31350
32411
  title: messages.reasoningSoftWrapTitle,
@@ -31370,7 +32431,6 @@ ${detail}` : ""}`
31370
32431
  );
31371
32432
  return () => {
31372
32433
  ownerWindow.removeEventListener(CODEX_USAGE_BANNER_CHANGE_EVENT, syncUsageBanner);
31373
- ownerWindow.removeEventListener(CPA_LIVE_VOICE_CHANGE_EVENT, syncLiveVoice);
31374
32434
  ownerWindow.removeEventListener(REASONING_SOFT_WRAP_CHANGE_EVENT, sync);
31375
32435
  disposeIdleRelease();
31376
32436
  };
@@ -31603,7 +32663,7 @@ ${detail}` : ""}`
31603
32663
  }
31604
32664
  function defaultImportName(source, existing) {
31605
32665
  const base = source.provider === "openai-codex" ? "codex" : "grok";
31606
- const used = new Set(existing.map((record5) => record5.name));
32666
+ const used = new Set(existing.map((record6) => record6.name));
31607
32667
  const valid = (name) => credentialImportNameSchema.safeParse(name).success;
31608
32668
  if (!used.has(base)) return base;
31609
32669
  const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
@@ -31626,7 +32686,7 @@ ${detail}` : ""}`
31626
32686
  const shown = (text) => accountDisplayText(text, hideEmails);
31627
32687
  const targetButtons = /* @__PURE__ */ new Map();
31628
32688
  const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
31629
- const sourceOf = (record5) => snapshot.sources.find((source) => source.id === record5.source.id);
32689
+ const sourceOf = (record6) => snapshot.sources.find((source) => source.id === record6.source.id);
31630
32690
  const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
31631
32691
  const compatibleSources = () => {
31632
32692
  const target = piTarget();
@@ -31664,7 +32724,7 @@ ${detail}` : ""}`
31664
32724
  sectionImport.addEventListener("click", () => {
31665
32725
  const sources = compatibleSources();
31666
32726
  const free = sources.find(
31667
- (source2) => !importedRecords().some((record5) => record5.source.id === source2.id)
32727
+ (source2) => !importedRecords().some((record6) => record6.source.id === source2.id)
31668
32728
  );
31669
32729
  const source = free ?? sources[0];
31670
32730
  if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
@@ -31714,30 +32774,30 @@ ${detail}` : ""}`
31714
32774
  mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
31715
32775
  return mark;
31716
32776
  };
31717
- const renderRow = (record5) => {
32777
+ const renderRow = (record6) => {
31718
32778
  const row = document2.createElement("div");
31719
32779
  row.className = "settings-pi-accounts__row";
31720
32780
  row.tabIndex = -1;
31721
- row.dataset.importName = record5.name;
31722
- row.setAttribute("aria-label", shown(record5.source.label));
31723
- const agent = record5.source.harnessId;
32781
+ row.dataset.importName = record6.name;
32782
+ row.setAttribute("aria-label", shown(record6.source.label));
32783
+ const agent = record6.source.harnessId;
31724
32784
  const mark = createMark(agent);
31725
32785
  const identity = document2.createElement("div");
31726
32786
  identity.className = "settings-pi-accounts__identity";
31727
32787
  const label = document2.createElement("strong");
31728
32788
  label.className = "settings-account-email";
31729
- label.textContent = shown(record5.source.label);
32789
+ label.textContent = shown(record6.source.label);
31730
32790
  label.title = label.textContent;
31731
32791
  label.translate = false;
31732
32792
  const meta3 = document2.createElement("div");
31733
32793
  meta3.className = "settings-account-metadata";
31734
- const source = sourceOf(record5);
32794
+ const source = sourceOf(record6);
31735
32795
  const parts = [
31736
32796
  metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
31737
- metaPart(`${record5.name}/\u2026`, void 0, true),
32797
+ metaPart(`${record6.name}/\u2026`, void 0, true),
31738
32798
  metaPart(messages.copied)
31739
32799
  ];
31740
- const time3 = formatImportedAt(record5.importedAt);
32800
+ const time3 = formatImportedAt(record6.importedAt);
31741
32801
  if (time3) parts.push(metaPart(time3));
31742
32802
  parts.forEach((part, index) => {
31743
32803
  if (index > 0) {
@@ -31754,23 +32814,23 @@ ${detail}` : ""}`
31754
32814
  reimport.type = "button";
31755
32815
  reimport.className = "settings-account-action";
31756
32816
  reimport.textContent = messages.rowReimport;
31757
- reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record5.source.label)}`);
32817
+ reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record6.source.label)}`);
31758
32818
  reimport.disabled = busy || !source;
31759
32819
  reimport.title = messages.reimport;
31760
32820
  reimport.addEventListener("click", () => {
31761
- if (source) openDialog("reimport", { source, record: record5 }, `row:${record5.name}`);
32821
+ if (source) openDialog("reimport", { source, record: record6 }, `row:${record6.name}`);
31762
32822
  });
31763
32823
  const remove = document2.createElement("button");
31764
32824
  remove.type = "button";
31765
32825
  remove.className = "settings-account-action settings-pi-accounts__remove";
31766
32826
  remove.textContent = messages.rowRemove;
31767
- remove.setAttribute("aria-label", `${messages.remove}: ${shown(record5.source.label)}`);
32827
+ remove.setAttribute("aria-label", `${messages.remove}: ${shown(record6.source.label)}`);
31768
32828
  remove.disabled = busy;
31769
- remove.addEventListener("click", () => openDialog("remove", { record: record5 }, `row:${record5.name}`));
32829
+ remove.addEventListener("click", () => openDialog("remove", { record: record6 }, `row:${record6.name}`));
31770
32830
  if (source) actions.append(reimport);
31771
32831
  actions.append(remove);
31772
32832
  row.append(mark, identity, actions);
31773
- rows.set(record5.name, row);
32833
+ rows.set(record6.name, row);
31774
32834
  return row;
31775
32835
  };
31776
32836
  const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
@@ -31923,7 +32983,7 @@ ${detail}` : ""}`
31923
32983
  const label = document2.createElement("strong");
31924
32984
  label.textContent = shown(choice.label);
31925
32985
  label.translate = false;
31926
- const existing = importedRecords().find((record5) => record5.source.id === choice.id);
32986
+ const existing = importedRecords().find((record6) => record6.source.id === choice.id);
31927
32987
  const agent = choice.harnessId;
31928
32988
  const detail = document2.createElement("span");
31929
32989
  detail.textContent = [
@@ -31964,7 +33024,7 @@ ${detail}` : ""}`
31964
33024
  const name = request.action === "list" ? void 0 : request.name;
31965
33025
  state = {
31966
33026
  source: state.source,
31967
- record: importedRecords().find((record5) => record5.name === name) ?? state.record
33027
+ record: importedRecords().find((record6) => record6.name === name) ?? state.record
31968
33028
  };
31969
33029
  show(next);
31970
33030
  } else {
@@ -31978,12 +33038,12 @@ ${detail}` : ""}`
31978
33038
  sourceRadios = [];
31979
33039
  body.replaceChildren();
31980
33040
  controls.replaceChildren();
31981
- const { source, record: record5 } = state;
33041
+ const { source, record: record6 } = state;
31982
33042
  const close = () => modal.close();
31983
33043
  if (mode === "add" || mode === "reimport") {
31984
33044
  title.textContent = mode === "add" ? messages.add : messages.reimport;
31985
33045
  modal.setAttribute("aria-label", title.textContent);
31986
- const active = source ?? record5?.source;
33046
+ const active = source ?? record6?.source;
31987
33047
  const choices = mode === "add" && state.choose ? compatibleSources() : [];
31988
33048
  if (choices.length > 1) body.append(sourcePicker(choices));
31989
33049
  else if (active) body.append(line(messages.source, shown(active.label)));
@@ -31992,8 +33052,8 @@ ${detail}` : ""}`
31992
33052
  input.maxLength = 48;
31993
33053
  input.autocomplete = "off";
31994
33054
  input.spellcheck = false;
31995
- input.value = record5?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
31996
- input.readOnly = Boolean(record5);
33055
+ input.value = record6?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
33056
+ input.readOnly = Boolean(record6);
31997
33057
  input.addEventListener("input", () => {
31998
33058
  nameEdited = true;
31999
33059
  });
@@ -32027,7 +33087,7 @@ ${detail}` : ""}`
32027
33087
  {
32028
33088
  action: mode === "reimport" ? "reimport" : "import",
32029
33089
  sourceId: source2.id,
32030
- name: record5?.name ?? input.value,
33090
+ name: record6?.name ?? input.value,
32031
33091
  confirmed: true
32032
33092
  },
32033
33093
  "done"
@@ -32037,16 +33097,16 @@ ${detail}` : ""}`
32037
33097
  )
32038
33098
  );
32039
33099
  (mode === "add" ? input : controls.children[0]).focus();
32040
- } else if (mode === "remove" && record5) {
33100
+ } else if (mode === "remove" && record6) {
32041
33101
  title.textContent = messages.remove;
32042
33102
  modal.setAttribute("aria-label", title.textContent);
32043
- body.append(note(messages.removeWarning.replace("{name}", record5.name)));
33103
+ body.append(note(messages.removeWarning.replace("{name}", record6.name)));
32044
33104
  const cancel = command(messages.cancel, close);
32045
33105
  controls.append(
32046
33106
  cancel,
32047
33107
  command(
32048
33108
  messages.remove,
32049
- () => submit({ action: "remove", name: record5.name, confirmed: true }, null),
33109
+ () => submit({ action: "remove", name: record6.name, confirmed: true }, null),
32050
33110
  "danger"
32051
33111
  )
32052
33112
  );
@@ -32054,7 +33114,7 @@ ${detail}` : ""}`
32054
33114
  } else {
32055
33115
  title.textContent = messages.doneTitle;
32056
33116
  modal.setAttribute("aria-label", title.textContent);
32057
- const name = record5?.name;
33117
+ const name = record6?.name;
32058
33118
  if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
32059
33119
  body.append(note(messages.done));
32060
33120
  const done = command(messages.close, close, "primary");
@@ -32101,21 +33161,21 @@ ${detail}` : ""}`
32101
33161
  (candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
32102
33162
  );
32103
33163
  if (!source || !target) return null;
32104
- const record5 = target.imports.find((candidate) => candidate.source.id === source.id);
33164
+ const record6 = target.imports.find((candidate) => candidate.source.id === source.id);
32105
33165
  const key = `${harnessId}:${accountLabel}:import`;
32106
33166
  const button2 = document2.createElement("button");
32107
33167
  button2.type = "button";
32108
33168
  button2.className = "settings-account-pi-import";
32109
33169
  button2.dataset.accountFocus = key;
32110
33170
  button2.disabled = busy;
32111
- const hint = record5 ? messages.importedHint.replace("{name}", record5.name) : messages.add;
33171
+ const hint = record6 ? messages.importedHint.replace("{name}", record6.name) : messages.add;
32112
33172
  button2.title = hint;
32113
33173
  button2.setAttribute("aria-label", hint);
32114
33174
  button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
32115
- if (record5) {
33175
+ if (record6) {
32116
33176
  button2.dataset.state = "imported";
32117
33177
  const name = document2.createElement("code");
32118
- name.textContent = `${record5.name}/\u2026`;
33178
+ name.textContent = `${record6.name}/\u2026`;
32119
33179
  name.translate = false;
32120
33180
  button2.append(name, createRendererSettingsIcon("check", 12));
32121
33181
  } else {
@@ -32123,7 +33183,7 @@ ${detail}` : ""}`
32123
33183
  button2.append(messages.add);
32124
33184
  }
32125
33185
  button2.addEventListener("click", () => {
32126
- if (!record5) {
33186
+ if (!record6) {
32127
33187
  openDialog("add", { source }, key);
32128
33188
  return;
32129
33189
  }
@@ -32132,7 +33192,7 @@ ${detail}` : ""}`
32132
33192
  renderSection();
32133
33193
  sectionToggle.setAttribute("aria-expanded", "true");
32134
33194
  }
32135
- const row = rows.get(record5.name);
33195
+ const row = rows.get(record6.name);
32136
33196
  row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
32137
33197
  row?.focus();
32138
33198
  });
@@ -33677,7 +34737,7 @@ ${detail}` : ""}`
33677
34737
  }
33678
34738
  });
33679
34739
  }
33680
- function createDefaultRendererSettingsPages(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread = () => Promise.reject(new Error("Imported Thread navigation is unavailable")), getLoadedSessionsClient = () => null, getRemoteConnections = () => null, requestUsageStatistics = () => Promise.reject(new Error("Local Host connection is unavailable"))) {
34740
+ function createDefaultRendererSettingsPages(messages = DEFAULT_RENDERER_SETTINGS_MESSAGES, getUpdateClient = () => null, getDiagnostics = () => null, getAccountClient = () => null, getSessionImportClient = () => null, openImportedThread = () => Promise.reject(new Error("Imported Thread navigation is unavailable")), getLoadedSessionsClient = () => null, getRemoteConnections = () => null, requestUsageStatistics = () => Promise.reject(new Error("Local Host connection is unavailable")), requestVoiceSettings = () => Promise.reject(new Error("Local Host connection is unavailable"))) {
33681
34741
  return Object.freeze([
33682
34742
  createConnectionsSettingsPage(messages, getDiagnostics, void 0, getRemoteConnections),
33683
34743
  createRemoteConnectionsPage(messages, getRemoteConnections),
@@ -33694,6 +34754,7 @@ ${detail}` : ""}`
33694
34754
  messages.locale
33695
34755
  ),
33696
34756
  createAppearanceSettingsPage(messages, getLoadedSessionsClient),
34757
+ createVoiceSettingsPage(messages.locale, requestVoiceSettings, { desktop: true }),
33697
34758
  updatesPage(messages, getUpdateClient),
33698
34759
  aboutPage(messages, getUpdateClient)
33699
34760
  ]);
@@ -36251,6 +37312,97 @@ ${detail}` : ""}`
36251
37312
  animation: none !important;
36252
37313
  }
36253
37314
  }
37315
+ .settings-voice__select {
37316
+ flex: none;
37317
+ width: 190px;
37318
+ max-width: 100%;
37319
+ min-height: 34px;
37320
+ padding: 6px 10px;
37321
+ border: 1px solid var(--settings-border);
37322
+ border-radius: 6px;
37323
+ color: var(--settings-text);
37324
+ background: var(--settings-panel);
37325
+ font: inherit;
37326
+ font-size: 13px;
37327
+ }
37328
+
37329
+ .settings-voice :disabled {
37330
+ opacity: 0.45;
37331
+ cursor: not-allowed;
37332
+ }
37333
+ .settings-voice__footer {
37334
+ display: flex;
37335
+ align-items: center;
37336
+ justify-content: space-between;
37337
+ flex-wrap: wrap;
37338
+ gap: 16px;
37339
+ margin-top: 28px;
37340
+ padding-top: 18px;
37341
+ border-top: 1px solid var(--settings-divider);
37342
+ font-size: 13px;
37343
+ }
37344
+ .settings-voice__footer p,
37345
+ .settings-voice__hint {
37346
+ margin: 4px 0 0;
37347
+ color: var(--settings-muted);
37348
+ font-size: 12px;
37349
+ line-height: 18px;
37350
+ }
37351
+ .settings-voice__actions,
37352
+ .settings-voice__gateway-actions {
37353
+ display: flex;
37354
+ align-items: center;
37355
+ flex-wrap: wrap;
37356
+ gap: 12px;
37357
+ }
37358
+ .settings-voice__gateway-actions {
37359
+ color: var(--settings-muted);
37360
+ font-size: 12px;
37361
+ }
37362
+ .settings-voice__details {
37363
+ padding: 12px 16px;
37364
+ border-top: 1px solid var(--settings-divider);
37365
+ color: var(--settings-muted);
37366
+ font-size: 12px;
37367
+ line-height: 18px;
37368
+ overflow-wrap: anywhere;
37369
+ }
37370
+ .settings-voice__confirmation {
37371
+ margin-top: 12px;
37372
+ font-size: 13px;
37373
+ line-height: 20px;
37374
+ }
37375
+ .settings-voice__confirmation button + button {
37376
+ margin-left: 8px;
37377
+ }
37378
+ .settings-voice [role="alert"] {
37379
+ color: var(--settings-danger);
37380
+ font-size: 13px;
37381
+ overflow-wrap: anywhere;
37382
+ }
37383
+ .settings-voice {
37384
+ container-type: inline-size;
37385
+ }
37386
+ @container (max-width: 620px) {
37387
+ .settings-voice__row {
37388
+ align-items: stretch;
37389
+ flex-direction: column;
37390
+ gap: 10px;
37391
+ }
37392
+ .settings-voice__select {
37393
+ width: 100%;
37394
+ }
37395
+ .settings-voice__row input[role="switch"] {
37396
+ align-self: flex-start;
37397
+ }
37398
+ .settings-voice__footer {
37399
+ align-items: stretch;
37400
+ flex-direction: column;
37401
+ }
37402
+ .settings-voice__actions > button {
37403
+ flex: 1;
37404
+ }
37405
+ }
36254
37406
  `;
36255
37407
 
36256
37408
  // src/settings/accounts.css
@@ -37142,6 +38294,17 @@ ${detail}` : ""}`
37142
38294
  gap: 8px;
37143
38295
  }
37144
38296
 
38297
+ .console-restart {
38298
+ width: 100%;
38299
+ min-width: 0;
38300
+ }
38301
+
38302
+ .console-restart > p {
38303
+ flex-basis: 100%;
38304
+ margin: 0;
38305
+ overflow-wrap: anywhere;
38306
+ }
38307
+
37145
38308
  .console-muted {
37146
38309
  margin: 0;
37147
38310
  color: var(--settings-muted);
@@ -38299,7 +39462,7 @@ th[aria-sort] .console-usage-sort__mark {
38299
39462
  `;
38300
39463
 
38301
39464
  // src/settings/tailwind.css
38302
- var tailwind_default = '@layer properties, theme, base, components, utilities;\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.top-full{top:100%}.left-0{left:0}.z-20{z-index:20}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-1{margin-left:var(--spacing)}.ml-\\[45px\\]{margin-left:45px}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-8{height:calc(var(--spacing) * 8)}.min-h-6{min-height:calc(var(--spacing) * 6)}.min-h-\\[60px\\]{min-height:60px}.w-9{width:calc(var(--spacing) * 9)}.w-14{width:calc(var(--spacing) * 14)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.w-px{width:1px}.max-w-64{max-width:calc(var(--spacing) * 64)}.min-w-0{min-width:0}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.overflow-x-auto{overflow-x:auto}.rounded-\\[10px\\]{border-radius:10px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-settings-border{border-color:var(--settings-border)}.border-settings-divider{border-color:var(--settings-divider)}.bg-settings-panel{background-color:var(--settings-panel)}.bg-settings-subtle{background-color:var(--settings-subtle)}.bg-settings-surface{background-color:var(--settings-surface)}.bg-settings-surface-hover{background-color:var(--settings-surface-hover)}.bg-transparent{background-color:#0000}.p-0{padding:0}.p-4{padding:calc(var(--spacing) * 4)}.\\!px-0{padding-inline:0!important}.px-1{padding-inline:var(--spacing)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pl-4{padding-left:calc(var(--spacing) * 4)}.\\!text-right{text-align:right!important}.text-left{text-align:left}.text-right{text-align:right}.align-top{vertical-align:top}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[11px\\]{font-size:11px}.text-\\[13px\\]{font-size:13px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-\\[18px\\]{--tw-leading:18px;line-height:18px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.text-wrap{text-wrap:wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-settings-muted{color:var(--settings-muted)}.text-settings-subtle{color:var(--settings-subtle)}.text-settings-text{color:var(--settings-text)}.text-settings-warning{color:var(--settings-warning)}.lowercase{text-transform:lowercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\\[0_10px_30px_rgb\\(0_0_0\\/0\\.22\\)\\]{--tw-shadow:0 10px 30px var(--tw-shadow-color,#00000038);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-settings-border{--tw-ring-color:var(--settings-border)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.outline-none{--tw-outline-style:none;outline-style:none}.ring-inset{--tw-ring-inset:inset}.group-focus-within\\:visible:is(:where(.group):focus-within *){visibility:visible}.group-focus-within\\:opacity-100:is(:where(.group):focus-within *){opacity:1}@media (hover:hover){.group-hover\\:visible:is(:where(.group):hover *){visibility:visible}.group-hover\\:opacity-100:is(:where(.group):hover *){opacity:1}}.group-data-\\[state\\=failed\\]\\/status\\:bg-settings-danger:is(:where(.group\\/status)[data-state=failed] *){background-color:var(--settings-danger)}.group-data-\\[state\\=unavailable\\]\\/status\\:bg-settings-warning:is(:where(.group\\/status)[data-state=unavailable] *){background-color:var(--settings-warning)}.marker\\:text-settings-subtle ::marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle::marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle ::-webkit-details-marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle::-webkit-details-marker{color:var(--settings-subtle)}.before\\:absolute:before{content:var(--tw-content);position:absolute}.before\\:top-0\\.5:before{content:var(--tw-content);top:calc(var(--spacing) * .5)}.before\\:left-0\\.5:before{content:var(--tw-content);left:calc(var(--spacing) * .5)}.before\\:size-4:before{content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.before\\:rounded-full:before{content:var(--tw-content);border-radius:3.40282e38px}.before\\:bg-white:before{content:var(--tw-content);background-color:#fff}.before\\:shadow-\\[0_1px_2px_rgb\\(0_0_0\\/0\\.3\\)\\]:before{content:var(--tw-content);--tw-shadow:0 1px 2px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.before\\:transition-transform:before{content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.first\\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}.first-of-type\\:mt-0:first-of-type{margin-top:0}.checked\\:bg-settings-focus:checked{background-color:var(--settings-focus)}.checked\\:ring-transparent:checked{--tw-ring-color:transparent}.checked\\:before\\:translate-x-4:checked:before{content:var(--tw-content);--tw-translate-x:calc(var(--spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.focus-within\\:border-settings-focus:focus-within{border-color:var(--settings-focus)}@media (hover:hover){.hover\\:text-settings-text:hover{color:var(--settings-text)}}.focus-visible\\:text-settings-text:focus-visible{color:var(--settings-text)}.focus-visible\\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\\:outline-settings-focus:focus-visible{outline-color:var(--settings-focus)}.data-\\[invalid\\=true\\]\\:border-settings-danger[data-invalid=true]{border-color:var(--settings-danger)}.data-\\[invalid\\=true\\]\\:text-settings-danger[data-invalid=true],.data-\\[state\\=failed\\]\\:text-settings-danger[data-state=failed]{color:var(--settings-danger)}.data-\\[state\\=unavailable\\]\\:text-settings-warning[data-state=unavailable]{color:var(--settings-warning)}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@layer properties{\n *, ::before, ::after, ::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-alpha:100%;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-offset-width:0;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-drop-shadow-alpha:100%;--tw-content:"";--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}\n';
39465
+ var tailwind_default = '@layer properties, theme, base, components, utilities;\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.top-full{top:100%}.left-0{left:0}.z-20{z-index:20}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-1{margin-left:var(--spacing)}.ml-\\[45px\\]{margin-left:45px}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-8{height:calc(var(--spacing) * 8)}.min-h-6{min-height:calc(var(--spacing) * 6)}.min-h-\\[60px\\]{min-height:60px}.w-9{width:calc(var(--spacing) * 9)}.w-14{width:calc(var(--spacing) * 14)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.w-px{width:1px}.max-w-64{max-width:calc(var(--spacing) * 64)}.min-w-0{min-width:0}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-disc{list-style-type:disc}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.overflow-x-auto{overflow-x:auto}.rounded-\\[10px\\]{border-radius:10px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-settings-border{border-color:var(--settings-border)}.border-settings-divider{border-color:var(--settings-divider)}.bg-settings-panel{background-color:var(--settings-panel)}.bg-settings-subtle{background-color:var(--settings-subtle)}.bg-settings-surface{background-color:var(--settings-surface)}.bg-settings-surface-hover{background-color:var(--settings-surface-hover)}.bg-transparent{background-color:#0000}.p-0{padding:0}.p-4{padding:calc(var(--spacing) * 4)}.\\!px-0{padding-inline:0!important}.px-1{padding-inline:var(--spacing)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pl-4{padding-left:calc(var(--spacing) * 4)}.\\!text-right{text-align:right!important}.text-left{text-align:left}.text-right{text-align:right}.align-top{vertical-align:top}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[11px\\]{font-size:11px}.text-\\[13px\\]{font-size:13px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-\\[18px\\]{--tw-leading:18px;line-height:18px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.text-wrap{text-wrap:wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-settings-muted{color:var(--settings-muted)}.text-settings-subtle{color:var(--settings-subtle)}.text-settings-text{color:var(--settings-text)}.lowercase{text-transform:lowercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\\[0_10px_30px_rgb\\(0_0_0\\/0\\.22\\)\\]{--tw-shadow:0 10px 30px var(--tw-shadow-color,#00000038);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-settings-border{--tw-ring-color:var(--settings-border)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.outline-none{--tw-outline-style:none;outline-style:none}.ring-inset{--tw-ring-inset:inset}.group-focus-within\\:visible:is(:where(.group):focus-within *){visibility:visible}.group-focus-within\\:opacity-100:is(:where(.group):focus-within *){opacity:1}@media (hover:hover){.group-hover\\:visible:is(:where(.group):hover *){visibility:visible}.group-hover\\:opacity-100:is(:where(.group):hover *){opacity:1}}.group-data-\\[state\\=failed\\]\\/status\\:bg-settings-danger:is(:where(.group\\/status)[data-state=failed] *){background-color:var(--settings-danger)}.group-data-\\[state\\=unavailable\\]\\/status\\:bg-settings-warning:is(:where(.group\\/status)[data-state=unavailable] *){background-color:var(--settings-warning)}.marker\\:text-settings-subtle ::marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle::marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle ::-webkit-details-marker{color:var(--settings-subtle)}.marker\\:text-settings-subtle::-webkit-details-marker{color:var(--settings-subtle)}.before\\:absolute:before{content:var(--tw-content);position:absolute}.before\\:top-0\\.5:before{content:var(--tw-content);top:calc(var(--spacing) * .5)}.before\\:left-0\\.5:before{content:var(--tw-content);left:calc(var(--spacing) * .5)}.before\\:size-4:before{content:var(--tw-content);width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.before\\:rounded-full:before{content:var(--tw-content);border-radius:3.40282e38px}.before\\:bg-white:before{content:var(--tw-content);background-color:#fff}.before\\:shadow-\\[0_1px_2px_rgb\\(0_0_0\\/0\\.3\\)\\]:before{content:var(--tw-content);--tw-shadow:0 1px 2px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.before\\:transition-transform:before{content:var(--tw-content);transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.first\\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}.first-of-type\\:mt-0:first-of-type{margin-top:0}.checked\\:bg-settings-focus:checked{background-color:var(--settings-focus)}.checked\\:ring-transparent:checked{--tw-ring-color:transparent}.checked\\:before\\:translate-x-4:checked:before{content:var(--tw-content);--tw-translate-x:calc(var(--spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.focus-within\\:border-settings-focus:focus-within{border-color:var(--settings-focus)}@media (hover:hover){.hover\\:text-settings-text:hover{color:var(--settings-text)}}.focus-visible\\:text-settings-text:focus-visible{color:var(--settings-text)}.focus-visible\\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\\:outline-settings-focus:focus-visible{outline-color:var(--settings-focus)}.data-\\[invalid\\=true\\]\\:border-settings-danger[data-invalid=true]{border-color:var(--settings-danger)}.data-\\[invalid\\=true\\]\\:text-settings-danger[data-invalid=true],.data-\\[state\\=failed\\]\\:text-settings-danger[data-state=failed]{color:var(--settings-danger)}.data-\\[state\\=unavailable\\]\\:text-settings-warning[data-state=unavailable]{color:var(--settings-warning)}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@layer properties{\n *, ::before, ::after, ::backdrop{--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-alpha:100%;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-offset-width:0;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-drop-shadow-alpha:100%;--tw-content:"";--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}\n';
38303
39466
 
38304
39467
  // src/settings/trigger.ts
38305
39468
  var SETTINGS_TRIGGER_ATTRIBUTE = "data-codexhost-settings-trigger";
@@ -38544,7 +39707,7 @@ th[aria-sort] .console-usage-sort__mark {
38544
39707
  place();
38545
39708
  const observer = ownerWindow ? new ownerWindow.MutationObserver((records) => {
38546
39709
  const titlebar = source?.closest("[data-app-shell-titlebar]");
38547
- if (!source?.isConnected || records.some((record5) => titlebar?.contains(record5.target))) {
39710
+ if (!source?.isConnected || records.some((record6) => titlebar?.contains(record6.target))) {
38548
39711
  place();
38549
39712
  }
38550
39713
  }) : null;
@@ -38978,7 +40141,8 @@ ${usage_default}`;
38978
40141
  },
38979
40142
  options.getLoadedSessionsClient ?? (() => null),
38980
40143
  options.getRemoteConnections ?? (() => null),
38981
- options.requestUsageStatistics
40144
+ options.requestUsageStatistics,
40145
+ options.requestVoiceSettings
38982
40146
  );
38983
40147
  const nextShell = installRendererSettingsShell(definitions, messages, ownerWindow.document, {
38984
40148
  onOpenChange(open) {
@@ -40055,7 +41219,14 @@ ${usage_default}`;
40055
41219
  });
40056
41220
  let connectionDiagnostics = null;
40057
41221
  const remoteConnections = createRemoteConnectionsControl(window, modelClientForHost);
41222
+ const requestLocalSettings = async (method, params) => {
41223
+ const route = window.__codexhostHostRoutingV1?.forHost("local");
41224
+ if (disposed || !route) throw new Error("Local Host connection is unavailable");
41225
+ return route.manager.sendRequest(method, params);
41226
+ };
41227
+ const stopVoiceSync = startVoiceSettingsSync(window, requestLocalSettings);
40058
41228
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
41229
+ requestVoiceSettings: (params) => requestLocalSettings("codexhost/voice/settings", params),
40059
41230
  getRemoteConnections: () => remoteConnections,
40060
41231
  getUpdateClient: () => modelControl,
40061
41232
  getAccountClient: () => modelControl,
@@ -42101,6 +43272,7 @@ ${usage_default}`;
42101
43272
  disposeReasoningSoftWrap();
42102
43273
  delegationMention?.dispose();
42103
43274
  sidebarAgentIcons.dispose();
43275
+ stopVoiceSync();
42104
43276
  settingsLifecycle.dispose();
42105
43277
  document.removeEventListener("beforeinput", onBeforeInput, true);
42106
43278
  document.removeEventListener("submit", onSubmit, true);
@@ -42161,14 +43333,16 @@ ${usage_default}`;
42161
43333
  }
42162
43334
 
42163
43335
  // src/renderer-external-voice-launch.ts
42164
- var HOOK_GLOBAL2 = "__codexhostExternalVoiceLaunchV1";
43336
+ var HOOK_GLOBAL3 = "__codexhostExternalVoiceLaunchV1";
42165
43337
  var SHARED_ASSET = "app-shared-8bd9d0399038.js";
42166
43338
  function isRecord16(value) {
42167
43339
  return typeof value === "object" && value !== null && !Array.isArray(value);
42168
43340
  }
42169
43341
  function routeExternalVoiceLaunch(request, routing) {
43342
+ rememberVoiceProductExperience(request);
42170
43343
  if (!routing || !isRecord16(request) || request.source !== "composer_button_new_thread")
42171
43344
  return request;
43345
+ if (request.productExperience === "chat") return request;
42172
43346
  const hostId2 = request.hostId ?? "local";
42173
43347
  if (typeof hostId2 !== "string" || !hostId2) return request;
42174
43348
  const route = routing.forComposer();
@@ -42194,7 +43368,7 @@ ${usage_default}`;
42194
43368
  }
42195
43369
  function installExternalVoiceLaunchHook(options = {}) {
42196
43370
  const target = options.target ?? globalThis;
42197
- const existing = target[HOOK_GLOBAL2];
43371
+ const existing = target[HOOK_GLOBAL3];
42198
43372
  if (existing) return existing;
42199
43373
  const config2 = readCpaLiveVoiceHookConfig(target);
42200
43374
  if (!config2) return { status: "disabled", dispose() {
@@ -42214,10 +43388,10 @@ ${usage_default}`;
42214
43388
  disposed = true;
42215
43389
  if (timer !== void 0) target.clearTimeout(timer);
42216
43390
  restore?.();
42217
- if (target[HOOK_GLOBAL2] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL2);
43391
+ if (target[HOOK_GLOBAL3] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL3);
42218
43392
  }
42219
43393
  };
42220
- target[HOOK_GLOBAL2] = handle;
43394
+ target[HOOK_GLOBAL3] = handle;
42221
43395
  const attempt = async () => {
42222
43396
  if (disposed) return;
42223
43397
  try {
@@ -42240,6 +43414,8 @@ ${usage_default}`;
42240
43414
  }
42241
43415
  const launch = (...args) => {
42242
43416
  let request = args[0];
43417
+ const chatStart = startNativeChatVoiceForRequest(request, target);
43418
+ if (chatStart) return chatStart;
42243
43419
  try {
42244
43420
  request = routeExternalVoiceLaunch(request, target.__codexhostHostRoutingV1);
42245
43421
  } catch {
@@ -42282,6 +43458,7 @@ ${usage_default}`;
42282
43458
  installCpaLiveVoiceHook();
42283
43459
  installClientOwnedVoiceHook();
42284
43460
  installExternalVoiceLaunchHook();
43461
+ installNativeChatVoiceHook();
42285
43462
  var installBinding = () => {
42286
43463
  installRendererBinding();
42287
43464
  };