diff --git a/public/app.js b/public/app.js index 33f036e..fccd169 100644 --- a/public/app.js +++ b/public/app.js @@ -2,7 +2,7 @@ (function () { 'use strict'; - const ASSET_VERSION = '20260615-reload-mcp'; + const ASSET_VERSION = '20260615-codexapp-steer-status'; const WS_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`; const RENDER_DEBOUNCE = 100; const COMPOSER_SUGGESTION_DEBOUNCE = 120; @@ -3066,7 +3066,16 @@ case 'system_message': if (!isCurrentSessionEvent(msg)) break; - appendSystemMessage(msg.message); + appendSystemMessage(msg.message, { + tone: msg.tone, + transient: msg.transient, + autoDismissMs: msg.autoDismissMs, + }); + break; + + case 'codex_app_steer_status': + if (!isCurrentSessionEvent(msg)) break; + updateCodexAppSteerMessage(msg.clientMessageId, msg.status, msg.message); break; case 'codex_app_user_input_request': @@ -3167,7 +3176,10 @@ break; } if (pendingNewSessionRequest) pendingNewSessionRequest = null; - appendError(msg.message); + appendError(msg.message, { + transient: msg.transient, + autoDismissMs: msg.autoDismissMs, + }); clearSessionLoading(); if (!isGenerating && currentSessionId) { setCurrentSessionRunningState(!!getSessionMeta(currentSessionId)?.isRunning); @@ -3372,6 +3384,54 @@ catch { return escapeHtml(text); } } + function codexAppSteerStatusLabel(status) { + if (status === 'inserted') return '已插入'; + if (status === 'failed') return '插入失败'; + return '引导中...'; + } + + function setCodexAppSteerStatusElement(element, status, message) { + if (!element) return false; + const normalized = ['pending', 'inserted', 'failed'].includes(status) ? status : 'pending'; + element.classList.add('codex-steer-message'); + element.classList.toggle('codex-steer-pending', normalized === 'pending'); + element.classList.toggle('codex-steer-inserted', normalized === 'inserted'); + element.classList.toggle('codex-steer-failed', normalized === 'failed'); + const bubble = element.querySelector('.msg-bubble'); + if (!bubble) return false; + let statusEl = bubble.querySelector('.codex-steer-status'); + if (!statusEl) { + statusEl = document.createElement('div'); + statusEl.className = 'codex-steer-status'; + bubble.appendChild(statusEl); + } + statusEl.dataset.status = normalized; + statusEl.textContent = message || codexAppSteerStatusLabel(normalized); + return true; + } + + function updateCodexAppSteerMessage(clientMessageId, status, message) { + const id = String(clientMessageId || '').trim(); + if (!id) return false; + const indexed = userMessageIndex.get(id); + const element = indexed?.element || messagesDiv.querySelector(`[data-message-id="${cssEscape(id)}"]`); + return setCodexAppSteerStatusElement(element, status, message); + } + + function scheduleTransientMessageRemoval(element, timeoutMs) { + const ttl = Number(timeoutMs); + if (!element || !Number.isFinite(ttl) || ttl <= 0) return; + window.setTimeout(() => { + if (!element || !element.isConnected) return; + element.classList.add('is-dismissing'); + window.setTimeout(() => { + if (!element || !element.isConnected) return; + element.remove(); + updateScrollbar(); + }, 220); + }, ttl); + } + function createMsgElement(role, content, attachments = [], meta = {}) { const div = document.createElement('div'); const isCrossConversation = role === 'user' && !!meta.crossConversation; @@ -3384,13 +3444,20 @@ } if (role === 'system') { + const tone = String(meta.tone || 'neutral').trim() || 'neutral'; const bubble = document.createElement('div'); bubble.className = 'msg-bubble'; + bubble.dataset.tone = tone; const text = document.createElement('span'); text.className = 'system-message-text'; text.textContent = content; bubble.appendChild(text); + const transient = !!meta.transient; + if (transient) { + div.classList.add('transient'); + } + const closeBtn = document.createElement('button'); closeBtn.type = 'button'; closeBtn.className = 'system-message-close'; @@ -3404,6 +3471,9 @@ }); bubble.appendChild(closeBtn); div.appendChild(bubble); + if (transient) { + scheduleTransientMessageRemoval(div, meta.autoDismissMs || 6000); + } return div; } @@ -3489,6 +3559,9 @@ hydrateAttachmentPreviews(bubble, attachments); div.appendChild(avatar); div.appendChild(bubble); + if (role === 'user' && meta.codexAppSteerStatus) { + setCodexAppSteerStatusElement(div, meta.codexAppSteerStatus, meta.codexAppSteerMessage); + } if (role === 'user') { registerUserMessage(resolvedMessageId, div, content); } @@ -4575,19 +4648,19 @@ overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); }); } - function appendSystemMessage(message) { + function appendSystemMessage(message, options = {}) { const welcome = messagesDiv.querySelector('.welcome-msg'); if (welcome) welcome.remove(); - messagesDiv.appendChild(createMsgElement('system', message)); + messagesDiv.appendChild(createMsgElement('system', message, [], options)); scrollToBottom(); } - function appendError(message) { - const div = document.createElement('div'); - div.className = 'msg system'; - div.innerHTML = `