glad-web 1.0.22 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/codex/structured-session.js +91 -11
- package/lib/web/index.html +55 -14
- package/package.json +1 -1
|
@@ -5,11 +5,38 @@ const crypto = require('crypto');
|
|
|
5
5
|
const PTYManager = require('../session/pty-manager');
|
|
6
6
|
|
|
7
7
|
const PERMISSION_MODES = new Set(['untrusted', 'on-request', 'never']);
|
|
8
|
+
const SANDBOX_MODES = new Set(['read-only', 'workspace-write', 'danger-full-access']);
|
|
8
9
|
const FALLBACK_EFFORTS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'ultra'];
|
|
9
10
|
|
|
10
11
|
function normalizePermissionMode(value) {
|
|
11
|
-
const mode = String(value || '
|
|
12
|
-
return PERMISSION_MODES.has(mode) ? mode :
|
|
12
|
+
const mode = String(value || 'default');
|
|
13
|
+
return PERMISSION_MODES.has(mode) ? mode : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function normalizeSandboxMode(value) {
|
|
17
|
+
const mode = String(value || 'default');
|
|
18
|
+
return SANDBOX_MODES.has(mode) ? mode : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function sandboxPolicyFor(mode, workingDir, workspaceOptions = {}) {
|
|
22
|
+
if (mode === 'danger-full-access') return { type: 'dangerFullAccess' };
|
|
23
|
+
if (mode === 'read-only') return { type: 'readOnly', networkAccess: false };
|
|
24
|
+
if (mode === 'workspace-write') {
|
|
25
|
+
const roots = Array.isArray(workspaceOptions.writable_roots) ? workspaceOptions.writable_roots : [];
|
|
26
|
+
return { type: 'workspaceWrite', writableRoots: [workingDir, ...roots.filter(root => root !== workingDir)],
|
|
27
|
+
networkAccess: Boolean(workspaceOptions.network_access),
|
|
28
|
+
excludeTmpdirEnvVar: Boolean(workspaceOptions.exclude_tmpdir_env_var),
|
|
29
|
+
excludeSlashTmp: Boolean(workspaceOptions.exclude_slash_tmp) };
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function sandboxModeFromPolicy(policy) {
|
|
35
|
+
const type = typeof policy === 'string' ? policy : policy?.type;
|
|
36
|
+
if (type === 'dangerFullAccess' || type === 'danger-full-access') return 'danger-full-access';
|
|
37
|
+
if (type === 'readOnly' || type === 'read-only') return 'read-only';
|
|
38
|
+
if (type === 'workspaceWrite' || type === 'workspace-write') return 'workspace-write';
|
|
39
|
+
return null;
|
|
13
40
|
}
|
|
14
41
|
|
|
15
42
|
function safeJson(value) {
|
|
@@ -96,6 +123,12 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
96
123
|
this.currentTurnId = null;
|
|
97
124
|
this.currentTurnStartedAt = null;
|
|
98
125
|
this.permissionMode = normalizePermissionMode(options.permissionMode);
|
|
126
|
+
this.sandboxMode = normalizeSandboxMode(options.sandboxMode);
|
|
127
|
+
this.effectivePermissionMode = null;
|
|
128
|
+
this.effectiveSandboxMode = null;
|
|
129
|
+
this.configPermissionMode = null;
|
|
130
|
+
this.configSandboxMode = null;
|
|
131
|
+
this.configSandboxWorkspaceWrite = {};
|
|
99
132
|
this.model = options.model || null;
|
|
100
133
|
this.effort = options.effort || null;
|
|
101
134
|
this.models = [];
|
|
@@ -135,7 +168,9 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
135
168
|
}
|
|
136
169
|
|
|
137
170
|
getControlState() {
|
|
138
|
-
return { permissionMode: this.permissionMode,
|
|
171
|
+
return { permissionMode: this.permissionMode || 'default', sandboxMode: this.sandboxMode || 'default',
|
|
172
|
+
effectivePermissionMode: this.effectivePermissionMode, effectiveSandboxMode: this.effectiveSandboxMode,
|
|
173
|
+
model: this.model, effort: this.effort,
|
|
139
174
|
status: this.status, threadId: this.threadId, presentation: this.presentation,
|
|
140
175
|
canAbort: this.presentation === 'structured' && this.status !== 'idle',
|
|
141
176
|
canSwitchToTerminal: this.presentation === 'structured' && this.status === 'idle' && Boolean(this.threadId),
|
|
@@ -209,6 +244,7 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
209
244
|
lines.on('line', line => this.handleRpcLine(line));
|
|
210
245
|
this.request('initialize', { clientInfo: { name: 'glad-web', title: 'Glad', version: '1.0' }, capabilities: { experimentalApi: true } })
|
|
211
246
|
.then(async () => {
|
|
247
|
+
try { await this.refreshConfigDefaults(); } catch (error) { this.logger.debugInfo?.(`[codex-app-server] config/read failed: ${error.message}`); }
|
|
212
248
|
try { await this.refreshModels(); } catch (error) { this.logger.debugInfo?.(`[codex-app-server] model/list failed: ${error.message}`); }
|
|
213
249
|
resolve();
|
|
214
250
|
}).catch(fail);
|
|
@@ -330,7 +366,8 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
330
366
|
const settings = params.threadSettings || {};
|
|
331
367
|
this.model = settings.model || this.model;
|
|
332
368
|
this.effort = settings.effort || this.effort;
|
|
333
|
-
this.
|
|
369
|
+
this.effectivePermissionMode = settings.approvalPolicy || this.effectivePermissionMode;
|
|
370
|
+
this.effectiveSandboxMode = sandboxModeFromPolicy(settings.sandboxPolicy) || this.effectiveSandboxMode;
|
|
334
371
|
this.emitEvent({ type: 'state', state: this.getControlState() });
|
|
335
372
|
return;
|
|
336
373
|
}
|
|
@@ -405,6 +442,18 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
405
442
|
return models;
|
|
406
443
|
}
|
|
407
444
|
|
|
445
|
+
async refreshConfigDefaults() {
|
|
446
|
+
const result = await this.request('config/read', { cwd: this.workingDir, includeLayers: false });
|
|
447
|
+
const config = result?.config || {};
|
|
448
|
+
this.configPermissionMode = config.approval_policy || null;
|
|
449
|
+
this.configSandboxMode = normalizeSandboxMode(config.sandbox_mode);
|
|
450
|
+
this.configSandboxWorkspaceWrite = config.sandbox_workspace_write || {};
|
|
451
|
+
if (!this.permissionMode) this.effectivePermissionMode = this.configPermissionMode;
|
|
452
|
+
if (!this.sandboxMode) this.effectiveSandboxMode = this.configSandboxMode;
|
|
453
|
+
this.emitEvent({ type: 'state', state: this.getControlState() });
|
|
454
|
+
return config;
|
|
455
|
+
}
|
|
456
|
+
|
|
408
457
|
async listResumeThreads() {
|
|
409
458
|
await this.ensureProcess();
|
|
410
459
|
const result = await this.request('thread/list', {
|
|
@@ -427,11 +476,30 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
427
476
|
|
|
428
477
|
async updateSettings(settings = {}) {
|
|
429
478
|
if (settings.permissionMode !== undefined) this.permissionMode = normalizePermissionMode(settings.permissionMode);
|
|
479
|
+
if (settings.sandboxMode !== undefined) this.sandboxMode = normalizeSandboxMode(settings.sandboxMode);
|
|
430
480
|
if (settings.model !== undefined) this.model = settings.model || null;
|
|
431
481
|
if (settings.effort !== undefined) this.effort = settings.effort || null;
|
|
482
|
+
const needsConfigDefaults = (settings.permissionMode !== undefined && !this.permissionMode)
|
|
483
|
+
|| (settings.sandboxMode !== undefined && !this.sandboxMode);
|
|
484
|
+
if (needsConfigDefaults && this.presentation === 'structured') {
|
|
485
|
+
await this.ensureProcess();
|
|
486
|
+
await this.refreshConfigDefaults();
|
|
487
|
+
}
|
|
432
488
|
if (this.threadId && this.presentation === 'structured') {
|
|
433
489
|
await this.ensureProcess();
|
|
434
|
-
|
|
490
|
+
const params = { threadId: this.threadId };
|
|
491
|
+
if (settings.permissionMode !== undefined) {
|
|
492
|
+
const approvalPolicy = this.permissionMode || this.configPermissionMode;
|
|
493
|
+
if (approvalPolicy) params.approvalPolicy = approvalPolicy;
|
|
494
|
+
}
|
|
495
|
+
if (settings.sandboxMode !== undefined) {
|
|
496
|
+
const sandboxPolicy = sandboxPolicyFor(this.sandboxMode || this.configSandboxMode, this.workingDir,
|
|
497
|
+
this.sandboxMode ? {} : this.configSandboxWorkspaceWrite);
|
|
498
|
+
if (sandboxPolicy) params.sandboxPolicy = sandboxPolicy;
|
|
499
|
+
}
|
|
500
|
+
if (settings.model !== undefined) params.model = this.model;
|
|
501
|
+
if (settings.effort !== undefined) params.effort = this.effort;
|
|
502
|
+
if (Object.keys(params).length > 1) await this.request('thread/settings/update', params);
|
|
435
503
|
}
|
|
436
504
|
this.emitEvent({ type: 'state', state: this.getControlState() });
|
|
437
505
|
return this.getControlState();
|
|
@@ -444,17 +512,24 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
444
512
|
this.append({ kind: 'user', text: prompt });
|
|
445
513
|
await this.ensureProcess();
|
|
446
514
|
if (!this.threadId) {
|
|
447
|
-
const
|
|
515
|
+
const params = { model: this.model, cwd: this.workingDir };
|
|
516
|
+
if (this.permissionMode) params.approvalPolicy = this.permissionMode;
|
|
517
|
+
if (this.sandboxMode) params.sandbox = this.sandboxMode;
|
|
518
|
+
const started = await this.request('thread/start', params);
|
|
448
519
|
this.threadId = started.thread?.id;
|
|
449
520
|
this.model = started.model || this.model;
|
|
450
521
|
this.effort = started.reasoningEffort || this.effort;
|
|
522
|
+
this.effectivePermissionMode = started.approvalPolicy || this.effectivePermissionMode;
|
|
523
|
+
this.effectiveSandboxMode = sandboxModeFromPolicy(started.sandbox) || this.effectiveSandboxMode;
|
|
451
524
|
this.emitEvent({ type: 'state', state: this.getControlState() });
|
|
452
525
|
}
|
|
453
526
|
this.setStatus('running');
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
527
|
+
const params = { threadId: this.threadId, input: [{ type: 'text', text: prompt }], cwd: this.workingDir,
|
|
528
|
+
model: this.model, effort: this.effort, summary: 'auto' };
|
|
529
|
+
if (this.permissionMode) params.approvalPolicy = this.permissionMode;
|
|
530
|
+
const sandboxPolicy = sandboxPolicyFor(this.sandboxMode, this.workingDir);
|
|
531
|
+
if (sandboxPolicy) params.sandboxPolicy = sandboxPolicy;
|
|
532
|
+
const started = await this.request('turn/start', params);
|
|
458
533
|
this.currentTurnId = started?.turn?.id || started?.turnId || this.currentTurnId;
|
|
459
534
|
return true;
|
|
460
535
|
}
|
|
@@ -521,9 +596,14 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
521
596
|
const target = String(threadId || this.threadId || '').trim();
|
|
522
597
|
if (!target || this.presentation !== 'structured' || this.status !== 'idle') return false;
|
|
523
598
|
await this.ensureProcess();
|
|
524
|
-
const
|
|
599
|
+
const params = { threadId: target, model: this.model, cwd: this.workingDir };
|
|
600
|
+
if (this.permissionMode) params.approvalPolicy = this.permissionMode;
|
|
601
|
+
if (this.sandboxMode) params.sandbox = this.sandboxMode;
|
|
602
|
+
const result = await this.request('thread/resume', params);
|
|
525
603
|
this.threadId = result.thread?.id || target;
|
|
526
604
|
this.model = result.model || this.model;
|
|
605
|
+
this.effectivePermissionMode = result.approvalPolicy || this.effectivePermissionMode;
|
|
606
|
+
this.effectiveSandboxMode = sandboxModeFromPolicy(result.sandbox) || this.effectiveSandboxMode;
|
|
527
607
|
const history = await this.request('thread/read', { threadId: this.threadId, includeTurns: true });
|
|
528
608
|
this.messages = [];
|
|
529
609
|
this.completedPermissions = [];
|
package/lib/web/index.html
CHANGED
|
@@ -117,8 +117,12 @@
|
|
|
117
117
|
.codex-inline-permission .claude-permission-actions { margin-top: 8px; }
|
|
118
118
|
@keyframes codex-spin { to { transform: rotate(360deg); } }
|
|
119
119
|
#codex-control-panel { display: none; width: min(100%, var(--control-content-max)); margin: 0 auto; padding: 8px 14px 10px; border-bottom: 1px solid #222; background: #121212; box-sizing: border-box; }
|
|
120
|
-
.codex-control-row { display: grid; grid-template-columns: repeat(
|
|
121
|
-
.codex-
|
|
120
|
+
.codex-control-row { display: grid; grid-template-columns: repeat(5, minmax(0, 116px)); justify-content: center; gap: 7px; align-items: center; }
|
|
121
|
+
.codex-control-row > * { width: 100%; }
|
|
122
|
+
.codex-select-control { position: relative; display: block; min-width: 0; height: 32px; }
|
|
123
|
+
.codex-select-label { display: flex; width: 100%; height: 100%; align-items: center; justify-content: center; box-sizing: border-box; border: 1px solid rgba(255,255,255,.1); border-radius: 16px; background: rgba(255,255,255,.08); color: #f5f5f7; font-size: 11px; font-weight: 800; white-space: nowrap; }
|
|
124
|
+
.codex-select-control:focus-within .codex-select-label { background: rgba(255,255,255,.14); border-color: rgba(0,122,255,.45); }
|
|
125
|
+
.codex-select { appearance: none; position: absolute; inset: 0; width: 100%; min-width: 0; height: 100%; opacity: 0; cursor: pointer; }
|
|
122
126
|
.codex-select option { background: #1c1c1e; color: #fff; }
|
|
123
127
|
#codex-model-panel, #codex-resume-panel { display: none; margin-top: 8px; border: 1px solid rgba(255,255,255,.1); background: rgba(28,28,30,.99); border-radius: 8px; box-shadow: 0 16px 36px rgba(0,0,0,.34); overflow: hidden; }
|
|
124
128
|
#codex-model-panel.active, #codex-resume-panel.active { display: block; }
|
|
@@ -128,7 +132,8 @@
|
|
|
128
132
|
.codex-picker-column + .codex-picker-column { border-left: 1px solid rgba(255,255,255,.08); }
|
|
129
133
|
.codex-picker-option { display: block; width: 100%; min-height: 38px; padding: 8px 10px; border: 0; border-bottom: 1px solid rgba(255,255,255,.06); background: transparent; color: #f5f5f7; text-align: left; font-size: 12px; font-weight: 700; overflow-wrap: anywhere; }
|
|
130
134
|
.codex-picker-option.selected { background: rgba(0,122,255,.18); color: #fff; }
|
|
131
|
-
#codex-state-bar { display:
|
|
135
|
+
#codex-state-bar { display: flex; align-items: center; gap: 7px; min-height: 24px; margin-top: 8px; color: var(--text-dim); font-size: 11px; overflow-x: auto; scrollbar-width: none; white-space: nowrap; }
|
|
136
|
+
#codex-state-bar::-webkit-scrollbar { display: none; }
|
|
132
137
|
#codex-resume-panel { max-height: min(280px, 38dvh); overflow-y: auto; }
|
|
133
138
|
.claude-context-size-badge { position: sticky; top: 0; z-index: 2; width: max-content; max-width: 100%; margin: 0 0 8px auto; border: 1px solid rgba(255,255,255,0.1); background: rgba(28,28,30,0.94); border-radius: 999px; padding: 4px 9px; color: #d1d5db; font-size: 11px; font-weight: 800; box-shadow: 0 8px 18px rgba(0,0,0,0.24); }
|
|
134
139
|
.claude-message { max-width: 92%; margin: 0 0 10px 0; padding: 10px 12px; border-radius: 8px; overflow-wrap: anywhere; line-height: 1.45; font-size: 14px; }
|
|
@@ -287,8 +292,10 @@
|
|
|
287
292
|
#nav-bar > div:last-child { gap: 5px !important; }
|
|
288
293
|
#nav-bar > div:last-child .icon-btn { min-width: 34px; min-height: 30px; padding: 5px 7px !important; }
|
|
289
294
|
#input-row { padding-left: 10px; padding-right: 10px; }
|
|
290
|
-
#codex-control-panel { padding-left:
|
|
291
|
-
.codex-control-row { gap:
|
|
295
|
+
#codex-control-panel { padding-left: 8px; padding-right: 8px; }
|
|
296
|
+
.codex-control-row { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 5px; }
|
|
297
|
+
.codex-control-row .claude-ctrl-btn { height: 36px; padding-left: 4px; padding-right: 4px; }
|
|
298
|
+
.codex-select-control { height: 36px; }
|
|
292
299
|
#codex-chat-container { padding: 10px 10px calc(22px + env(safe-area-inset-bottom)); }
|
|
293
300
|
.codex-message.user { max-width: 94%; }
|
|
294
301
|
.claude-permission-actions { justify-content: flex-start; }
|
|
@@ -405,9 +412,18 @@
|
|
|
405
412
|
</div>
|
|
406
413
|
<div id="codex-control-panel">
|
|
407
414
|
<div class="codex-control-row">
|
|
408
|
-
<
|
|
409
|
-
<
|
|
410
|
-
|
|
415
|
+
<label class="codex-select-control" title="Sandbox mode">
|
|
416
|
+
<span class="codex-select-label" aria-hidden="true">Sandbox</span>
|
|
417
|
+
<select id="codex-sandbox-select" class="codex-select" aria-label="Sandbox mode" onchange="updateCodexSettingsFromControls()">
|
|
418
|
+
<option value="default">Default</option><option value="read-only">Read only</option><option value="workspace-write">Workspace write</option><option value="danger-full-access">Full access</option>
|
|
419
|
+
</select>
|
|
420
|
+
</label>
|
|
421
|
+
<label class="codex-select-control" title="Approval policy">
|
|
422
|
+
<span class="codex-select-label" aria-hidden="true">Ask</span>
|
|
423
|
+
<select id="codex-permission-select" class="codex-select" aria-label="Approval policy" onchange="updateCodexSettingsFromControls()">
|
|
424
|
+
<option value="default">Default</option><option value="untrusted">Untrusted</option><option value="on-request">On request</option><option value="never">Never ask</option>
|
|
425
|
+
</select>
|
|
426
|
+
</label>
|
|
411
427
|
<button id="codex-model-btn" class="claude-ctrl-btn" onclick="toggleCodexModelPanel()" title="Model and effort">Model</button>
|
|
412
428
|
<button id="codex-abort-btn" class="claude-ctrl-btn danger" onclick="abortCodexSession()" title="Abort current Codex turn">Abort</button>
|
|
413
429
|
<button id="codex-resume-btn" class="claude-ctrl-btn primary" onclick="toggleCodexResumePanel()" title="Resume a Codex thread">Resume</button>
|
|
@@ -607,7 +623,7 @@
|
|
|
607
623
|
let claudeResumeItemsLoaded = false;
|
|
608
624
|
let codexMessages = [];
|
|
609
625
|
let codexPendingPermissions = [];
|
|
610
|
-
let codexState = { permissionMode: '
|
|
626
|
+
let codexState = { permissionMode: 'default', sandboxMode: 'default', effectivePermissionMode: null, effectiveSandboxMode: null, model: null, effort: null, status: 'idle', threadId: null, presentation: 'structured', models: [], canAbort: false, canSwitchToTerminal: false, canSwitchToStructured: false };
|
|
611
627
|
let codexModelPanelOpen = false;
|
|
612
628
|
let codexModelCandidate = null;
|
|
613
629
|
let codexResumePanelOpen = false;
|
|
@@ -2113,23 +2129,43 @@
|
|
|
2113
2129
|
i += 1;
|
|
2114
2130
|
}
|
|
2115
2131
|
for (const request of codexPendingPermissions) if (!usedPermissions.has(request.id)) parts.push(renderCodexPermission(request));
|
|
2132
|
+
if (codexState.status === 'running') {
|
|
2133
|
+
parts.push('<div class="claude-status">Codex is working...</div>');
|
|
2134
|
+
}
|
|
2116
2135
|
container.innerHTML = `<div class="codex-conversation">${parts.join('') || '<div class="codex-message event">Send a message to start Codex.</div>'}</div>`;
|
|
2117
2136
|
requestAnimationFrame(() => { container.scrollTop = container.scrollHeight; });
|
|
2118
2137
|
}
|
|
2119
2138
|
|
|
2120
2139
|
function applyCodexState(state = {}) {
|
|
2140
|
+
const presentationChanged = state.presentation !== undefined && state.presentation !== codexState.presentation;
|
|
2121
2141
|
codexState = { ...codexState, ...state };
|
|
2122
2142
|
const permission = document.getElementById('codex-permission-select');
|
|
2123
|
-
if (permission)
|
|
2143
|
+
if (permission) {
|
|
2144
|
+
const defaultOption = permission.querySelector('option[value="default"]');
|
|
2145
|
+
const labels = { untrusted: 'Untrusted', 'on-request': 'On request', never: 'Never ask' };
|
|
2146
|
+
if (defaultOption) defaultOption.textContent = codexState.effectivePermissionMode
|
|
2147
|
+
? `Default (${labels[codexState.effectivePermissionMode] || codexState.effectivePermissionMode})`
|
|
2148
|
+
: 'Default';
|
|
2149
|
+
permission.value = codexState.permissionMode || 'default';
|
|
2150
|
+
}
|
|
2151
|
+
const sandbox = document.getElementById('codex-sandbox-select');
|
|
2152
|
+
if (sandbox) {
|
|
2153
|
+
const defaultOption = sandbox.querySelector('option[value="default"]');
|
|
2154
|
+
const labels = { 'read-only': 'Read only', 'workspace-write': 'Workspace write', 'danger-full-access': 'Full access' };
|
|
2155
|
+
if (defaultOption) defaultOption.textContent = codexState.effectiveSandboxMode
|
|
2156
|
+
? `Default (${labels[codexState.effectiveSandboxMode] || codexState.effectiveSandboxMode})`
|
|
2157
|
+
: 'Default';
|
|
2158
|
+
sandbox.value = codexState.sandboxMode || 'default';
|
|
2159
|
+
}
|
|
2124
2160
|
const modelButton = document.getElementById('codex-model-btn');
|
|
2125
|
-
if (modelButton) modelButton.textContent =
|
|
2161
|
+
if (modelButton) modelButton.textContent = 'Model';
|
|
2126
2162
|
const abort = document.getElementById('codex-abort-btn');
|
|
2127
2163
|
if (abort) abort.disabled = !codexState.canAbort;
|
|
2128
2164
|
const terminal = document.getElementById('codex-terminal-switch');
|
|
2129
2165
|
if (terminal) { terminal.textContent = codexState.presentation === 'terminal' ? 'CHAT' : 'TERM'; terminal.disabled = codexState.presentation === 'structured' && !codexState.canSwitchToTerminal; terminal.title = codexState.presentation === 'terminal' ? 'Return to Codex chat' : 'Switch to Codex terminal'; }
|
|
2130
2166
|
renderCodexStateBar();
|
|
2131
2167
|
renderCodexModelPanel();
|
|
2132
|
-
setClaudeModeEnabled(isClaudeSession());
|
|
2168
|
+
if (presentationChanged) setClaudeModeEnabled(isClaudeSession());
|
|
2133
2169
|
renderCodexChat();
|
|
2134
2170
|
}
|
|
2135
2171
|
|
|
@@ -2185,7 +2221,12 @@
|
|
|
2185
2221
|
}
|
|
2186
2222
|
|
|
2187
2223
|
function sendCodexSettings(settings) { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-settings', settings })); }
|
|
2188
|
-
function updateCodexSettingsFromControls() {
|
|
2224
|
+
function updateCodexSettingsFromControls() {
|
|
2225
|
+
const permissionMode = document.getElementById('codex-permission-select').value;
|
|
2226
|
+
const sandboxMode = document.getElementById('codex-sandbox-select').value;
|
|
2227
|
+
applyCodexState({ permissionMode, sandboxMode });
|
|
2228
|
+
sendCodexSettings({ permissionMode, sandboxMode });
|
|
2229
|
+
}
|
|
2189
2230
|
function abortCodexSession() { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-abort' })); }
|
|
2190
2231
|
function respondCodexPermission(id, decision) { if (currentSocket?.readyState === 1) currentSocket.send(JSON.stringify({ type: 'codex-permission', id, decision })); }
|
|
2191
2232
|
async function toggleCodexResumePanel() {
|
|
@@ -2345,7 +2386,7 @@
|
|
|
2345
2386
|
codexResumePanelOpen = false;
|
|
2346
2387
|
document.getElementById('codex-model-panel').classList.remove('active');
|
|
2347
2388
|
document.getElementById('codex-resume-panel').classList.remove('active');
|
|
2348
|
-
codexState = { permissionMode: '
|
|
2389
|
+
codexState = { permissionMode: 'default', sandboxMode: 'default', effectivePermissionMode: null, effectiveSandboxMode: null, model: null, effort: null, status: 'idle', threadId: null, presentation: 'structured', models: [], canAbort: false, canSwitchToTerminal: false, canSwitchToStructured: false };
|
|
2349
2390
|
setClaudeModeEnabled(false);
|
|
2350
2391
|
applyCodexState(codexState);
|
|
2351
2392
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|