@karlorz/codexhost-cli-darwin-x64 0.13.3-4 → 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,396 +6,103 @@
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;
24
- }
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
- }
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;
53
- }
54
- return {
55
- enabled: true,
56
- auditedDesktopVersion: value.auditedDesktopVersion,
57
- auditedAppInitialAsset: value.auditedAppInitialAsset,
58
- ...typeof value.desktopVersion === "string" ? { desktopVersion: value.desktopVersion } : {}
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 [];
59
21
  };
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;
68
- }
69
- });
70
- }
71
- function resourceNamesFromPerformance() {
72
- if (typeof performance === "undefined" || typeof performance.getEntriesByType !== "function") {
22
+ const first = fiber(value);
23
+ if (!first)
73
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);
74
34
  }
75
- return performance.getEntriesByType("resource").map((entry) => entry.name).filter((name) => typeof name === "string");
76
- }
77
- function resourceNamesFromDocument(root) {
78
- const names = resourceNamesFromPerformance();
79
- if (!root || !("querySelectorAll" in root)) return names;
80
- for (const element of root.querySelectorAll("script[src], link[href]")) {
81
- const value = element.getAttribute("src") ?? element.getAttribute("href");
82
- if (value) names.push(value);
83
- }
84
- return names;
85
- }
86
- function statsigClients(globalObject) {
87
- const registry2 = globalObject.__STATSIG__;
88
- if (!isRecord(registry2)) return [];
89
- const clients = new Set(
90
- isRecord(registry2.instances) ? Object.values(registry2.instances) : []
91
- );
92
- if (registry2.firstInstance) clients.add(registry2.firstInstance);
93
- return [...clients].filter(
94
- (client) => isRecord(client) && typeof client.checkGate === "function"
95
- );
96
- }
97
- function wrapCheckGate(client) {
98
- if (originalCheckGate.has(client)) return false;
99
- const original = client.checkGate;
100
- originalCheckGate.set(client, original);
101
- client.checkGate = function(name, ...rest) {
102
- return name === THREAD_REALTIME_EXISTING_CALL_GATE ? false : original.call(this, name, ...rest);
103
- };
104
- return true;
105
- }
106
- function restoreCheckGate(client) {
107
- const original = originalCheckGate.get(client);
108
- if (!original) return;
109
- client.checkGate = original;
110
- originalCheckGate.delete(client);
111
- }
112
- function configAllowsInstall(config2, resourceNames) {
113
- if (config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion) {
114
- return false;
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);
115
61
  }
116
- if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION) return false;
117
- if (config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET) return false;
118
- return auditedAppInitialAssetPresent(resourceNames, config2.auditedAppInitialAsset);
119
- }
120
- function installCpaLiveVoiceHook(options = {}) {
121
- const globalObject = options.globalThis ?? globalThis;
122
- const config2 = options.config === void 0 ? readCpaLiveVoiceHookConfig(globalObject) : options.config;
123
- if (!config2?.enabled || !cpaLiveVoicePreferenceAllowsInstall(globalObject)) {
124
- return { status: "disabled", dispose() {
125
- } };
62
+ if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
63
+ return path.reverse();
126
64
  }
127
- const root = options.document ?? globalObject.document;
128
- const wrapped = [];
129
- let disposed = false;
130
- let auditedAssetFound = false;
131
- const handle = {
132
- status: "pending",
133
- dispose() {
134
- disposed = true;
135
- for (const client of wrapped) restoreCheckGate(client);
136
- wrapped.length = 0;
137
- }
138
- };
139
- const attempt = () => {
140
- if (!auditedAssetFound) {
141
- const resourceNames = options.resourceNames ?? resourceNamesFromDocument(root);
142
- auditedAssetFound = configAllowsInstall(config2, resourceNames);
143
- if (!auditedAssetFound) return false;
144
- }
145
- for (const client of statsigClients(globalObject)) {
146
- if (wrapCheckGate(client)) wrapped.push(client);
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;
147
79
  }
148
- if (wrapped.length === 0) return false;
149
- handle.status = "active";
150
- return true;
151
- };
152
- if (attempt()) return handle;
153
- if (options.resourceNames && !configAllowsInstall(config2, options.resourceNames)) {
154
- handle.status = "unsupported";
155
- return handle;
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 });
156
86
  }
157
- const started = Date.now();
158
- const tick = () => {
159
- if (disposed || attempt()) return;
160
- if (Date.now() - started > DISCOVERY_TIMEOUT_MS) {
161
- handle.status = "unsupported";
162
- return;
163
- }
164
- globalThis.setTimeout(tick, 250);
165
- };
166
- globalThis.setTimeout(tick, 250);
167
- return handle;
87
+ return stack.length > 0 ? exhausted() : [];
168
88
  }
169
89
 
170
- // src/agent-selection-state.ts
171
- var DEFAULT_RENDERER_AGENTS = ["codex"];
172
- function defaultIdFactory(sequence) {
173
- return `codexhost-composer-${Date.now().toString(36)}-${sequence.toString(36)}`;
174
- }
175
- function isDefaultTarget(target) {
176
- return target?.[0] === "default";
177
- }
178
- function isConversationTarget(target) {
179
- return target?.[0] === "conversation";
180
- }
181
- function isIdentifiedTarget(target) {
182
- return target?.[0] === "conversation" || target?.[0] === "default" && typeof target[1] === "string" && target[1].startsWith("client-new-thread:");
183
- }
184
- function sameTarget(left, right) {
185
- return left.length === right.length && left.every((value, index) => value === right[index]);
186
- }
187
- var DraftAgentController = class {
188
- #idFactory;
189
- #defaultAgent;
190
- #enabledAgents;
191
- #targetStates = [];
192
- #modelRequestGenerations = /* @__PURE__ */ new WeakMap();
193
- #ownershipRequestGenerations = /* @__PURE__ */ new WeakMap();
194
- #states = /* @__PURE__ */ new WeakMap();
195
- #switching = /* @__PURE__ */ new Set();
196
- #pendingSubmissions = /* @__PURE__ */ new Set();
197
- #composerSequence = 0;
198
- #modelRequestSequence = 0;
199
- #ownershipRequestSequence = 0;
200
- #lastSubmittedAgent;
201
- constructor(options = {}) {
202
- this.#idFactory = options.idFactory ?? defaultIdFactory;
203
- this.#enabledAgents = new Set(options.enabledAgents ?? DEFAULT_RENDERER_AGENTS);
204
- if (!this.#enabledAgents.has("codex"))
205
- throw new Error("Renderer enabled Agents must include Codex");
206
- this.#defaultAgent = options.defaultAgent ?? "codex";
207
- this.#lastSubmittedAgent = this.#defaultAgent;
208
- }
209
- setEnabledAgents(agents) {
210
- this.#enabledAgents = /* @__PURE__ */ new Set(["codex", ...agents]);
211
- }
212
- get(composer) {
213
- return this.#state(composer);
214
- }
215
- detach(composer, preservePendingSubmission = false) {
216
- const state = this.#states.get(composer);
217
- if (state && !preservePendingSubmission) this.#pendingSubmissions.delete(state);
218
- this.#states.delete(composer);
219
- }
220
- mount(composer, target, preferredNewThreadAgent) {
221
- const bound = this.#targetState(target);
222
- if (bound) {
223
- this.#states.set(composer, bound);
224
- return bound;
225
- }
226
- const preferredAgent = preferredNewThreadAgent ?? this.#lastSubmittedAgent;
227
- const state = this.#state(composer, isDefaultTarget(target) ? preferredAgent : "codex");
228
- if (isIdentifiedTarget(target)) this.#targetStates.push({ target, state });
229
- return state;
230
- }
231
- isSwitching(composer) {
232
- return this.#switching.has(this.#state(composer));
233
- }
234
- beginModelRequest(composer) {
235
- const state = this.#state(composer);
236
- const generation = ++this.#modelRequestSequence;
237
- this.#modelRequestGenerations.set(state, generation);
238
- return generation;
239
- }
240
- invalidateModelRequests(composer) {
241
- this.beginModelRequest(composer);
242
- }
243
- isCurrentModelRequest(composer, generation) {
244
- return (this.#modelRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
245
- }
246
- beginOwnershipRequest(composer) {
247
- const generation = ++this.#ownershipRequestSequence;
248
- this.#ownershipRequestGenerations.set(this.#state(composer), generation);
249
- return generation;
250
- }
251
- isCurrentOwnershipRequest(composer, generation) {
252
- return (this.#ownershipRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
253
- }
254
- rebindConversation(composer, target) {
255
- if (!isConversationTarget(target)) return null;
256
- const previous = this.#state(composer);
257
- this.#pendingSubmissions.delete(previous);
258
- this.#modelRequestGenerations.set(previous, ++this.#modelRequestSequence);
259
- this.#ownershipRequestGenerations.set(previous, ++this.#ownershipRequestSequence);
260
- let state = this.#targetState(target);
261
- if (!state) {
262
- state = {
263
- agent: "codex",
264
- phase: "draft",
265
- composerId: this.#idFactory(++this.#composerSequence)
266
- };
267
- this.#targetStates.push({ target, state });
268
- }
269
- this.#states.set(composer, state);
270
- this.#modelRequestGenerations.set(state, ++this.#modelRequestSequence);
271
- this.#ownershipRequestGenerations.set(state, ++this.#ownershipRequestSequence);
272
- return state;
273
- }
274
- restore(composer, agent, model2, thinkingOptionId, permissionModeId) {
275
- const state = this.#state(composer);
276
- this.#pendingSubmissions.delete(state);
277
- state.agent = agent;
278
- state.phase = "locked";
279
- if (agent !== "codex") {
280
- state.configurationByAgent = {
281
- ...state.configurationByAgent,
282
- [agent]: {
283
- ...model2 ? { model: model2 } : {},
284
- ...thinkingOptionId ? { thinkingOptionId } : {},
285
- ...permissionModeId ? { permissionModeId } : {}
286
- }
287
- };
288
- }
289
- return state;
290
- }
291
- clearConfiguration(composer) {
292
- delete this.#state(composer).configurationByAgent;
293
- }
294
- modelForAgent(composer, agent) {
295
- return this.#state(composer).configurationByAgent?.[agent]?.model;
296
- }
297
- thinkingOptionForAgent(composer, agent) {
298
- return this.#state(composer).configurationByAgent?.[agent]?.thinkingOptionId;
299
- }
300
- permissionModeForAgent(composer, agent) {
301
- return this.#state(composer).configurationByAgent?.[agent]?.permissionModeId;
302
- }
303
- setExternalPermissionMode(composer, agent, permissionModeId) {
304
- return this.#configure(composer, agent, { permissionModeId });
305
- }
306
- setExternalModel(composer, agent, model2) {
307
- return this.#configure(composer, agent, { model: model2 });
308
- }
309
- setExternalThinkingOption(composer, agent, thinkingOptionId) {
310
- const state = this.#configure(composer, agent, {});
311
- const configuration = state.configurationByAgent?.[agent];
312
- if (!configuration) return state;
313
- if (thinkingOptionId) configuration.thinkingOptionId = thinkingOptionId;
314
- else delete configuration.thinkingOptionId;
315
- return state;
316
- }
317
- #configure(composer, agent, patch) {
318
- const state = this.#state(composer);
319
- state.configurationByAgent = {
320
- ...state.configurationByAgent,
321
- [agent]: { ...state.configurationByAgent?.[agent], ...patch }
322
- };
323
- return state;
324
- }
325
- lock(composer) {
326
- const state = this.#state(composer);
327
- this.#pendingSubmissions.delete(state);
328
- state.phase = "locked";
329
- return state;
330
- }
331
- markSubmissionPending(composer) {
332
- const state = this.#state(composer);
333
- if (state.phase === "draft") this.#pendingSubmissions.add(state);
334
- return state;
335
- }
336
- isSubmissionPending(composer) {
337
- return this.#pendingSubmissions.has(this.#state(composer));
338
- }
339
- clearPendingSubmission(composer) {
340
- this.#pendingSubmissions.delete(this.#state(composer));
341
- }
342
- recordSubmission(composer) {
343
- const state = this.#state(composer);
344
- this.#lastSubmittedAgent = state.agent;
345
- return state;
346
- }
347
- transfer(source, replacement, target = null) {
348
- const state = this.#states.get(source);
349
- if (!state) return false;
350
- const bound = this.#targetState(target);
351
- if (bound && bound !== state) return false;
352
- if (source !== replacement) {
353
- if (this.#states.has(replacement)) return false;
354
- this.#states.set(replacement, state);
355
- }
356
- if (isIdentifiedTarget(target) && !bound) this.#targetStates.push({ target, state });
357
- if (isConversationTarget(target) && this.#pendingSubmissions.delete(state))
358
- state.phase = "locked";
359
- return true;
360
- }
361
- async switchAgent(composer, nextAgent, operations) {
362
- const state = this.#state(composer);
363
- if (!this.#enabledAgents.has(nextAgent)) return false;
364
- if (state.phase !== "draft" || this.#switching.has(state)) return false;
365
- if (state.agent === nextAgent) return true;
366
- this.#pendingSubmissions.delete(state);
367
- this.#switching.add(state);
368
- try {
369
- if (!operations.applyAgent(nextAgent)) return false;
370
- try {
371
- await operations.clearPrewarm();
372
- } catch (error51) {
373
- if (!operations.applyAgent(state.agent))
374
- throw new Error("Draft Agent switch could not restore the prior Agent", { cause: error51 });
375
- return false;
376
- }
377
- state.agent = nextAgent;
378
- return true;
379
- } finally {
380
- this.#switching.delete(state);
381
- }
382
- }
383
- #targetState(target) {
384
- if (!isIdentifiedTarget(target)) return null;
385
- return this.#targetStates.find((candidate) => sameTarget(candidate.target, target))?.state ?? null;
386
- }
387
- #state(composer, initialAgent) {
388
- const existing = this.#states.get(composer);
389
- if (existing) return existing;
390
- const created = {
391
- agent: initialAgent ?? this.#defaultAgent,
392
- phase: "draft",
393
- composerId: this.#idFactory(++this.#composerSequence)
394
- };
395
- this.#states.set(composer, created);
396
- return created;
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 {
397
103
  }
398
- };
104
+ owner.console?.info?.("[codexhost-chat-voice]", event, detail);
105
+ }
399
106
 
400
107
  // ../../node_modules/zod/v4/classic/external.js
401
108
  var external_exports = {};
@@ -1119,9 +826,9 @@
1119
826
  return ratio - roundedRatio;
1120
827
  }
1121
828
  var EVALUATING = /* @__PURE__ */ Symbol("evaluating");
1122
- function defineLazy(object2, key, getter) {
829
+ function defineLazy(object3, key, getter) {
1123
830
  let value = void 0;
1124
- Object.defineProperty(object2, key, {
831
+ Object.defineProperty(object3, key, {
1125
832
  get() {
1126
833
  if (value === EVALUATING) {
1127
834
  return void 0;
@@ -1133,7 +840,7 @@
1133
840
  return value;
1134
841
  },
1135
842
  set(v) {
1136
- Object.defineProperty(object2, key, {
843
+ Object.defineProperty(object3, key, {
1137
844
  value: v
1138
845
  // configurable: true,
1139
846
  });
@@ -15210,6 +14917,55 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15210
14917
  var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
15211
14918
  var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
15212
14919
 
14920
+ // ../shared-contracts/dist/realtime-call.js
14921
+ var REALTIME_CALL_METHOD = "codexhost/realtime/call";
14922
+ var REALTIME_CALL_FORWARDED_HEADERS = [
14923
+ "openai-alpha",
14924
+ "thread-id",
14925
+ "session-id",
14926
+ "originator",
14927
+ "x-codex-turn-metadata"
14928
+ ];
14929
+ var FORWARDED_HEADERS = new Set(REALTIME_CALL_FORWARDED_HEADERS);
14930
+ function filterRealtimeCallHeaders(headers) {
14931
+ const result = {};
14932
+ for (const [name, value] of Object.entries(headers ?? {})) {
14933
+ const key = name.toLowerCase();
14934
+ if (FORWARDED_HEADERS.has(key) && value.length > 0 && value.length <= 4096)
14935
+ result[key] = value;
14936
+ }
14937
+ return result;
14938
+ }
14939
+ var REALTIME_CALL_ID_PATTERN = /^rtc_[A-Za-z0-9_-]{1,128}$/u;
14940
+ function isRealtimeCallId(value) {
14941
+ return typeof value === "string" && REALTIME_CALL_ID_PATTERN.test(value);
14942
+ }
14943
+ function realtimeCallIdFromLocation(location) {
14944
+ const path = location.split(/[?#]/u)[0] ?? "";
14945
+ if (/^[A-Za-z0-9_-]{1,128}$/u.test(path))
14946
+ return path;
14947
+ return /\/(?:calls|live)\/([A-Za-z0-9_-]{1,128})$/u.exec(path)?.[1];
14948
+ }
14949
+ var requestId = external_exports.string().min(1).max(128);
14950
+ var realtimeCallParamsSchema = external_exports.discriminatedUnion("operation", [
14951
+ external_exports.object({
14952
+ operation: external_exports.literal("create"),
14953
+ requestId,
14954
+ body: external_exports.string().min(1).max(16 << 20),
14955
+ headers: external_exports.record(external_exports.string(), external_exports.string()).default({})
14956
+ }),
14957
+ external_exports.object({ operation: external_exports.literal("cancel"), requestId }),
14958
+ external_exports.object({
14959
+ operation: external_exports.literal("hangup"),
14960
+ callId: external_exports.string().regex(REALTIME_CALL_ID_PATTERN)
14961
+ })
14962
+ ]);
14963
+ var realtimeCallResponseSchema = external_exports.object({
14964
+ status: external_exports.number().int().min(200).max(599),
14965
+ body: external_exports.string(),
14966
+ headers: external_exports.record(external_exports.string(), external_exports.string())
14967
+ });
14968
+
15213
14969
  // ../shared-contracts/dist/console.js
15214
14970
  var consoleAnnouncementSchema = external_exports.strictObject({
15215
14971
  title: external_exports.string().trim().min(1).max(200),
@@ -15223,6 +14979,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15223
14979
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
15224
14980
  });
15225
14981
  var CONSOLE_HOST_METHODS = Object.freeze([
14982
+ "codexhost/voice/gateway-status",
15226
14983
  "codexhost/console/remote-connections",
15227
14984
  "codexhost/runtime/status",
15228
14985
  "codexhost/remote/ssh-setup",
@@ -16398,11 +16155,1323 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16398
16155
  external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
16399
16156
  ]);
16400
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
+
16401
16205
  // ../shared-contracts/dist/index.js
16402
16206
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
16403
16207
 
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
+ }
16224
+ }
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) => {
16303
+ try {
16304
+ const url2 = new URL(name, "app://-/");
16305
+ return url2.protocol === "app:" && url2.hostname === "-" && url2.pathname === `/assets/${asset}`;
16306
+ } catch {
16307
+ return false;
16308
+ }
16309
+ });
16310
+ }
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);
16342
+ };
16343
+ return true;
16344
+ }
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)) {
16363
+ return { status: "disabled", dispose() {
16364
+ } };
16365
+ }
16366
+ const root = options.document ?? globalObject.document;
16367
+ const wrapped = [];
16368
+ let disposed = false;
16369
+ let auditedAssetFound = false;
16370
+ const handle = {
16371
+ status: "pending",
16372
+ dispose() {
16373
+ disposed = true;
16374
+ for (const client of wrapped) restoreCheckGate(client);
16375
+ wrapped.length = 0;
16376
+ }
16377
+ };
16378
+ const attempt = () => {
16379
+ if (!auditedAssetFound) {
16380
+ const resourceNames = options.resourceNames ?? loadedAssetNames(root);
16381
+ auditedAssetFound = configAllowsInstall(config2, resourceNames);
16382
+ if (!auditedAssetFound) return false;
16383
+ }
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) {
16400
+ handle.status = "unsupported";
16401
+ return;
16402
+ }
16403
+ globalThis.setTimeout(tick, 250);
16404
+ };
16405
+ globalThis.setTimeout(tick, 250);
16406
+ return handle;
16407
+ }
16408
+
16409
+ // src/agent-selection-state.ts
16410
+ var DEFAULT_RENDERER_AGENTS = ["codex"];
16411
+ function defaultIdFactory(sequence) {
16412
+ return `codexhost-composer-${Date.now().toString(36)}-${sequence.toString(36)}`;
16413
+ }
16414
+ function isDefaultTarget(target) {
16415
+ return target?.[0] === "default";
16416
+ }
16417
+ function isConversationTarget(target) {
16418
+ return target?.[0] === "conversation";
16419
+ }
16420
+ function isIdentifiedTarget(target) {
16421
+ return target?.[0] === "conversation" || target?.[0] === "default" && typeof target[1] === "string" && target[1].startsWith("client-new-thread:");
16422
+ }
16423
+ function sameTarget(left, right) {
16424
+ return left.length === right.length && left.every((value, index) => value === right[index]);
16425
+ }
16426
+ var DraftAgentController = class {
16427
+ #idFactory;
16428
+ #defaultAgent;
16429
+ #enabledAgents;
16430
+ #targetStates = [];
16431
+ #modelRequestGenerations = /* @__PURE__ */ new WeakMap();
16432
+ #ownershipRequestGenerations = /* @__PURE__ */ new WeakMap();
16433
+ #states = /* @__PURE__ */ new WeakMap();
16434
+ #switching = /* @__PURE__ */ new Set();
16435
+ #pendingSubmissions = /* @__PURE__ */ new Set();
16436
+ #composerSequence = 0;
16437
+ #modelRequestSequence = 0;
16438
+ #ownershipRequestSequence = 0;
16439
+ #lastSubmittedAgent;
16440
+ constructor(options = {}) {
16441
+ this.#idFactory = options.idFactory ?? defaultIdFactory;
16442
+ this.#enabledAgents = new Set(options.enabledAgents ?? DEFAULT_RENDERER_AGENTS);
16443
+ if (!this.#enabledAgents.has("codex"))
16444
+ throw new Error("Renderer enabled Agents must include Codex");
16445
+ this.#defaultAgent = options.defaultAgent ?? "codex";
16446
+ this.#lastSubmittedAgent = this.#defaultAgent;
16447
+ }
16448
+ setEnabledAgents(agents) {
16449
+ this.#enabledAgents = /* @__PURE__ */ new Set(["codex", ...agents]);
16450
+ }
16451
+ get(composer) {
16452
+ return this.#state(composer);
16453
+ }
16454
+ detach(composer, preservePendingSubmission = false) {
16455
+ const state = this.#states.get(composer);
16456
+ if (state && !preservePendingSubmission) this.#pendingSubmissions.delete(state);
16457
+ this.#states.delete(composer);
16458
+ }
16459
+ mount(composer, target, preferredNewThreadAgent) {
16460
+ const bound = this.#targetState(target);
16461
+ if (bound) {
16462
+ this.#states.set(composer, bound);
16463
+ return bound;
16464
+ }
16465
+ const preferredAgent = preferredNewThreadAgent ?? this.#lastSubmittedAgent;
16466
+ const state = this.#state(composer, isDefaultTarget(target) ? preferredAgent : "codex");
16467
+ if (isIdentifiedTarget(target)) this.#targetStates.push({ target, state });
16468
+ return state;
16469
+ }
16470
+ isSwitching(composer) {
16471
+ return this.#switching.has(this.#state(composer));
16472
+ }
16473
+ beginModelRequest(composer) {
16474
+ const state = this.#state(composer);
16475
+ const generation = ++this.#modelRequestSequence;
16476
+ this.#modelRequestGenerations.set(state, generation);
16477
+ return generation;
16478
+ }
16479
+ invalidateModelRequests(composer) {
16480
+ this.beginModelRequest(composer);
16481
+ }
16482
+ isCurrentModelRequest(composer, generation) {
16483
+ return (this.#modelRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
16484
+ }
16485
+ beginOwnershipRequest(composer) {
16486
+ const generation = ++this.#ownershipRequestSequence;
16487
+ this.#ownershipRequestGenerations.set(this.#state(composer), generation);
16488
+ return generation;
16489
+ }
16490
+ isCurrentOwnershipRequest(composer, generation) {
16491
+ return (this.#ownershipRequestGenerations.get(this.#state(composer)) ?? 0) === generation;
16492
+ }
16493
+ rebindConversation(composer, target) {
16494
+ if (!isConversationTarget(target)) return null;
16495
+ const previous = this.#state(composer);
16496
+ this.#pendingSubmissions.delete(previous);
16497
+ this.#modelRequestGenerations.set(previous, ++this.#modelRequestSequence);
16498
+ this.#ownershipRequestGenerations.set(previous, ++this.#ownershipRequestSequence);
16499
+ let state = this.#targetState(target);
16500
+ if (!state) {
16501
+ state = {
16502
+ agent: "codex",
16503
+ phase: "draft",
16504
+ composerId: this.#idFactory(++this.#composerSequence)
16505
+ };
16506
+ this.#targetStates.push({ target, state });
16507
+ }
16508
+ this.#states.set(composer, state);
16509
+ this.#modelRequestGenerations.set(state, ++this.#modelRequestSequence);
16510
+ this.#ownershipRequestGenerations.set(state, ++this.#ownershipRequestSequence);
16511
+ return state;
16512
+ }
16513
+ restore(composer, agent, model2, thinkingOptionId, permissionModeId) {
16514
+ const state = this.#state(composer);
16515
+ this.#pendingSubmissions.delete(state);
16516
+ state.agent = agent;
16517
+ state.phase = "locked";
16518
+ if (agent !== "codex") {
16519
+ state.configurationByAgent = {
16520
+ ...state.configurationByAgent,
16521
+ [agent]: {
16522
+ ...model2 ? { model: model2 } : {},
16523
+ ...thinkingOptionId ? { thinkingOptionId } : {},
16524
+ ...permissionModeId ? { permissionModeId } : {}
16525
+ }
16526
+ };
16527
+ }
16528
+ return state;
16529
+ }
16530
+ clearConfiguration(composer) {
16531
+ delete this.#state(composer).configurationByAgent;
16532
+ }
16533
+ modelForAgent(composer, agent) {
16534
+ return this.#state(composer).configurationByAgent?.[agent]?.model;
16535
+ }
16536
+ thinkingOptionForAgent(composer, agent) {
16537
+ return this.#state(composer).configurationByAgent?.[agent]?.thinkingOptionId;
16538
+ }
16539
+ permissionModeForAgent(composer, agent) {
16540
+ return this.#state(composer).configurationByAgent?.[agent]?.permissionModeId;
16541
+ }
16542
+ setExternalPermissionMode(composer, agent, permissionModeId) {
16543
+ return this.#configure(composer, agent, { permissionModeId });
16544
+ }
16545
+ setExternalModel(composer, agent, model2) {
16546
+ return this.#configure(composer, agent, { model: model2 });
16547
+ }
16548
+ setExternalThinkingOption(composer, agent, thinkingOptionId) {
16549
+ const state = this.#configure(composer, agent, {});
16550
+ const configuration = state.configurationByAgent?.[agent];
16551
+ if (!configuration) return state;
16552
+ if (thinkingOptionId) configuration.thinkingOptionId = thinkingOptionId;
16553
+ else delete configuration.thinkingOptionId;
16554
+ return state;
16555
+ }
16556
+ #configure(composer, agent, patch) {
16557
+ const state = this.#state(composer);
16558
+ state.configurationByAgent = {
16559
+ ...state.configurationByAgent,
16560
+ [agent]: { ...state.configurationByAgent?.[agent], ...patch }
16561
+ };
16562
+ return state;
16563
+ }
16564
+ lock(composer) {
16565
+ const state = this.#state(composer);
16566
+ this.#pendingSubmissions.delete(state);
16567
+ state.phase = "locked";
16568
+ return state;
16569
+ }
16570
+ markSubmissionPending(composer) {
16571
+ const state = this.#state(composer);
16572
+ if (state.phase === "draft") this.#pendingSubmissions.add(state);
16573
+ return state;
16574
+ }
16575
+ isSubmissionPending(composer) {
16576
+ return this.#pendingSubmissions.has(this.#state(composer));
16577
+ }
16578
+ clearPendingSubmission(composer) {
16579
+ this.#pendingSubmissions.delete(this.#state(composer));
16580
+ }
16581
+ recordSubmission(composer) {
16582
+ const state = this.#state(composer);
16583
+ this.#lastSubmittedAgent = state.agent;
16584
+ return state;
16585
+ }
16586
+ transfer(source, replacement, target = null) {
16587
+ const state = this.#states.get(source);
16588
+ if (!state) return false;
16589
+ const bound = this.#targetState(target);
16590
+ if (bound && bound !== state) return false;
16591
+ if (source !== replacement) {
16592
+ if (this.#states.has(replacement)) return false;
16593
+ this.#states.set(replacement, state);
16594
+ }
16595
+ if (isIdentifiedTarget(target) && !bound) this.#targetStates.push({ target, state });
16596
+ if (isConversationTarget(target) && this.#pendingSubmissions.delete(state))
16597
+ state.phase = "locked";
16598
+ return true;
16599
+ }
16600
+ async switchAgent(composer, nextAgent, operations) {
16601
+ const state = this.#state(composer);
16602
+ if (!this.#enabledAgents.has(nextAgent)) return false;
16603
+ if (state.phase !== "draft" || this.#switching.has(state)) return false;
16604
+ if (state.agent === nextAgent) return true;
16605
+ this.#pendingSubmissions.delete(state);
16606
+ this.#switching.add(state);
16607
+ try {
16608
+ if (!operations.applyAgent(nextAgent)) return false;
16609
+ try {
16610
+ await operations.clearPrewarm();
16611
+ } catch (error51) {
16612
+ if (!operations.applyAgent(state.agent))
16613
+ throw new Error("Draft Agent switch could not restore the prior Agent", { cause: error51 });
16614
+ return false;
16615
+ }
16616
+ state.agent = nextAgent;
16617
+ return true;
16618
+ } finally {
16619
+ this.#switching.delete(state);
16620
+ }
16621
+ }
16622
+ #targetState(target) {
16623
+ if (!isIdentifiedTarget(target)) return null;
16624
+ return this.#targetStates.find((candidate) => sameTarget(candidate.target, target))?.state ?? null;
16625
+ }
16626
+ #state(composer, initialAgent) {
16627
+ const existing = this.#states.get(composer);
16628
+ if (existing) return existing;
16629
+ const created = {
16630
+ agent: initialAgent ?? this.#defaultAgent,
16631
+ phase: "draft",
16632
+ composerId: this.#idFactory(++this.#composerSequence)
16633
+ };
16634
+ this.#states.set(composer, created);
16635
+ return created;
16636
+ }
16637
+ };
16638
+
16639
+ // src/renderer-new-thread-preference.ts
16640
+ var RENDERER_NEW_THREAD_PREFERENCE_KEY = "codexhost.new-thread-preference.v1";
16641
+ function rendererNewThreadPreferenceStorage(hostId2 = "local") {
16642
+ if (!hostId2) return null;
16643
+ try {
16644
+ const storage = window.localStorage;
16645
+ if (hostId2 === "local") return storage;
16646
+ const scopedKey = (key) => `${key}.host.${encodeURIComponent(hostId2)}`;
16647
+ return {
16648
+ getItem: (key) => storage.getItem(scopedKey(key)),
16649
+ setItem: (key, value) => storage.setItem(scopedKey(key), value)
16650
+ };
16651
+ } catch {
16652
+ return null;
16653
+ }
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
+
16404
17473
  // src/codex-ssh-adapter.ts
16405
- var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
17474
+ var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16406
17475
  function createCodexSshClient(ownerWindow) {
16407
17476
  function request(operation, params, signal) {
16408
17477
  const bridge = ownerWindow.electronBridge;
@@ -16410,7 +17479,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16410
17479
  return Promise.reject(new Error("Codex SSH settings are unavailable in this window"));
16411
17480
  if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
16412
17481
  return new Promise((resolve, reject) => {
16413
- const requestId = ownerWindow.crypto.randomUUID();
17482
+ const requestId2 = ownerWindow.crypto.randomUUID();
16414
17483
  const finish = (error51, value) => {
16415
17484
  ownerWindow.clearTimeout(timer);
16416
17485
  ownerWindow.removeEventListener("message", receive);
@@ -16421,7 +17490,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16421
17490
  const abort = () => finish(new DOMException("Aborted", "AbortError"));
16422
17491
  const receive = (event) => {
16423
17492
  const message2 = event.data;
16424
- if (!record2(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId)
17493
+ if (!record3(message2) || message2.type !== "fetch-response" || message2.requestId !== requestId2)
16425
17494
  return;
16426
17495
  if (message2.responseType !== "success" || typeof message2.status !== "number" || message2.status < 200 || message2.status >= 300 || typeof message2.bodyJsonString !== "string") {
16427
17496
  finish(new Error("Codex SSH request failed; check the native Connections settings"));
@@ -16443,7 +17512,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16443
17512
  Promise.resolve(
16444
17513
  bridge.sendMessageFromView({
16445
17514
  type: "fetch",
16446
- requestId,
17515
+ requestId: requestId2,
16447
17516
  method: "POST",
16448
17517
  url: `vscode://codex/${operation}`,
16449
17518
  body: JSON.stringify(params),
@@ -16457,12 +17526,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16457
17526
  }
16458
17527
  async function list(signal) {
16459
17528
  const result = await request("refresh-remote-connections", {}, signal);
16460
- if (!record2(result) || !Array.isArray(result.remoteConnections))
17529
+ if (!record3(result) || !Array.isArray(result.remoteConnections))
16461
17530
  throw new Error("Invalid Codex SSH connection list");
16462
17531
  return result.remoteConnections.filter(
16463
- (item) => !(record2(item) && ["wsl", "remote-control"].includes(String(item.source)))
17532
+ (item) => !(record3(item) && ["wsl", "remote-control"].includes(String(item.source)))
16464
17533
  ).map((item) => {
16465
- 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)) {
16466
17535
  throw new Error(
16467
17536
  "This Codex version uses an unsupported SSH configuration; open native settings"
16468
17537
  );
@@ -16534,11 +17603,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16534
17603
  },
16535
17604
  async state(hostId2, signal) {
16536
17605
  const result = await request("app-server-connection-state", { hostId: hostId2 }, signal);
16537
- if (!record2(result) || typeof result.state !== "string")
17606
+ if (!record3(result) || typeof result.state !== "string")
16538
17607
  throw new Error("Invalid Codex connection state");
16539
17608
  return {
16540
17609
  state: result.state,
16541
- 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
16542
17611
  };
16543
17612
  }
16544
17613
  };
@@ -16616,87 +17685,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16616
17685
  return control;
16617
17686
  }
16618
17687
 
16619
- // ../desktop-control/dist/renderer-react-ownership.js
16620
- var REACT_FIBER_WALK_LIMIT_EVENT = "codexhost:react-fiber-walk-limit";
16621
- function committedReactAncestors(value) {
16622
- const MAX_VISITED_FIBERS = 2e5;
16623
- const fiber = (value2) => typeof value2 === "object" && value2 !== null ? value2 : null;
16624
- const exhausted = () => {
16625
- const target = globalThis;
16626
- if (typeof target.dispatchEvent === "function" && typeof CustomEvent === "function")
16627
- target.dispatchEvent(new CustomEvent("codexhost:react-fiber-walk-limit", {
16628
- detail: { limit: MAX_VISITED_FIBERS }
16629
- }));
16630
- return [];
16631
- };
16632
- const first = fiber(value);
16633
- if (!first)
16634
- return [];
16635
- const previous = [];
16636
- const seen = /* @__PURE__ */ new Set();
16637
- for (let node = first; node; node = fiber(node.return)) {
16638
- if (seen.has(node))
16639
- return [];
16640
- if (seen.size >= MAX_VISITED_FIBERS)
16641
- return exhausted();
16642
- seen.add(node);
16643
- previous.push(node);
16644
- }
16645
- const rootState = fiber(previous.at(-1)?.stateNode);
16646
- if (!rootState || !("current" in rootState))
16647
- return previous;
16648
- const current = fiber(rootState.current);
16649
- if (!current)
16650
- return [];
16651
- const alternate = fiber(first.alternate);
16652
- const path = [current];
16653
- seen.clear();
16654
- seen.add(current);
16655
- for (let index = previous.length - 2; index >= 0; index -= 1) {
16656
- const expected = previous[index];
16657
- const expectedAlternate = fiber(expected?.alternate);
16658
- let child = fiber(path.at(-1)?.child);
16659
- let matched = false;
16660
- while (child && !seen.has(child) && seen.size < MAX_VISITED_FIBERS) {
16661
- seen.add(child);
16662
- if (child === expected || child === expectedAlternate) {
16663
- matched = true;
16664
- break;
16665
- }
16666
- child = fiber(child.sibling);
16667
- }
16668
- if (!matched || !child)
16669
- break;
16670
- path.push(child);
16671
- }
16672
- if (path.length === previous.length && (path.at(-1) === first || path.at(-1) === alternate)) {
16673
- return path.reverse();
16674
- }
16675
- const stack = [{ node: current, parent: null }];
16676
- seen.clear();
16677
- while (stack.length > 0 && seen.size < MAX_VISITED_FIBERS) {
16678
- const entry = stack.pop();
16679
- if (!entry)
16680
- break;
16681
- if (seen.has(entry.node))
16682
- return [];
16683
- seen.add(entry.node);
16684
- if (entry.node === first || entry.node === alternate) {
16685
- const ancestors = [];
16686
- for (let cursor = entry; cursor; cursor = cursor.parent)
16687
- ancestors.push(cursor.node);
16688
- return ancestors;
16689
- }
16690
- const sibling = entry.parent && fiber(entry.node.sibling);
16691
- if (sibling)
16692
- stack.push({ node: sibling, parent: entry.parent });
16693
- const child = fiber(entry.node.child);
16694
- if (child)
16695
- stack.push({ node: child, parent: entry });
16696
- }
16697
- return stack.length > 0 ? exhausted() : [];
16698
- }
16699
-
16700
17688
  // src/renderer-composer-kind.ts
16701
17689
  function orbitComposerKind(composer) {
16702
17690
  let element = composer.querySelector('[contenteditable="true"], textarea, [role="textbox"]') ?? composer;
@@ -18815,16 +19803,6 @@ ${error51.stderrTail}`] : []
18815
19803
  "When this is on, that card is hidden on every Composer, including Codex threads. Reset usage and Upgrade stay available in Settings.",
18816
19804
  "Turning this off only shows the native card again. Send on this Composer, including Codex threads, is already separated from that quota card."
18817
19805
  ]),
18818
- cpaLiveVoiceTitle: "Override live voice",
18819
- cpaLiveVoiceDescription: "On by default. Host creates the realtime call instead of ChatGPT.",
18820
- cpaLiveVoiceHelpLabel: "About overriding live voice",
18821
- cpaLiveVoiceHelp: Object.freeze([
18822
- "Overrides Desktop's existing-call path on audited 26.1007.30912 so a local host can create the WebRTC call.",
18823
- "This switch applies on the next voice session. No relaunch.",
18824
- "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.",
18825
- "CODEXHOST_CPA_LIVE_VOICE=0 is not live. Relaunch Codex after changing that environment variable."
18826
- ]),
18827
- cpaLiveVoiceRestartRequired: "This override is not injected. Unset CODEXHOST_CPA_LIVE_VOICE=0 and relaunch Codex. The switch cannot take effect until then.",
18828
19806
  loadedSessions: {
18829
19807
  title: "Loaded sessions",
18830
19808
  description: "Local external Harnesses only. Refreshes every 10 seconds without waking sessions or resetting activity. Released sessions disappear from this list.",
@@ -19080,6 +20058,7 @@ ${error51.stderrTail}`] : []
19080
20058
  connections: "Connections",
19081
20059
  "remote-connections": "Remote connections",
19082
20060
  appearance: "General",
20061
+ voice: "Voice",
19083
20062
  accounts: "Accounts",
19084
20063
  "session-import": "Session Import",
19085
20064
  "usage-statistics": "Usage statistics",
@@ -19106,16 +20085,6 @@ ${error51.stderrTail}`] : []
19106
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",
19107
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"
19108
20087
  ]),
19109
- cpaLiveVoiceTitle: "\u6539\u5199\u5B9E\u65F6\u8BED\u97F3",
19110
- cpaLiveVoiceDescription: "\u9ED8\u8BA4\u5F00\u542F\u3002\u7531 Host \u521B\u5EFA realtime \u901A\u8BDD\uFF0C\u800C\u4E0D\u662F ChatGPT\u3002",
19111
- cpaLiveVoiceHelpLabel: "\u6539\u5199\u5B9E\u65F6\u8BED\u97F3\u8BF4\u660E",
19112
- cpaLiveVoiceHelp: Object.freeze([
19113
- "\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",
19114
- "\u6B64\u5F00\u5173\u5728\u4E0B\u4E00\u6B21\u8BED\u97F3\u4F1A\u8BDD\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u65B0\u542F\u52A8\u3002",
19115
- "\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",
19116
- "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"
19117
- ]),
19118
- 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",
19119
20088
  loadedSessions: {
19120
20089
  title: "\u5DF2\u52A0\u8F7D\u4F1A\u8BDD",
19121
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",
@@ -19371,6 +20340,7 @@ ${error51.stderrTail}`] : []
19371
20340
  connections: "\u8FDE\u63A5",
19372
20341
  "remote-connections": "\u8FDC\u7A0B\u8FDE\u63A5",
19373
20342
  appearance: "\u901A\u7528",
20343
+ voice: "\u8BED\u97F3",
19374
20344
  accounts: "\u8D26\u53F7",
19375
20345
  "session-import": "\u4F1A\u8BDD\u5BFC\u5165",
19376
20346
  "usage-statistics": "\u7528\u91CF\u7EDF\u8BA1",
@@ -22671,7 +23641,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22671
23641
  const composer = element.closest(CODEX_COMPOSER_SELECTOR);
22672
23642
  return composer && !isOrbitComposer(composer) ? composer : null;
22673
23643
  }
22674
- function isRecord2(value) {
23644
+ function isRecord3(value) {
22675
23645
  return typeof value === "object" && value !== null && !Array.isArray(value);
22676
23646
  }
22677
23647
  function isNativeModelControlCandidate(element) {
@@ -22687,7 +23657,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22687
23657
  let fiber = fiberName ? Object.getOwnPropertyDescriptor(element, fiberName)?.value : null;
22688
23658
  for (let depth = 0; fiber && depth < 60; depth += 1) {
22689
23659
  const props = fiber.memoizedProps;
22690
- 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)) {
22691
23661
  return true;
22692
23662
  }
22693
23663
  const parent = fiber.return;
@@ -22707,7 +23677,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
22707
23677
  let ownsComposerPermissionState = false;
22708
23678
  for (let depth = 0; fiber && depth < 60; depth += 1) {
22709
23679
  const props = fiber.memoizedProps;
22710
- if (isRecord2(props)) {
23680
+ if (isRecord3(props)) {
22711
23681
  if (props["data-composer-navigation-target"] === "permissions" && props["aria-haspopup"] === "menu") {
22712
23682
  ownsTrigger = true;
22713
23683
  }
@@ -23200,19 +24170,19 @@ Codex Fast mode prioritizes requests and may increase usage.`
23200
24170
 
23201
24171
  // src/renderer-codex-usage-banner.ts
23202
24172
  var MAX_FIBERS = 2e4;
23203
- function isRecord3(value) {
24173
+ function isRecord4(value) {
23204
24174
  return typeof value === "object" && value !== null && !Array.isArray(value);
23205
24175
  }
23206
24176
  function isUsageBanner(props) {
23207
- 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";
23208
24178
  }
23209
24179
  function isElement(value) {
23210
- return isRecord3(value) && typeof value.setAttribute === "function" && isRecord3(value.style);
24180
+ return isRecord4(value) && typeof value.setAttribute === "function" && isRecord4(value.style);
23211
24181
  }
23212
24182
  function hostElements(fiber, budget) {
23213
24183
  const result = [];
23214
24184
  const visit = (node) => {
23215
- for (let current = node; isRecord3(current); current = current.sibling) {
24185
+ for (let current = node; isRecord4(current); current = current.sibling) {
23216
24186
  if (budget.remaining-- <= 0) return;
23217
24187
  const { stateNode } = current;
23218
24188
  if (isElement(stateNode)) result.push(stateNode);
@@ -23223,13 +24193,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23223
24193
  return result;
23224
24194
  }
23225
24195
  function findCodexUsageBannerElements(owner) {
23226
- if (!isRecord3(owner)) return [];
24196
+ if (!isRecord4(owner)) return [];
23227
24197
  const budget = { remaining: MAX_FIBERS };
23228
24198
  const found = [];
23229
24199
  const stack = [owner.child];
23230
24200
  while (stack.length > 0 && budget.remaining > 0) {
23231
24201
  const node = stack.pop();
23232
- if (!isRecord3(node)) continue;
24202
+ if (!isRecord4(node)) continue;
23233
24203
  budget.remaining -= 1;
23234
24204
  const fiber = node;
23235
24205
  stack.push(fiber.sibling);
@@ -23274,13 +24244,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23274
24244
  var MAX_HOOKS = 4096;
23275
24245
  var MAX_DOM_DEPTH = 12;
23276
24246
  var RETRY_DELAY_MS = 1e3;
23277
- function isRecord4(value) {
24247
+ function isRecord5(value) {
23278
24248
  return typeof value === "object" && value !== null && !Array.isArray(value);
23279
24249
  }
23280
24250
  function hooksOf(fiber) {
23281
24251
  const result = [];
23282
- let hook = isRecord4(fiber) ? fiber.memoizedState : null;
23283
- while (isRecord4(hook) && result.length < MAX_HOOKS) {
24252
+ let hook = isRecord5(fiber) ? fiber.memoizedState : null;
24253
+ while (isRecord5(hook) && result.length < MAX_HOOKS) {
23284
24254
  result.push(hook);
23285
24255
  hook = hook.next;
23286
24256
  }
@@ -23298,7 +24268,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23298
24268
  );
23299
24269
  const scopes = [];
23300
24270
  ancestors.forEach(({ memoizedProps: props }, index) => {
23301
- if (isRecord4(props) && "onLocalSubmitStart" in props && typeof props.submitDisabled === "boolean") {
24271
+ if (isRecord5(props) && "onLocalSubmitStart" in props && typeof props.submitDisabled === "boolean") {
23302
24272
  scopes.push({ owner: ancestors[index], fibers: ancestors.slice(0, index + 1) });
23303
24273
  }
23304
24274
  });
@@ -23324,11 +24294,11 @@ Codex Fast mode prioritizes requests and may increase usage.`
23324
24294
  const [subscriber, dependencies] = memo;
23325
24295
  if (dependencies.length !== 2) return null;
23326
24296
  const signal = dependencies[0];
23327
- 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";
23328
24298
  const [store, atom] = adapted ? [signal.store, signal.atom] : dependencies;
23329
24299
  const instance = hook.next?.queue;
23330
24300
  const effect = hook.next?.next?.memoizedState;
23331
- 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) {
23332
24302
  return null;
23333
24303
  }
23334
24304
  return {
@@ -23370,10 +24340,10 @@ Codex Fast mode prioritizes requests and may increase usage.`
23370
24340
  visiting.delete(dependency);
23371
24341
  }
23372
24342
  }
23373
- if (!isRecord4(value)) return value;
24343
+ if (!isRecord5(value)) return value;
23374
24344
  if (typeof value.hardBlocked === "boolean") return trace(value, "reserve");
23375
24345
  if ("authMethod" in value) return trace(value, "auth");
23376
- if (isRecord4(value.data) && isRecord4(value.data.rate_limit)) {
24346
+ if (isRecord5(value.data) && isRecord5(value.data.rate_limit)) {
23377
24347
  return {
23378
24348
  ...value,
23379
24349
  data: { ...value.data, rate_limit: trace(value.data.rate_limit, "limit") }
@@ -23485,7 +24455,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
23485
24455
  }
23486
24456
  function isBound(projections) {
23487
24457
  return [...projections].every(({ fiber, subscriber, instance }) => {
23488
- const alternate = isRecord4(fiber.alternate) ? fiber.alternate : null;
24458
+ const alternate = isRecord5(fiber.alternate) ? fiber.alternate : null;
23489
24459
  return [fiber, alternate].some(
23490
24460
  (candidate) => hooksOf(candidate).some(
23491
24461
  (hook) => Array.isArray(hook.memoizedState) && hook.memoizedState[0] === subscriber && hook.next?.queue === instance
@@ -23665,13 +24635,13 @@ Codex Fast mode prioritizes requests and may increase usage.`
23665
24635
  }
23666
24636
 
23667
24637
  // src/renderer-native-thread.ts
23668
- function isRecord5(value) {
24638
+ function isRecord6(value) {
23669
24639
  return typeof value === "object" && value !== null && !Array.isArray(value);
23670
24640
  }
23671
24641
  async function verifyNativeCodexThread(sendRequest, threadId) {
23672
24642
  const native = await sendRequest("thread/read", { threadId, includeTurns: false });
23673
- const thread = isRecord5(native) ? native.thread : null;
23674
- 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") {
23675
24645
  throw new Error("Native Thread response cannot establish Codex ownership");
23676
24646
  }
23677
24647
  }
@@ -23750,15 +24720,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
23750
24720
  var CODEX_ACCOUNT_LIST_METHOD = "codexhost/account/list";
23751
24721
  var CODEX_ACCOUNT_REFRESH_METHOD = "codexhost/account/refresh";
23752
24722
  var CODEX_ACCOUNT_CHANGED_METHOD = "codexhost/account/changed";
23753
- function isRecord6(value) {
24723
+ function isRecord7(value) {
23754
24724
  return typeof value === "object" && value !== null && !Array.isArray(value);
23755
24725
  }
23756
24726
  function notifiedThreadId(notification) {
23757
- if (!isRecord6(notification) || !THREAD_USAGE_REFRESH_METHODS.includes(notification.method)) {
24727
+ if (!isRecord7(notification) || !THREAD_USAGE_REFRESH_METHODS.includes(notification.method)) {
23758
24728
  return null;
23759
24729
  }
23760
24730
  const params = notification.params;
23761
- if (!isRecord6(params)) return null;
24731
+ if (!isRecord7(params)) return null;
23762
24732
  const parsed = hostThreadIdSchema.safeParse(params.threadId);
23763
24733
  return parsed.success ? parsed.data : null;
23764
24734
  }
@@ -24076,7 +25046,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24076
25046
  throw new Error("Renderer Account notification callback is unavailable");
24077
25047
  }
24078
25048
  return notifications.addNotificationCallback(CODEX_ACCOUNT_CHANGED_METHOD, (notification) => {
24079
- if (!isRecord6(notification) || notification.method !== CODEX_ACCOUNT_CHANGED_METHOD) return;
25049
+ if (!isRecord7(notification) || notification.method !== CODEX_ACCOUNT_CHANGED_METHOD) return;
24080
25050
  const state = codexAccountChangedSchema.safeParse(notification.params);
24081
25051
  if (state.success) listener(state.data);
24082
25052
  });
@@ -24085,16 +25055,16 @@ Codex Fast mode prioritizes requests and may increase usage.`
24085
25055
  }
24086
25056
 
24087
25057
  // src/renderer-external-queue.ts
24088
- function isRecord7(value) {
25058
+ function isRecord8(value) {
24089
25059
  return value !== null && typeof value === "object" && !Array.isArray(value);
24090
25060
  }
24091
25061
  function installRendererExternalQueue(target) {
24092
- if (!isRecord7(target) || typeof target.getTurnCoordinator !== "function" || typeof target.getConversation !== "function") {
25062
+ if (!isRecord8(target) || typeof target.getTurnCoordinator !== "function" || typeof target.getConversation !== "function") {
24093
25063
  return null;
24094
25064
  }
24095
25065
  const coordinator = target.getTurnCoordinator();
24096
- const queue = isRecord7(coordinator) ? coordinator.serverQueue : null;
24097
- 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;
24098
25068
  const descriptor = Object.getOwnPropertyDescriptor(queue, "isEnabled");
24099
25069
  if (!descriptor?.writable) return null;
24100
25070
  const original = queue.isEnabled;
@@ -24103,7 +25073,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24103
25073
  const threadId = args[0];
24104
25074
  if (typeof threadId === "string") {
24105
25075
  const conversation = getConversation.call(target, threadId);
24106
- 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
24107
25077
  // Desktop in both newly created and hydrated conversation metadata.
24108
25078
  conversation.modelProvider === "codexhost") {
24109
25079
  return false;
@@ -24119,19 +25089,19 @@ Codex Fast mode prioritizes requests and may increase usage.`
24119
25089
 
24120
25090
  // src/renderer-external-steering.ts
24121
25091
  var THREAD_OWNERSHIP_LIST_METHOD2 = "codexhost/thread/ownership/list";
24122
- function isRecord8(value) {
25092
+ function isRecord9(value) {
24123
25093
  return value !== null && typeof value === "object" && !Array.isArray(value);
24124
25094
  }
24125
25095
  function isManager(value) {
24126
- return isRecord8(value) && ["sendRequest", "steerTurn", "startTurn", "getTurnCoordinator"].every(
25096
+ return isRecord9(value) && ["sendRequest", "steerTurn", "startTurn", "getTurnCoordinator"].every(
24127
25097
  (key) => typeof value[key] === "function"
24128
25098
  );
24129
25099
  }
24130
25100
  function submissionHost(manager) {
24131
25101
  const coordinator = manager.getTurnCoordinator();
24132
- const options = isRecord8(coordinator) ? coordinator.options : null;
24133
- const host = isRecord8(options) ? options.submissionHost : null;
24134
- 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") {
24135
25105
  throw new Error("Desktop turn submission binding is unavailable");
24136
25106
  }
24137
25107
  return {
@@ -24173,20 +25143,20 @@ Codex Fast mode prioritizes requests and may increase usage.`
24173
25143
  var INTERRUPTED_QUEUE_REASON = "Interrupted before the steer was accepted.";
24174
25144
  async function preserveQueuedFollowUps(manager, threadId) {
24175
25145
  const coordinator = manager.getTurnCoordinator();
24176
- 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") {
24177
25147
  throw new Error("Desktop follow-up queue binding is unavailable");
24178
25148
  }
24179
25149
  await coordinator.loadMessages.call(coordinator, threadId);
24180
25150
  const messages = coordinator.readMessages.call(coordinator, threadId);
24181
25151
  if (!Array.isArray(messages)) throw new Error("Desktop follow-up queue is unavailable");
24182
25152
  const alreadyPaused = new Set(
24183
- 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)
24184
25154
  );
24185
25155
  return () => {
24186
25156
  coordinator.mutate.call(coordinator, threadId, (current) => {
24187
25157
  if (!Array.isArray(current)) return current;
24188
25158
  return current.map((message2) => {
24189
- 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)
24190
25160
  return message2;
24191
25161
  const resumed = { ...message2 };
24192
25162
  delete resumed.pausedReason;
@@ -24207,9 +25177,9 @@ Codex Fast mode prioritizes requests and may increase usage.`
24207
25177
  if ((method === "turn/start" || method === "turn/steer") && prepareTurnInput) {
24208
25178
  params = prepareTurnInput(params);
24209
25179
  }
24210
- const messageId = isRecord8(params) ? params.clientUserMessageId : null;
24211
- const route = typeof messageId === "string" && isRecord8(params) ? routes.get(`${params.threadId}\0${messageId}`) : void 0;
24212
- 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) {
24213
25183
  if (method === "turn/start" && sendTurnStart) {
24214
25184
  return sendTurnStart(params, (input) => {
24215
25185
  if (disposed) throw new Error("External submission binding was disposed");
@@ -24235,7 +25205,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24235
25205
  options
24236
25206
  )
24237
25207
  ).then((response) => {
24238
- if (!isRecord8(response) || typeof response.turnId !== "string" || !response.turnId) {
25208
+ if (!isRecord9(response) || typeof response.turnId !== "string" || !response.turnId) {
24239
25209
  throw new Error("External steering returned no replacement Turn identity");
24240
25210
  }
24241
25211
  return {
@@ -24266,7 +25236,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24266
25236
  ] = args;
24267
25237
  if (typeof threadId !== "string") return originalSteer.apply(manager, args);
24268
25238
  const role = manager.getStreamRole?.(threadId);
24269
- if (isRecord8(role) && role.role === "follower") return originalSteer.apply(manager, args);
25239
+ if (isRecord9(role) && role.role === "follower") return originalSteer.apply(manager, args);
24270
25240
  let host = null;
24271
25241
  let expectedTurnId;
24272
25242
  try {
@@ -24295,15 +25265,15 @@ Codex Fast mode prioritizes requests and may increase usage.`
24295
25265
  if (owner === "codex") return originalSteer.apply(manager, args);
24296
25266
  if (!host) throw new Error("Desktop turn submission binding is unavailable");
24297
25267
  const currentRole = manager.getStreamRole?.(threadId);
24298
- if (isRecord8(currentRole) && currentRole.role === "follower")
25268
+ if (isRecord9(currentRole) && currentRole.role === "follower")
24299
25269
  return originalSteer.apply(manager, args);
24300
25270
  if (!Array.isArray(input) || input.length === 0 || input.some(
24301
- (item) => !isRecord8(item) || item.type !== "text" || typeof item.text !== "string"
24302
- ) || !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())) {
24303
25273
  throw new Error("External steering requires non-empty text input");
24304
25274
  }
24305
25275
  if (toolOutput != null) throw new Error("External steering cannot replace a tool response");
24306
- if (!isRecord8(restoreMessage) || !isRecord8(restoreMessage.context)) {
25276
+ if (!isRecord9(restoreMessage) || !isRecord9(restoreMessage.context)) {
24307
25277
  throw new Error("Desktop steering message context is unavailable");
24308
25278
  }
24309
25279
  const messageId = typeof clientUserMessageId === "string" && clientUserMessageId ? clientUserMessageId : typeof restoreMessage.id === "string" && restoreMessage.id ? restoreMessage.id : crypto.randomUUID();
@@ -24351,7 +25321,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24351
25321
  },
24352
25322
  onMessageAdded
24353
25323
  );
24354
- if (!isRecord8(response) || !isRecord8(response.turn) || typeof response.turn.id !== "string") {
25324
+ if (!isRecord9(response) || !isRecord9(response.turn) || typeof response.turn.id !== "string") {
24355
25325
  throw new Error("Desktop returned no replacement Turn identity");
24356
25326
  }
24357
25327
  try {
@@ -24382,7 +25352,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24382
25352
  }
24383
25353
 
24384
25354
  // src/renderer-remote-attachments.ts
24385
- function isRecord9(value) {
25355
+ function isRecord10(value) {
24386
25356
  return value !== null && typeof value === "object" && !Array.isArray(value);
24387
25357
  }
24388
25358
  var MAX_IMAGE_BYTES = 20 * 1024 * 1024;
@@ -24434,14 +25404,14 @@ Codex Fast mode prioritizes requests and may increase usage.`
24434
25404
  function createRemoteAttachmentSender(target, hostId2, isCurrent) {
24435
25405
  const prepared = /* @__PURE__ */ new WeakMap();
24436
25406
  return (params, send) => {
24437
- 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")
24438
25408
  return send(params);
24439
25409
  const images = params.input.filter(
24440
- (item) => isRecord9(item) && (item.type === "image" || item.type === "localImage")
25410
+ (item) => isRecord10(item) && (item.type === "image" || item.type === "localImage")
24441
25411
  );
24442
25412
  if (images.length === 0) return send(params);
24443
25413
  const conversation = target.getConversation.call(target, params.threadId);
24444
- if (!isRecord9(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25414
+ if (!isRecord10(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
24445
25415
  return send(params);
24446
25416
  const assertCurrent = () => {
24447
25417
  if (!isCurrent()) throw new Error("Remote attachment connection is no longer available");
@@ -24454,7 +25424,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24454
25424
  const cached2 = prepared.get(params);
24455
25425
  if (cached2) return cached2.then(dispatch);
24456
25426
  const input = params.input;
24457
- 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");
24458
25428
  const existingPaths = nativeImagePaths(text);
24459
25429
  const prepare = async () => {
24460
25430
  if (existingPaths.length === images.length) return params;
@@ -24486,7 +25456,7 @@ Codex Fast mode prioritizes requests and may increase usage.`
24486
25456
  contents: file2.contents,
24487
25457
  label: `image-${index + 1}.${file2.extension}`
24488
25458
  });
24489
- if (!isRecord9(saved) || !filePath(saved.path) || saved.fsPath !== saved.path) {
25459
+ if (!isRecord10(saved) || !filePath(saved.path) || saved.fsPath !== saved.path) {
24490
25460
  throw new Error("Desktop returned an invalid remote attachment path");
24491
25461
  }
24492
25462
  created.push(saved.path);
@@ -24537,9 +25507,9 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24537
25507
  }
24538
25508
 
24539
25509
  // src/renderer-thread-reference-capability.ts
24540
- var record3 = (value) => typeof value === "object" && value !== null;
25510
+ var record4 = (value) => typeof value === "object" && value !== null;
24541
25511
  function restoreThreadReferenceCapability(client, manager, isCurrent) {
24542
- if (!record3(manager) || !record3(manager.storage)) return client;
25512
+ if (!record4(manager) || !record4(manager.storage)) return client;
24543
25513
  const storage = manager.storage;
24544
25514
  const read = storage.readValue;
24545
25515
  const write = storage.writeValue;
@@ -24574,14 +25544,14 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24574
25544
  }
24575
25545
 
24576
25546
  // src/renderer-thread-reference-context.ts
24577
- var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25547
+ var record5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
24578
25548
  function createThreadReferenceContext(manager, hostId2, isCurrent) {
24579
25549
  const prepared = /* @__PURE__ */ new WeakMap();
24580
25550
  return (params) => {
24581
- 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")
24582
25552
  return params;
24583
25553
  const conversation = manager.getConversation.call(manager, params.threadId);
24584
- if (!record4(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
25554
+ if (!record5(conversation) || conversation.id !== params.threadId || conversation.modelProvider !== "codexhost")
24585
25555
  return params;
24586
25556
  if (!isCurrent()) throw new Error("Thread reference connection is no longer available");
24587
25557
  const cached2 = prepared.get(params);
@@ -24593,11 +25563,11 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24593
25563
  }
24594
25564
 
24595
25565
  // src/renderer-manual-compaction.ts
24596
- function isRecord10(value) {
25566
+ function isRecord11(value) {
24597
25567
  return value !== null && typeof value === "object" && !Array.isArray(value);
24598
25568
  }
24599
25569
  function installRendererManualCompaction(target, hostId2, messages) {
24600
- 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") {
24601
25571
  return null;
24602
25572
  }
24603
25573
  const register = target.registerPendingManualContextCompaction;
@@ -24606,18 +25576,18 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24606
25576
  const listener = (event) => {
24607
25577
  if (event.source != null && event.source !== messages) return;
24608
25578
  const message2 = event.data;
24609
- 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) {
24610
25580
  return;
24611
25581
  }
24612
25582
  const params = threadManualCompactionStartedSchema.safeParse(message2.params);
24613
25583
  if (!params.success) return;
24614
25584
  const { threadId } = params.data;
24615
25585
  const conversation = getConversation.call(target, threadId);
24616
- if (!isRecord10(conversation) || conversation.id !== threadId || conversation.modelProvider !== "codexhost") {
25586
+ if (!isRecord11(conversation) || conversation.id !== threadId || conversation.modelProvider !== "codexhost") {
24617
25587
  return;
24618
25588
  }
24619
25589
  const role = getStreamRole?.call(target, threadId);
24620
- if (isRecord10(role) && role.role === "follower") return;
25590
+ if (isRecord11(role) && role.role === "follower") return;
24621
25591
  register.call(target, threadId);
24622
25592
  };
24623
25593
  messages.addEventListener("message", listener);
@@ -24832,7 +25802,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24832
25802
  var SIDEBAR_THREAD_HOST_ID_ATTRIBUTE = "data-app-action-sidebar-thread-host-id";
24833
25803
  var SIDEBAR_AGENT_ICON_ATTRIBUTE = "data-codexhost-sidebar-agent-icon";
24834
25804
  var OWNERSHIP_RETRY_DELAYS_MS = [100, 300, 800, 1500, 3e3];
24835
- function isRecord11(value) {
25805
+ function isRecord12(value) {
24836
25806
  return typeof value === "object" && value !== null && !Array.isArray(value);
24837
25807
  }
24838
25808
  function sidebarThreadAttributes(element) {
@@ -24859,19 +25829,19 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
24859
25829
  const fiberName = fiberNames[0];
24860
25830
  if (fiberNames.length !== 1 || !fiberName) return null;
24861
25831
  const firstFiber2 = Object.getOwnPropertyDescriptor(element, fiberName)?.value;
24862
- if (!isRecord11(firstFiber2)) return null;
25832
+ if (!isRecord12(firstFiber2)) return null;
24863
25833
  const candidates = /* @__PURE__ */ new Set();
24864
25834
  let fiber = firstFiber2;
24865
25835
  for (let depth = 0; fiber && depth < 12; depth += 1) {
24866
25836
  const props = fiber.memoizedProps;
24867
- if (isRecord11(props) && isRecord11(props.dataAttributes)) {
25837
+ if (isRecord12(props) && isRecord12(props.dataAttributes)) {
24868
25838
  const dataAttributes = props.dataAttributes;
24869
25839
  const threadId = hostThreadIdSchema.safeParse(props.conversationId);
24870
25840
  if (threadId.success && dataAttributes[SIDEBAR_THREAD_ROW_ATTRIBUTE] === rowMarker && dataAttributes[SIDEBAR_THREAD_ID_ATTRIBUTE] === taskKey && dataAttributes[SIDEBAR_THREAD_HOST_ID_ATTRIBUTE] === hostId2) {
24871
25841
  candidates.add(threadId.data);
24872
25842
  }
24873
25843
  }
24874
- fiber = isRecord11(fiber.return) ? fiber.return : null;
25844
+ fiber = isRecord12(fiber.return) ? fiber.return : null;
24875
25845
  }
24876
25846
  return candidates.size === 1 ? candidates.values().next().value ?? null : null;
24877
25847
  }
@@ -25281,7 +26251,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25281
26251
  if (row) finish(row);
25282
26252
  });
25283
26253
  }
25284
- function isRecord12(value) {
26254
+ function isRecord13(value) {
25285
26255
  return typeof value === "object" && value !== null && !Array.isArray(value);
25286
26256
  }
25287
26257
  function firstFiber(element) {
@@ -25291,7 +26261,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25291
26261
  const name = names[0];
25292
26262
  if (names.length !== 1 || !name) return null;
25293
26263
  const value = Object.getOwnPropertyDescriptor(element, name)?.value;
25294
- return isRecord12(value) ? value : null;
26264
+ return isRecord13(value) ? value : null;
25295
26265
  }
25296
26266
  function directForkAncestors(first) {
25297
26267
  const ancestors = [];
@@ -25301,7 +26271,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25301
26271
  if (seen.has(fiber)) return [];
25302
26272
  seen.add(fiber);
25303
26273
  ancestors.push(fiber);
25304
- fiber = isRecord12(fiber.return) ? fiber.return : null;
26274
+ fiber = isRecord13(fiber.return) ? fiber.return : null;
25305
26275
  }
25306
26276
  return ancestors;
25307
26277
  }
@@ -25319,7 +26289,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25319
26289
  let hasForkCallback = false;
25320
26290
  for (const fiber of ancestors) {
25321
26291
  const props = fiber.memoizedProps;
25322
- if (!isRecord12(props)) continue;
26292
+ if (!isRecord13(props)) continue;
25323
26293
  if (!hasForkCallback && typeof props.onFork !== "function" && ownsOtherCallback(fiber, props)) {
25324
26294
  return null;
25325
26295
  }
@@ -25351,7 +26321,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25351
26321
  if (!threadId.success || !turnId.success) return null;
25352
26322
  const fiber = firstFiber(button2);
25353
26323
  const buttonProps = fiber?.memoizedProps;
25354
- if (!fiber || !isRecord12(buttonProps) || !Object.hasOwn(buttonProps, "aria-busy")) return null;
26324
+ if (!fiber || !isRecord13(buttonProps) || !Object.hasOwn(buttonProps, "aria-busy")) return null;
25355
26325
  return forkTargetFromAncestors(button2, threadId.data, turnId.data, directForkAncestors(fiber)) ?? forkTargetFromAncestors(button2, threadId.data, turnId.data, committedReactAncestors(fiber));
25356
26326
  }
25357
26327
  var BrowserRendererForkDom = class {
@@ -25441,7 +26411,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25441
26411
  }
25442
26412
  var DRAFT_PREWARM_POLICY_WAIT_TIMEOUT_MS = 1e4;
25443
26413
  var DRAFT_PREWARM_POLICY_POLL_INTERVAL_MS = 25;
25444
- function isRecord13(value) {
26414
+ function isRecord14(value) {
25445
26415
  return typeof value === "object" && value !== null && !Array.isArray(value);
25446
26416
  }
25447
26417
  function decodeOpenCodeTransportModelId(value) {
@@ -25606,7 +26576,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25606
26576
  let fiber = findComposerFiber(composer);
25607
26577
  for (let depth = 0; fiber && depth < 120; depth += 1) {
25608
26578
  const props = fiber.memoizedProps;
25609
- if (isRecord13(props) && "conversationId" in props && props.conversationId != null) {
26579
+ if (isRecord14(props) && "conversationId" in props && props.conversationId != null) {
25610
26580
  const candidate = hostThreadIdSchema.safeParse(props.conversationId);
25611
26581
  if (!candidate.success || threadId !== void 0 && threadId !== candidate.data) {
25612
26582
  return null;
@@ -25619,12 +26589,12 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25619
26589
  return threadId;
25620
26590
  }
25621
26591
  function isLegacySevenSlotDraftWrapper(value) {
25622
- 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) {
25623
26593
  return false;
25624
26594
  }
25625
26595
  try {
25626
26596
  const draft = value[3].get();
25627
- return isRecord13(draft) && "modelSettings" in draft && "isManuallyChanged" in draft;
26597
+ return isRecord14(draft) && "modelSettings" in draft && "isManuallyChanged" in draft;
25628
26598
  } catch {
25629
26599
  return false;
25630
26600
  }
@@ -25658,8 +26628,8 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25658
26628
  let fiber = findComposerFiber(composer);
25659
26629
  for (let depth = 0; fiber && depth < 120; depth += 1) {
25660
26630
  const updateQueue = fiber.updateQueue;
25661
- const memoCache = isRecord13(updateQueue) ? updateQueue.memoCache : null;
25662
- 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 : [];
25663
26633
  for (const value of data) {
25664
26634
  const draftId = draftIdFromMemoValue(value);
25665
26635
  if (draftId) draftIds.add(draftId);
@@ -25687,7 +26657,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25687
26657
  return ["default", draftIds.values().next().value];
25688
26658
  }
25689
26659
  function isDraftPrewarmPolicyReady(value) {
25690
- 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";
25691
26661
  }
25692
26662
  async function waitForRendererDraftPrewarmPolicy(target, composer) {
25693
26663
  const deadline = Date.now() + DRAFT_PREWARM_POLICY_WAIT_TIMEOUT_MS;
@@ -25937,116 +26907,6 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
25937
26907
  }
25938
26908
  }
25939
26909
 
25940
- // src/renderer-new-thread-preference.ts
25941
- var RENDERER_NEW_THREAD_PREFERENCE_KEY = "codexhost.new-thread-preference.v1";
25942
- function rendererNewThreadPreferenceStorage(hostId2 = "local") {
25943
- if (!hostId2) return null;
25944
- try {
25945
- const storage = window.localStorage;
25946
- if (hostId2 === "local") return storage;
25947
- const scopedKey = (key) => `${key}.host.${encodeURIComponent(hostId2)}`;
25948
- return {
25949
- getItem: (key) => storage.getItem(scopedKey(key)),
25950
- setItem: (key, value) => storage.setItem(scopedKey(key), value)
25951
- };
25952
- } catch {
25953
- return null;
25954
- }
25955
- }
25956
- function isRecord14(value) {
25957
- return typeof value === "object" && value !== null && !Array.isArray(value);
25958
- }
25959
- function parseExternalConfiguration(value) {
25960
- if (!isRecord14(value)) return void 0;
25961
- const model2 = harnessModelRefSchema.safeParse(value.model);
25962
- if (!model2.success) return void 0;
25963
- const thinkingOptionId = harnessThinkingOptionIdSchema.safeParse(value.thinkingOptionId);
25964
- const permissionModeId = harnessPermissionModeIdSchema.safeParse(value.permissionModeId);
25965
- return {
25966
- model: model2.data,
25967
- ...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {},
25968
- ...permissionModeId.success ? { permissionModeId: permissionModeId.data } : {}
25969
- };
25970
- }
25971
- function readPreference(storage) {
25972
- if (!storage) return void 0;
25973
- try {
25974
- const raw = storage.getItem(RENDERER_NEW_THREAD_PREFERENCE_KEY);
25975
- if (!raw) return void 0;
25976
- const parsed = JSON.parse(raw);
25977
- if (!isRecord14(parsed) || parsed.version !== 1) return void 0;
25978
- if (parsed.lastAgent !== "codex" && !harnessPluginIdSchema.safeParse(parsed.lastAgent).success)
25979
- return void 0;
25980
- const externalByAgent = isRecord14(parsed.externalByAgent) ? parsed.externalByAgent : {};
25981
- const parsedExternal = Object.fromEntries(
25982
- Object.keys(externalByAgent).filter((agent) => harnessPluginIdSchema.safeParse(agent).success).flatMap((agent) => {
25983
- const configuration = parseExternalConfiguration(externalByAgent[agent]);
25984
- return configuration ? [[agent, configuration]] : [];
25985
- })
25986
- );
25987
- return {
25988
- version: 1,
25989
- lastAgent: parsed.lastAgent,
25990
- externalByAgent: parsedExternal
25991
- };
25992
- } catch {
25993
- return void 0;
25994
- }
25995
- }
25996
- function writePreference(preference, storage) {
25997
- if (!storage) return;
25998
- try {
25999
- storage.setItem(RENDERER_NEW_THREAD_PREFERENCE_KEY, JSON.stringify(preference));
26000
- } catch {
26001
- }
26002
- }
26003
- function readNewThreadAgentPreference(enabledAgents, storage = rendererNewThreadPreferenceStorage()) {
26004
- const agent = readPreference(storage)?.lastAgent;
26005
- return agent && (!enabledAgents || enabledAgents.has(agent)) ? agent : void 0;
26006
- }
26007
- function readNewThreadExternalConfigurationPreference(agent, catalog, permissionModes, storage = rendererNewThreadPreferenceStorage()) {
26008
- const preference = readPreference(storage)?.externalByAgent[agent];
26009
- if (!preference) return void 0;
26010
- const catalogModel = catalogModelForRef(catalog, preference.model);
26011
- if (!catalogModel) return void 0;
26012
- const thinkingOptionId = preference.thinkingOptionId && catalogModel.supportedThinkingOptionIds?.includes(preference.thinkingOptionId) ? preference.thinkingOptionId : void 0;
26013
- const permissionModeId = preference.permissionModeId && permissionModes?.modes.some(({ id }) => id === preference.permissionModeId) ? preference.permissionModeId : void 0;
26014
- return {
26015
- model: catalogModel.ref,
26016
- ...thinkingOptionId ? { thinkingOptionId } : {},
26017
- ...permissionModeId ? { permissionModeId } : {}
26018
- };
26019
- }
26020
- function writeNewThreadAgentPreference(agent, storage = rendererNewThreadPreferenceStorage()) {
26021
- const current = readPreference(storage);
26022
- writePreference(
26023
- {
26024
- version: 1,
26025
- lastAgent: agent,
26026
- externalByAgent: current?.externalByAgent ?? {}
26027
- },
26028
- storage
26029
- );
26030
- }
26031
- function writeNewThreadExternalConfigurationPreference(agent, model2, thinkingOptionId, permissionModeId, storage = rendererNewThreadPreferenceStorage()) {
26032
- const current = readPreference(storage);
26033
- writePreference(
26034
- {
26035
- version: 1,
26036
- lastAgent: current?.lastAgent ?? "codex",
26037
- externalByAgent: {
26038
- ...current?.externalByAgent,
26039
- [agent]: {
26040
- model: harnessModelRefSchema.parse(model2),
26041
- ...thinkingOptionId ? { thinkingOptionId: harnessThinkingOptionIdSchema.parse(thinkingOptionId) } : {},
26042
- ...permissionModeId ? { permissionModeId: harnessPermissionModeIdSchema.parse(permissionModeId) } : {}
26043
- }
26044
- }
26045
- },
26046
- storage
26047
- );
26048
- }
26049
-
26050
26910
  // src/renderer-harness-command-claim.ts
26051
26911
  function inputEvent(editor, text) {
26052
26912
  const view = editor.ownerDocument.defaultView;
@@ -26152,7 +27012,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26152
27012
  return Promise.reject(new Error("Codex locale bridge is unavailable"));
26153
27013
  }
26154
27014
  if (signal?.aborted) return Promise.reject(abortError2());
26155
- const requestId = ownerWindow.crypto.randomUUID();
27015
+ const requestId2 = ownerWindow.crypto.randomUUID();
26156
27016
  return new Promise((resolve, reject) => {
26157
27017
  let settled = false;
26158
27018
  const cleanup = () => {
@@ -26170,7 +27030,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26170
27030
  const onMessage = (event) => {
26171
27031
  const message3 = event.data;
26172
27032
  if (!isRecord15(message3) || message3.type !== "fetch-response") return;
26173
- if (message3.requestId !== requestId) return;
27033
+ if (message3.requestId !== requestId2) return;
26174
27034
  if (message3.responseType !== "success" || typeof message3.status !== "number" || message3.status < 200 || message3.status >= 300 || typeof message3.bodyJsonString !== "string") {
26175
27035
  settle(() => reject(new Error("Codex locale request failed")));
26176
27036
  return;
@@ -26190,7 +27050,7 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26190
27050
  signal?.addEventListener("abort", onAbort, { once: true });
26191
27051
  const message2 = {
26192
27052
  type: "fetch",
26193
- requestId,
27053
+ requestId: requestId2,
26194
27054
  method: "POST",
26195
27055
  url: request.url,
26196
27056
  ...request.body === void 0 ? {} : { body: request.body },
@@ -26304,6 +27164,518 @@ ${text.includes("## My request:") ? "" : "\n## My request:\n"}`,
26304
27164
  return element;
26305
27165
  }
26306
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
+
26307
27679
  // src/console/usage/model-labels.ts
26308
27680
  function usageModelLabel(model2, labels, harness2) {
26309
27681
  const names = new Set(
@@ -28631,6 +30003,12 @@ ${detail}` : ""}`
28631
30003
  stopped: "codexhost is not running",
28632
30004
  stoppedDetail: "Start codexhost to use Codex Desktop with your Harnesses.",
28633
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.",
28634
30012
  starting: "Starting\u2026",
28635
30013
  startingTitle: "codexhost is starting",
28636
30014
  startingDetail: "Preparing Codex Desktop. Please wait; there is no need to start it again.",
@@ -28814,6 +30192,12 @@ ${detail}` : ""}`
28814
30192
  stopped: "codexhost \u672A\u8FD0\u884C",
28815
30193
  stoppedDetail: "\u542F\u52A8 codexhost \u540E\u5373\u53EF\u5728 Codex Desktop \u4E2D\u4F7F\u7528\u5404\u4E2A Harness\u3002",
28816
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",
28817
30201
  starting: "\u6B63\u5728\u542F\u52A8\u2026",
28818
30202
  startingTitle: "codexhost \u6B63\u5728\u542F\u52A8",
28819
30203
  startingDetail: "\u6B63\u5728\u51C6\u5907 Codex Desktop\uFF0C\u8BF7\u7A0D\u5019\uFF0C\u65E0\u9700\u91CD\u590D\u542F\u52A8\u3002",
@@ -29343,104 +30727,6 @@ ${detail}` : ""}`
29343
30727
  return card;
29344
30728
  }
29345
30729
 
29346
- // src/settings/preference-ui.ts
29347
- var nextPreferenceId = 0;
29348
- function preferenceId(prefix) {
29349
- nextPreferenceId += 1;
29350
- return `codexhost-${prefix}-${nextPreferenceId}`;
29351
- }
29352
- function createPreferenceGroup(document2, title) {
29353
- const group = document2.createElement("section");
29354
- group.className = "mt-7 first-of-type:mt-0";
29355
- const header = document2.createElement("div");
29356
- header.className = "mb-2 flex min-h-6 items-center gap-2 px-1";
29357
- const heading = document2.createElement("h3");
29358
- heading.id = preferenceId("preference-group");
29359
- heading.className = "m-0 text-[13px] leading-5 font-semibold text-settings-text";
29360
- heading.textContent = title;
29361
- header.append(heading);
29362
- const card = document2.createElement("div");
29363
- card.className = "rounded-[10px] border border-settings-border bg-settings-panel";
29364
- group.setAttribute("aria-labelledby", heading.id);
29365
- group.append(header, card);
29366
- return { group, header, card };
29367
- }
29368
- function createPreferenceItem(document2, input) {
29369
- const item = document2.createElement("div");
29370
- 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";
29371
- const copy = document2.createElement("div");
29372
- copy.className = "flex min-w-0 flex-col gap-0.5";
29373
- const heading = document2.createElement("div");
29374
- heading.className = "flex items-center gap-1.5";
29375
- const title = document2.createElement("label");
29376
- title.htmlFor = input.controlId;
29377
- title.className = "cursor-pointer text-[13px] leading-5 font-medium text-settings-text";
29378
- title.textContent = input.title;
29379
- heading.append(title);
29380
- if (input.help) heading.append(createHelpTooltip(document2, input.help.label, input.help.lines));
29381
- const description = document2.createElement("div");
29382
- description.id = preferenceId("preference-description");
29383
- description.className = "text-xs leading-[18px] text-settings-muted data-[invalid=true]:text-settings-danger";
29384
- description.textContent = input.description;
29385
- copy.append(heading, description);
29386
- item.append(copy);
29387
- return { item, description };
29388
- }
29389
- function createHelpTooltip(document2, label, lines) {
29390
- const wrapper = document2.createElement("span");
29391
- wrapper.className = "group relative inline-flex";
29392
- const button2 = document2.createElement("button");
29393
- button2.type = "button";
29394
- 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";
29395
- button2.setAttribute("aria-label", label);
29396
- button2.append(createRendererSettingsIcon("help", 14));
29397
- const tooltip = document2.createElement("div");
29398
- tooltip.id = preferenceId("preference-tooltip");
29399
- tooltip.setAttribute("role", "tooltip");
29400
- 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";
29401
- const list = document2.createElement("ul");
29402
- list.className = "m-0 grid list-disc gap-1 pl-4 marker:text-settings-subtle";
29403
- for (const line of lines) {
29404
- const item = document2.createElement("li");
29405
- item.textContent = line;
29406
- list.append(item);
29407
- }
29408
- tooltip.append(list);
29409
- button2.setAttribute("aria-describedby", tooltip.id);
29410
- button2.addEventListener("keydown", (event) => {
29411
- if (event.key === "Escape") button2.blur();
29412
- });
29413
- wrapper.append(button2, tooltip);
29414
- return wrapper;
29415
- }
29416
- function createPreferenceSwitch(document2, id, describedBy) {
29417
- const input = document2.createElement("input");
29418
- input.type = "checkbox";
29419
- input.id = id;
29420
- input.setAttribute("role", "switch");
29421
- input.setAttribute("aria-describedby", describedBy);
29422
- 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";
29423
- return input;
29424
- }
29425
- function createNumberField(document2, input) {
29426
- const field = document2.createElement("div");
29427
- 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";
29428
- const control = document2.createElement("input");
29429
- control.type = "number";
29430
- control.id = input.id;
29431
- control.min = String(input.min);
29432
- control.max = String(input.max);
29433
- control.step = "1";
29434
- control.setAttribute("aria-describedby", input.describedBy);
29435
- control.className = "w-14 border-0 bg-transparent p-0 text-right text-[13px] leading-5 text-settings-text tabular-nums outline-none";
29436
- const unit = document2.createElement("span");
29437
- unit.className = "text-xs text-settings-muted";
29438
- unit.setAttribute("aria-hidden", "true");
29439
- unit.textContent = input.unit;
29440
- field.append(control, unit);
29441
- return { field, control };
29442
- }
29443
-
29444
30730
  // src/settings/remote-connections-dialogs.ts
29445
30731
  function createRemoteDialog({ container, signal, t }, title) {
29446
30732
  if (signal.aborted || container.querySelector("dialog")) return null;
@@ -31120,31 +32406,6 @@ ${detail}` : ""}`
31120
32406
  ownerWindow.addEventListener(CODEX_USAGE_BANNER_CHANGE_EVENT, syncUsageBanner);
31121
32407
  usageBannerRow.item.append(usageBanner);
31122
32408
  card.append(usageBannerRow.item);
31123
- const liveVoiceId = preferenceId("cpa-live-voice");
31124
- const liveVoiceRow = createPreferenceItem(document2, {
31125
- title: messages.cpaLiveVoiceTitle,
31126
- description: messages.cpaLiveVoiceDescription,
31127
- controlId: liveVoiceId,
31128
- help: { label: messages.cpaLiveVoiceHelpLabel, lines: messages.cpaLiveVoiceHelp }
31129
- });
31130
- const liveVoice = createPreferenceSwitch(document2, liveVoiceId, liveVoiceRow.description.id);
31131
- liveVoice.checked = readCpaLiveVoicePreference(ownerWindow);
31132
- liveVoice.addEventListener("change", () => {
31133
- writeCpaLiveVoicePreference(ownerWindow, liveVoice.checked);
31134
- });
31135
- const syncLiveVoice = () => {
31136
- liveVoice.checked = readCpaLiveVoicePreference(ownerWindow);
31137
- };
31138
- ownerWindow.addEventListener(CPA_LIVE_VOICE_CHANGE_EVENT, syncLiveVoice);
31139
- liveVoiceRow.item.append(liveVoice);
31140
- if (!readCpaLiveVoiceHookConfig(ownerWindow)) {
31141
- const warning = document2.createElement("div");
31142
- warning.className = "text-xs leading-[18px] text-settings-warning";
31143
- warning.setAttribute("role", "status");
31144
- warning.textContent = messages.cpaLiveVoiceRestartRequired;
31145
- liveVoiceRow.description.after(warning);
31146
- }
31147
- card.append(liveVoiceRow.item);
31148
32409
  const softWrapId = preferenceId("reasoning-soft-wrap");
31149
32410
  const row = createPreferenceItem(document2, {
31150
32411
  title: messages.reasoningSoftWrapTitle,
@@ -31170,7 +32431,6 @@ ${detail}` : ""}`
31170
32431
  );
31171
32432
  return () => {
31172
32433
  ownerWindow.removeEventListener(CODEX_USAGE_BANNER_CHANGE_EVENT, syncUsageBanner);
31173
- ownerWindow.removeEventListener(CPA_LIVE_VOICE_CHANGE_EVENT, syncLiveVoice);
31174
32434
  ownerWindow.removeEventListener(REASONING_SOFT_WRAP_CHANGE_EVENT, sync);
31175
32435
  disposeIdleRelease();
31176
32436
  };
@@ -31403,7 +32663,7 @@ ${detail}` : ""}`
31403
32663
  }
31404
32664
  function defaultImportName(source, existing) {
31405
32665
  const base = source.provider === "openai-codex" ? "codex" : "grok";
31406
- const used = new Set(existing.map((record5) => record5.name));
32666
+ const used = new Set(existing.map((record6) => record6.name));
31407
32667
  const valid = (name) => credentialImportNameSchema.safeParse(name).success;
31408
32668
  if (!used.has(base)) return base;
31409
32669
  const local = source.label.includes("@") ? source.label.split("@")[0] ?? "" : "";
@@ -31426,7 +32686,7 @@ ${detail}` : ""}`
31426
32686
  const shown = (text) => accountDisplayText(text, hideEmails);
31427
32687
  const targetButtons = /* @__PURE__ */ new Map();
31428
32688
  const importedRecords = () => snapshot.targets.find((target) => target.harnessId === TARGET_HARNESS_ID)?.imports ?? [];
31429
- 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);
31430
32690
  const piTarget = () => snapshot.targets.find((candidate) => candidate.harnessId === TARGET_HARNESS_ID);
31431
32691
  const compatibleSources = () => {
31432
32692
  const target = piTarget();
@@ -31464,7 +32724,7 @@ ${detail}` : ""}`
31464
32724
  sectionImport.addEventListener("click", () => {
31465
32725
  const sources = compatibleSources();
31466
32726
  const free = sources.find(
31467
- (source2) => !importedRecords().some((record5) => record5.source.id === source2.id)
32727
+ (source2) => !importedRecords().some((record6) => record6.source.id === source2.id)
31468
32728
  );
31469
32729
  const source = free ?? sources[0];
31470
32730
  if (source) openDialog("add", { source, choose: true }, SECTION_IMPORT_KEY);
@@ -31514,30 +32774,30 @@ ${detail}` : ""}`
31514
32774
  mark.append(createRendererAgentIcon(agent ?? "pi", 26, document2, pluginFor(agent ?? "pi")));
31515
32775
  return mark;
31516
32776
  };
31517
- const renderRow = (record5) => {
32777
+ const renderRow = (record6) => {
31518
32778
  const row = document2.createElement("div");
31519
32779
  row.className = "settings-pi-accounts__row";
31520
32780
  row.tabIndex = -1;
31521
- row.dataset.importName = record5.name;
31522
- row.setAttribute("aria-label", shown(record5.source.label));
31523
- 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;
31524
32784
  const mark = createMark(agent);
31525
32785
  const identity = document2.createElement("div");
31526
32786
  identity.className = "settings-pi-accounts__identity";
31527
32787
  const label = document2.createElement("strong");
31528
32788
  label.className = "settings-account-email";
31529
- label.textContent = shown(record5.source.label);
32789
+ label.textContent = shown(record6.source.label);
31530
32790
  label.title = label.textContent;
31531
32791
  label.translate = false;
31532
32792
  const meta3 = document2.createElement("div");
31533
32793
  meta3.className = "settings-account-metadata";
31534
- const source = sourceOf(record5);
32794
+ const source = sourceOf(record6);
31535
32795
  const parts = [
31536
32796
  metaPart(rendererAgentLabel(agent, pluginFor(agent)), "settings-pi-accounts__agent"),
31537
- metaPart(`${record5.name}/\u2026`, void 0, true),
32797
+ metaPart(`${record6.name}/\u2026`, void 0, true),
31538
32798
  metaPart(messages.copied)
31539
32799
  ];
31540
- const time3 = formatImportedAt(record5.importedAt);
32800
+ const time3 = formatImportedAt(record6.importedAt);
31541
32801
  if (time3) parts.push(metaPart(time3));
31542
32802
  parts.forEach((part, index) => {
31543
32803
  if (index > 0) {
@@ -31554,23 +32814,23 @@ ${detail}` : ""}`
31554
32814
  reimport.type = "button";
31555
32815
  reimport.className = "settings-account-action";
31556
32816
  reimport.textContent = messages.rowReimport;
31557
- reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record5.source.label)}`);
32817
+ reimport.setAttribute("aria-label", `${messages.reimport}: ${shown(record6.source.label)}`);
31558
32818
  reimport.disabled = busy || !source;
31559
32819
  reimport.title = messages.reimport;
31560
32820
  reimport.addEventListener("click", () => {
31561
- if (source) openDialog("reimport", { source, record: record5 }, `row:${record5.name}`);
32821
+ if (source) openDialog("reimport", { source, record: record6 }, `row:${record6.name}`);
31562
32822
  });
31563
32823
  const remove = document2.createElement("button");
31564
32824
  remove.type = "button";
31565
32825
  remove.className = "settings-account-action settings-pi-accounts__remove";
31566
32826
  remove.textContent = messages.rowRemove;
31567
- remove.setAttribute("aria-label", `${messages.remove}: ${shown(record5.source.label)}`);
32827
+ remove.setAttribute("aria-label", `${messages.remove}: ${shown(record6.source.label)}`);
31568
32828
  remove.disabled = busy;
31569
- remove.addEventListener("click", () => openDialog("remove", { record: record5 }, `row:${record5.name}`));
32829
+ remove.addEventListener("click", () => openDialog("remove", { record: record6 }, `row:${record6.name}`));
31570
32830
  if (source) actions.append(reimport);
31571
32831
  actions.append(remove);
31572
32832
  row.append(mark, identity, actions);
31573
- rows.set(record5.name, row);
32833
+ rows.set(record6.name, row);
31574
32834
  return row;
31575
32835
  };
31576
32836
  const loginTypeLabel = (type) => type === "oauth" ? messages.typeOauth : type === "api_key" ? messages.typeApiKey : messages.typeOther;
@@ -31723,7 +32983,7 @@ ${detail}` : ""}`
31723
32983
  const label = document2.createElement("strong");
31724
32984
  label.textContent = shown(choice.label);
31725
32985
  label.translate = false;
31726
- const existing = importedRecords().find((record5) => record5.source.id === choice.id);
32986
+ const existing = importedRecords().find((record6) => record6.source.id === choice.id);
31727
32987
  const agent = choice.harnessId;
31728
32988
  const detail = document2.createElement("span");
31729
32989
  detail.textContent = [
@@ -31764,7 +33024,7 @@ ${detail}` : ""}`
31764
33024
  const name = request.action === "list" ? void 0 : request.name;
31765
33025
  state = {
31766
33026
  source: state.source,
31767
- record: importedRecords().find((record5) => record5.name === name) ?? state.record
33027
+ record: importedRecords().find((record6) => record6.name === name) ?? state.record
31768
33028
  };
31769
33029
  show(next);
31770
33030
  } else {
@@ -31778,12 +33038,12 @@ ${detail}` : ""}`
31778
33038
  sourceRadios = [];
31779
33039
  body.replaceChildren();
31780
33040
  controls.replaceChildren();
31781
- const { source, record: record5 } = state;
33041
+ const { source, record: record6 } = state;
31782
33042
  const close = () => modal.close();
31783
33043
  if (mode === "add" || mode === "reimport") {
31784
33044
  title.textContent = mode === "add" ? messages.add : messages.reimport;
31785
33045
  modal.setAttribute("aria-label", title.textContent);
31786
- const active = source ?? record5?.source;
33046
+ const active = source ?? record6?.source;
31787
33047
  const choices = mode === "add" && state.choose ? compatibleSources() : [];
31788
33048
  if (choices.length > 1) body.append(sourcePicker(choices));
31789
33049
  else if (active) body.append(line(messages.source, shown(active.label)));
@@ -31792,8 +33052,8 @@ ${detail}` : ""}`
31792
33052
  input.maxLength = 48;
31793
33053
  input.autocomplete = "off";
31794
33054
  input.spellcheck = false;
31795
- input.value = record5?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
31796
- input.readOnly = Boolean(record5);
33055
+ input.value = record6?.name ?? (source ? defaultImportName(source, importedRecords()) : "codex");
33056
+ input.readOnly = Boolean(record6);
31797
33057
  input.addEventListener("input", () => {
31798
33058
  nameEdited = true;
31799
33059
  });
@@ -31827,7 +33087,7 @@ ${detail}` : ""}`
31827
33087
  {
31828
33088
  action: mode === "reimport" ? "reimport" : "import",
31829
33089
  sourceId: source2.id,
31830
- name: record5?.name ?? input.value,
33090
+ name: record6?.name ?? input.value,
31831
33091
  confirmed: true
31832
33092
  },
31833
33093
  "done"
@@ -31837,16 +33097,16 @@ ${detail}` : ""}`
31837
33097
  )
31838
33098
  );
31839
33099
  (mode === "add" ? input : controls.children[0]).focus();
31840
- } else if (mode === "remove" && record5) {
33100
+ } else if (mode === "remove" && record6) {
31841
33101
  title.textContent = messages.remove;
31842
33102
  modal.setAttribute("aria-label", title.textContent);
31843
- body.append(note(messages.removeWarning.replace("{name}", record5.name)));
33103
+ body.append(note(messages.removeWarning.replace("{name}", record6.name)));
31844
33104
  const cancel = command(messages.cancel, close);
31845
33105
  controls.append(
31846
33106
  cancel,
31847
33107
  command(
31848
33108
  messages.remove,
31849
- () => submit({ action: "remove", name: record5.name, confirmed: true }, null),
33109
+ () => submit({ action: "remove", name: record6.name, confirmed: true }, null),
31850
33110
  "danger"
31851
33111
  )
31852
33112
  );
@@ -31854,7 +33114,7 @@ ${detail}` : ""}`
31854
33114
  } else {
31855
33115
  title.textContent = messages.doneTitle;
31856
33116
  modal.setAttribute("aria-label", title.textContent);
31857
- const name = record5?.name;
33117
+ const name = record6?.name;
31858
33118
  if (name) body.append(line(messages.entry, `${name}/\u2026`, true));
31859
33119
  body.append(note(messages.done));
31860
33120
  const done = command(messages.close, close, "primary");
@@ -31901,21 +33161,21 @@ ${detail}` : ""}`
31901
33161
  (candidate) => candidate.harnessId === TARGET_HARNESS_ID && source && candidate.providers.includes(source.provider)
31902
33162
  );
31903
33163
  if (!source || !target) return null;
31904
- const record5 = target.imports.find((candidate) => candidate.source.id === source.id);
33164
+ const record6 = target.imports.find((candidate) => candidate.source.id === source.id);
31905
33165
  const key = `${harnessId}:${accountLabel}:import`;
31906
33166
  const button2 = document2.createElement("button");
31907
33167
  button2.type = "button";
31908
33168
  button2.className = "settings-account-pi-import";
31909
33169
  button2.dataset.accountFocus = key;
31910
33170
  button2.disabled = busy;
31911
- const hint = record5 ? messages.importedHint.replace("{name}", record5.name) : messages.add;
33171
+ const hint = record6 ? messages.importedHint.replace("{name}", record6.name) : messages.add;
31912
33172
  button2.title = hint;
31913
33173
  button2.setAttribute("aria-label", hint);
31914
33174
  button2.append(createRendererAgentIcon("pi", 12, document2, pluginFor("pi")));
31915
- if (record5) {
33175
+ if (record6) {
31916
33176
  button2.dataset.state = "imported";
31917
33177
  const name = document2.createElement("code");
31918
- name.textContent = `${record5.name}/\u2026`;
33178
+ name.textContent = `${record6.name}/\u2026`;
31919
33179
  name.translate = false;
31920
33180
  button2.append(name, createRendererSettingsIcon("check", 12));
31921
33181
  } else {
@@ -31923,7 +33183,7 @@ ${detail}` : ""}`
31923
33183
  button2.append(messages.add);
31924
33184
  }
31925
33185
  button2.addEventListener("click", () => {
31926
- if (!record5) {
33186
+ if (!record6) {
31927
33187
  openDialog("add", { source }, key);
31928
33188
  return;
31929
33189
  }
@@ -31932,7 +33192,7 @@ ${detail}` : ""}`
31932
33192
  renderSection();
31933
33193
  sectionToggle.setAttribute("aria-expanded", "true");
31934
33194
  }
31935
- const row = rows.get(record5.name);
33195
+ const row = rows.get(record6.name);
31936
33196
  row?.scrollIntoView({ block: "nearest", behavior: "smooth" });
31937
33197
  row?.focus();
31938
33198
  });
@@ -33477,7 +34737,7 @@ ${detail}` : ""}`
33477
34737
  }
33478
34738
  });
33479
34739
  }
33480
- 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"))) {
33481
34741
  return Object.freeze([
33482
34742
  createConnectionsSettingsPage(messages, getDiagnostics, void 0, getRemoteConnections),
33483
34743
  createRemoteConnectionsPage(messages, getRemoteConnections),
@@ -33494,6 +34754,7 @@ ${detail}` : ""}`
33494
34754
  messages.locale
33495
34755
  ),
33496
34756
  createAppearanceSettingsPage(messages, getLoadedSessionsClient),
34757
+ createVoiceSettingsPage(messages.locale, requestVoiceSettings, { desktop: true }),
33497
34758
  updatesPage(messages, getUpdateClient),
33498
34759
  aboutPage(messages, getUpdateClient)
33499
34760
  ]);
@@ -36051,6 +37312,97 @@ ${detail}` : ""}`
36051
37312
  animation: none !important;
36052
37313
  }
36053
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
+ }
36054
37406
  `;
36055
37407
 
36056
37408
  // src/settings/accounts.css
@@ -36942,6 +38294,17 @@ ${detail}` : ""}`
36942
38294
  gap: 8px;
36943
38295
  }
36944
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
+
36945
38308
  .console-muted {
36946
38309
  margin: 0;
36947
38310
  color: var(--settings-muted);
@@ -38099,7 +39462,7 @@ th[aria-sort] .console-usage-sort__mark {
38099
39462
  `;
38100
39463
 
38101
39464
  // src/settings/tailwind.css
38102
- 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';
38103
39466
 
38104
39467
  // src/settings/trigger.ts
38105
39468
  var SETTINGS_TRIGGER_ATTRIBUTE = "data-codexhost-settings-trigger";
@@ -38344,7 +39707,7 @@ th[aria-sort] .console-usage-sort__mark {
38344
39707
  place();
38345
39708
  const observer = ownerWindow ? new ownerWindow.MutationObserver((records) => {
38346
39709
  const titlebar = source?.closest("[data-app-shell-titlebar]");
38347
- if (!source?.isConnected || records.some((record5) => titlebar?.contains(record5.target))) {
39710
+ if (!source?.isConnected || records.some((record6) => titlebar?.contains(record6.target))) {
38348
39711
  place();
38349
39712
  }
38350
39713
  }) : null;
@@ -38778,7 +40141,8 @@ ${usage_default}`;
38778
40141
  },
38779
40142
  options.getLoadedSessionsClient ?? (() => null),
38780
40143
  options.getRemoteConnections ?? (() => null),
38781
- options.requestUsageStatistics
40144
+ options.requestUsageStatistics,
40145
+ options.requestVoiceSettings
38782
40146
  );
38783
40147
  const nextShell = installRendererSettingsShell(definitions, messages, ownerWindow.document, {
38784
40148
  onOpenChange(open) {
@@ -39855,7 +41219,14 @@ ${usage_default}`;
39855
41219
  });
39856
41220
  let connectionDiagnostics = null;
39857
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);
39858
41228
  const settingsLifecycle = installRendererSettingsLifecycle(window, {
41229
+ requestVoiceSettings: (params) => requestLocalSettings("codexhost/voice/settings", params),
39859
41230
  getRemoteConnections: () => remoteConnections,
39860
41231
  getUpdateClient: () => modelControl,
39861
41232
  getAccountClient: () => modelControl,
@@ -41901,6 +43272,7 @@ ${usage_default}`;
41901
43272
  disposeReasoningSoftWrap();
41902
43273
  delegationMention?.dispose();
41903
43274
  sidebarAgentIcons.dispose();
43275
+ stopVoiceSync();
41904
43276
  settingsLifecycle.dispose();
41905
43277
  document.removeEventListener("beforeinput", onBeforeInput, true);
41906
43278
  document.removeEventListener("submit", onSubmit, true);
@@ -41961,14 +43333,16 @@ ${usage_default}`;
41961
43333
  }
41962
43334
 
41963
43335
  // src/renderer-external-voice-launch.ts
41964
- var HOOK_GLOBAL = "__codexhostExternalVoiceLaunchV1";
43336
+ var HOOK_GLOBAL3 = "__codexhostExternalVoiceLaunchV1";
41965
43337
  var SHARED_ASSET = "app-shared-8bd9d0399038.js";
41966
43338
  function isRecord16(value) {
41967
43339
  return typeof value === "object" && value !== null && !Array.isArray(value);
41968
43340
  }
41969
43341
  function routeExternalVoiceLaunch(request, routing) {
43342
+ rememberVoiceProductExperience(request);
41970
43343
  if (!routing || !isRecord16(request) || request.source !== "composer_button_new_thread")
41971
43344
  return request;
43345
+ if (request.productExperience === "chat") return request;
41972
43346
  const hostId2 = request.hostId ?? "local";
41973
43347
  if (typeof hostId2 !== "string" || !hostId2) return request;
41974
43348
  const route = routing.forComposer();
@@ -41994,12 +43368,12 @@ ${usage_default}`;
41994
43368
  }
41995
43369
  function installExternalVoiceLaunchHook(options = {}) {
41996
43370
  const target = options.target ?? globalThis;
41997
- const existing = target[HOOK_GLOBAL];
43371
+ const existing = target[HOOK_GLOBAL3];
41998
43372
  if (existing) return existing;
41999
43373
  const config2 = readCpaLiveVoiceHookConfig(target);
42000
43374
  if (!config2) return { status: "disabled", dispose() {
42001
43375
  } };
42002
- if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION || config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET || config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion)
43376
+ if (config2.auditedDesktopVersion !== AUDITED_CPA_LIVE_VOICE_DESKTOP_VERSION || config2.auditedAppInitialAsset !== AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET || config2.desktopVersion !== void 0 && config2.desktopVersion !== config2.auditedDesktopVersion && config2.desktopVersion !== CLIENT_OWNED_VOICE_VERSION)
42003
43377
  return { status: "unsupported", dispose() {
42004
43378
  } };
42005
43379
  const importModule = options.importModule ?? ((url2) => import(url2));
@@ -42014,22 +43388,22 @@ ${usage_default}`;
42014
43388
  disposed = true;
42015
43389
  if (timer !== void 0) target.clearTimeout(timer);
42016
43390
  restore?.();
42017
- if (target[HOOK_GLOBAL] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL);
43391
+ if (target[HOOK_GLOBAL3] === handle) Reflect.deleteProperty(target, HOOK_GLOBAL3);
42018
43392
  }
42019
43393
  };
42020
- target[HOOK_GLOBAL] = handle;
43394
+ target[HOOK_GLOBAL3] = handle;
42021
43395
  const attempt = async () => {
42022
43396
  if (disposed) return;
42023
43397
  try {
42024
- const names = target.performance?.getEntriesByType("resource").map((entry) => entry.name) ?? [];
42025
- for (const element of target.document?.querySelectorAll("script[src], link[href]") ?? []) {
42026
- const name = element.getAttribute("src") ?? element.getAttribute("href");
42027
- if (name) names.push(name);
42028
- }
42029
- if (auditedAppInitialAssetPresent(names, AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET) && auditedAppInitialAssetPresent(names, SHARED_ASSET)) {
42030
- module ??= await importModule(`app://-/assets/${SHARED_ASSET}`);
43398
+ const names = loadedAssetNames(target.document, target.performance);
43399
+ const clientOwned = auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_INITIAL_ASSET) && auditedAppInitialAssetPresent(names, CLIENT_OWNED_VOICE_SHARED_ASSET);
43400
+ const legacy = auditedAppInitialAssetPresent(names, AUDITED_CPA_LIVE_VOICE_APP_INITIAL_ASSET) && auditedAppInitialAssetPresent(names, SHARED_ASSET);
43401
+ if (clientOwned || legacy) {
43402
+ module ??= await importModule(
43403
+ `app://-/assets/${clientOwned ? CLIENT_OWNED_VOICE_SHARED_ASSET : SHARED_ASSET}`
43404
+ );
42031
43405
  if (disposed) return;
42032
- const services = module?.fN;
43406
+ const services = clientOwned ? module?.Kat : module?.fN;
42033
43407
  if (isRecord16(services)) {
42034
43408
  const original = services.realtimeVoiceRuntime;
42035
43409
  if (typeof original === "function" || isRecord16(original)) {
@@ -42040,6 +43414,8 @@ ${usage_default}`;
42040
43414
  }
42041
43415
  const launch = (...args) => {
42042
43416
  let request = args[0];
43417
+ const chatStart = startNativeChatVoiceForRequest(request, target);
43418
+ if (chatStart) return chatStart;
42043
43419
  try {
42044
43420
  request = routeExternalVoiceLaunch(request, target.__codexhostHostRoutingV1);
42045
43421
  } catch {
@@ -42080,7 +43456,9 @@ ${usage_default}`;
42080
43456
 
42081
43457
  // src/production-entry.ts
42082
43458
  installCpaLiveVoiceHook();
43459
+ installClientOwnedVoiceHook();
42083
43460
  installExternalVoiceLaunchHook();
43461
+ installNativeChatVoiceHook();
42084
43462
  var installBinding = () => {
42085
43463
  installRendererBinding();
42086
43464
  };