#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const repoRoot = path.resolve(__dirname, '..'); const runtimePath = path.join(repoRoot, 'rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js'); const routePath = path.join(repoRoot, 'rust/crates/mnote-web/src/routes/page_ai_openhub.rs'); const routesModPath = path.join(repoRoot, 'rust/crates/mnote-web/src/routes/mod.rs'); const runtime = fs.readFileSync(runtimePath, 'utf8'); const route = fs.readFileSync(routePath, 'utf8'); const routesMod = fs.readFileSync(routesModPath, 'utf8'); const checks = [ ['openhub host enabled by default', runtime.includes('function pageAiOpenHubHostEnabled()') && runtime.includes('return true;') && runtime.includes('data-page-ai-openhub-host')], ['openhub bootstrap api', runtime.includes('/api/page-ai/openhub/bootstrap') && routesMod.includes('/api/page-ai/openhub/bootstrap')], ['mnote auth truth copy', route.includes('"authTruth": "mnote_session"') && runtime.includes('拒绝 OpenHub JWT/localStorage')], ['openhub user key derived', route.includes('"openhubUserKey"') && route.includes('stable_hash("openhub_user"')], ['workspace session tool scope', route.includes('"openhubSessionScope"') && route.includes('"skillScope"') && route.includes('"mcpScope"') && route.includes('"toolPermissionScope"')], ['proxy injects mnote scope headers', route.includes('add_mnote_scope_headers') && route.includes('x-mnote-user-key') && route.includes('x-mnote-user-id') && route.includes('x-mnote-display-name') && route.includes('x-mnote-workspace-key') && route.includes('x-mnote-session-scope') && route.includes('x-mnote-tool-permission-scope') && route.includes('x-mnote-weknora-tool-scope')], ['proxy carries full mnote scope internally', route.includes('mnoteScope') && route.includes('mnote_scope_from_query') && route.includes('proxy_query_without_internal_scope')], ['snake case bootstrap scope aliases', route.includes('"openhub_user_key"') && route.includes('"workspace_key"') && route.includes('"session_scope"') && route.includes('"tool_permission_scope"')], ['weknora tool scope', route.includes('"weknoraToolScope"') && route.includes('"weknora_tool_scope"') && runtime.includes('weknora_tool_scope')], ['layered status endpoint', route.includes('"openhub_fastapi"') && route.includes('"opencode"') && route.includes('"weknora"') && route.includes('"mnote_binding"')], ['degraded external services are explicit', route.includes('"degraded"') && route.includes('reachable') && route.includes('upstream_http_')], ['ai proxy boundary', route.includes('pub async fn ai_proxy') && routesMod.includes('/page-ai/openhub/ai/{*path}')], ['no visible opencode fallback action', !runtime.includes('openhub-use-opencode-fallback')], ['non ai route guard', route.includes('page_ai_openhub_non_ai_route_guarded') && routesMod.includes('/page-ai/openhub/knowledge/{*path}') && routesMod.includes('/page-ai/openhub/file/{*path}') && routesMod.includes('/page-ai/openhub/git/{*path}')], ['static ai shell', route.includes('data-mnote-openhub-ai-shell="static-boundary"') && routesMod.includes('/page-ai/openhub/ai')], ['openhub quick address actions are native openhub source not proxy overlay', !route.includes('data-mnote-openhub-ai-quick-actions') && !route.includes('data-mnote-openhub-send-current-tab') && !route.includes('data-mnote-openhub-send-current-folder')], ['openhub quick address bridge uses active tab only', runtime.includes("message.source === 'openhub-ai'") && runtime.includes("message.type === 'mnote:get-active-tab-address'") && runtime.includes('pageAiCurrentActiveTabEditorTarget') && runtime.includes("type: 'mnote:active-tab-address'")], ['openhub folder action sends folder address only', runtime.includes('pageAiCurrentActiveTabAddressPayload') && runtime.includes('folderUrl') && runtime.includes("kind === 'folder' ? addressPayload.folderUrl : addressPayload.tabUrl")], ['openhub diagnostics are hidden from user chrome', runtime.includes('wolai-page-ai-openhub-diagnostics') && runtime.includes('data-page-ai-openhub-bootstrap-copy hidden aria-hidden="true"')], ['no duplicate mnote openhub shell header', !runtime.includes('