['runtime has receipt UI display',runtime.includes('receipts')],
// === Runtime JS: independent native drawer ===
['runtime checks enabled flag via status API but does not hide launcher behind it',runtime.includes('enabled')&&runtime.includes('checkStatus')],
['runtime renders independent Pi Lab drawer',runtime.includes('data-page-ai-pi-lab-drawer')&&runtime.includes('data-page-ai-pi-lab')&&runtime.includes('drawer')],
['runtime creates drawer through ensureDrawer',runtime.includes('function ensureDrawer')&&runtime.includes('setDrawerVisible')],
['runtime does NOT mount inside OpenHub drawer',!runtime.includes('attachPanelToDrawer')&&!runtime.includes('wolai-page-ai-drawer')],
['runtime does NOT toggle OpenHub iframe visibility',!runtime.includes('setOpenHubVisible')&&!runtime.includes('data-page-ai-openhub-frame-wrap')],
['runtime has no OpenHub provider tab inside Pi Lab',!runtime.includes('data-page-ai-pi-lab-openhub-tab')],
['runtime has context strip chips',runtime.includes('data-page-ai-pi-lab-context-strip')&&runtime.includes('data-page-ai-pi-lab-current-page')&&runtime.includes('data-page-ai-pi-lab-allowed-roots')&&runtime.includes('data-page-ai-pi-lab-lightrag')],
['runtime collapses secondary context/settings like OpenHub chrome',runtime.includes('<details class="wolai-page-ai-pi-lab-settings"')&&runtime.includes('<details class="wolai-page-ai-pi-lab-context-strip"')],
['runtime settings gear opens AI management page',runtime.includes('data-page-ai-pi-lab-open-settings title="AI 管理"')&&runtime.includes("window.location.assign('/user/ai#ai-admin-access')")],
['runtime keeps only meaningful top commandbar buttons',runtime.includes('data-page-ai-pi-lab-new')&&runtime.includes('data-page-ai-pi-lab-history')&&runtime.includes('data-page-ai-pi-lab-btn-clear')&&runtime.includes('data-page-ai-pi-lab-open-settings')],
['runtime removes no-op top commandbar buttons',!runtime.includes('data-page-ai-pi-lab-open title=')&&!runtime.includes('data-page-ai-pi-lab-toggle-artifacts')&&!runtime.includes('data-page-ai-pi-lab-clock')&&!runtime.includes('data-page-ai-pi-lab-notify')],
['runtime has OpenHub-style left history drawer markers',runtime.includes('data-page-ai-pi-lab-history-layer')&&runtime.includes('wolai-page-ai-pi-lab-history-scrim')&&runtime.includes('历史对话')],
['runtime history drawer supports refresh/delete/export/clear',runtime.includes('data-page-ai-pi-lab-history-refresh')&&runtime.includes('data-page-ai-pi-lab-history-delete')&&runtime.includes('data-page-ai-pi-lab-history-export')&&runtime.includes('data-page-ai-pi-lab-history-clear')],
['runtime does not expose manual Pi runtime start button',!runtime.includes('data-page-ai-pi-lab-btn-start')&&!runtime.includes('启动 Pi runtime')&&!runtime.includes('预启动 Pi 会话')],
['runtime auto starts Pi session when drawer opens',runtime.includes('function showPiLab')&&runtime.includes('checkStatus().then(function ()')&&runtime.includes('return startRuntime();')],
['runtime has native model controls',runtime.includes('data-page-ai-pi-lab-model-provider')&&runtime.includes('data-page-ai-pi-lab-model-id')&&runtime.includes('data-page-ai-pi-lab-model-custom')],
['runtime collapses secondary right rail sections',runtime.includes('<details class="wolai-page-ai-pi-lab-rail-section"')&&runtime.includes('data-page-ai-pi-lab-receipts-section')],
['runtime has diagnostics collapsed by default',runtime.includes('<details class="wolai-page-ai-pi-lab-diagnostics"')&&!runtime.includes('<details class="wolai-page-ai-pi-lab-diagnostics" open')],
// === Runtime JS: default model (omniroute/freefirst) ===
['runtime has defaultModelProvider with omniroute',runtime.includes('defaultModelProvider')&&runtime.includes('omniroute')],
['runtime has defaultModelId with freefirst',runtime.includes('defaultModelId')&&runtime.includes('freefirst')],
['runtime shows default model in header label',runtime.includes('updateModelLabel')&&runtime.includes('defaultModelProvider')&&runtime.includes('defaultModelId')],
['runtime consumes defaultModelProvider from backend status',runtime.includes('data.defaultModelProvider')],
['runtime consumes defaultModelId from backend status',runtime.includes('data.defaultModelId')],
['runtime shows "omniroute/freefirst" in empty state',runtime.includes('omniroute')&&runtime.includes('freefirst')&&runtime.includes('默认模型')],
['route has status endpoint',route.includes('pub async fn status')],
['route has start endpoint',route.includes('pub async fn start')],
['route has send endpoint',route.includes('pub async fn send')],
['route has abort endpoint',route.includes('pub async fn abort')],
['route has events SSE endpoint',route.includes('pub async fn events')],
['route has bootstrap endpoint (legacy)',route.includes('pub async fn bootstrap')],
['route has tool_call endpoint',route.includes('pub async fn tool_call')],
['route has internal tool_call_bridge endpoint',route.includes('pub async fn tool_call_bridge')],
['route uses AppConfig enable_page_ai_pi_lab instead of direct env gate',route.includes('state.config().enable_page_ai_pi_lab')&&!route.includes('std::env::var("MNOTE_PAGE_AI_PI_LAB")')],
['route returns enabled=false when not enabled',route.includes('"enabled": false')],
['route marks independent native drawer ui mode',route.includes('independent_mnote_native_drawer')],
['route does not return openHubDefaultPreserved marker',!route.includes('openHubDefaultPreserved')],
['route has default model provider constant PI_LAB_DEFAULT_MODEL_PROVIDER=omniroute',route.includes('PI_LAB_DEFAULT_MODEL_PROVIDER')&&route.includes('omniroute')],
['route has default model id constant PI_LAB_DEFAULT_MODEL_ID=freefirst',route.includes('PI_LAB_DEFAULT_MODEL_ID')&&route.includes('freefirst')],
['route defaults to Pi Rust runtime implementation',route.includes('PI_LAB_RUNTIME_IMPL_RUST')&&route.includes('"pi-rust"')&&route.includes('MNOTE_PAGE_AI_PI_RUST_BIN')],
['route keeps TS Pi as explicit fallback only',route.includes('PI_LAB_RUNTIME_IMPL_TS')&&route.includes('MNOTE_PAGE_AI_PI_TS_BIN')],
['route tool_receipt.write is not a silent no-op',route.includes('"requestedReceipt"')&&route.includes('execute_tool 统一写入')],
['route has bridge token header and non-serialized session token',route.includes('HEADER_PI_LAB_BRIDGE_TOKEN')&&route.includes('x-mnote-pi-lab-bridge-token')&&route.includes('skip_serializing')],
['route generates bridge token from OS randomness',route.includes('generate_bridge_token')&&route.includes('/dev/urandom')&&!route.includes('bridge_token: generate_id("pi_bridge")')],
['route does not write obsolete private MCP bridge config',!route.includes('write_session_mcp_bridge_config')&&!route.includes('mnote.pi.mcp-bridge.v1')&&!route.includes('mnote-bridge.json')],
['route never writes bridge token into generated extension source',!route.includes('const BRIDGE_TOKEN = {bridge_token}')],
['route loads official MNote Pi package extension',route.includes('mnote_pi_extension_path')&&route.includes('packages/pi-mnote/extensions/mnote-bridge.ts')],
['route starts Pi with explicit MNote extension bridge',route.includes('--extension')&&route.includes('mnotePiExtension')],
['route starts Pi with MNote tool allowlist',route.includes('--tools')&&route.includes('mnoteToolNames')&&route.includes('pi_lab_extension_tool_names')],
['route passes MNote tool manifest to extension env',route.includes('MNOTE_PI_BRIDGE_TOOLS')&&route.includes('PI_MNOTE_BRIDGE_TOOLS')&&route.includes('mnote_pi_tool_manifest')],
['route writes dynamic Pi Rust MNote context file',route.includes('mnote.pi.context.v1')&&route.includes('PI_MNOTE_CONTEXT_FILE')&&route.includes('write_pi_mnote_context_snapshot')],
['route injects dynamic Pi Rust input context',route.includes('MNOTE_PI_CONTEXT_V1')&&route.includes('pi_mnote_input_context_prefix')],
['route disables Pi builtins by default unless external permission extension is opt-in',route.includes('pi_lab_enabled_builtin_tools')&&route.includes('MNOTE_PAGE_AI_PI_ALLOW_EXTERNAL_EXTENSIONS')&&route.includes('configuredPiExtensionSources')&&route.includes('pi_lab_runtime_extension_sources')],
['route exposes Rust Pi runtime diagnostics',route.includes('hashline_edit')&&route.includes('runtimeImplementation')&&route.includes('runtimeBinary')&&route.includes('runtimeAvailable')&&route.includes('runtimeInstallHint')&&route.includes('runtimeError')],
['runtime send path auto-starts Pi Rust instead of dead-end not-ready toast',runtime.includes('Pi Rust 正在启动,启动后自动发送')&&runtime.includes('piLabStartPromise')&&!runtime.includes('Pi 会话尚未就绪,请重新打开 Pi 面板或稍后重试')],
['@mnote/pi MCP extension uses official synchronous child_process bridge',mnotePiMcpExtension.includes('execFileSync')&&mnotePiMcpExtension.includes('client.mjs')&&mnotePiMcpExtension.includes('transport: "pi-rust-sync-client"')&&!mnotePiMcpExtension.includes('/api/page-ai/pi/mcp-call-bridge')&&!mnotePiMcpExtension.includes('fetch(')],
['@mnote/pi MCP extension does not depend on private session token config',!mnotePiMcpExtension.includes('mnote-bridge.json')&&!mnotePiMcpExtension.includes('BRIDGE_TOKEN')&&!mnotePiMcpExtension.includes('SESSION_ID')],
['@mnote/pi MCP client implements protocol handshake and tool calls',mnotePiMcpClient.includes('"initialize"')&&mnotePiMcpClient.includes('"tools/list"')&&mnotePiMcpClient.includes('"tools/call"')],
['@mnote/pi MCP client supports stdio and streamable HTTP',mnotePiMcpClient.includes('spawn(')&&mnotePiMcpClient.includes('text/event-stream')],
['route loads built-in Pi Rust MCP extension',route.includes('mnote_pi_mcp_extension_path')&&route.includes('packages/pi-mnote/extensions/mnote-mcp/index.ts')],
['route stages per-session MCP config next to built-in extension',route.includes('stage_project_mcp_config_for_extension')&&route.includes('extension_dir.join(".pi")')&&route.includes('mcp.json')],
['route does not pass unsupported Pi Rust --mcp-config flag',!route.includes('.arg("--mcp-config")')],
['route does not globally disable Pi Rust extension capability policy',!route.includes('command.env("PI_EXTENSION_ALLOW_DANGEROUS"')&&!route.includes('pi_tool_names.push("bash".into())')],
['route narrowly enables Pi Rust sync exec only for configured MCP sessions',route.includes('if pi_lab_mcp_enabled(&session)')&&route.includes('command.env("PIJS_ALLOW_UNSAFE_SYNC_EXEC", "1")')],
['mod.rs mounts pi session history delete and clear routes',routesMod.includes('get(page_ai_pi::list_sessions).delete(page_ai_pi::clear_sessions)')&&routesMod.includes('.delete(page_ai_pi::delete_session_history)')],