from __future__ import annotations from pathlib import Path ROOT = Path(__file__).resolve().parents[2] WEB = ROOT / "apps" / "web-console" def vue_shell() -> str: return (WEB / "src" / "App.vue").read_text(encoding="utf-8") def test_console_contains_ai_assistant_surface(): html = (WEB / "index.html").read_text(encoding="utf-8") template = vue_shell() vite_entry = (WEB / "src" / "main.js").read_text(encoding="utf-8") assert 'id="assistantTranscript"' in template assert 'id="assistantMessages"' in template assert "你好,我是 AI助手。你可以向我提问" in template assert 'aria-label="AI助手对话"' in template assert 'placeholder="向 AI助手提问或交代工作"' in template assert 'aria-label="发送消息"' in template assert 'import "../assistant-chat.css";' in vite_entry assert 'src="/assistant-chat.js?v=codex-assistant-39-video-media"' in html def test_codex_assistant_assets_are_versioned_together_in_the_service_worker(): service_worker = (ROOT / "apps/web-console/service-worker.js").read_text(encoding="utf-8") assert ( 'const CACHE_VERSION = "cognitive-agent-pad-v336-seat-preset"' in service_worker ) assert '"/assistant-chat.css?v=codex-assistant-30"' in service_worker assert '"/assistant-chat.js?v=codex-assistant-39-video-media"' in service_worker def test_codex_frontend_uses_one_streaming_endpoint_and_agent_work_events(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert '"/api/assistant/stream"' in script assert 'Accept: "application/x-ndjson"' in script assert '"action.started", "action.progress"' in script assert 'event.type === "action.completed"' in script assert 'event.type === "answer.delta"' in script assert '"work.started", "work.progress"' in script assert 'event.type === "work.completed"' in script assert 'event.type === "validated_control_commands"' in script assert '"cognitive-agent:validated-can-commands"' in script assert '"cognitive-agent:control-request-start"' in script assert "speech_utterance_id:" in script assert "speech_value:" in script assert 'Object.prototype.hasOwnProperty.call(event, "answer")' in script assert 'pendingController.abort("user_stop")' in script assert 'signal.addEventListener("abort", cancelReader, { once: true })' in script assert "reader.cancel(signal.reason)" in script assert 'signal.removeEventListener("abort", cancelReader)' in script assert "reader.releaseLock()" in script assert 'if (!answerCompleted) throw new Error("助手响应意外中断,请重试。")' in script assert "event.stopImmediatePropagation()" in script assert "confirmation" not in script.lower() def test_unsupported_control_suggestions_are_clickable_accessible_and_deduplicated(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert 'event.type === "control.suggestions"' in script assert "event.suggestions || event.recommended_commands" in script assert "function normalizeControlSuggestions(rawSuggestions)" in script assert "seenCommands.has(commandKey)" in script assert "MAX_CONTROL_SUGGESTIONS = 4" in script assert "function appendControlSuggestions(message, rawSuggestions)" in script assert 'message.article?.classList.add("assistant-message-control-suggestions")' in script assert 'group.setAttribute("role", "group")' in script assert 'group.setAttribute("aria-label", "可以尝试的其他控制指令")' in script assert 'button.type = "button"' in script assert 'button.setAttribute("aria-label", `执行控制指令:${suggestion.label}`)' in script assert "submitSuggestedCommand(suggestion.command, group, button)" in script assert "setSuggestionGroupPending(group, button, true)" in script assert "await submitAssistant(command)" in script assert ".assistant-control-suggestions" in css assert ".assistant-message-control-suggestions .assistant-message-body" in css assert ".assistant-control-suggestion:focus-visible" in css assert ".assistant-control-suggestion.is-sending" in css def test_validated_controls_are_mirrored_into_a_compact_assistant_card(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert "function appendDispatchedControls(message, result = {})" in script assert "window.CognitiveAgentConsoleV2?.getParsedCanCommands?.(result)" in script assert "fallbackAssistantControlCommands(result)" in script assert 'card.className = "assistant-dispatched-controls"' in script assert 'const headingText = previewOnly ? "控制指令预览(未下发)" : "下发控制指令"' in script assert 'count.className = "assistant-dispatched-controls-count"' in script assert 'list.className = "assistant-dispatched-controls-list"' in script assert "value.textContent = assistantControlValue(item)" in script assert 'return ({ 1: "3档", 2: "1档" })[level]' in script assert '{ 1: "3档(高)", 2: "1档(低)" }' in script assert "语义控制指令:" in script assert "实际控制指令:" in script assert "appendDispatchedControls(message, event.payload)" in script assert "function announceModeExecution(" in script assert "announceModeExecution," in script assert "function beginModeExecution(" in script assert "function completeModeExecution(" in script assert "appendDispatchedControls(message, modeExecutionPreviewResult(profile))" in script assert "beginModeExecution," in script assert "completeModeExecution," in script assert "功能模式部分完成" not in script assert "功能模式指令已提交" in script assert "未由 PC 执行的" in script assert "const operationByRef = new Map()" in script assert 'deliveryState: "submitting"' in script assert 'deliveryLabel: "正在下发"' in script assert '"seat.set_cushion_tilt": "坐盆"' in script assert '"seat.set_backrest_recline": "靠背"' in script assert '"seat.set_legrest_height": "腿托"' in script assert '"seat.set_legrest_extension": "腿托"' in script assert '"ambient_light.set_illumination": "氛围灯颜色与亮度"' in script assert '"android.launch_app": "打开视频媒体"' in script assert 'if (capability === "android.launch_app")' in script assert "parameters.package_name" in script assert "parameters.activity_name" in script assert '.replaceAll("_", "-")' in script assert ".assistant-dispatched-controls > summary" in css assert ".assistant-dispatched-controls-list > li" in css assert ".assistant-dispatched-control-value" in css assert ".assistant-dispatched-controls[open]" in css def test_explicit_nfc_authorization_block_is_rendered_as_safety_blocked(): console = (ROOT / "apps/web-console/console-v2.js").read_text(encoding="utf-8") assert 'executionStatus === "blocked"' in console assert "Boolean(telemetry.authorization_reason)" in console assert 'deliveryState = aborted' in console assert '? "blocked"' in console assert '? "安全阻止"' in console def test_n7_video_launch_uses_chinese_mode_card_labels(): app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8") assert 'android: "车机媒体"' in app assert 'headunit: "车机"' in app assert '"android.launch_app": "打开视频媒体"' in app assert 'package_name: "应用包名"' in app assert 'activity_name: "启动页面"' in app def test_latest_dispatched_control_group_is_the_only_group_expanded(): assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text( encoding="utf-8" ) vue_ui = (ROOT / "apps/web-console/vue-ui.js").read_text(encoding="utf-8") assert "function focusLatestDispatchedControls(container)" in assistant assert 'transcript.querySelectorAll(".assistant-dispatched-controls")' in assistant assert "card.open = card === activeCard" in assistant assert "focusLatestDispatchedControls(host)" in assistant assert "focusLatestDispatchedControls(card)" in assistant assert 'querySelectorAll(".assistant-dispatched-controls[open]")' in assistant assert 'querySelectorAll(".assistant-dispatched-controls[open]")' in vue_ui assert "if (card !== event.currentTarget) card.open = false" in vue_ui def test_saved_mode_execution_opens_with_pending_flow_before_http_completion(): app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8") flow = app.split( "async function executeSavedModeProfile", 1 )[1].split("function applyModeCommand", 1)[0] begin_index = flow.index("assistant?.beginModeExecution?.(mode") request_index = flow.index("await postControlPhase(") assert begin_index < request_index assert "assistant.completeModeExecution(assistantModeHandle, mode, payload" in flow assert "assistant.completeModeExecution(assistantModeHandle, mode, null" in flow def test_seat_control_cards_name_the_controlled_seat_component(): console = (ROOT / "apps/web-console/console-v2.js").read_text(encoding="utf-8") assert '"seat.set_cushion_tilt": ["副驾座椅坐盆调节"' in console assert 'backrest: "主驾座椅靠背调节"' in console assert 'basin: "主驾座椅坐盆调节"' in console assert 'legrest: "主驾座椅腿托调节"' in console assert 'horizontal: "主驾座椅前后调节"' in console def test_codex_request_keeps_trusted_vehicle_context_without_legacy_model_routing(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") request_body = script.split("function requestBody(message)", 1)[1].split( "async function readErrorResponse", 1 )[0] assert 'client_type: "web_console_codex_assistant"' in request_body for field in ( "execution_mode", "control_transport", "vehicle_id", "hardware_client_id", "simulation_fault", ): assert field in request_body assert "history" not in request_body assert "provider" not in request_body assert "reasoning_effort" not in request_body assert 'const executionMode = modeConfigurationPreview ? "dry_run"' in request_body def test_codex_request_reuses_only_the_console_validated_hardware_client_id(): app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8") assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert "const HARDWARE_CLIENT_ID_PATTERN" in app assert "function validatedHardwareClientId()" in app assert "getHardwareClientId()" in app assert "return validatedHardwareClientId();" in app assert "window.CognitiveAgentConsole?.getHardwareClientId?.()" in assistant assert "/^hwc-[a-z0-9-]{8,80}$/.test(value)" in assistant def test_starting_a_new_codex_conversation_rotates_the_conversation_id(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert 'const CONVERSATION_STORAGE_KEY = "cognitive-agent.conversation-id"' in script assert "function createConversationId()" in script assert "const nextConversationId = createConversationId()" in script assert ( "sessionStorage.setItem(CONVERSATION_STORAGE_KEY, nextConversationId)" in script ) def test_assistant_uses_the_shared_top_right_dock_and_opens_by_default(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert 'trigger.id = "assistantDrawerToggle"' in script assert 'drawer.id = "assistantDrawer"' in script assert 'drawer.setAttribute("role", "dialog")' in script assert 'drawer.setAttribute("aria-label", "AI助手")' in script assert 'trigger.setAttribute("aria-controls", drawer.id)' in script assert 'trigger.setAttribute("aria-pressed", "false")' in script assert 'trigger.classList.toggle("active", open)' in script assert 'trigger.setAttribute("aria-pressed", String(open))' in script assert 'drawer.toggleAttribute("inert", !open)' in script assert 'trigger.className = "assistant-drawer-toggle v2-panel-control-button"' in script assert 'const panelDock = $("#v2PanelControlDock")' in script assert "panelDock.insertBefore(trigger, firstRightPanelToggle)" in script assert "document.body.append(trigger)" in script assert 'id = "assistantDrawerClose"' not in script assert "setDrawerOpen(true)" in script assert 'event.key === "Escape"' in script assert "#v2PanelControlDock > .assistant-drawer-toggle" in css assert ".assistant-drawer-open .v2-operation-shell" in css assert "position: fixed" in css assert "position: relative" in css assert "grid-template-rows: 56px auto minmax(0, 1fr)" in css assert ".v2-output-shell" in css def test_assistant_mode_creation_previews_then_saves_to_the_compact_mode_strip(): app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8") assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert "function startModeCreation()" in assistant assert 'input.value = "请帮我创建一个"' in assistant assert "function appendModeDraftState(message, draft, actions)" in assistant assert "function modeDraftRows(draft, rawActions)" in assistant assert "event.payload.mode_profile_draft" in assistant assert 'event.payload.orchestration_route === "mode_profile_create_preview"' in assistant assert "appendModeDraftState(" in assistant assert "保存为功能模式" in assistant assert "重新校验(不下发)" in assistant assert "创建阶段仅生成并校验控制方案,不会向 CAN 或红外外设发送指令" in assistant assert 'label = String(action?.target?.name || action?.target?.device || "红外外设")' in assistant save_flow = assistant.split( "async function saveModeProfileDraft", 1 )[1].split("async function tryModeProfileDraft", 1)[0] assert 'const existingModeId = String(draft.existing_mode_id || "").trim()' in save_flow assert "encodeURIComponent(existingModeId)" in save_flow assert '"/api/mode-profiles"' in save_flow assert "request(endpoint" in save_flow assert 'method: "POST"' in save_flow for field in ("name", "instruction", "source_request_id", "vehicle_id"): assert field in save_flow assert "response.ok" in save_flow assert "refreshModeProfiles?.(payload.mode_profile?.id)" in save_flow assert "appendModeCreatedState(message, payload.mode_profile" in save_flow assert "updated: Boolean(existingModeId)" in save_flow assert "确认更新此模式" in assistant assert "已载入现有功能模式" in assistant for action_label in ( "座椅前后位置", "坐垫角度", "靠背角度", "腿托高度", "空调循环", "内循环", ): assert action_label in assistant assert "tryModeDraft?.({ ...draft, actions })" in assistant assert '["mode_profile_create", "mode_profile_update"].includes(' in assistant assert "appendModeCreatedState(message, event.payload.mode_profile, {" in assistant assert ( 'updated: event.payload.orchestration_route === "mode_profile_update"' in assistant ) assert "refreshModeProfiles?.(" in assistant assert "revealModeProfile?.(String(profile.id), { focus: true })" in assistant assert "function revealModeProfile(modeProfileId" in app assert "refreshModeProfiles" in app assert "tryModeDraft" in app assert "const actionSignature = (action) =>" in app assert 'apiRequest("/api/mode-profile-drafts/trial"' in app assert "source_request_id: draft.source_request_id" in app assert "const expectedSignatures = Array.isArray(draft?.actions)" in app assert "signature === actualSignatures[index]" in app assert "|| !sameActions" in app assert 'button.classList.add("just-created")' in app assert 'window.addEventListener("cognitive-agent:request-complete"' in app assert ".assistant-mode-draft" in css assert ".assistant-mode-draft-row" in css assert ".assistant-mode-draft-save" in css assert ".assistant-mode-draft-status.failed" in css assert ".assistant-mode-created" in css def test_assistant_carries_only_the_active_mode_draft_reference_to_follow_up_turns(): assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") request_body = assistant.split("function requestBody(message)", 1)[1].split( "async function readErrorResponse", 1 )[0] context_flow = assistant.split("function sanitizeModeDraftContext", 1)[1].split( "function loadStoredMessages", 1 )[0] assert ( 'const ACTIVE_MODE_DRAFT_STORAGE_KEY = "cognitive-agent.active-mode-draft"' in assistant ) assert "mode_profile_draft_context: modeProfileDraftContext" in request_body assert "requestModeDraftContext(message)" in request_body assert "name: context.name" in context_flow assert "source_request_id: context.source_request_id" in context_flow assert "vehicle_id: context.vehicle_id" in context_flow assert "actions" not in context_flow assert "rememberModeDraftContext(draft)" in assistant assert "activeModeDraftContext = loadActiveModeDraftContext()" in assistant assert "function isModeDraftUpdateRequest(message, context)" in assistant assert "normalizeModeName(matched[nameIndex]) === normalizeModeName(context.name)" in assistant def test_latest_same_name_mode_draft_retires_stale_card_and_lifecycle_clears_context(): assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") replace_flow = assistant.split("function supersedeModeDraftCards", 1)[1].split( "function appendModeDraftState", 1 )[0] save_flow = assistant.split("async function saveModeProfileDraft", 1)[1].split( "async function tryModeProfileDraft", 1 )[0] new_conversation_flow = assistant.split( "function resetConversation()", 1 )[1].split("function initialize()", 1)[0] assert "card.dataset.assistantModeName !== nextName" in replace_flow assert "card.dataset.assistantModeDraft === nextRequestId" in replace_flow assert 'card.classList.add("is-superseded")' in replace_flow assert "button.disabled = true" in replace_flow assert "已由下方最新草稿替换" in replace_flow assert "clearActiveModeDraftContext(draft.source_request_id)" in save_flow assert "clearActiveModeDraftContext()" in new_conversation_flow assert ".assistant-mode-draft.is-superseded" in css assert ".assistant-mode-draft-status.superseded" in css def test_new_conversation_resets_chat_in_place_and_keeps_panel_order_spatial(): app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8") assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text( encoding="utf-8" ) reset_flow = assistant.split("function resetConversation()", 1)[1].split( "function initialize()", 1 )[0] app_flow = app.split("function startNewConversation", 1)[1].split( "window.CognitiveAgentConsole", 1 )[0] assert 'activeController.abort("new_conversation")' in reset_flow assert "sessionStorage.removeItem(STORAGE_KEY)" in reset_flow assert "renderInitialMessages()" in reset_flow assert "setComposerPending(false)" in reset_flow assert '"cognitive-agent:new-conversation"' in reset_flow assert "window.location.reload()" not in app_flow assert ( 'window.addEventListener("cognitive-agent:new-conversation", ' "startNewConversation)" ) in app assert 'const firstRightPanelToggle = $("[data-panel-toggle]", panelDock)' in assistant assert "panelDock.insertBefore(trigger, firstRightPanelToggle)" in assistant def test_assistant_composer_grows_to_a_cap_then_scrolls_its_own_content(): assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") resize_flow = assistant.split( "function resizeComposerInput", 1 )[1].split("function createMessage", 1)[0] assert "const COMPOSER_MIN_HEIGHT = 64" in assistant assert "const COMPOSER_MAX_HEIGHT = 116" in assistant assert 'input.style.height = "auto"' in resize_flow assert "input.scrollHeight" in resize_flow assert "Math.min(contentHeight, COMPOSER_MAX_HEIGHT)" in resize_flow assert 'input.style.height = `${nextHeight}px`' in resize_flow assert 'input.classList.toggle("is-scrollable", scrollable)' in resize_flow assert "if (!scrollable) input.scrollTop = 0" in resize_flow assert 'input.addEventListener("input", () => resizeComposerInput(input))' in assistant assert "resizeComposerInput(input)" in assistant composer_styles = css.split( ".v2-request-form .command-composer", 1 )[1].split("}", 1)[0] assert "height: auto" in composer_styles input_styles = css.split( ".v2-request-form #utterance", 1 )[1].split("}", 1)[0] assert "max-height: 116px" in input_styles assert "overflow-y: hidden" in input_styles scrollable_styles = css.split("#utterance.is-scrollable", 1)[1].split("}", 1)[0] assert "overflow-y: auto" in scrollable_styles assert "scrollbar-width: thin" in scrollable_styles assert "overscroll-behavior: contain" in scrollable_styles def test_assistant_composer_keeps_the_microphone_visible_and_aligned(): html = vue_shell() css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert 'id="speechDictationButton"' in html assert 'data-lucide="mic"' in html assert ".v2-request-form .speech-dictation" in css assert "right: 53px" in css assert "bottom: auto" in css assert "display: grid !important" in css assert "transform: translateY(-50%)" in css assert ".v2-request-form .speech-status:empty" in css def test_voice_input_supports_direct_manual_capture_and_background_wake_standby(): html = vue_shell() script = (ROOT / "apps/web-console/speech-input.js").read_text(encoding="utf-8") assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert 'aria-label="开始语音输入"' in html assert 'const DEFAULT_WAKE_WORD = "你好,小迪"' in script assert 'new Set(["arming", "armed", "capturing", "finalizing"])' in script assert "async function startManualDictation()" in script assert "async function startWakeStandby({ automatic = true } = {})" in script assert 'return startCapture("manual")' in script assert 'return startCapture("wake", { automatic })' in script assert 'else void startManualDictation()' in script assert 'const manualInput = speech.inputMode === "manual"' in script assert "const detectedWake = manualInput || wakeWord.detected === true" in script assert 'fetch("/api/speech/preview"' in script assert '"X-Speech-Preview-Sequence"' in script assert '"X-Speech-Input-Mode": speech.inputMode' in script assert 'result.stale === true' in script assert 'sequence <= speech.lastAppliedPreviewSequence' in script assert "wakeWord.remainder ?? result.live_text" in script assert "status.wake_word.primary" in script assert 'if (speech.wakeDetected && liveText)' in script assert 'replaceInput(liveText, "partial")' in script assert '"X-Speech-Input-Mode": inputMode' in script assert '"X-Speech-Wake-Word-Required": inputMode === "wake" ? "1" : "0"' in script assert ( "result.assistant_text || result.clean_text || result.live_text || " "result.raw_text || result.text" ) in script assert "commands.length" not in script assert "input.dataset.speechExecutionEligible =" not in script assert "void speech.setAssistantOpen(open)" in assistant assert '["capturing", "finalizing"].includes(speechPhase)' in assistant assert 'speechPhase === "arming" && speechInputMode === "manual"' in assistant assert "请等待语音整理完成后再发送" in assistant def test_voice_lifecycle_releases_hidden_or_collapsed_microphone(): script = (ROOT / "apps/web-console/speech-input.js").read_text(encoding="utf-8") assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert 'document.addEventListener("visibilitychange"' in script assert "ACTIVE_PHASES.has(speech.phase)" in script assert 'window.addEventListener("pagehide"' in script assert "speech.stream?.getTracks().forEach((track) => track.stop())" in script assert "speech.previewController?.abort" in script assert "speech.finalController?.abort" in script assert 'typeof speech?.setAssistantOpen === "function"' in assistant assert "void speech.setAssistantOpen(open)" in assistant def test_model_text_is_rendered_through_text_nodes_not_raw_html(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") assert "document.createTextNode(part)" in script assert "code.textContent =" in script assert "contentNode.textContent = content" in script assert "innerHTML = content" not in script def test_chat_styles_include_accessible_responsive_and_reduced_motion_states(): css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert ".assistant-message-user" in css assert ".assistant-action-status.success" in css assert "@media (max-width: 900px)" in css assert "@media (max-width: 560px)" in css assert ".v2-unified-right-rail" in css assert "grid-template-columns: minmax(0, 1fr) !important" in css assert "@media (prefers-reduced-motion: reduce)" in css def test_dispatched_control_card_spans_the_full_assistant_message_row(): css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") layout = css.split("/* Compact command receipt", 1)[1].split( "/* The function-mode strip", 1 )[0] assert "grid-template-columns: 30px minmax(0, 1fr)" in layout assert "display: contents" in layout assert "grid-column: 1 / -1" in layout assert "max-width: none" in layout def test_assistant_does_not_restore_collapsed_sidebars_and_uses_mobile_overlays(): script = (ROOT / "apps/web-console/assistant-chat.js").read_text(encoding="utf-8") css = (ROOT / "apps/web-console/assistant-chat.css").read_text(encoding="utf-8") assert "--assistant-drawer-width: clamp(340px, 26vw, 410px);" in css assert "@media (min-width: 901px)" in css assert ".assistant-drawer-open.v2-sidebar-collapsed .workspace" in css assert "grid-template-columns: 0 minmax(0, 1fr);" in css assert ".assistant-drawer-open.v2-sidebar-collapsed .command-panel.v2-sidebar" in css assert "visibility: hidden;" in css assert "grid-template-columns: var(--assistant-drawer-width) minmax(0, 1fr);" in css assert "#v2PanelControlDock > .assistant-drawer-toggle" in css assert "opacity: 1 !important;" in css assert "pointer-events: auto !important;" in css assert "@media (max-width: 900px)" in css assert "width: min(86vw, 320px);" in css assert "width: min(86vw, 360px);" in css assert "top: 60px;" in css assert 'event.key === "Escape"' in script