fanluc 2.0.0 → 2.4.0
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/README.md +83 -0
- package/dist/assets/{abnfDiagram-O67JEVCF-hiYMdxpV.js → abnfDiagram-O67JEVCF-Di2iDQfl.js} +1 -1
- package/dist/assets/{arc-DokRg_wy.js → arc-wXq_yD5s.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-UzHYe9Bx.js → architectureDiagram-NJMV4G6O-CTXbg-3W.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-DqM5UILT.js → blockDiagram-BEXU5L5S-DSDoL3RP.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-Cxkdm7sV.js → c4Diagram-YGBWAQC7-3sFM3iyw.js} +1 -1
- package/dist/assets/channel-atnI5OIR.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-Nl4zmLlG.js → chunk-2Q5K7J3B-DUOKiJNI.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-BCol78O2.js → chunk-3FUC2YCW-ablWb8_c.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-1u4YRv2Y.js → chunk-5VM5RSS4-qmlSVZ_1.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-BG9YIV2h.js → chunk-GTNCS2PH-PLlC7cNS.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BTKfkJAH.js → chunk-GWA4HPMP-DK-1a6YJ.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DCjElfA7.js → chunk-JWPE2WC7-D9zynFKs.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-QoJORlVn.js → chunk-NETBCI7D-BvzPMYyE.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-Da-T8ct9.js → chunk-WEXAMYUT-CzcfZFWB.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-CLu69Uei.js → chunk-XXDRQBXY-DznN-rwG.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-DIXavbI9.js → classDiagram-v2-NBCMYWYE-D4jem0hV.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-DuWclG8-.js → cose-bilkent-JH36ORCC-VALsUQJS.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-D2CG5-xd.js → cynefin-OW5HDTMX-DK77QSI8.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-goI7_Qfg.js → cynefinDiagram-VND7K2PF-CdYXfGNR.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-BmOaZ0cm.js → dagre-6A5THRUB-DeeUQzDV.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-DjDJFMw3.js → diagram-22UHCM2B-B9shZ914.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-J6z81NH3.js → diagram-3UASUU5V-gSHvaXBI.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-B1MPU8ai.js → diagram-ATOU4E4O-BrCI5HzS.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-X5Uss0Yv.js → diagram-CDSNMT55-XtVlMRq0.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-CRDqfYy1.js → diagram-MLGK6HIB-BVa6KsvA.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-bhJtyiOq.js → diagram-MPIPVDR6-C8P23P2T.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-Dn1mZAV8.js → ebnfDiagram-ZINNZB2B-BrooaQj5.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-C93BlBEU.js → elk-276RUBZZ-B-qiKlkF.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-PuzjAvhD.js → erDiagram-OPXOYQCR-CL1bp2Mf.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-oRhFgO0p.js → flowDiagram-KWPJA3E3-BMQvaQ-5.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-DKiU1XjU.js → ganttDiagram-FUAMR5RP-PLnTGRI8.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-CWBMI0vb.js → gitGraphDiagram-X574FWY7-CiTN3Joc.js} +1 -1
- package/dist/assets/index-BEKLwzQT.css +1 -0
- package/dist/assets/index-C8gDJtDK.js +2841 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-C5Hd4Afz.js → infoDiagram-VRGFBTTK-ComkS_96.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-BdD6ulRK.js → ishikawaDiagram-OU5B5YK6-D-dNoDFJ.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-CzT-uvks.js → journeyDiagram-ZHPQQLJL-BMm9BQM8.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BkrazFMR.js → kanban-definition-PNTS6WVX-D5If-l_D.js} +1 -1
- package/dist/assets/{linear-B0wSM1Dr.js → linear-DXAHb0Ag.js} +1 -1
- package/dist/assets/{mindmap-definition-NLK3R4M7-Df1Acqkf.js → mindmap-definition-NLK3R4M7-CIdwCXTJ.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-DK_F7h_0.js → pegDiagram-GJSIUBJH-MY7FoVQh.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-BMXyNb9R.js → pieDiagram-5QR66LMP-C7lWWAtM.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-Dfu7Z8so.js → quadrantDiagram-O4NWA36T-jHqCwvi8.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-CfnBD-aQ.js → railroadDiagram-XR7U4H2S-BwoIA8Ln.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-DrvsZJPP.js → requirementDiagram-PLB6GJNP-Cw8w0Rwb.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-DvdVDpT1.js → sankeyDiagram-IPEJSGJF-DTRo1Yxy.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-D1UTrvZH.js → sequenceDiagram-PO4LG4MO-DqZddXsc.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-CJrOBcai.js → sizeCapture-INFHLROL-BAEQ4XP5.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-CX8VmtqD.js → stateDiagram-v2-GCMORJYK-CYB4CouD.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-DUWmhiK6.js → swimlanes-2SLR337P-Dw53LU13.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-Dzkep6h_.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-CBovVdOU.js → timeline-definition-EJHVYXUP-Chk-unGo.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-LD5N5BAG.js → usecaseDiagram-POWQR4AR-D_JpD-4l.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-DdwfzB3A.js → vennDiagram-UO4OBE2U-BnPO8gk8.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-BMHK4bav.js → wardleyDiagram-VNRHLVJA-CD0z1l8R.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-q1BNzMC-.js → xychartDiagram-PMCCYNJV-CHEqj1Pe.js} +1 -1
- package/dist/cli.js +52 -57
- package/dist/index.html +4 -4
- package/dist/server.cjs +2144 -841
- package/dist/server.cjs.map +4 -4
- package/dist/tui.js +3220 -3310
- package/docs/fanluc_ui.md +120 -40
- package/docs/guide-connect.md +233 -4
- package/docs/run-cmd-security.md +26 -0
- package/index.html +2 -2
- package/mcp.json +3 -0
- package/package.json +88 -92
- package/searxng/docker-compose.yml +3 -3
- package/vite.config.ts +2 -2
- package/dist/assets/channel-SPfNTvmj.js +0 -1
- package/dist/assets/index-BylpTP-E.css +0 -1
- package/dist/assets/index-DcpVteR3.js +0 -3237
- package/dist/assets/permissionHelper--88tJJlz.js +0 -3
- package/dist/assets/swimlanesDiagram-TC7HE7FX-DMQy1553.js +0 -8
package/dist/server.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../server.ts", "../
|
|
4
|
-
"sourcesContent": ["import express from \"express\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport { fileURLToPath } from \"url\";\nimport { execFile, execFileSync } from \"child_process\";\nimport { createServer as createViteServer } from \"vite\";\nimport { translate } from \"google-translate-api-x\";\nimport { JSDOM } from \"jsdom\";\nimport { Readability } from \"@mozilla/readability\";\nimport dotenv from \"dotenv\";\nimport dns from \"node:dns/promises\";\nimport net from \"node:net\";\nimport { decodeTextBuffer } from \"./src/utils/decodeText\";\ndotenv.config();\n\nconst IS_WINDOWS = process.platform === \"win32\";\nimport { findBlockedPattern as findBlockedCommand } from \"./src/core/security/blocklist\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\n// ============================================================================\n// run_cmd \u2014 sandboxed real shell execution (replaces the old browser-only\n// run_js/run_py simulators). This is the one thing on this server that can\n// touch the real filesystem and spawn real processes, so it gets its own\n// layered defenses instead of trusting the AI's text output directly:\n//\n// 1. cwd is hard-pinned to WORKSPACE_DIR for every call (never the app's\n// own source tree, never the real project root) \u2014 a fresh child\n// process each time, so nothing persists across calls except what was\n// actually written to disk in that folder.\n// 2. process.env is replaced with a minimal SAFE_ENV so secrets like\n// GEMINI/API keys in the server's real environment are never visible\n// to a command the AI asked to run (no `env`/`printenv` leak).\n// 3. A regex blocklist rejects the most obviously destructive/exfiltrating\n// patterns before anything is even spawned. This is defense-in-depth,\n// not a airtight sandbox by itself \u2014 see (4).\n// 4. If `firejail` is installed on the host, commands are wrapped in it\n// (--private home jail, --net=none, resource limits) for a real OS\n// level containment boundary. Without firejail, layers 1\u20133 still apply\n// but a truly hostile command run as the server's own OS user could in\n// principle still affect that user's files \u2014 for real Claude-grade\n// isolation, run this whole server inside a Docker container (see\n// docs/run-cmd-security.md) so the \"OS user\" itself is disposable.\n// 5. Hard timeout + output size caps so nothing can hang or flood memory.\n// ============================================================================\n\nfunction resolveWorkspaceDir(): string {\n // CLI sets FANLUC_WORKSPACE to current directory (= workspace is project root)\n // Web fallback is ./workspace subdirectory (existing behavior, no breaking change)\n const override = process.env.FANLUC_WORKSPACE?.trim();\n if (override) return path.resolve(override);\n // Also support legacy WORKSPACE_DIR env for flexibility\n if (process.env.WORKSPACE_DIR?.trim()) return path.resolve(process.env.WORKSPACE_DIR.trim());\n return path.join(process.cwd(), \"workspace\");\n}\n\nexport const WORKSPACE_DIR = resolveWorkspaceDir();\n\nfunction isInsideWorkspace(p: string): boolean {\n const rel = path.relative(WORKSPACE_DIR, path.resolve(p));\n return rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel));\n}\n\ntry {\n fs.mkdirSync(WORKSPACE_DIR, { recursive: true });\n} catch (e) {\n console.error(\"Failed to create workspace dir:\", e);\n}\n\n// Minimal environment handed to every run_cmd child process. Real secrets\n// (GEMINI_API_KEY, etc.) living in the actual server env are deliberately\n// left out so a shell command can never read or exfiltrate them.\nconst SAFE_ENV: NodeJS.ProcessEnv = IS_WINDOWS\n ? {\n PATH: process.env.PATH,\n SystemRoot: process.env.SystemRoot,\n windir: process.env.windir,\n COMSPEC: process.env.COMSPEC,\n OS: process.env.OS,\n SystemDrive: process.env.SystemDrive,\n TEMP: process.env.TEMP,\n TMP: process.env.TMP,\n // On Windows, don't override HOME/USERPROFILE to WORKSPACE_DIR \u2014 that causes\n // PowerShell to create AppData\\Local inside the workspace (polluting project).\n // Keep original USERPROFILE/HOME so profile data stays in real home.\n HOME: process.env.HOME || process.env.USERPROFILE || WORKSPACE_DIR,\n USERPROFILE: process.env.USERPROFILE || process.env.HOME || WORKSPACE_DIR,\n APPDATA: process.env.APPDATA,\n LOCALAPPDATA: process.env.LOCALAPPDATA,\n PYTHONDONTWRITEBYTECODE: \"1\",\n PATHEXT: process.env.PATHEXT,\n LANG: process.env.LANG || \"en_US.UTF-8\",\n }\n : {\n PATH: process.env.PATH,\n HOME: WORKSPACE_DIR,\n LANG: process.env.LANG || \"en_US.UTF-8\",\n PYTHONDONTWRITEBYTECODE: \"1\",\n };\n\n// Permission grants cho ch\u1EBF \u0111\u1ED9 ask/autoEdit (Fix 2) \u2014 in-memory, TTL 5 ph\u00FAt\nlet permissionGrants: { file: number; shell: number } = { file: 0, shell: 0 };\n// TTL m\u1EB7c \u0111\u1ECBnh 5 ph\u00FAt; override b\u1EB1ng FANLUC_GRANT_TTL_MS (ms) \u2014 d\u00F9ng cho test / m\u00F4i tr\u01B0\u1EDDng mu\u1ED1n ng\u1EAFn h\u01A1n.\nconst GRANT_TTL_MS = Number(process.env.FANLUC_GRANT_TTL_MS) > 0 ? Number(process.env.FANLUC_GRANT_TTL_MS) : 5 * 60 * 1000;\nfunction isGranted(type: \"file\" | \"shell\"): boolean {\n return permissionGrants[type] > Date.now();\n}\nfunction grantPermission(type: \"file\" | \"shell\" | \"all\") {\n const until = Date.now() + GRANT_TTL_MS;\n if (type === \"all\" || type === \"file\") permissionGrants.file = until;\n if (type === \"all\" || type === \"shell\") permissionGrants.shell = until;\n}\nfunction clearGrants() {\n permissionGrants = { file: 0, shell: 0 };\n}\n\nlet FIREJAIL_AVAILABLE = false;\nif (!IS_WINDOWS) {\n try {\n execFileSync(\"which\", [\"firejail\"], { stdio: \"ignore\" });\n FIREJAIL_AVAILABLE = true;\n console.log(\"[run_cmd] firejail detected \u2014 sandboxing run_cmd with it.\");\n } catch {\n console.warn(\n \"[run_cmd] firejail not found \u2014 run_cmd will still be jailed to \" +\n WORKSPACE_DIR + \" with a stripped env + blocklist, but for real OS-level \" +\n \"isolation install firejail (`sudo apt-get install -y firejail`) or run \" +\n \"this whole server inside a Docker container.\"\n );\n }\n} else {\n console.log(\"[run_cmd] Windows detected \u2014 firejail disabled, using PowerShell/cmd sandbox (blocklist enforced, permission ask blocks by default)\");\n}\n\nlet ZIP_AVAILABLE = false;\nlet UNZIP_AVAILABLE = false;\nif (!IS_WINDOWS) {\n try {\n execFileSync(\"which\", [\"zip\"], { stdio: \"ignore\" });\n ZIP_AVAILABLE = true;\n } catch {}\n try {\n execFileSync(\"which\", [\"unzip\"], { stdio: \"ignore\" });\n UNZIP_AVAILABLE = true;\n } catch {}\n} else {\n // On Windows, prefer python zipfile fallback; check if powershell Expand-Archive exists\n // We keep false to trigger python fallback unless zip/unzip are on PATH\n try {\n execFileSync(\"where\", [\"zip\"], { stdio: \"ignore\" });\n ZIP_AVAILABLE = true;\n } catch {}\n try {\n execFileSync(\"where\", [\"unzip\"], { stdio: \"ignore\" });\n UNZIP_AVAILABLE = true;\n } catch {}\n}\n\nfunction preprocessCommand(command: string): string {\n let trimmed = command.trim();\n\n // If command calls zip and zip CLI is missing, fallback to python3 zipfile\n if (!ZIP_AVAILABLE && /^zip\\s+/i.test(trimmed)) {\n const parts = trimmed.split(/\\s+/).slice(1);\n if (parts.length >= 2) {\n const zipFile = parts[0];\n const files = parts.slice(1).join(\" \");\n return `python3 -m zipfile -c ${zipFile} ${files}`;\n }\n }\n\n // If command calls unzip and unzip CLI is missing, fallback to python3 zipfile\n if (!UNZIP_AVAILABLE && /^unzip\\s+/i.test(trimmed)) {\n const parts = trimmed.split(/\\s+/).slice(1);\n let zipFile = \"\";\n let outDir = WORKSPACE_DIR;\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] === \"-d\" && parts[i + 1]) {\n outDir = parts[i + 1];\n i++;\n } else if (!zipFile && !parts[i].startsWith(\"-\")) {\n zipFile = parts[i];\n }\n }\n if (zipFile) {\n return `python3 -m zipfile -e ${zipFile} ${outDir}`;\n }\n }\n\n return trimmed;\n}\n\n// Defense-in-depth blocklist: obviously destructive, exfiltrating, or\n// privilege-escalating patterns get rejected outright before spawning\n// anything. Not meant to be a complete sandbox on its own.\n// G\u01102: logic \u0111\u00E3 t\u00E1ch sang src/core/security/blocklist.ts (pure, c\u00F3 test).\n// PowerShell `Remove-Item -Recurse` kh\u00F4ng c\u00F2n b\u1ECB ch\u1EB7n b\u1EEBa: ch\u1EC9 ch\u1EB7n khi \u0111\u00EDch\n// nguy hi\u1EC3m (g\u1ED1c \u1ED5 \u0111\u0129a, ngo\u00E0i workspace, ~, $HOME, wildcard tr\u00F9m h\u1EBFt, ...).\nfunction findBlockedPattern(command: string): string | null {\n return findBlockedCommand(command, { workspaceDir: WORKSPACE_DIR, platform: process.platform });\n}\n\n// ============================================================================\n// Web Search & Fetch helpers\n//\n// Goal: search multiple free, no-API-key engines in parallel (so one engine\n// getting blocked/rate-limited doesn't take the whole tool down), then filter\n// out domains that are known to block scraping / require login / render\n// nothing without JS, and rank the survivors so well-established, reputable\n// sources are offered first. Fetch then extracts the actual article content\n// (via Mozilla's Readability algorithm - the same engine behind Firefox's\n// Reader View) instead of dumping every nav/ads/footer string on the page.\n// ============================================================================\n\nconst DESKTOP_UA =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\";\n\n// Hosts that are effectively unfetchable as plain HTML: they either require a\n// login, render everything client-side via JS, or actively block scrapers.\n// Kept out of search results entirely, and fast-failed (no network round\n// trip) if the AI tries to fetch() one directly.\nconst BLOCKED_HOST_SUFFIXES = [\n \"facebook.com\",\n \"fb.com\",\n \"instagram.com\",\n \"threads.net\",\n \"twitter.com\",\n \"x.com\",\n \"tiktok.com\",\n \"linkedin.com\",\n \"pinterest.com\",\n \"pinterest.jp\",\n \"quora.com\",\n \"discord.com\",\n \"discord.gg\",\n \"messenger.com\",\n \"whatsapp.com\",\n \"t.me\",\n \"telegram.org\",\n \"youtube.com\",\n \"youtu.be\",\n \"music.youtube.com\",\n \"zalo.me\",\n \"scribd.com\",\n \"academia.edu\",\n \"accounts.google.com\",\n \"myaccount.google.com\",\n];\n\n// Hosts that ARE fetchable, just not at the URL an engine hands back. Rewrite\n// before fetching instead of blocking outright.\nconst DOMAIN_REWRITES: Record<string, string> = {\n \"reddit.com\": \"old.reddit.com\",\n \"www.reddit.com\": \"old.reddit.com\",\n};\n\n// Sources worth ranking higher: encyclopedic/reference, .gov/.edu, major wire\n// services & newsrooms, and well-known Vietnamese outlets (since this tool is\n// used mostly for Vietnamese-language queries). This is a ranking boost, not\n// an allowlist - unknown domains still get through, just lower in the list.\nconst REPUTABLE_HOST_SUFFIXES = [\n \"wikipedia.org\",\n \"github.com\",\n \"stackoverflow.com\",\n \"developer.mozilla.org\",\n \"docs.python.org\",\n \"npmjs.com\",\n \"arxiv.org\",\n \"bbc.com\",\n \"reuters.com\",\n \"apnews.com\",\n \"nytimes.com\",\n \"theguardian.com\",\n \"forbes.com\",\n \"bloomberg.com\",\n \"nature.com\",\n \"sciencedirect.com\",\n \"vnexpress.net\",\n \"tuoitre.vn\",\n \"thanhnien.vn\",\n \"nhandan.vn\",\n \"baochinhphu.vn\",\n \"vietnamnet.vn\",\n \"laodong.vn\",\n \"dantri.com.vn\",\n \"vtv.vn\",\n \"vov.vn\",\n];\nconst REPUTABLE_TLD_SUFFIXES = [\".gov\", \".edu\", \".gov.vn\", \".edu.vn\"];\n\nconst NON_HTML_EXTENSIONS = [\n \".pdf\", \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\",\n \".zip\", \".rar\", \".7z\", \".tar\", \".gz\",\n \".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".svg\", \".bmp\", \".ico\",\n \".mp3\", \".mp4\", \".avi\", \".mov\", \".wav\", \".exe\", \".apk\", \".dmg\",\n];\n\nfunction hostMatchesSuffixList(hostname: string, suffixes: string[]): boolean {\n const h = hostname.toLowerCase().replace(/^www\\./, \"\");\n return suffixes.some((s) => h === s || h.endsWith(\".\" + s));\n}\n\nfunction isBlockedHost(hostname: string): boolean {\n if (!hostname) return false;\n return hostMatchesSuffixList(hostname, BLOCKED_HOST_SUFFIXES);\n}\n\nfunction applyDomainRewrite(urlStr: string): string {\n try {\n const u = new URL(urlStr);\n const host = u.hostname.toLowerCase();\n if (DOMAIN_REWRITES[host]) {\n u.hostname = DOMAIN_REWRITES[host];\n return u.toString();\n }\n return urlStr;\n } catch {\n return urlStr;\n }\n}\n\nfunction reputationScore(hostname: string): number {\n if (!hostname) return 0;\n const h = hostname.toLowerCase();\n if (hostMatchesSuffixList(h, REPUTABLE_HOST_SUFFIXES)) return 10;\n if (REPUTABLE_TLD_SUFFIXES.some((tld) => h.endsWith(tld))) return 8;\n return 0;\n}\n\nfunction looksLikeNonHtmlFile(urlStr: string): boolean {\n try {\n const p = new URL(urlStr).pathname.toLowerCase();\n return NON_HTML_EXTENSIONS.some((ext) => p.endsWith(ext));\n } catch {\n return false;\n }\n}\n\nfunction decodeHtmlEntities(str: string): string {\n if (!str) return \"\";\n return str\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, \"\\\"\")\n .replace(/�?39;/g, \"'\")\n .replace(/'/g, \"'\")\n .replace(/’|‘/g, \"'\")\n .replace(/”|“/g, \"\\\"\")\n .replace(/—/g, \"\u2014\")\n .replace(/–/g, \"\u2013\")\n .replace(/…/g, \"\u2026\")\n .replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))\n .replace(/&#(\\d+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10)));\n}\n\nfunction stripInnerTags(str: string): string {\n if (!str) return \"\";\n return str.replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim();\n}\n\ninterface RawSearchResult {\n url: string;\n title: string;\n snippet: string;\n engine: string;\n}\n\n// --- Engine 1: DuckDuckGo HTML (no JS, no API key, generally the most\n// scrape-tolerant of the major engines) ---\nasync function searchDuckDuckGo(query: string, count: number): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n try {\n const q = encodeURIComponent(query.trim());\n const resp = await fetch(`https://html.duckduckgo.com/html/?q=${q}&kl=wt-wt`, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n });\n if (!resp.ok) return results;\n const html = await resp.text();\n const resultRegex = /<a[^>]+class=\"result__a\"[^>]+href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<a[^>]+class=\"result__snippet\"[^>]*>([\\s\\S]*?)<\\/a>/gi;\n let m: RegExpExecArray | null;\n while ((m = resultRegex.exec(html)) !== null && results.length < count * 2) {\n let url = m[1];\n if (url.startsWith(\"//duckduckgo.com/l/\")) {\n const uddgMatch = url.match(/[?&]uddg=([^&]+)/);\n if (uddgMatch) url = decodeURIComponent(uddgMatch[1]);\n } else if (url.startsWith(\"//\")) {\n url = \"https:\" + url;\n }\n if (!url.startsWith(\"http\")) continue;\n const title = decodeHtmlEntities(stripInnerTags(m[2]));\n const snippet = decodeHtmlEntities(stripInnerTags(m[3])) || title;\n if (!title && !snippet) continue;\n results.push({ url, title, snippet, engine: \"duckduckgo\" });\n }\n } catch (err) {\n console.warn(\"DuckDuckGo search error:\", err);\n }\n return results;\n}\n\n// --- Engine 2: Bing HTML (organic results render with real hrefs in the\n// no-JS markup) ---\nasync function searchBing(query: string, count: number): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n try {\n const q = encodeURIComponent(query.trim());\n const resp = await fetch(`https://www.bing.com/search?q=${q}&count=${Math.min(30, count * 3)}&setlang=en-US`, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n });\n if (!resp.ok) return results;\n const html = await resp.text();\n const resultRegex = /<li class=\"b_algo\"[^>]*>[\\s\\S]*?<h2>[\\s\\S]*?<a href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<\\/h2>([\\s\\S]*?)<\\/li>/gi;\n let m: RegExpExecArray | null;\n while ((m = resultRegex.exec(html)) !== null && results.length < count * 2) {\n const url = m[1];\n if (!url.startsWith(\"http\")) continue;\n const title = decodeHtmlEntities(stripInnerTags(m[2]));\n const bodyBlock = m[3] || \"\";\n const snippetMatch =\n bodyBlock.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/i) ||\n bodyBlock.match(/<div class=\"b_caption\"[^>]*>([\\s\\S]*?)<\\/div>/i);\n const snippet = snippetMatch ? decodeHtmlEntities(stripInnerTags(snippetMatch[1])) : title;\n if (!title && !snippet) continue;\n results.push({ url, title, snippet, engine: \"bing\" });\n }\n } catch (err) {\n console.warn(\"Bing search error:\", err);\n }\n return results;\n}\n\n// --- Engine 3: Yahoo Japan search (kept from the original implementation as\n// a third, independent fallback source) ---\nasync function searchYahooJP(query: string, count: number): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n const q = encodeURIComponent(query.trim());\n\n try {\n const response = await fetch(`https://search.yahoo.co.jp/search?p=${q}`, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n });\n\n if (response.ok) {\n const html = await response.text();\n const sectionRegex = /<div class=\"sw-Card[^\"]*\"[\\s\\S]*?<a\\s+href=\"([^\"]+)\"[^>]*>[\\s\\S]*?<h3[^>]*>([\\s\\S]*?)<\\/h3>[\\s\\S]*?(?:<p class=\"sw-Card__summary\">([\\s\\S]*?)<\\/p>)?/gi;\n let match: RegExpExecArray | null;\n while ((match = sectionRegex.exec(html)) !== null && results.length < count) {\n const url = match[1];\n if (url.startsWith(\"http\") && !url.includes(\"search.yahoo.co.jp\")) {\n const title = decodeHtmlEntities(stripInnerTags(match[2]));\n const snippet = match[3] ? decodeHtmlEntities(stripInnerTags(match[3])) : title;\n results.push({ url, title, snippet, engine: \"yahoo\" });\n }\n }\n }\n } catch (err) {\n console.warn(\"Yahoo search primary endpoint error:\", err);\n }\n\n if (results.length === 0) {\n try {\n const newsRes = await fetch(`https://news.search.yahoo.com/search?p=${q}`, {\n headers: { \"User-Agent\": DESKTOP_UA },\n });\n if (newsRes.ok) {\n const newsHtml = await newsRes.text();\n const newsRegex = /<h4[^>]*><a[^>]+href=\"([^\"]+)\"[^>]*>(.*?)<\\/a><\\/h4>/gi;\n let nMatch: RegExpExecArray | null;\n while ((nMatch = newsRegex.exec(newsHtml)) !== null && results.length < count) {\n let link = nMatch[1];\n if (link.includes(\"/RU=\")) {\n const ruMatch = link.match(/\\/RU=([^/]+)/);\n if (ruMatch) link = decodeURIComponent(ruMatch[1]);\n }\n const title = decodeHtmlEntities(stripInnerTags(nMatch[2]));\n if (link.startsWith(\"http\")) {\n results.push({ url: link, title, snippet: title, engine: \"yahoo-news\" });\n }\n }\n }\n } catch (err) {\n console.warn(\"Yahoo news fallback error:\", err);\n }\n }\n\n return results;\n}\n\nfunction interleaveResults(arrays: RawSearchResult[][]): RawSearchResult[] {\n const out: RawSearchResult[] = [];\n const maxLen = Math.max(0, ...arrays.map((a) => a.length));\n for (let i = 0; i < maxLen; i++) {\n for (const arr of arrays) {\n if (arr[i]) out.push(arr[i]);\n }\n }\n return out;\n}\n\nfunction normalizeForDedupe(url: string): string {\n try {\n const u = new URL(url);\n return (u.hostname.replace(/^www\\./, \"\") + u.pathname.replace(/\\/$/, \"\")).toLowerCase();\n } catch {\n return url.toLowerCase();\n }\n}\n\n// Filters out unfetchable/blocked/non-HTML results, de-duplicates, caps how\n// many results a single domain can contribute (keeps sources diverse), and\n// sorts reputable domains first.\nfunction mergeAndFilterResults(all: RawSearchResult[], count: number): { url: string; snippet: string }[] {\n const seen = new Set<string>();\n const perDomainCount = new Map<string, number>();\n const filtered: (RawSearchResult & { score: number })[] = [];\n\n for (const r of all) {\n if (!r.url || !r.url.startsWith(\"http\")) continue;\n let hostname = \"\";\n try {\n hostname = new URL(r.url).hostname.toLowerCase();\n } catch {\n continue;\n }\n if (isBlockedHost(hostname)) continue;\n if (looksLikeNonHtmlFile(r.url)) continue;\n\n const dedupeKey = normalizeForDedupe(r.url);\n if (seen.has(dedupeKey)) continue;\n\n const domainKey = hostname.replace(/^www\\./, \"\");\n const domainCount = perDomainCount.get(domainKey) || 0;\n if (domainCount >= 2) continue;\n\n seen.add(dedupeKey);\n perDomainCount.set(domainKey, domainCount + 1);\n filtered.push({ ...r, url: applyDomainRewrite(r.url), score: reputationScore(hostname) });\n }\n\n filtered.sort((a, b) => b.score - a.score);\n\n return filtered.slice(0, count).map((r) => ({\n url: r.url,\n snippet: (r.snippet && r.snippet.trim()) || r.title || r.url,\n }));\n}\n\n// --- Fetch-with-byte-cap: reads the response body incrementally and stops\n// once MAX_FETCH_BYTES is hit, instead of buffering an unbounded page ---\nconst MAX_FETCH_BYTES = 6 * 1024 * 1024; // 6MB safety cap\n\nasync function fetchWithByteLimit(\n url: string,\n signal: AbortSignal,\n maxBytes: number\n): Promise<{ ok: boolean; status: number; contentType: string; body: string }> {\n const response = await fetch(url, {\n signal,\n redirect: \"follow\",\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n \"Accept-Language\": \"vi-VN,vi;q=0.9,en-US;q=0.8,en;q=0.7\",\n },\n });\n\n const contentType = response.headers.get(\"content-type\") || \"\";\n\n if (!response.body) {\n const text = await response.text();\n return { ok: response.ok, status: response.status, contentType, body: text.slice(0, maxBytes) };\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let received = 0;\n let body = \"\";\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n received += value.byteLength;\n body += decoder.decode(value, { stream: true });\n if (received >= maxBytes) {\n try {\n await reader.cancel();\n } catch {\n // ignore\n }\n break;\n }\n }\n body += decoder.decode();\n return { ok: response.ok, status: response.status, contentType, body };\n}\n\nfunction fallbackCleanHtml(html: string): string {\n const stripped = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, \" \")\n .replace(/<svg[\\s\\S]*?<\\/svg>/gi, \" \")\n .replace(/<iframe[\\s\\S]*?<\\/iframe>/gi, \" \")\n .replace(/<!--[\\s\\S]*?-->/g, \" \")\n .replace(/<(nav|header|footer|aside|form|button|select|figure|figcaption)[^>]*>[\\s\\S]*?<\\/\\1>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n return decodeHtmlEntities(stripped);\n}\n\n// Extracts the actual article content from a raw HTML page. Tries Mozilla's\n// Readability algorithm first (the same one behind Firefox Reader View -\n// strips nav/ads/footers/comments and keeps just the article body); falls\n// back to tag-stripping (still boilerplate-tag-aware) if Readability can't\n// find an article on the page (e.g. it's a listing/home page, not an article).\nfunction extractReadableContent(\n html: string,\n url: string\n): { title: string; text: string; usedReadability: boolean } {\n try {\n const dom = new JSDOM(html, { url });\n const doc = dom.window.document;\n doc.querySelectorAll(\"script, style, noscript, iframe, svg, form\").forEach((el) => el.remove());\n\n const reader = new Readability(doc, { charThreshold: 200 });\n const article = reader.parse();\n\n if (article && article.textContent && article.textContent.trim().length > 150) {\n const cleanText = article.textContent.replace(/[ \\t]+/g, \" \").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n return { title: article.title || \"\", text: cleanText, usedReadability: true };\n }\n } catch (err: any) {\n console.warn(\"Readability extraction failed, falling back:\", err?.message);\n }\n\n return { title: \"\", text: fallbackCleanHtml(html), usedReadability: false };\n}\n\n\n// ============================================================================\n// SearXNG \u2014 default search engine, Yahoo JP fallback\n// Config: SEARXNG_URL (or SEARXNG) env var, defaults to http://localhost:8080\n// Needs settings.yml: search.formats: [html, json] and server.limiter: false\n// Test: curl \"http://localhost:8080/search?q=test&format=json\"\n// ============================================================================\n// Opt-in: empty = disabled (no wasted request to a SearXNG that is not running).\nconst SEARXNG_URL = (process.env.SEARXNG_URL || process.env.SEARXNG || \"\").replace(/\\/$/, \"\");\n\nasync function searchSearXNG(query: string, count: number, categories: \"general\" | \"images\" = \"general\", baseUrl: string = SEARXNG_URL): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n if (!baseUrl) return results;\n try {\n const params = new URLSearchParams({ q: query.trim(), format: \"json\", categories, pageno: \"1\" });\n const url = `${baseUrl}/search?${params.toString()}`;\n const resp = await fetch(url, {\n signal: AbortSignal.timeout(6000),\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept\": \"application/json\",\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n });\n if (!resp.ok) {\n console.warn(`SearXNG search failed ${resp.status} for \"${query}\"`);\n return results;\n }\n const j: any = await resp.json();\n const raw = Array.isArray(j.results) ? j.results : [];\n for (const x of raw) {\n if (results.length >= count * 2) break;\n if (categories === \"images\") {\n const title = (x.title || x.content || \"\").toString();\n const url = (x.url || x.img_src || \"\").toString();\n const img_src = (x.img_src || x.url || \"\").toString();\n const thumb = (x.thumbnail_src || x.img_src || x.thumbnail || \"\").toString();\n if (!img_src && !url) continue;\n results.push({\n url: url || img_src,\n title,\n snippet: title,\n engine: \"searxng-images\",\n _img_src: img_src,\n _thumb: thumb,\n } as any);\n } else {\n const title = (x.title || \"\").toString();\n const url = (x.url || \"\").toString();\n const snippet = (x.content || x.title || \"\").toString();\n if (!url || !url.startsWith(\"http\")) continue;\n results.push({ url, title, snippet, engine: \"searxng\" });\n }\n }\n } catch (err) {\n console.warn(\"SearXNG search error:\", err);\n }\n return results;\n}\n\n\n// ---- User-supplied URLs (from browser settings): must be public http(s) ----\nfunction isPrivateIp(ip: string): boolean {\n const v = ip.toLowerCase();\n if (v.startsWith(\"::ffff:\")) return isPrivateIp(v.slice(7));\n if (net.isIPv4(v)) {\n const [a, b] = v.split(\".\").map(Number);\n return a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127);\n }\n return v === \"::1\" || v === \"::\" || v.startsWith(\"fc\") || v.startsWith(\"fd\") || v.startsWith(\"fe80\");\n}\nasync function assertPublicUrl(raw: string): Promise<URL> {\n const u = new URL(raw);\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new Error(\"Only http/https URLs are allowed\");\n if (process.env.ALLOW_PRIVATE_URLS === \"1\") return u;\n const host = u.hostname.replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\" || host.endsWith(\".local\") || host.endsWith(\".internal\")) throw new Error(\"Private/local hosts are not allowed\");\n const addrs = net.isIP(host) ? [{ address: host }] : await dns.lookup(host, { all: true });\n for (const a of addrs) if (isPrivateIp(a.address)) throw new Error(\"Private/local hosts are not allowed\");\n return u;\n}\nasync function resolveSearxUrl(req: any): Promise<string> {\n const raw = String(req.body?.searxngUrl || req.headers[\"x-searxng-url\"] || \"\").trim();\n if (!raw) return SEARXNG_URL;\n try {\n const u = await assertPublicUrl(raw);\n return (u.origin + u.pathname).replace(/\\/$/, \"\");\n } catch (e: any) {\n console.warn(\"[SearXNG] user URL rejected:\", e?.message);\n return SEARXNG_URL;\n }\n}\n\nasync function searchSearXNGGeneral(query: string, count: number): Promise<RawSearchResult[]> {\n return searchSearXNG(query, count, \"general\");\n}\n\n// ============================================================================\n// Image search helpers (SearXNG categories=images) + image proxy\n// ============================================================================\ninterface ImageResult {\n title: string;\n src: string;\n thumb: string;\n page: string;\n}\n\n// ============================================================================\n// MCP \u2014 file-based config (mcp.json), server.ts as bridge\n// Format: Claude Code style { \"mcpServers\": { name: {type, command, args, url, headers, env, enabled} } }\n// Also supports opencode style { \"mcp\": { ... } } / { \"mcp\": { \"servers\": { ... } } }\n// Web can't spawn processes, so server.ts bridges via MCP SDK\n// Security: only read config from file on server; never accept command/url from client\n// ============================================================================\nfunction stripJsonc(s: string): string {\n // Remove // and /* */ comments but keep them inside strings (e.g. \"https://...\")\n return s.replace(/(\"(?:\\\\.|[^\"\\\\])*\")|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm, (_m, str) => str ?? \"\");\n}\nfunction isLocalRequest(req: any): boolean {\n const ip = String(req.socket?.remoteAddress || \"\");\n const loop = ip === \"127.0.0.1\" || ip === \"::1\" || ip === \"::ffff:127.0.0.1\";\n return loop && !req.headers[\"x-forwarded-for\"]; // tunnels (ngrok) add x-forwarded-for\n}\nfunction mcpAdminGuard(req: any, res: any, next: any) {\n const token = process.env.ADMIN_TOKEN;\n if (!token) return next(); // no ADMIN_TOKEN set = open (personal instance), same as before\n if (req.headers[\"x-admin-token\"] === token) return next();\n return res.status(403).json({ error: \"Admin only: send header x-admin-token matching ADMIN_TOKEN.\" });\n}\nfunction resolveEnvVars(str: string): string {\n if (typeof str !== \"string\") return str;\n return str.replace(/\\$\\{([^}]+)\\}/g, (_, name) => process.env[name.trim()] ?? \"\");\n}\nfunction resolveEnvObject(obj: Record<string, string> | undefined): Record<string, string> | undefined {\n if (!obj || typeof obj !== \"object\") return obj;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(obj)) {\n out[k] = typeof v === \"string\" ? resolveEnvVars(v) : v;\n }\n return out;\n}\n\ntype McpEntry = {\n client: Client | null;\n tools: any[];\n status: \"connected\" | \"failed\" | \"disabled\" | \"connecting\";\n error?: string;\n config: any;\n type: string;\n};\n\nconst mcp = new Map<string, McpEntry>();\n\nfunction normalizeMcpType(t: string): \"stdio\" | \"http\" {\n const low = (t || \"\").toLowerCase();\n if (low === \"http\" || low === \"remote\" || low === \"streamablehttp\" || low === \"sse\") return \"http\";\n return \"stdio\";\n}\n\nasync function connectMcp(name: string, cfg: any) {\n const explicitlyDisabled = cfg.enabled === false || cfg.disabled === true;\n if (explicitlyDisabled) {\n mcp.set(name, { client: null, tools: [], status: \"disabled\", config: cfg, type: normalizeMcpType(cfg.type) });\n return;\n }\n const type = normalizeMcpType(cfg.type || (cfg.url ? \"http\" : \"stdio\"));\n const entry: McpEntry = { client: null, tools: [], status: \"connecting\", config: cfg, type };\n mcp.set(name, entry);\n try {\n let transport: any;\n if (type === \"http\") {\n const rawUrl = cfg.url;\n if (!rawUrl) throw new Error(\"Missing url for http/remote MCP server\");\n const resolvedUrl = resolveEnvVars(String(rawUrl));\n const headers = resolveEnvObject(cfg.headers) || {};\n transport = new StreamableHTTPClientTransport(new URL(resolvedUrl), { requestInit: { headers } } as any);\n } else {\n let command: string | undefined = cfg.command;\n let args: string[] = Array.isArray(cfg.args) ? cfg.args : [];\n let env: Record<string, string> | undefined = resolveEnvObject(cfg.env || cfg.environment);\n if (Array.isArray(command)) {\n args = (command as string[]).slice(1);\n command = (command as string[])[0];\n }\n if (!command) throw new Error(\"Missing command for stdio/local MCP server\");\n const resolvedCommand = resolveEnvVars(String(command));\n const resolvedArgs = args.map((a) => resolveEnvVars(String(a)));\n transport = new StdioClientTransport({ command: resolvedCommand, args: resolvedArgs, env: env as any } as any);\n }\n const client = new Client({ name: \"fanluc\", version: \"1.0.0\" } as any, { capabilities: {} } as any);\n await client.connect(transport);\n const toolsRes: any = await client.listTools();\n const tools = Array.isArray(toolsRes?.tools) ? toolsRes.tools : [];\n const truncated = tools.map((t: any) => ({\n ...t,\n description: typeof t.description === \"string\" ? t.description : t.description,\n }));\n mcp.set(name, { client, tools: truncated, status: \"connected\", config: cfg, type });\n console.log(`[MCP] ${name} connected \u2014 ${truncated.length} tools`);\n } catch (e: any) {\n const msg = e?.message || String(e);\n console.warn(`[MCP] ${name} failed:`, msg);\n mcp.set(name, { client: null as any, tools: [], status: \"failed\", error: msg, config: cfg, type });\n }\n}\n\nfunction getFanlucConfigDir(): string {\n // Same logic as src/cli/config.ts \u2014 keep in sync\n if (process.env.FANLUC_CONFIG_DIR?.trim()) return process.env.FANLUC_CONFIG_DIR.trim();\n if (IS_WINDOWS) {\n const appData = process.env.APPDATA;\n if (appData) return path.join(appData, \"fanluc\");\n return path.join(os.homedir(), \"AppData\", \"Roaming\", \"fanluc\");\n }\n const xdg = process.env.XDG_CONFIG_HOME;\n if (xdg) return path.join(xdg, \"fanluc\");\n return path.join(os.homedir(), \".config\", \"fanluc\");\n}\n\n\n/** mcp.json lives in the fanluc config dir (never in the user's project directory). */\nfunction mcpConfigPath(): string {\n const dir = getFanlucConfigDir();\n try { fs.mkdirSync(dir, { recursive: true }); } catch {}\n return path.join(dir, \"mcp.json\");\n}\nfunction readMcpServersFile(mcpPath: string): Record<string, any> {\n if (!fs.existsSync(mcpPath)) return {};\n const raw = fs.readFileSync(mcpPath, \"utf-8\").replace(/^\\uFEFF/, \"\");\n if (!raw.trim()) return {};\n const j = JSON.parse(stripJsonc(raw));\n if (j.mcpServers) return j.mcpServers;\n if (j.mcp && j.mcp.servers) return j.mcp.servers;\n if (j.mcp && typeof j.mcp === \"object\") return j.mcp;\n return j;\n}\n\nfunction loadMcpConfigSync(): Record<string, any> {\n const configDir = getFanlucConfigDir();\n // G\u01101-fix4: ch\u1EC9 \u0111\u1ECDc t\u1EEB config dir, kh\u00F4ng t\u1EF1 n\u1EA1p cwd/mcp.json\n const candidates = [\n path.join(configDir, \"mcp.json\"),\n path.join(configDir, \"mcp.jsonc\"),\n ];\n for (const p of candidates) {\n try {\n if (fs.existsSync(p)) {\n const raw = fs.readFileSync(p, \"utf-8\").replace(/^\\uFEFF/, \"\");\n const cleaned = stripJsonc(raw);\n const j = JSON.parse(cleaned);\n if (j.mcpServers && typeof j.mcpServers === \"object\") return j.mcpServers;\n if (j.mcp && j.mcp.servers && typeof j.mcp.servers === \"object\") return j.mcp.servers;\n if (j.mcp && typeof j.mcp === \"object\" && !j.mcp.servers) {\n const maybe = j.mcp;\n const vals = Object.values(maybe) as any[];\n if (vals.length && vals.every((v: any) => v && typeof v.type === \"string\")) return maybe;\n }\n const topVals = Object.values(j) as any[];\n if (topVals.length && topVals.every((v: any) => v && typeof v.type === \"string\")) return j;\n return {};\n }\n } catch (e) {\n console.warn(`Failed to load MCP config from ${p}:`, e);\n }\n }\n return {};\n}\n\nasync function initMcpFromFile() {\n const cfgMap = loadMcpConfigSync();\n const entries = Object.entries(cfgMap);\n if (entries.length === 0) {\n console.log(\"[MCP] no mcp.json found or empty \u2014 skipping MCP init\");\n return;\n }\n console.log(`[MCP] loading ${entries.length} server(s) from mcp.json`);\n for (const [name, cfg] of entries) {\n await connectMcp(name, cfg);\n }\n}\n\nfunction getMcpToolsForModel(): any[] {\n const out: any[] = [];\n for (const [server, entry] of mcp.entries()) {\n if (entry.status !== \"connected\") continue;\n for (const t of entry.tools) {\n out.push({\n server,\n name: `${server}_${t.name}`,\n originalName: t.name,\n description: t.description || \"\",\n inputSchema: t.inputSchema,\n });\n }\n }\n return out;\n}\n\n\nasync function startServer() {\n const app = express();\n\n // When bound to loopback only, refuse requests whose Host header is not local (blocks DNS-rebinding from web pages).\n {\n const bind = process.env.HOST || \"0.0.0.0\";\n if (bind === \"127.0.0.1\" || bind === \"localhost\" || bind === \"::1\") {\n app.use((req, res, next) => {\n const h = String(req.headers.host || \"\").replace(/:\\d+$/, \"\").replace(/^\\[|\\]$/g, \"\");\n if (h === \"localhost\" || h === \"127.0.0.1\" || h === \"::1\") return next();\n return res.status(403).json({ error: \"Forbidden host\" });\n });\n }\n }\n const PORT = Number(process.env.PORT) || 3000;\n\n app.use(express.json({ limit: \"50mb\" }));\n\n // Init MCP servers from mcp.json (non-blocking, log errors)\n initMcpFromFile().catch((e) => console.warn(\"[MCP] init failed:\", e));\n\n // API Proxy endpoint to solve CORS issues with ngrok / custom REST APIs (Google Colab, Kaggle, Local)\n app.post(\"/api/proxy-chat\", async (req, res) => {\n try {\n const { apiUrl, apiKey, body, customHeaders } = req.body;\n\n if (!apiUrl) {\n return res.status(400).json({ error: \"Missing apiUrl parameter\" });\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"ngrok-skip-browser-warning\": \"true\",\n \"User-Agent\": \"AI-Studio-Rest-Client/1.0\",\n \"Authorization\": `Bearer ${apiKey || \"\"}`,\n ...(customHeaders || {}),\n };\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 300000); // 300 second (5 min) timeout\n\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const responseText = await response.text();\n return res.status(response.status).send(responseText);\n }\n\n if (body?.stream && response.body) {\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(Buffer.from(value));\n }\n } catch (streamErr) {\n console.warn(\"Proxy stream pipe interrupted:\", streamErr);\n } finally {\n res.end();\n }\n return;\n }\n\n const responseText = await response.text();\n try {\n const data = JSON.parse(responseText);\n return res.json(data);\n } catch {\n return res.send(responseText);\n }\n } catch (error: any) {\n console.error(\"Proxy error:\", error);\n if (error?.name === \"AbortError\") {\n return res.status(504).json({\n error: \"API response timed out (>5 min) or instance disconnected.\",\n });\n }\n return res.status(500).json({ error: error?.message || \"Internal Proxy Error\" });\n }\n });\n\n // Web Search endpoint (SearXNG primary, multi-engine fallback)\n // SearXNG self-hosted is primary (free, no limits, supports images/news).\n // Yahoo JP kept as fallback. Route kept as /api/yahoo-search for frontend compat.\n app.post(\"/api/yahoo-search\", async (req, res) => {\n try {\n const { query, count = 7 } = req.body;\n if (!query || typeof query !== \"string\") {\n return res.status(400).json({ error: \"Missing query parameter\" });\n }\n\n const maxCount = Math.min(15, Math.max(1, parseInt(count) || 7));\n\n // 1) Try SearXNG first (default)\n let searxResults: RawSearchResult[] = [];\n try {\n searxResults = await searchSearXNG(query, maxCount, \"general\", await resolveSearxUrl(req));\n } catch (e) {\n console.warn(\"SearXNG general search error, falling back:\", e);\n }\n\n if (searxResults.length > 0) {\n // Filter + rank SearXNG results through same pipeline for quality\n let results = mergeAndFilterResults(searxResults, maxCount);\n if (results.length === 0) {\n // If filtering removed everything, use raw\n results = searxResults.slice(0, maxCount).map((r) => ({ url: r.url, snippet: r.snippet || r.title || r.url }));\n }\n const formattedText = `${results.length} results:\\n` + results.map((r) => `${r.url}: ${r.snippet}`).join(\"\\n\");\n return res.json({ count: results.length, results, formattedText, engine: \"searxng\" });\n }\n\n // 2) Fallback to multi-engine (DuckDuckGo + Bing + Yahoo JP)\n const perEngineCount = Math.min(20, maxCount + 6);\n const withTimeout = <T,>(p: Promise<T[]>, ms = 8000): Promise<T[]> =>\n Promise.race([p.catch(() => [] as T[]), new Promise<T[]>((r) => setTimeout(() => r([]), ms))]);\n const [ddgResults, bingResults, yahooResults] = await Promise.all([\n withTimeout(searchDuckDuckGo(query, perEngineCount)),\n withTimeout(searchBing(query, perEngineCount)),\n withTimeout(searchYahooJP(query, perEngineCount)),\n ]);\n\n let results = mergeAndFilterResults(\n interleaveResults([ddgResults, bingResults, yahooResults]),\n maxCount\n );\n\n if (results.length === 0) {\n const rawAll = [...ddgResults, ...bingResults, ...yahooResults];\n results = rawAll.slice(0, maxCount).map((r) => ({ url: r.url, snippet: r.snippet || r.title || r.url }));\n }\n\n const formattedText =\n results.length > 0\n ? `${results.length} results:\\n` + results.map((r) => `${r.url}: ${r.snippet}`).join(\"\\n\")\n : `0 results:\\n(no results found for \"${query}\")`;\n\n return res.json({\n count: results.length,\n results,\n formattedText,\n engine: results.length ? \"fallback\" : \"none\",\n });\n } catch (error: any) {\n console.error(\"Web search error:\", error);\n return res.status(500).json({ error: error?.message || \"Web search failed\" });\n }\n });\n\n // Dedicated SearXNG search (optional direct access)\n app.post(\"/api/searxng-search\", async (req, res) => {\n try {\n const { query, count = 7, categories = \"general\" } = req.body;\n if (!query || typeof query !== \"string\") return res.status(400).json({ error: \"Missing query\" });\n const maxCount = Math.min(15, Math.max(1, parseInt(count) || 7));\n const cat = categories === \"images\" ? \"images\" : \"general\";\n const raw = await searchSearXNG(query, maxCount, cat as any, await resolveSearxUrl(req));\n let results: any[] = [];\n if (cat === \"images\") {\n // Return image-mapped results\n const filtered = raw.slice(0, maxCount).map((r: any) => ({\n title: r.title,\n src: (r as any)._img_src || r.url,\n thumb: (r as any)._thumb || (r as any)._img_src || r.url,\n page: r.url,\n url: r.url,\n }));\n return res.json({ count: filtered.length, results: filtered, formattedText: filtered.length ? `${filtered.length} images:${filtered.map((x:any)=>\" \"+x.src).join(\",\")}` : \"0 images\" });\n } else {\n results = mergeAndFilterResults(raw, maxCount);\n if (results.length === 0) results = raw.slice(0, maxCount).map((r) => ({ url: r.url, snippet: r.snippet }));\n const formattedText = results.length ? `${results.length} results:\\n` + results.map((r:any)=>`${r.url}: ${r.snippet}`).join(\"\\n\") : `0 results\\n(no results)`;\n return res.json({ count: results.length, results, formattedText });\n }\n } catch (e:any){ return res.status(500).json({error:e?.message});}\n });\n\n // Image search (SearXNG categories=images, fallback to empty)\n app.post(\"/api/image-search\", async (req, res) => {\n try {\n const { query, count = 6 } = req.body;\n if (!query || typeof query !== \"string\") return res.status(400).json({ error: \"Missing query\" });\n const maxCount = Math.min(12, Math.max(1, parseInt(count) || 6));\n const raw = await searchSearXNG(query, maxCount, \"images\", await resolveSearxUrl(req));\n // Map to UI-friendly shape\n let images: ImageResult[] = raw.slice(0, maxCount).map((r: any) => ({\n title: r.title || query,\n src: (r as any)._img_src || r.url,\n thumb: (r as any)._thumb || (r as any)._img_src || r.url,\n page: r.url,\n })).filter((x) => x.src && x.src.startsWith(\"http\"));\n // Dedupe by src\n const seen = new Set<string>();\n images = images.filter((x) => { if(seen.has(x.src)) return false; seen.add(x.src); return true; });\n const formattedText = images.length ? `\u0110\u00E3 hi\u1EC3n th\u1ECB ${images.length} \u1EA3nh v\u1EC1 \"${query}\"` : `Kh\u00F4ng t\u00ECm th\u1EA5y \u1EA3nh cho \"${query}\"`;\n return res.json({ count: images.length, images, formattedText });\n } catch (e:any){\n console.error(\"Image search error:\", e);\n return res.status(500).json({ error: e?.message || \"Image search failed\" });\n }\n });\n\n // Image proxy (to avoid hotlink blocking)\n app.get(\"/api/image-proxy\", async (req, res) => {\n try {\n const url = String(req.query.url || \"\");\n if (!url || !url.startsWith(\"http\")) return res.status(400).send(\"Missing url\");\n const parsed = new URL(url);\n if (isBlockedHost(parsed.hostname)) return res.status(403).send(\"Blocked host\");\n let resp: Response | null = null;\n let cur = url;\n for (let hop = 0; hop < 4; hop++) {\n const h = new URL(cur).hostname;\n if (isBlockedHost(h)) return res.status(403).send(\"Blocked host\");\n resp = await fetch(cur, { redirect: \"manual\", headers: { \"User-Agent\": DESKTOP_UA, \"Accept\": \"image/*,*/*\" } } as any);\n const loc = resp.headers.get(\"location\");\n if (resp.status >= 300 && resp.status < 400 && loc) { cur = new URL(loc, cur).toString(); resp = null; continue; }\n break;\n }\n if (!resp) return res.status(508).send(\"Too many redirects\");\n if (!resp.ok) return res.status(resp.status).send(\"Fetch failed\");\n const ct = resp.headers.get(\"content-type\") || \"image/jpeg\";\n if (!ct.startsWith(\"image/\")) return res.status(415).send(\"Not an image\");\n res.setHeader(\"Content-Type\", ct);\n res.setHeader(\"Cache-Control\", \"public, max-age=86400\");\n if (resp.body) {\n const reader = resp.body.getReader();\n // stream\n res.flushHeaders?.();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(Buffer.from(value));\n }\n res.end();\n } else {\n const buf = Buffer.from(await resp.arrayBuffer());\n res.send(buf);\n }\n } catch (e:any){ return res.status(500).send(e?.message); }\n });\n\n // ==========================================================================\n // MCP endpoints\n // Security: config only from file; client never sends command/url\n // ==========================================================================\n app.get(\"/api/mcp/status\", (_req, res) => {\n const list = [...mcp.entries()].map(([name, v]) => ({\n name,\n type: v.type, // stdio / http\n status: v.status, // connected / failed / disabled / connecting\n tools: v.tools,\n toolCount: v.tools.length,\n error: v.error || null,\n }));\n // Also include tools for model (prefixed)\n const modelTools = getMcpToolsForModel();\n res.json({ servers: list, modelTools, count: list.length });\n });\n\n app.get(\"/api/mcp/tools\", (_req, res) => {\n // For model injection: only enabled connected servers, truncated\n res.json({ tools: getMcpToolsForModel() });\n });\n\n app.post(\"/api/mcp/call\", async (req, res) => {\n try {\n const { server, tool, args, arguments: altArgs } = req.body || {};\n const toolName = tool;\n const toolArgs = args ?? altArgs ?? {};\n if (!server || !toolName) return res.status(400).json({ error: \"Missing server or tool\" });\n const entry = mcp.get(server);\n if (!entry) return res.status(404).json({ error: `MCP server \"${server}\" not found` });\n if (entry.status !== \"connected\" || !entry.client) return res.status(400).json({ error: `MCP server \"${server}\" not connected (${entry.status})${entry.error ? \": \"+entry.error : \"\"}` });\n // Validate tool exists on this server (or with prefix)\n const actualTool = toolName.includes(\"_\") && toolName.startsWith(server + \"_\")\n ? toolName.slice(server.length + 1)\n : toolName;\n const result: any = await entry.client.callTool({ name: actualTool, arguments: toolArgs });\n return res.json(result);\n } catch (e:any){\n console.error(\"MCP call error:\", e);\n return res.status(500).json({ error: e?.message || \"MCP call failed\" });\n }\n });\n\n // ---- Browser-configured MCP (http only, stateless: connect per request) ----\n async function withUserMcp<T>(cfg: any, fn: (c: Client) => Promise<T>): Promise<T> {\n const u = await assertPublicUrl(String(cfg?.url || \"\"));\n const headers: Record<string, string> = {};\n if (cfg?.headers && typeof cfg.headers === \"object\") {\n for (const [k, v] of Object.entries(cfg.headers)) if (typeof v === \"string\" && /^[\\w-]+$/.test(k)) headers[k] = v;\n }\n const transport = new StreamableHTTPClientTransport(u, { requestInit: { headers } } as any);\n const client = new Client({ name: \"fanluc\", version: \"1.0.0\" } as any, { capabilities: {} } as any);\n let timer: any;\n try {\n const run = (async () => { await client.connect(transport); return fn(client); })();\n return await Promise.race([run, new Promise<never>((_, rej) => { timer = setTimeout(() => rej(new Error(\"MCP timeout (20s)\")), 20000); })]);\n } finally {\n clearTimeout(timer);\n try { await client.close(); } catch {}\n }\n }\n\n app.post(\"/api/mcp/user/probe\", async (req, res) => {\n const list = Array.isArray(req.body?.servers) ? req.body.servers.slice(0, 8) : [];\n const out = await Promise.all(list.map(async (s: any) => {\n const name = String(s?.name || \"\").replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 40);\n try {\n const tools = await withUserMcp(s, async (c) => { const r: any = await c.listTools(); return Array.isArray(r?.tools) ? r.tools : []; });\n const t = tools.map((x: any) => ({ ...x, description: typeof x.description === \"string\" ? x.description : x.description }));\n return { name, type: \"http\", status: \"connected\", tools: t, toolCount: t.length, error: null, source: \"browser\" };\n } catch (e: any) {\n return { name, type: \"http\", status: \"failed\", tools: [], toolCount: 0, error: e?.message || String(e), source: \"browser\" };\n }\n }));\n res.json({ servers: out });\n });\n\n app.post(\"/api/mcp/user/call\", async (req, res) => {\n try {\n const { server, tool, args } = req.body || {};\n if (!server || !tool) return res.status(400).json({ error: \"Missing server or tool\" });\n const name = String(server.name || \"\");\n const actual = String(tool).startsWith(name + \"_\") ? String(tool).slice(name.length + 1) : String(tool);\n const r = await withUserMcp(server, (c) => c.callTool({ name: actual, arguments: args && typeof args === \"object\" ? args : {} }));\n return res.json(r);\n } catch (e: any) {\n return res.status(500).json({ error: e?.message || \"MCP call failed\" });\n }\n });\n\n app.post(\"/api/mcp/reconnect\", mcpAdminGuard, async (req, res) => {\n try {\n const { server } = req.body || {};\n if (!server) return res.status(400).json({ error: \"Missing server\" });\n const cfgMap = loadMcpConfigSync();\n const cfg = cfgMap[server];\n if (!cfg) return res.status(404).json({ error: \"Server not found in mcp.json\" });\n // Close old client if exists\n const old = mcp.get(server);\n try { await (old?.client as any)?.close?.(); } catch {}\n await connectMcp(server, cfg);\n const entry = mcp.get(server)!;\n return res.json({ name: server, status: entry.status, toolCount: entry.tools.length, error: entry.error || null });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n app.post(\"/api/mcp/toggle\", mcpAdminGuard, async (req, res) => {\n try {\n const { server, enabled } = req.body || {};\n if (!server) return res.status(400).json({ error: \"Missing server\" });\n const cfgMap = loadMcpConfigSync();\n // If server not in file, check memory\n let cfg = cfgMap[server];\n if (!cfg) {\n const mem = mcp.get(server);\n if (!mem) return res.status(404).json({ error: \"Server not found\" });\n cfg = mem.config;\n }\n const newEnabled = enabled !== undefined ? !!enabled : mcp.get(server)?.status === \"disabled\";\n const newCfg = { ...cfg, enabled: newEnabled, disabled: !newEnabled };\n if (newEnabled) {\n await connectMcp(server, newCfg);\n } else {\n const old = mcp.get(server);\n try { await (old?.client as any)?.close?.(); } catch {}\n mcp.set(server, { client: null, tools: [], status: \"disabled\", config: newCfg, type: normalizeMcpType(newCfg.type) });\n }\n // Persist the enabled flag so the choice survives a restart\n try {\n const mcpPath = mcpConfigPath();\n const existing = readMcpServersFile(mcpPath);\n if (existing[server]) {\n existing[server] = { ...existing[server], enabled: newEnabled };\n delete existing[server].disabled;\n fs.writeFileSync(mcpPath, JSON.stringify({ mcpServers: existing }, null, 2), \"utf-8\");\n }\n } catch (e: any) { console.warn(\"[MCP] could not persist toggle:\", e?.message); }\n const entry = mcp.get(server)!;\n return res.json({ name: server, status: entry.status, enabled: newEnabled });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n app.post(\"/api/mcp/add\", mcpAdminGuard, async (req, res) => {\n try {\n const { name, type, command, args, url, headers, env, enabled = true } = req.body || {};\n if (!name || typeof name !== \"string\") return res.status(400).json({ error: \"Missing name\" });\n const cleanName = name.trim().replace(/[^a-zA-Z0-9_-]/g, \"_\");\n if (!cleanName) return res.status(400).json({ error: \"Invalid name\" });\n // Security: only allow server-side file write; validate inputs\n const newCfg: any = { type: type || (url ? \"http\" : \"stdio\"), enabled: !!enabled };\n if (newCfg.type === \"http\" || newCfg.type === \"remote\") {\n if (!url || !String(url).startsWith(\"http\")) return res.status(400).json({ error: \"Invalid url for http server\" });\n newCfg.url = String(url);\n if (headers && typeof headers === \"object\") newCfg.headers = headers;\n } else {\n if (!command || typeof command !== \"string\") return res.status(400).json({ error: \"Missing command for stdio server\" });\n newCfg.command = String(command);\n if (Array.isArray(args) && args.length) newCfg.args = args.map(String);\n else if (typeof args === \"string\" && args.trim()) newCfg.args = String(args).trim().split(/\\s+/);\n if (env && typeof env === \"object\") newCfg.env = env;\n }\n // Persist to <configDir>/mcp.json (the file the loader actually reads)\n const mcpPath = mcpConfigPath();\n let existing: Record<string, any> = {};\n try { existing = readMcpServersFile(mcpPath); }\n catch (e: any) { return res.status(500).json({ error: \"mcp.json is invalid, refusing to overwrite: \" + (e?.message || e) }); }\n existing[cleanName] = newCfg;\n const toWrite = { mcpServers: existing };\n fs.writeFileSync(mcpPath, JSON.stringify(toWrite, null, 2));\n await connectMcp(cleanName, newCfg);\n const entry = mcp.get(cleanName)!;\n return res.json({ name: cleanName, status: entry.status, toolCount: entry.tools.length, error: entry.error || null });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n\n // Fetch URL endpoint - extracts clean article text via Readability instead\n // of dumping the whole stripped-tag page (nav/ads/footer/comment junk).\n app.post(\"/api/fetch-url\", async (req, res) => {\n const errorFallback = \"you entered an incorrect URL, are missing characters, or the website no longer exists\";\n try {\n const { url, length = 1100 } = req.body;\n if (!url || typeof url !== \"string\") {\n return res.json({\n url: url || \"\",\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n // Extract valid URL even if AI attached trailing titles, colons or spaces\n const urlMatch = url.match(/https?:\\/\\/[^\\s\"']+/);\n let targetUrl = urlMatch ? urlMatch[0] : url.trim();\n\n try {\n new URL(targetUrl);\n } catch {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n targetUrl = applyDomainRewrite(targetUrl);\n\n let hostname = \"\";\n try {\n hostname = new URL(targetUrl).hostname.toLowerCase();\n } catch {\n // already validated above, shouldn't happen\n }\n\n if (isBlockedHost(hostname)) {\n const blockedMsg = `This site (${hostname}) blocks automated crawling or requires login, so its content cannot be reliably extracted. Try a different, publicly accessible source instead.`;\n return res.json({\n url: targetUrl,\n text: blockedMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${blockedMsg}`,\n });\n }\n\n if (looksLikeNonHtmlFile(targetUrl)) {\n const fileMsg = \"This URL points to a non-HTML file (document, image, archive, or media) and cannot be read as article text.\";\n return res.json({\n url: targetUrl,\n text: fileMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${fileMsg}`,\n });\n }\n\n const cleanLength = Math.min(10000, Math.max(100, parseInt(length) || 1100));\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 20000); // 20s timeout\n\n let fetchResult: { ok: boolean; status: number; contentType: string; body: string };\n try {\n fetchResult = await fetchWithByteLimit(targetUrl, controller.signal, MAX_FETCH_BYTES);\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!fetchResult.ok) {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n if (fetchResult.contentType && !/text\\/html|application\\/xhtml/i.test(fetchResult.contentType)) {\n const nonHtmlMsg = `This URL returned non-HTML content (${fetchResult.contentType.split(\";\")[0]}) and cannot be read as article text.`;\n return res.json({\n url: targetUrl,\n text: nonHtmlMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${nonHtmlMsg}`,\n });\n }\n\n const { title, text: extractedFull } = extractReadableContent(fetchResult.body, targetUrl);\n\n if (!extractedFull) {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n const extracted = extractedFull.slice(0, cleanLength);\n const titlePart = title ? `title: ${title}\\n` : \"\";\n const formattedText = `fetched url: ${targetUrl}\\n${titlePart}text: ${extracted}`;\n\n return res.json({\n url: targetUrl,\n title,\n text: extracted,\n formattedText,\n });\n } catch (error: any) {\n console.error(\"Fetch URL error:\", error);\n return res.json({\n url: req.body?.url,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n });\n\n // Read doc from /docs endpoint\n app.post(\"/api/read-doc\", async (req, res) => {\n try {\n const { name } = req.body;\n if (!name || typeof name !== \"string\") {\n return res.status(400).json({ error: \"Missing name parameter\" });\n }\n\n const cleanName = name.trim().toLowerCase().replace(/^['\"`]|['\"`]$/g, \"\");\n const docsDir = path.join(process.cwd(), \"docs\");\n\n try {\n const files = await fs.promises.readdir(docsDir);\n let targetFile = files.find(\n (f) => f.toLowerCase() === cleanName || f.toLowerCase() === `${cleanName}.md`\n );\n\n if (!targetFile) {\n if (cleanName.includes(\"fanluc\")) targetFile = files.find((f) => f.includes(\"fanluc\"));\n else if (cleanName.includes(\"guide\")) targetFile = files.find((f) => f.includes(\"guide\"));\n else if (cleanName.includes(\"mondk\")) targetFile = files.find((f) => f.includes(\"mondk\"));\n else if (cleanName.includes(\"msh\")) targetFile = files.find((f) => f.includes(\"msh\"));\n else targetFile = files.find((f) => f.toLowerCase().includes(cleanName));\n }\n\n if (targetFile) {\n const content = await fs.promises.readFile(path.join(docsDir, targetFile), \"utf-8\");\n return res.json({\n found: true,\n fileName: targetFile,\n content,\n formattedText: `doc: ${targetFile}\\ncontent:\\n${content}`,\n });\n }\n\n return res.json({\n found: false,\n fileName: name,\n content: `Doc '${name}' not found in /docs/`,\n formattedText: `Doc '${name}' not found in /docs/`,\n });\n } catch (err: any) {\n return res.json({\n found: false,\n fileName: name,\n content: `Error reading docs directory: ${err?.message}`,\n formattedText: `Error reading docs directory: ${err?.message}`,\n });\n }\n } catch (error: any) {\n return res.status(500).json({ error: error?.message || \"Failed to read doc\" });\n }\n });\n\n // Translation endpoint using google-translate-api-x\n app.post(\"/api/translate\", async (req, res) => {\n try {\n const { text, to = \"en\", from = \"auto\" } = req.body;\n if (!text || typeof text !== \"string\") {\n return res.status(400).json({ error: \"Missing text parameter\" });\n }\n\n const cleanText = text.trim();\n if (!cleanText) {\n return res.status(400).json({ error: \"Empty text parameter\" });\n }\n\n const result = await translate(cleanText, {\n to: to || \"en\",\n from: from || \"auto\",\n });\n\n const translatedText = typeof result?.text === \"string\" ? result.text : String(result?.text ?? \"\");\n const detectedFrom = result?.from?.language?.iso || from || \"auto\";\n\n return res.json({\n translatedText,\n detectedFrom,\n originalText: cleanText,\n targetLang: to,\n formattedText: `translated \"${cleanText}\" (${detectedFrom} -> ${to}): \"${translatedText}\"`,\n });\n } catch (error: any) {\n console.error(\"Translation API error:\", error);\n return res.status(500).json({\n error: error?.message || \"Translation failed\",\n translatedText: \"\",\n detectedFrom: req.body?.from || \"auto\",\n formattedText: `translation failed: ${error?.message || \"error\"}`,\n });\n }\n });\n\n // Weather endpoint for show_weather\n app.get(\"/api/weather\", async (req, res) => {\n try {\n const { lat, lon, city } = req.query;\n let finalLat = lat;\n let finalLon = lon;\n let locationName = \"Unknown Location\";\n\n if (city && city !== \"auto\") {\n // Geocode city using Open-Meteo\n const geoRes = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(String(city))}&count=1&language=en&format=json`);\n const geoData = await geoRes.json();\n if (geoData.results && geoData.results.length > 0) {\n finalLat = geoData.results[0].latitude;\n finalLon = geoData.results[0].longitude;\n locationName = geoData.results[0].name + (geoData.results[0].country ? `, ${geoData.results[0].country}` : \"\");\n } else {\n return res.status(404).json({ error: \"City not found\" });\n }\n } else if (lat && lon) {\n // Reverse geocode for name using BigDataCloud free client API\n try {\n const revGeoRes = await fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lon}&localityLanguage=en`);\n const revGeoData = await revGeoRes.json();\n locationName = revGeoData.city || revGeoData.locality || revGeoData.principalSubdivision || \"Your Location\";\n } catch (e) {\n locationName = \"Your Location\";\n }\n } else {\n return res.status(400).json({ error: \"Provide lat/lon or city\" });\n }\n\n // Fetch weather using Open-Meteo\n const weatherRes = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${finalLat}&longitude=${finalLon}¤t_weather=true`);\n const weatherData = await weatherRes.json();\n\n if (!weatherData.current_weather) {\n return res.status(500).json({ error: \"Weather data not available\" });\n }\n\n const current = weatherData.current_weather;\n // Map WMO weather code to condition\n const code = current.weathercode;\n let condition = \"Clear\";\n if (code === 0) condition = \"Sunny\"; // Clear sky\n else if (code === 1 || code === 2 || code === 3) condition = \"Cloudy\"; // Mainly clear, partly cloudy, and overcast\n else if (code === 45 || code === 48) condition = \"Fog\";\n else if (code >= 51 && code <= 67) condition = \"Rainy\"; // Drizzle and Rain\n else if (code >= 71 && code <= 77) condition = \"Snow\";\n else if (code >= 80 && code <= 82) condition = \"Rainy\"; // Rain showers\n else if (code >= 85 && code <= 86) condition = \"Snow\"; // Snow showers\n else if (code >= 95 && code <= 99) condition = \"Stormy\"; // Thunderstorm\n\n // Determine if Windy based on windspeed (rough estimation)\n if (current.windspeed > 20 && (condition === \"Sunny\" || condition === \"Cloudy\" || condition === \"Clear\")) {\n condition = \"Windy\";\n }\n\n res.json({\n location: locationName,\n temperature: current.temperature,\n condition,\n isDay: current.is_day === 1,\n time: current.time,\n });\n } catch (error: any) {\n console.error(\"Weather API error:\", error);\n res.status(500).json({ error: \"Failed to fetch weather\" });\n }\n });\n\n // Permission helper (3 ch\u1EBF \u0111\u1ED9: ask / autoEdit / readOnly)\n function getPermissionMode(): string {\n const m = (process.env.FANLUC_PERMISSION || \"\").trim();\n if (m === \"readOnly\" || m === \"autoEdit\" || m === \"ask\") return m;\n // fallback: try reading settings.json from config dir (strip BOM)\n try {\n const cfgDir = getFanlucConfigDir();\n const p = path.join(cfgDir, \"settings.json\");\n if (fs.existsSync(p)) {\n const raw = fs.readFileSync(p, \"utf-8\").replace(/^\\uFEFF/, \"\");\n const j = JSON.parse(raw);\n if (j.permission === \"readOnly\" || j.permission === \"autoEdit\" || j.permission === \"ask\") return j.permission;\n }\n } catch {}\n return \"ask\";\n }\n\n // FANLUC.md \u2014 workspace context endpoint (for G\u01101: auto-inject into system prompt)\n function loadFanlucMdSync(): { path: string; content: string } | null {\n const candidates = [\n path.join(WORKSPACE_DIR, \"FANLUC.md\"),\n path.join(WORKSPACE_DIR, \"fanluc.md\"),\n path.join(WORKSPACE_DIR, \".fanluc\", \"FANLUC.md\"),\n ];\n for (const p of candidates) {\n try {\n if (fs.existsSync(p) && fs.statSync(p).isFile()) {\n const raw = fs.readFileSync(p, \"utf-8\").replace(/^\\uFEFF/, \"\");\n const MAX = 6000;\n const content = raw.length > MAX ? raw.slice(0, MAX) + \"\\n\\n[... truncated ...]\" : raw;\n return { path: p, content };\n }\n } catch {}\n }\n return null;\n }\n\n app.get(\"/api/fanluc-md\", (_req, res) => {\n const md = loadFanlucMdSync();\n if (!md) return res.json({ found: false, path: null, content: \"\" });\n return res.json({ found: true, path: md.path, content: md.content });\n });\n\n app.get(\"/api/config\", (_req, res) => {\n const cfgDir = getFanlucConfigDir();\n const perm = getPermissionMode();\n const ws = WORKSPACE_DIR;\n const md = loadFanlucMdSync();\n res.json({\n workspace: ws,\n configDir: cfgDir,\n permission: perm,\n fanlucMd: md ? { path: md.path, length: md.content.length } : null,\n platform: process.platform,\n });\n });\n\n // Permission endpoints (Fix 2: ask c\u1EA7n x\u00E1c nh\u1EADn qua ConfirmModal)\n app.get(\"/api/permission/status\", (_req, res) => {\n const perm = getPermissionMode();\n res.json({\n permission: perm,\n fileGranted: isGranted(\"file\"),\n shellGranted: isGranted(\"shell\"),\n ttlMs: GRANT_TTL_MS,\n });\n });\n app.post(\"/api/permission/approve\", (req, res) => {\n const { type } = req.body || {};\n const t = type === \"file\" ? \"file\" : type === \"shell\" ? \"shell\" : \"all\";\n const perm = getPermissionMode();\n if (perm === \"readOnly\") {\n return res.status(403).json({ error: \"readOnly: cannot grant permission\" });\n }\n grantPermission(t as any);\n res.json({ ok: true, granted: t, until: Date.now() + GRANT_TTL_MS });\n });\n app.post(\"/api/permission/mode\", (req, res) => {\n const m = String(req.body?.mode || \"\");\n if (m !== \"ask\" && m !== \"autoEdit\" && m !== \"readOnly\") return res.status(400).json({ error: \"mode must be ask | autoEdit | readOnly\" });\n process.env.FANLUC_PERMISSION = m;\n return res.json({ ok: true, permission: m });\n });\n\n app.post(\"/api/permission/reset\", (_req, res) => {\n clearGrants();\n res.json({ ok: true });\n });\n\n // run_cmd \u2014 real, sandboxed shell execution. See the layered-defense\n // comment near WORKSPACE_DIR/SAFE_ENV/DANGEROUS_PATTERNS above.\n // Windows: PowerShell sandbox, permission ask blocks by default\n app.post(\"/api/run-cmd\", (req, res) => {\n if (process.env.DISABLE_RUN_CMD === \"1\") {\n const msg = \"run_cmd is disabled on this server.\";\n return res.json({ stdout: \"\", stderr: msg, formattedText: msg, blocked: true });\n }\n const perm = getPermissionMode();\n // Fix 2: ask ch\u1EB7n shell cho t\u1EDBi khi ConfirmModal approve; autoEdit c\u0169ng ch\u1EB7n shell\n const needShellGrant = perm === \"ask\" || perm === \"autoEdit\";\n if (perm === \"readOnly\" || (needShellGrant && !isGranted(\"shell\"))) {\n const hint = perm === \"readOnly\"\n ? \"readOnly \u2014 shell disabled\"\n : `permission '${perm}' requires confirmation via web ConfirmModal or POST /api/permission/approve {type:'shell'}`;\n const msg = `Blocked by permission mode '${perm}': shell execution requires confirmation. ${hint}`;\n return res.status(403).json({ stdout: \"\", stderr: msg, formattedText: msg, blocked: true, needConfirm: true, permission: perm });\n }\n const { command } = req.body || {};\n if (!command || typeof command !== \"string\" || !command.trim()) {\n return res.status(400).json({ error: \"Missing command\", formattedText: \"Error: missing command\" });\n }\n const trimmed = preprocessCommand(command.trim());\n\n const blockedReason = findBlockedPattern(trimmed);\n if (blockedReason) {\n const msg = `Command blocked for safety: ${blockedReason}.`;\n return res.json({ stdout: \"\", stderr: msg, formattedText: msg, blocked: true });\n }\n\n const TIMEOUT_MS = 20000;\n const MAX_BUFFER = 2 * 1024 * 1024; // 2MB\n\n let bin: string;\n let args: string[];\n if (IS_WINDOWS) {\n // Windows: always use PowerShell (reliable). WSL's bash.exe is a stub that requires a distribution\n // and would break `echo`, `dir`, etc. Git Bash is optional but PowerShell handles\n // `echo`, `dir`, `python`, `node` etc. via aliases/callable executables.\n bin = \"powershell.exe\";\n // Windows PowerShell 5.1 defaults to the OEM/ANSI code page: force UTF-8 for console output and\n // for the cmdlets that read/write files (Get-Content would otherwise garble BOM-less UTF-8).\n const PS_UTF8 =\n \"[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false);\" +\n \"$OutputEncoding=[Console]::OutputEncoding;\" +\n \"$PSDefaultParameterValues['Get-Content:Encoding']='utf8';\" +\n \"$PSDefaultParameterValues['Set-Content:Encoding']='utf8';\" +\n \"$PSDefaultParameterValues['Add-Content:Encoding']='utf8';\" +\n \"$PSDefaultParameterValues['Out-File:Encoding']='utf8';\";\n args = [\"-NoProfile\", \"-Command\", PS_UTF8 + trimmed];\n } else if (FIREJAIL_AVAILABLE) {\n bin = \"firejail\";\n args = [\n \"--quiet\",\n \"--noprofile\",\n `--private=${WORKSPACE_DIR}`,\n \"--net=none\",\n \"--rlimit-fsize=50000000\",\n \"--rlimit-as=1073741824\",\n \"bash\",\n \"-c\",\n trimmed,\n ];\n } else {\n bin = \"bash\";\n args = [\"-c\", trimmed];\n }\n\n execFile(\n bin,\n args,\n { cwd: WORKSPACE_DIR, timeout: TIMEOUT_MS, maxBuffer: MAX_BUFFER, env: SAFE_ENV },\n (err: any, stdout, stderr) => {\n const out = (stdout || \"\").toString().slice(0, 20000);\n const errOut = (stderr || \"\").toString().slice(0, 20000);\n\n if (err && err.killed) {\n const msg = `Command timed out (${TIMEOUT_MS / 1000}s limit).`;\n return res.json({ stdout: out, stderr: msg, formattedText: `$ ${trimmed}\\n${out}\\n${msg}`.trim(), timedOut: true });\n }\n\n const exitCode = err ? (typeof err.code === \"number\" ? err.code : 1) : 0;\n const body = `${out}${errOut ? (out ? \"\\n\" : \"\") + errOut : \"\"}`.trim() || \"(no output)\";\n const formattedText = `$ ${trimmed}\\n${body}`;\n\n return res.json({ stdout: out, stderr: errOut, exitCode, formattedText });\n }\n );\n });\n\n // Upload workspace file endpoint (permission-aware, Fix 2)\n app.post(\"/api/upload-workspace-file\", express.json({ limit: \"10mb\" }), async (req, res) => {\n const perm = getPermissionMode();\n if (perm === \"readOnly\" || (perm === \"ask\" && !isGranted(\"file\"))) {\n const hint = perm === \"ask\" ? \"requires confirmation via ConfirmModal or POST /api/permission/approve {type:'file'}\" : \"readOnly\";\n return res.status(403).json({ error: `Blocked by permission mode '${perm}': file write ${hint}`, needConfirm: perm === \"ask\", permission: perm });\n }\n try {\n const { name, content, encoding = \"utf-8\" } = req.body || {};\n if (!name || typeof name !== \"string\") {\n return res.status(400).json({ error: \"Missing file name\" });\n }\n const cleanName = name.trim().replace(/^(\\.\\/|\\/)+/, \"\");\n const filePath = path.join(WORKSPACE_DIR, cleanName);\n\n const dir = path.dirname(filePath);\n if (!isInsideWorkspace(dir)) {\n return res.status(403).json({ error: \"Invalid file path outside workspace\" });\n }\n await fs.promises.mkdir(dir, { recursive: true });\n\n let buffer: Buffer;\n if ((encoding === \"base64\" || cleanName.toLowerCase().endsWith(\".zip\")) && typeof content === \"string\") {\n let rawBase64 = content;\n if (rawBase64.includes(\",\")) {\n rawBase64 = rawBase64.split(\",\")[1];\n }\n buffer = Buffer.from(rawBase64, \"base64\");\n } else if (typeof content === \"string\") {\n buffer = Buffer.from(content, \"utf-8\");\n } else {\n buffer = Buffer.from(\"\");\n }\n\n await fs.promises.writeFile(filePath, buffer);\n const stats = await fs.promises.stat(filePath);\n\n return res.json({\n success: true,\n path: cleanName,\n name: path.basename(cleanName),\n size: stats.size,\n updatedAt: stats.mtimeMs,\n });\n } catch (err: any) {\n console.error(\"Upload workspace file error:\", err);\n return res.status(500).json({ error: err?.message || \"Failed to upload workspace file\" });\n }\n });\n\n // Delete workspace file endpoint (permission-aware, Fix 2)\n app.post(\"/api/delete-workspace-file\", express.json(), async (req, res) => {\n const perm = getPermissionMode();\n if (perm === \"readOnly\" || (perm === \"ask\" && !isGranted(\"file\"))) {\n const hint = perm === \"ask\" ? \"requires confirmation via ConfirmModal or POST /api/permission/approve {type:'file'}\" : \"readOnly\";\n return res.status(403).json({ error: `Blocked by permission mode '${perm}': file delete ${hint}`, needConfirm: perm === \"ask\", permission: perm });\n }\n try {\n const { path: filePathParam } = req.body || {};\n if (!filePathParam || typeof filePathParam !== \"string\") {\n return res.status(400).json({ error: \"Missing file path\" });\n }\n const cleanName = filePathParam.trim().replace(/^(\\.\\/|\\/)+/, \"\");\n const targetPath = path.join(WORKSPACE_DIR, cleanName);\n\n if (!isInsideWorkspace(targetPath)) {\n return res.status(403).json({ error: \"Invalid file path outside workspace\" });\n }\n\n if (fs.existsSync(targetPath)) {\n await fs.promises.rm(targetPath, { recursive: true, force: true });\n }\n\n return res.json({ success: true, path: cleanName });\n } catch (err: any) {\n console.error(\"Delete workspace file error:\", err);\n return res.status(500).json({ error: err?.message || \"Failed to delete workspace file\" });\n }\n });\n\n // List workspace files endpoint\n app.get(\"/api/workspace-files\", async (_req, res) => {\n try {\n const filesMap: Record<string, any> = {};\n\n async function walkDir(currentDir: string, relativeDir: string = \"\") {\n let entries: fs.Dirent[] = [];\n try {\n entries = await fs.promises.readdir(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n\n const fullPath = path.join(currentDir, entry.name);\n const relPath = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await walkDir(fullPath, relPath);\n } else if (entry.isFile()) {\n try {\n const stats = await fs.promises.stat(fullPath);\n if (stats.size <= 2 * 1024 * 1024) {\n const ext = entry.name.split(\".\").pop()?.toLowerCase() || \"\";\n const isBinary = [\"zip\", \"gz\", \"tar\", \"tgz\", \"rar\", \"7z\", \"png\", \"jpg\", \"jpeg\", \"gif\", \"pdf\", \"exe\", \"bin\", \"apk\", \"iso\"].includes(ext);\n let content = \"\";\n let fileEncoding = \"utf-8\";\n if (isBinary) {\n content = `[Binary File: ${entry.name} (${(stats.size / 1024).toFixed(1)} KB)]`;\n } else {\n try {\n const dec = decodeTextBuffer(await fs.promises.readFile(fullPath));\n content = dec.text;\n fileEncoding = dec.encoding;\n } catch {\n content = `[Unreadable File: ${(stats.size / 1024).toFixed(1)} KB]`;\n }\n }\n filesMap[relPath] = {\n path: relPath,\n name: entry.name,\n content: content,\n size: stats.size,\n language: ext,\n encoding: fileEncoding,\n updatedAt: stats.mtimeMs,\n };\n } else {\n filesMap[relPath] = {\n path: relPath,\n name: entry.name,\n content: `[Large File: ${(stats.size / 1024).toFixed(1)} KB]`,\n size: stats.size,\n language: entry.name.split(\".\").pop()?.toLowerCase() || \"binary\",\n updatedAt: stats.mtimeMs,\n };\n }\n } catch {\n // Ignore unreadable binary files\n }\n }\n }\n }\n\n await walkDir(WORKSPACE_DIR);\n\n return res.json({ files: filesMap });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Failed to list workspace files\" });\n }\n });\n\n app.get(\"/api/health\", (_req, res) => {\n res.json({ status: \"ok\", workspace: WORKSPACE_DIR, permission: getPermissionMode(), platform: process.platform });\n });\n\n if (process.env.NODE_ENV !== \"production\") {\n const vite = await createViteServer({\n server: { middlewareMode: true },\n appType: \"spa\",\n });\n app.use(vite.middlewares);\n } else {\n const distPath = path.join(process.cwd(), \"dist\");\n app.use(express.static(distPath));\n app.get(\"*\", (_req, res) => {\n res.sendFile(path.join(distPath, \"index.html\"));\n });\n }\n\n const HOST = process.env.HOST || \"0.0.0.0\";\n // Log startup context (workspace, config, FANLUC.md)\n const cfgDir = getFanlucConfigDir();\n const permMode = getPermissionMode();\n const fanlucMd = loadFanlucMdSync();\n console.log(`[fanluc] Workspace : ${WORKSPACE_DIR}`);\n console.log(`[fanluc] Config dir: ${cfgDir}`);\n console.log(`[fanluc] Permission: ${permMode}`);\n if (fanlucMd) console.log(`[fanluc] FANLUC.md : ${fanlucMd.path} (${fanlucMd.content.length} chars)`);\n else console.log(`[fanluc] FANLUC.md : (none)`);\n\n app.listen(PORT, HOST, () => {\n const displayHost = HOST === \"0.0.0.0\" ? \"localhost\" : HOST;\n console.log(`Server running on http://${displayHost}:${PORT}`);\n console.log(`Health: http://${displayHost}:${PORT}/api/health`);\n });\n}\n\nexport { startServer };\n\n// Auto-start when file is executed directly (both ESM via tsx and CJS via node dist/server.cjs)\n// Skip only if explicitly disabled via FANLUC_NO_AUTO_START=1 (for tests / library import)\nif (process.env.FANLUC_NO_AUTO_START !== \"1\") {\n startServer().catch((e) => {\n console.error(\"Failed to start server:\", e);\n process.exit(1);\n });\n}\n", "/**\n * Decode a file buffer to text without mojibake.\n * Windows tools disagree on encoding: Windows PowerShell 5.1 `>` / Out-File write UTF-16LE (with BOM),\n * Set-Content writes ANSI, editors add a UTF-8 BOM, Node/VS Code write UTF-8 without BOM.\n */\nexport function decodeTextBuffer(buf: Buffer): { text: string; encoding: string } {\n if (buf.length >= 3 && buf[0] === 0xef && buf[1] === 0xbb && buf[2] === 0xbf) {\n return { text: buf.subarray(3).toString(\"utf8\"), encoding: \"utf-8-bom\" };\n }\n if (buf.length >= 2 && buf[0] === 0xff && buf[1] === 0xfe) {\n return { text: buf.subarray(2).toString(\"utf16le\"), encoding: \"utf-16le\" };\n }\n if (buf.length >= 2 && buf[0] === 0xfe && buf[1] === 0xff) {\n const sw = Buffer.from(buf.subarray(2));\n for (let i = 0; i + 1 < sw.length; i += 2) { const t = sw[i]; sw[i] = sw[i + 1]; sw[i + 1] = t; }\n return { text: sw.toString(\"utf16le\"), encoding: \"utf-16be\" };\n }\n // BOM-less UTF-16LE (mostly ASCII text => every other byte is NUL)\n const sample = buf.subarray(0, Math.min(buf.length, 1024));\n let nulOdd = 0, nulTotal = 0;\n for (let i = 0; i < sample.length; i++) if (sample[i] === 0) { nulTotal++; if (i % 2 === 1) nulOdd++; }\n if (sample.length >= 4 && nulTotal > sample.length * 0.2 && nulOdd >= nulTotal * 0.9) {\n return { text: buf.toString(\"utf16le\"), encoding: \"utf-16le\" };\n }\n try {\n return { text: new TextDecoder(\"utf-8\", { fatal: true }).decode(buf), encoding: \"utf-8\" };\n } catch {}\n // Not valid UTF-8: legacy ANSI code page (Vietnamese Windows = 1258).\n try { return { text: new TextDecoder(\"windows-1258\").decode(buf), encoding: \"windows-1258\" }; } catch {}\n return { text: buf.toString(\"latin1\"), encoding: \"latin1\" };\n}\n\n", "/**\n * run_cmd blocklist (G\u01102) \u2014 pure module, kh\u00F4ng ph\u1EE5 thu\u1ED9c server/DOM n\u00EAn test \u0111\u01B0\u1EE3c.\n *\n * Defense-in-depth, KH\u00D4NG ph\u1EA3i sandbox ho\u00E0n ch\u1EC9nh: ch\u1EB7n c\u00E1c pattern ph\u00E1 ho\u1EA1i /\n * \u0111\u00E1nh c\u1EAFp / leo quy\u1EC1n r\u00F5 r\u00E0ng tr\u01B0\u1EDBc khi spawn process.\n *\n * Thay \u0111\u1ED5i so v\u1EDBi G\u01101 (m\u1EE5c 2 trong phan-con-lai-GD1.txt):\n * Tr\u01B0\u1EDBc: m\u1ECDi `Remove-Item ... -Recurse` \u0111\u1EC1u b\u1ECB ch\u1EB7n (k\u1EC3 c\u1EA3 `-Recurse .\\tmp`).\n * Nay: ph\u00E2n t\u00EDch \u0110\u00CDCH xo\u00E1. Ch\u1EC9 ch\u1EB7n khi \u0111\u00EDch nguy hi\u1EC3m:\n * - g\u1ED1c \u1ED5 \u0111\u0129a / \u0111\u01B0\u1EDDng d\u1EABn tuy\u1EC7t \u0111\u1ED1i ngo\u00E0i workspace / UNC\n * - ~, $HOME, $env:..., %VAR%, bi\u1EBFn/subexpression kh\u00F4ng resolve \u0111\u01B0\u1EE3c\n * - \u0111i l\u00EAn ngo\u00E0i workspace b\u1EB1ng `..`\n * - ch\u00EDnh th\u01B0 m\u1EE5c workspace (khi -Recurse)\n * - wildcard \"tr\u00F9m h\u1EBFt\" (`*`, `.\\*`, `*.*`) khi -Recurse\n * - b\u1EA5t k\u1EF3 wildcard n\u00E0o khi c\u00F3 \u0111\u1EE7 -Recurse + -Force\n * - -Recurse m\u00E0 \u0111\u00EDch \u0111\u1EBFn t\u1EEB pipeline (kh\u00F4ng bi\u1EBFt xo\u00E1 g\u00EC)\n */\nimport path from \"node:path\";\n\nexport interface BlockRule {\n pattern: RegExp;\n reason: string;\n}\n\nexport interface BlockOptions {\n /** Th\u01B0 m\u1EE5c workspace (\u0111\u01B0\u1EDDng d\u1EABn tuy\u1EC7t \u0111\u1ED1i). C\u00F3 th\u00EC m\u1EDBi x\u00E1c \u0111\u1ECBnh \u0111\u01B0\u1EE3c \"ngo\u00E0i workspace\". */\n workspaceDir?: string;\n /** M\u1EB7c \u0111\u1ECBnh process.platform. \"win32\" b\u1EADt th\u00EAm alias rm/del/rd/... c\u1EE7a PowerShell. */\n platform?: NodeJS.Platform;\n}\n\n/** C\u00E1c rule regex \"ph\u1EB3ng\". Rule Remove-Item -Recurse c\u0169 \u0111\u00E3 \u0111\u01B0\u1EE3c thay b\u1EB1ng analyzePowerShellDelete(). */\nexport const DANGEROUS_PATTERNS: BlockRule[] = [\n { pattern: /\\bsudo\\b|\\bsu\\s+(-|root)\\b/i, reason: \"privilege escalation (sudo/su)\" },\n { pattern: /\\brm\\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\\s+\\/(?!home\\/|tmp\\/|workspace)/i, reason: \"recursive delete outside the workspace\" },\n { pattern: /\\brm\\s+(-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*)\\s+[~*]\\s*(\\/|$)/i, reason: \"recursive delete of home/root\" },\n { pattern: /:\\(\\)\\s*\\{\\s*:\\s*\\|\\s*:\\s*&?\\s*\\}\\s*;/, reason: \"fork bomb\" },\n { pattern: /\\bmkfs\\b|\\bdd\\s+if=.*of=\\/dev\\/|\\bshred\\b/i, reason: \"disk-level destructive command\" },\n { pattern: /\\b(shutdown|reboot|halt|poweroff)\\b/i, reason: \"system power control\" },\n { pattern: /\\bchmod\\s+.*777\\s+\\//i, reason: \"world-writable permission change on root\" },\n { pattern: /\\b(curl|wget)\\b[^\\n|]*\\|\\s*(sudo\\s+)?(bash|sh|zsh)\\b/i, reason: \"piping a remote script straight into a shell\" },\n { pattern: /\\/etc\\/(passwd|shadow|sudoers)\\b/i, reason: \"reading system credential files\" },\n { pattern: /\\.env\\b/i, reason: \"accessing .env (may contain server secrets, not exposed to run_cmd on purpose)\" },\n { pattern: /\\bnc\\b.*-e\\b|\\/dev\\/tcp\\//i, reason: \"raw reverse-shell / netcat exec pattern\" },\n { pattern: /\\bcrontab\\b/i, reason: \"persistence via crontab\" },\n // --- Windows / PowerShell ---\n { pattern: /\\b(rd|rmdir)\\b[^&|;]*\\/s/i, reason: \"Windows rd/rmdir /s recursive delete\" },\n { pattern: /\\b(del|erase)\\b[^&|;]*\\/s/i, reason: \"Windows del/erase /s recursive delete\" },\n { pattern: /\\b(Format-Volume|Format-C|Clear-Disk|Remove-Partition)\\b/i, reason: \"Windows disk destructive command\" },\n { pattern: /\\b(iwr|Invoke-WebRequest|Invoke-RestMethod|curl|wget)\\b[^\\n|;]*\\|\\s*(iex|Invoke-Expression)\\b/i, reason: \"PowerShell piping remote script into Invoke-Expression (iwr | iex)\" },\n { pattern: /\\biex\\b|\\bInvoke-Expression\\b/i, reason: \"PowerShell Invoke-Expression\" },\n { pattern: /\\b(Start-Process|Invoke-Item)\\b.*\\b(powershell|cmd|wscript|cscript)\\b/i, reason: \"PowerShell spawning shell via Start-Process\" },\n { pattern: /-EncodedCommand\\b/i, reason: \"PowerShell EncodedCommand (obfuscated script)\" },\n { pattern: /\\bFromBase64String\\b/i, reason: \"PowerShell FromBase64String (obfuscated)\" },\n];\n\n// ---------------------------------------------------------------------------\n// Tokenizer t\u1ED1i gi\u1EA3n cho PowerShell: t\u00E1ch theo segment (; | & newline { } ( ))\n// v\u00E0 token (kho\u1EA3ng tr\u1EAFng, d\u1EA5u ph\u1EA9y), c\u00F3 x\u1EED l\u00FD quote '...' v\u00E0 \"...\".\n// ---------------------------------------------------------------------------\n\ninterface Segment {\n tokens: string[];\n /** Segment n\u00E0y \u0111\u1EE9ng ngay sau d\u1EA5u `|` (nh\u1EADn input t\u1EEB pipeline). */\n fromPipe: boolean;\n}\n\nfunction tokenizeSegments(cmd: string): Segment[] {\n const segments: Segment[] = [];\n let tokens: string[] = [];\n let cur = \"\";\n let hasCur = false;\n let curFromPipe = false;\n\n const pushToken = () => {\n if (hasCur) tokens.push(cur);\n cur = \"\";\n hasCur = false;\n };\n const endSegment = (sep: string) => {\n pushToken();\n if (tokens.length) segments.push({ tokens, fromPipe: curFromPipe });\n tokens = [];\n curFromPipe = sep === \"|\"; // segment k\u1EBF ti\u1EBFp nh\u1EADn input t\u1EEB pipeline n\u1EBFu ng\u0103n c\u00E1ch b\u1EDFi `|`\n };\n\n for (let i = 0; i < cmd.length; i++) {\n const ch = cmd[i];\n if (ch === \"'\" || ch === '\"') {\n hasCur = true;\n const q = ch;\n i++;\n while (i < cmd.length) {\n if (cmd[i] === q) {\n if (cmd[i + 1] === q) { cur += q; i += 2; continue; } // '' ho\u1EB7c \"\" = quote literal\n break;\n }\n if (q === '\"' && cmd[i] === \"`\" && i + 1 < cmd.length) { cur += cmd[i + 1]; i += 2; continue; }\n cur += cmd[i++];\n }\n continue;\n }\n if (ch === \";\" || ch === \"\\n\" || ch === \"\\r\" || ch === \"&\" || ch === \"{\" || ch === \"}\" || ch === \"(\" || ch === \")\") {\n endSegment(ch);\n continue;\n }\n if (ch === \"|\") { endSegment(\"|\"); continue; }\n if (ch === \" \" || ch === \"\\t\" || ch === \",\") { pushToken(); continue; }\n cur += ch;\n hasCur = true;\n }\n endSegment(\";\");\n return segments;\n}\n\n// ---------------------------------------------------------------------------\n// Path classification\n// ---------------------------------------------------------------------------\n\nfunction looksWindows(opts: BlockOptions): boolean {\n const ws = opts.workspaceDir || \"\";\n return opts.platform === \"win32\" || /^[a-zA-Z]:[\\\\/]/.test(ws) || ws.startsWith(\"\\\\\\\\\");\n}\n\n/** Wildcard \"tr\u00F9m h\u1EBFt\": *, .\\*, ./*, *.*, ** */\nconst UNIVERSAL_WILDCARD = /^(\\.?[\\\\/])?\\*+(\\.\\*)?$/;\n\nfunction classifyTarget(rawTarget: string, recurse: boolean, force: boolean, opts: BlockOptions): string | null {\n const t = rawTarget.trim();\n if (!t) return null;\n\n // Home / env / bi\u1EBFn kh\u00F4ng resolve \u0111\u01B0\u1EE3c \u2014 lu\u00F4n nguy hi\u1EC3m (k\u1EC3 c\u1EA3 kh\u00F4ng recurse, gi\u1ED1ng rule G\u01101)\n if (t === \"~\" || /^~[\\\\/]/.test(t) || /\\$home\\b/i.test(t) || /\\$env:/i.test(t) || /%[^%]+%/.test(t)) {\n return \"target is home directory or environment path (~, $HOME, $env:, %VAR%)\";\n }\n if (recurse && (/\\$/.test(t) || /`/.test(t))) {\n return \"recursive delete with a target that cannot be resolved statically (variable / subexpression)\";\n }\n\n const hasWildcard = /[*?]/.test(t);\n if (recurse && UNIVERSAL_WILDCARD.test(t)) {\n return \"recursive delete of everything via wildcard (*)\";\n }\n if (recurse && force && hasWildcard) {\n return \"recursive + force delete with a wildcard target\";\n }\n\n const isWin = looksWindows(opts);\n const p = isWin ? path.win32 : path.posix;\n const isAbs =\n /^[a-zA-Z]:/.test(t) || t.startsWith(\"\\\\\\\\\") || t.startsWith(\"\\\\\") || t.startsWith(\"/\") || p.isAbsolute(t);\n\n // \u0110\u01B0\u1EDDng d\u1EABn ki\u1EC3u Windows (C:\\, \\\\server, \\x) kh\u00F4ng th\u1EC3 n\u1EB1m trong workspace POSIX\n if (!isWin && (/^[a-zA-Z]:/.test(t) || t.startsWith(\"\\\\\"))) {\n return \"target is a Windows-style absolute path outside the workspace\";\n }\n\n const ws = opts.workspaceDir ? p.resolve(opts.workspaceDir) : null;\n const norm = (s: string) => (isWin ? s.toLowerCase() : s);\n\n // B\u1ECF ph\u1EA7n wildcard cu\u1ED1i \u0111\u1EC3 resolve th\u01B0 m\u1EE5c cha (vd .\\build\\* -> .\\build)\n const forResolve = hasWildcard ? t.replace(/[\\\\/]?[^\\\\/]*[*?][^\\\\/]*$/, \"\") || \".\" : t;\n\n if (!ws) {\n // Kh\u00F4ng bi\u1EBFt workspace: ch\u1EC9 cho ph\u00E9p \u0111\u01B0\u1EDDng d\u1EABn t\u01B0\u01A1ng \u0111\u1ED1i kh\u00F4ng ch\u1EE9a `..`\n if (isAbs) return \"absolute path target (workspace unknown)\";\n if (forResolve.split(/[\\\\/]+/).includes(\"..\")) return \"target escapes the workspace (..)\";\n return null;\n }\n\n const resolved = p.resolve(ws, forResolve);\n const rel = p.relative(norm(ws), norm(resolved));\n const escapes = rel === \"..\" || rel.startsWith(\"..\" + p.sep) || p.isAbsolute(rel);\n if (escapes) {\n return isAbs ? \"target is an absolute path outside the workspace\" : \"target escapes the workspace (..)\";\n }\n if (recurse && rel === \"\" && !hasWildcard) {\n return \"recursive delete of the workspace root itself\";\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// PowerShell delete analysis\n// ---------------------------------------------------------------------------\n\nconst PS_ONLY_DELETE = new Set([\"remove-item\", \"ri\"]);\nconst WIN_ALIAS_DELETE = new Set([\"rm\", \"del\", \"erase\", \"rd\", \"rmdir\"]);\nconst VALUE_FLAGS_TARGET = [\"path\", \"literalpath\"];\nconst VALUE_FLAGS_SKIP = [\"include\", \"exclude\", \"filter\", \"credential\", \"stream\"];\n\n/** C\u1EDD PowerShell c\u00F3 th\u1EC3 vi\u1EBFt t\u1EAFt: -Rec, -Recurse, -r ... */\nfunction flagMatches(name: string, full: string, minLen: number): boolean {\n const n = name.toLowerCase();\n return n.length >= minLen && full.startsWith(n);\n}\n\nfunction analyzePowerShellDelete(command: string, opts: BlockOptions): string | null {\n const platform = opts.platform ?? process.platform;\n const heads = new Set(PS_ONLY_DELETE);\n if (platform === \"win32\") for (const a of WIN_ALIAS_DELETE) heads.add(a);\n\n const segments = tokenizeSegments(command);\n let analyzedRemoveItem = 0;\n\n for (const seg of segments) {\n // b\u1ECF qua token \u0111\u1EA7u ki\u1EC3u \".\" (dot-source) v\u00E0 module-qualified name\n const head = (seg.tokens[0] || \"\").toLowerCase().replace(/^.*\\\\/, \"\");\n if (!heads.has(head)) continue;\n if (head === \"remove-item\") analyzedRemoveItem++;\n\n let recurse = false;\n let force = false;\n const targets: string[] = [];\n\n for (let i = 1; i < seg.tokens.length; i++) {\n const tok = seg.tokens[i];\n if (tok.startsWith(\"-\") && tok.length > 1 && !/^-\\d/.test(tok)) {\n const body = tok.slice(1);\n const colon = body.indexOf(\":\");\n const name = colon >= 0 ? body.slice(0, colon) : body;\n const inlineVal = colon >= 0 ? body.slice(colon + 1) : null;\n\n if (flagMatches(name, \"recurse\", 1)) {\n recurse = !(inlineVal && /^\\$?false$/i.test(inlineVal));\n } else if (flagMatches(name, \"force\", 2)) {\n force = !(inlineVal && /^\\$?false$/i.test(inlineVal));\n } else if (VALUE_FLAGS_TARGET.some((f) => flagMatches(name, f, 1))) {\n const v = inlineVal ?? seg.tokens[++i];\n if (v) targets.push(v);\n } else if (VALUE_FLAGS_SKIP.some((f) => flagMatches(name, f, 1))) {\n if (inlineVal === null) i++; // b\u1ECF gi\u00E1 tr\u1ECB \u0111i k\u00E8m\n }\n continue;\n }\n targets.push(tok);\n }\n\n if (recurse && targets.length === 0 && seg.fromPipe) {\n return \"recursive delete with pipeline input (target unknown)\";\n }\n if (recurse && targets.length === 0) {\n return \"recursive delete without an explicit target\";\n }\n for (const t of targets) {\n const why = classifyTarget(t, recurse, force, opts);\n if (why) return `PowerShell delete blocked: ${why}`;\n }\n }\n\n // Remove-Item xu\u1EA5t hi\u1EC7n nh\u01B0ng kh\u00F4ng n\u1EB1m \u1EDF \u0111\u1EA7u segment n\u00E0o (vd. n\u1EB1m trong\n // `powershell -c \"...\"`, `cmd /c ...`, `-Command '...'`): kh\u00F4ng ph\u00E2n t\u00EDch \u0111\u01B0\u1EE3c\n // \u2192 fallback v\u1EC1 h\u00E0nh vi nghi\u00EAm c\u1EE7a G\u01101, ch\u1EC9 cho tr\u01B0\u1EDDng h\u1EE3p c\u00F3 -Recurse.\n const rawCount = (command.match(/\\bRemove-Item\\b/gi) || []).length;\n if (rawCount > analyzedRemoveItem && /-r(e(c(u(r(s(e)?)?)?)?)?)?\\b/i.test(command)) {\n return \"PowerShell recursive delete inside a nested/quoted command (cannot verify target)\";\n }\n return null;\n}\n\n/** Tr\u1EA3 v\u1EC1 l\u00FD do b\u1ECB ch\u1EB7n, ho\u1EB7c null n\u1EBFu cho ph\u00E9p. */\nexport function findBlockedPattern(command: string, opts: BlockOptions = {}): string | null {\n for (const { pattern, reason } of DANGEROUS_PATTERNS) {\n if (pattern.test(command)) return reason;\n }\n return analyzePowerShellDelete(command, opts);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["path", "
|
|
3
|
+
"sources": ["../server.ts", "../localExec.ts", "../permissions.ts", "../localSearch.ts"],
|
|
4
|
+
"sourcesContent": ["import express from \"express\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { execFile, execFileSync, spawn } from \"child_process\";\nimport { createServer as createViteServer } from \"vite\";\nimport { translate } from \"google-translate-api-x\";\nimport { JSDOM } from \"jsdom\";\nimport { Readability } from \"@mozilla/readability\";\nimport dotenv from \"dotenv\";\nimport dns from \"node:dns/promises\";\nimport net from \"node:net\";\ndotenv.config();\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { registerLocalRoutes, getWorkspace, onWorkspaceChange, requireLocal, SHELL } from \"./localExec\";\nimport { searchImages, searchMojeek, searchBingLocal, searchWikipedia, raceUntilEnough, runEngine, cached, fuseResults, engineStatus, LOCALE, ACCEPT_LANGUAGE } from \"./localSearch\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\n\n// ============================================================================\n// Web Search & Fetch helpers\n//\n// Goal: search multiple free, no-API-key engines in parallel (so one engine\n// getting blocked/rate-limited doesn't take the whole tool down), then filter\n// out domains that are known to block scraping / require login / render\n// nothing without JS, and rank the survivors so well-established, reputable\n// sources are offered first. Fetch then extracts the actual article content\n// (via Mozilla's Readability algorithm - the same engine behind Firefox's\n// Reader View) instead of dumping every nav/ads/footer string on the page.\n// ============================================================================\n\nconst DESKTOP_UA =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\";\n\n// Hosts that are effectively unfetchable as plain HTML: they either require a\n// login, render everything client-side via JS, or actively block scrapers.\n// Kept out of search results entirely, and fast-failed (no network round\n// trip) if the AI tries to fetch() one directly.\nconst BLOCKED_HOST_SUFFIXES = [\n \"facebook.com\",\n \"fb.com\",\n \"instagram.com\",\n \"threads.net\",\n \"twitter.com\",\n \"x.com\",\n \"tiktok.com\",\n \"linkedin.com\",\n \"pinterest.com\",\n \"pinterest.jp\",\n \"quora.com\",\n \"discord.com\",\n \"discord.gg\",\n \"messenger.com\",\n \"whatsapp.com\",\n \"t.me\",\n \"telegram.org\",\n \"youtube.com\",\n \"youtu.be\",\n \"music.youtube.com\",\n \"zalo.me\",\n \"scribd.com\",\n \"academia.edu\",\n \"accounts.google.com\",\n \"myaccount.google.com\",\n];\n\n// Hosts that ARE fetchable, just not at the URL an engine hands back. Rewrite\n// before fetching instead of blocking outright.\nconst DOMAIN_REWRITES: Record<string, string> = {\n \"reddit.com\": \"old.reddit.com\",\n \"www.reddit.com\": \"old.reddit.com\",\n};\n\n// Sources worth ranking higher: encyclopedic/reference, .gov/.edu, major wire\n// services & newsrooms, and well-known Vietnamese outlets (since this tool is\n// used mostly for Vietnamese-language queries). This is a ranking boost, not\n// an allowlist - unknown domains still get through, just lower in the list.\nconst REPUTABLE_HOST_SUFFIXES = [\n \"wikipedia.org\",\n \"github.com\",\n \"stackoverflow.com\",\n \"developer.mozilla.org\",\n \"docs.python.org\",\n \"npmjs.com\",\n \"arxiv.org\",\n \"bbc.com\",\n \"reuters.com\",\n \"apnews.com\",\n \"nytimes.com\",\n \"theguardian.com\",\n \"forbes.com\",\n \"bloomberg.com\",\n \"nature.com\",\n \"sciencedirect.com\",\n \"vnexpress.net\",\n \"tuoitre.vn\",\n \"thanhnien.vn\",\n \"nhandan.vn\",\n \"baochinhphu.vn\",\n \"vietnamnet.vn\",\n \"laodong.vn\",\n \"dantri.com.vn\",\n \"vtv.vn\",\n \"vov.vn\",\n];\nconst REPUTABLE_TLD_SUFFIXES = [\".gov\", \".edu\", \".gov.vn\", \".edu.vn\"];\n\nconst NON_HTML_EXTENSIONS = [\n \".pdf\", \".doc\", \".docx\", \".xls\", \".xlsx\", \".ppt\", \".pptx\",\n \".zip\", \".rar\", \".7z\", \".tar\", \".gz\",\n \".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".svg\", \".bmp\", \".ico\",\n \".mp3\", \".mp4\", \".avi\", \".mov\", \".wav\", \".exe\", \".apk\", \".dmg\",\n];\n\nfunction hostMatchesSuffixList(hostname: string, suffixes: string[]): boolean {\n const h = hostname.toLowerCase().replace(/^www\\./, \"\");\n return suffixes.some((s) => h === s || h.endsWith(\".\" + s));\n}\n\nfunction isBlockedHost(hostname: string): boolean {\n if (!hostname) return false;\n return hostMatchesSuffixList(hostname, BLOCKED_HOST_SUFFIXES);\n}\n\nfunction applyDomainRewrite(urlStr: string): string {\n try {\n const u = new URL(urlStr);\n const host = u.hostname.toLowerCase();\n if (DOMAIN_REWRITES[host]) {\n u.hostname = DOMAIN_REWRITES[host];\n return u.toString();\n }\n return urlStr;\n } catch {\n return urlStr;\n }\n}\n\nfunction reputationScore(hostname: string): number {\n if (!hostname) return 0;\n const h = hostname.toLowerCase();\n if (hostMatchesSuffixList(h, REPUTABLE_HOST_SUFFIXES)) return 10;\n if (REPUTABLE_TLD_SUFFIXES.some((tld) => h.endsWith(tld))) return 8;\n return 0;\n}\n\nfunction looksLikeNonHtmlFile(urlStr: string): boolean {\n try {\n const p = new URL(urlStr).pathname.toLowerCase();\n return NON_HTML_EXTENSIONS.some((ext) => p.endsWith(ext));\n } catch {\n return false;\n }\n}\n\nfunction decodeHtmlEntities(str: string): string {\n if (!str) return \"\";\n return str\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, \"\\\"\")\n .replace(/�?39;/g, \"'\")\n .replace(/'/g, \"'\")\n .replace(/’|‘/g, \"'\")\n .replace(/”|“/g, \"\\\"\")\n .replace(/—/g, \"\u2014\")\n .replace(/–/g, \"\u2013\")\n .replace(/…/g, \"\u2026\")\n .replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))\n .replace(/&#(\\d+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10)));\n}\n\nfunction stripInnerTags(str: string): string {\n if (!str) return \"\";\n return str.replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim();\n}\n\ninterface RawSearchResult {\n url: string;\n title: string;\n snippet: string;\n engine: string;\n}\n\n\n// --- Engine 2: Bing HTML (organic results render with real hrefs in the\n// no-JS markup) ---\nasync function searchBing(query: string, count: number): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n try {\n const q = encodeURIComponent(query.trim());\n const resp = await fetch(`https://www.bing.com/search?q=${q}&count=${Math.min(30, count * 3)}&setlang=en-US`, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n });\n if (!resp.ok) return results;\n const html = await resp.text();\n const resultRegex = /<li class=\"b_algo\"[^>]*>[\\s\\S]*?<h2>[\\s\\S]*?<a href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<\\/h2>([\\s\\S]*?)<\\/li>/gi;\n let m: RegExpExecArray | null;\n while ((m = resultRegex.exec(html)) !== null && results.length < count * 2) {\n const url = m[1];\n if (!url.startsWith(\"http\")) continue;\n const title = decodeHtmlEntities(stripInnerTags(m[2]));\n const bodyBlock = m[3] || \"\";\n const snippetMatch =\n bodyBlock.match(/<p[^>]*>([\\s\\S]*?)<\\/p>/i) ||\n bodyBlock.match(/<div class=\"b_caption\"[^>]*>([\\s\\S]*?)<\\/div>/i);\n const snippet = snippetMatch ? decodeHtmlEntities(stripInnerTags(snippetMatch[1])) : title;\n if (!title && !snippet) continue;\n results.push({ url, title, snippet, engine: \"bing\" });\n }\n } catch (err) {\n console.warn(\"Bing search error:\", err);\n }\n return results;\n}\n\n// --- Engine 3: Yahoo Japan search (primary Yahoo engine) ---\nasync function searchYahooJP(query: string, count: number): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n const q = encodeURIComponent(query.trim());\n\n try {\n const response = await fetch(`https://search.yahoo.co.jp/search?p=${q}`, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n signal: AbortSignal.timeout(5000),\n });\n\n if (response.ok) {\n const html = await response.text();\n const cardRegex = /<a\\s+[^>]*href=\"([^\"]+)\"[^>]*>[\\s\\S]*?<h3[^>]*>([\\s\\S]*?)<\\/h3>[\\s\\S]*?(?:<(?:p|div)[^>]*class=\"[^\"]*(?:summary|Snippet|desc|text)[^\"]*\"[^>]*>([\\s\\S]*?)<\\/(?:p|div)>)?/gi;\n let match: RegExpExecArray | null;\n const seen = new Set<string>();\n while ((match = cardRegex.exec(html)) !== null && results.length < count) {\n const url = match[1];\n if (!url || !url.startsWith(\"http\") || url.includes(\"search.yahoo.co.jp\") || url === \"https://www.yahoo.co.jp\" || url === \"https://www.yahoo.co.jp/\") continue;\n if (seen.has(url)) continue;\n seen.add(url);\n const title = decodeHtmlEntities(stripInnerTags(match[2]));\n const snippet = match[3] ? decodeHtmlEntities(stripInnerTags(match[3])) : title;\n if (title) {\n results.push({ url, title, snippet, engine: \"yahoo\" });\n }\n }\n }\n } catch (_err) {\n // Silently continue to fallback engines\n }\n\n if (results.length === 0) {\n try {\n const newsRes = await fetch(`https://news.search.yahoo.com/search?p=${q}`, {\n headers: { \"User-Agent\": DESKTOP_UA },\n signal: AbortSignal.timeout(5000),\n });\n if (newsRes.ok) {\n const newsHtml = await newsRes.text();\n const newsRegex = /<h4[^>]*><a[^>]+href=\"([^\"]+)\"[^>]*>(.*?)<\\/a><\\/h4>/gi;\n let nMatch: RegExpExecArray | null;\n while ((nMatch = newsRegex.exec(newsHtml)) !== null && results.length < count) {\n let link = nMatch[1];\n if (link.includes(\"/RU=\")) {\n const ruMatch = link.match(/\\/RU=([^/]+)/);\n if (ruMatch) link = decodeURIComponent(ruMatch[1]);\n }\n const title = decodeHtmlEntities(stripInnerTags(nMatch[2]));\n if (link.startsWith(\"http\")) {\n results.push({ url: link, title, snippet: title, engine: \"yahoo-news\" });\n }\n }\n }\n } catch (_err) {\n // ignore\n }\n }\n\n return results;\n}\n\nfunction interleaveResults(arrays: RawSearchResult[][]): RawSearchResult[] {\n const out: RawSearchResult[] = [];\n const maxLen = Math.max(0, ...arrays.map((a) => a.length));\n for (let i = 0; i < maxLen; i++) {\n for (const arr of arrays) {\n if (arr[i]) out.push(arr[i]);\n }\n }\n return out;\n}\n\nfunction normalizeForDedupe(url: string): string {\n try {\n const u = new URL(url);\n return (u.hostname.replace(/^www\\./, \"\") + u.pathname.replace(/\\/$/, \"\")).toLowerCase();\n } catch {\n return url.toLowerCase();\n }\n}\n\n// Filters out unfetchable/blocked/non-HTML results, de-duplicates, caps how\n// many results a single domain can contribute (keeps sources diverse), and\n// sorts reputable domains first.\nfunction mergeAndFilterResults(all: RawSearchResult[], count: number): { url: string; snippet: string }[] {\n const seen = new Set<string>();\n const perDomainCount = new Map<string, number>();\n const filtered: (RawSearchResult & { score: number })[] = [];\n\n for (const r of all) {\n if (!r.url || !r.url.startsWith(\"http\")) continue;\n let hostname = \"\";\n try {\n hostname = new URL(r.url).hostname.toLowerCase();\n } catch {\n continue;\n }\n if (isBlockedHost(hostname)) continue;\n if (looksLikeNonHtmlFile(r.url)) continue;\n\n const dedupeKey = normalizeForDedupe(r.url);\n if (seen.has(dedupeKey)) continue;\n\n const domainKey = hostname.replace(/^www\\./, \"\");\n const domainCount = perDomainCount.get(domainKey) || 0;\n if (domainCount >= 2) continue;\n\n seen.add(dedupeKey);\n perDomainCount.set(domainKey, domainCount + 1);\n filtered.push({ ...r, url: applyDomainRewrite(r.url), score: reputationScore(hostname) });\n }\n\n filtered.sort((a, b) => b.score - a.score);\n\n return filtered.slice(0, count).map((r) => ({\n url: r.url,\n snippet: (r.snippet && r.snippet.trim()) || r.title || r.url,\n }));\n}\n\n// --- Fetch-with-byte-cap: reads the response body incrementally and stops\n// once MAX_FETCH_BYTES is hit, instead of buffering an unbounded page ---\nconst MAX_FETCH_BYTES = Number(process.env.FANLUC_MAX_FETCH_MB) > 0 ? Number(process.env.FANLUC_MAX_FETCH_MB) * 1024 * 1024 : 30 * 1024 * 1024; // 30MB default\n\n// ============================================================================\n// Virtual docs sites (served from the local ./docs folder, no network):\n// - https://fanluc.docs/ -> any web search whose query contains \"fanluc\"\n// - https://mondk-msh.docs/ -> any web search whose query contains the word \"mondk\" or \"msh\"\n// Each matching site gets its URL inserted FIRST in the results (the last real\n// results are dropped so the result count stays the same). /api/fetch-url serves\n// the pages from the docs folder.\n// ============================================================================\nconst DOCS_VIRTUAL_HOST = \"fanluc.docs\";\nconst DOCS_VIRTUAL_URL = `https://${DOCS_VIRTUAL_HOST}/`;\nconst MONDK_MSH_VIRTUAL_HOST = \"mondk-msh.docs\";\nconst MONDK_MSH_VIRTUAL_URL = `https://${MONDK_MSH_VIRTUAL_HOST}/`;\nconst DOCS_MAX_CHARS = 40000;\n\nconst VIRTUAL_DOCS_SITES: { host: string; url: string; trigger: RegExp; snippet: string }[] = [\n {\n host: DOCS_VIRTUAL_HOST,\n url: DOCS_VIRTUAL_URL,\n trigger: /fanluc/i,\n snippet:\n \"Official FANLUC docs (detailed interface/UI description, creator mondk, msh, connection guide) - fetch this URL to read them in full.\",\n },\n {\n host: MONDK_MSH_VIRTUAL_HOST,\n url: MONDK_MSH_VIRTUAL_URL,\n trigger: /\\b(?:mondk|msh)\\b/i,\n snippet:\n \"Official docs about the author mondk and the msh project (docs/mondk.md and docs/msh.md) - fetch this URL to read them in full.\",\n },\n];\n\nfunction injectDocsResult(\n query: string,\n results: { url: string; snippet: string }[],\n maxCount: number\n): { url: string; snippet: string }[] {\n const sites = VIRTUAL_DOCS_SITES.filter((site) => site.trigger.test(query || \"\"));\n if (sites.length === 0) return results;\n const rest = results.filter((r) => !sites.some((site) => r.url.toLowerCase().includes(site.host)));\n const keepCount = Math.max(1, maxCount - sites.length);\n const kept = rest.length > keepCount && maxCount > sites.length ? rest.slice(0, keepCount) : rest;\n return [...sites.map((site) => ({ url: site.url, snippet: site.snippet })), ...kept];\n}\n\n/** Reads one file from ./docs by short name (e.g. \"mondk\" -> mondk.md). */\nasync function readDocsFile(name: string): Promise<{ file: string; text: string } | null> {\n const docsDir = path.join(process.cwd(), \"docs\");\n let files: string[] = [];\n try {\n files = (await fs.promises.readdir(docsDir)).filter((f) => /\\.(md|txt)$/i.test(f));\n } catch {\n return null;\n }\n const file =\n files.find((f) => f.toLowerCase() === name || f.toLowerCase() === `${name}.md`) ||\n files.find((f) => f.toLowerCase().includes(name));\n if (!file) return null;\n return { file, text: await fs.promises.readFile(path.join(docsDir, file), \"utf-8\") };\n}\n\n/** https://mondk-msh.docs/ -> both docs; /mondk or /msh -> a single doc. */\nasync function readMondkMshPage(pathname: string): Promise<{ title: string; text: string }> {\n let name = \"\";\n try {\n name = decodeURIComponent(pathname || \"\");\n } catch {\n name = pathname || \"\";\n }\n name = name.replace(/^\\/+|\\/+$/g, \"\").toLowerCase().replace(/\\.md$/, \"\");\n const pages = [\"mondk\", \"msh\"];\n if (name && name !== \"index\") {\n if (!pages.includes(name)) {\n return {\n title: \"Not found\",\n text: `Page '${name}' not found. Available: ${pages.map((n) => MONDK_MSH_VIRTUAL_URL + n).join(\", \")}`,\n };\n }\n const doc = await readDocsFile(name);\n if (!doc) return { title: \"Not found\", text: `docs/${name}.md was not found on this server.` };\n return { title: doc.file, text: doc.text.slice(0, DOCS_MAX_CHARS) };\n }\n const parts: string[] = [];\n for (const n of pages) {\n const doc = await readDocsFile(n);\n parts.push(`=== docs/${doc ? doc.file : n + \".md\"} ===\\n${doc ? doc.text.trim() : \"(file not found)\"}`);\n }\n return { title: \"MONDK and MSH docs\", text: parts.join(\"\\n\\n\").slice(0, DOCS_MAX_CHARS) };\n}\n\nasync function readVirtualDocsPage(pathname: string): Promise<{ title: string; text: string }> {\n const docsDir = path.join(process.cwd(), \"docs\");\n let files: string[] = [];\n try {\n files = (await fs.promises.readdir(docsDir)).filter((f) => /\\.(md|txt)$/i.test(f));\n } catch {\n /* no docs dir */\n }\n let name = \"\";\n try {\n name = decodeURIComponent(pathname || \"\");\n } catch {\n name = pathname || \"\";\n }\n name = name.replace(/^\\/+|\\/+$/g, \"\").toLowerCase().replace(/\\.md$/, \"\");\n const find = (n: string) =>\n files.find((f) => f.toLowerCase() === n || f.toLowerCase() === `${n}.md`) ||\n files.find((f) => f.toLowerCase().includes(n));\n const read = (f: string) => fs.promises.readFile(path.join(docsDir, f), \"utf-8\");\n\n if (!name || name === \"index\") {\n const ui = find(\"fanluc\");\n const pages = [\"fanluc\", \"guide\", \"mondk\", \"msh\"].filter((n) => find(n));\n const index =\n \"FANLUC docs index:\\n\" + pages.map((n) => `- ${DOCS_VIRTUAL_URL}${n === \"fanluc\" ? \"\" : n}`).join(\"\\n\") + \"\\n\\n\";\n const body = ui ? await read(ui) : \"(fanluc ui doc not found)\";\n return { title: \"FANLUC docs\", text: (index + body).slice(0, DOCS_MAX_CHARS) };\n }\n const file = find(name);\n if (!file) {\n return {\n title: \"Not found\",\n text: `Page '${name}' not found. Available: ${[\"fanluc\", \"guide\", \"mondk\", \"msh\"].map((n) => DOCS_VIRTUAL_URL + (n === \"fanluc\" ? \"\" : n)).join(\", \")}`,\n };\n }\n return { title: file, text: (await read(file)).slice(0, DOCS_MAX_CHARS) };\n}\n\nasync function fetchWithByteLimit(\n url: string,\n signal: AbortSignal,\n maxBytes: number\n): Promise<{ ok: boolean; status: number; contentType: string; body: string }> {\n const response = await fetch(url, {\n signal,\n redirect: \"follow\",\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n \"Accept-Language\": \"vi-VN,vi;q=0.9,en-US;q=0.8,en;q=0.7\",\n },\n });\n\n const contentType = response.headers.get(\"content-type\") || \"\";\n\n if (!response.body) {\n const text = await response.text();\n return { ok: response.ok, status: response.status, contentType, body: text.slice(0, maxBytes) };\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let received = 0;\n let body = \"\";\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n received += value.byteLength;\n body += decoder.decode(value, { stream: true });\n if (received >= maxBytes) {\n try {\n await reader.cancel();\n } catch {\n // ignore\n }\n break;\n }\n }\n body += decoder.decode();\n return { ok: response.ok, status: response.status, contentType, body };\n}\n\nfunction fallbackCleanHtml(html: string): string {\n const stripped = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, \" \")\n .replace(/<svg[\\s\\S]*?<\\/svg>/gi, \" \")\n .replace(/<iframe[\\s\\S]*?<\\/iframe>/gi, \" \")\n .replace(/<!--[\\s\\S]*?-->/g, \" \")\n .replace(/<(nav|header|footer|aside|form|button|select|figure|figcaption)[^>]*>[\\s\\S]*?<\\/\\1>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n return decodeHtmlEntities(stripped);\n}\n\n// Extracts the actual article content from a raw HTML page. Tries Mozilla's\n// Readability algorithm first (the same one behind Firefox Reader View -\n// strips nav/ads/footers/comments and keeps just the article body); falls\n// back to tag-stripping (still boilerplate-tag-aware) if Readability can't\n// find an article on the page (e.g. it's a listing/home page, not an article).\nfunction extractReadableContent(\n html: string,\n url: string\n): { title: string; text: string; usedReadability: boolean } {\n try {\n const dom = new JSDOM(html, { url });\n const doc = dom.window.document;\n doc.querySelectorAll(\"script, style, noscript, iframe, svg, form\").forEach((el) => el.remove());\n\n const reader = new Readability(doc, { charThreshold: 200 });\n const article = reader.parse();\n\n if (article && article.textContent && article.textContent.trim().length > 150) {\n const cleanText = article.textContent.replace(/[ \\t]+/g, \" \").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n return { title: article.title || \"\", text: cleanText, usedReadability: true };\n }\n } catch (err: any) {\n console.warn(\"Readability extraction failed, falling back:\", err?.message);\n }\n\n return { title: \"\", text: fallbackCleanHtml(html), usedReadability: false };\n}\n\n\n// ============================================================================\n// SearXNG \u2014 optional search engine, Yahoo JP / Bing / DDG automatic fallback\n// Config: SEARXNG_URL (or SEARXNG) env var\n// ============================================================================\nconst SEARXNG_URL = (process.env.SEARXNG_URL || process.env.SEARXNG || \"\").replace(/\\/$/, \"\");\n\nasync function searchSearXNG(query: string, count: number, categories: \"general\" | \"images\" = \"general\", baseUrl: string = SEARXNG_URL): Promise<RawSearchResult[]> {\n const results: RawSearchResult[] = [];\n if (!baseUrl || !baseUrl.startsWith(\"http\")) return results;\n try {\n const params = new URLSearchParams({ q: query.trim(), format: \"json\", categories, pageno: \"1\" });\n const url = `${baseUrl}/search?${params.toString()}`;\n const resp = await fetch(url, {\n headers: {\n \"User-Agent\": DESKTOP_UA,\n \"Accept\": \"application/json\",\n \"Accept-Language\": \"en-US,en;q=0.9,vi;q=0.8\",\n },\n signal: AbortSignal.timeout(3000),\n });\n if (!resp.ok) {\n return results;\n }\n const j: any = await resp.json();\n const raw = Array.isArray(j.results) ? j.results : [];\n for (const x of raw) {\n if (results.length >= count * 2) break;\n if (categories === \"images\") {\n const title = (x.title || x.content || \"\").toString();\n const url = (x.url || x.img_src || \"\").toString();\n const img_src = (x.img_src || x.url || \"\").toString();\n const thumb = (x.thumbnail_src || x.img_src || x.thumbnail || \"\").toString();\n if (!img_src && !url) continue;\n results.push({\n url: url || img_src,\n title,\n snippet: title,\n engine: \"searxng-images\",\n _img_src: img_src,\n _thumb: thumb,\n } as any);\n } else {\n const title = (x.title || \"\").toString();\n const url = (x.url || \"\").toString();\n const snippet = (x.content || x.title || \"\").toString();\n if (!url || !url.startsWith(\"http\")) continue;\n results.push({ url, title, snippet, engine: \"searxng\" });\n }\n }\n } catch (_err) {\n // Silently fallback to Yahoo / Multi-engine\n }\n return results;\n}\n\n\n// ---- User-supplied URLs (from browser settings): must be public http(s) ----\nfunction isPrivateIp(ip: string): boolean {\n const v = ip.toLowerCase();\n if (v.startsWith(\"::ffff:\")) return isPrivateIp(v.slice(7));\n if (net.isIPv4(v)) {\n const [a, b] = v.split(\".\").map(Number);\n return a === 0 || a === 10 || a === 127 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127);\n }\n return v === \"::1\" || v === \"::\" || v.startsWith(\"fc\") || v.startsWith(\"fd\") || v.startsWith(\"fe80\");\n}\nasync function assertPublicUrl(raw: string): Promise<URL> {\n const u = new URL(raw);\n if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new Error(\"Only http/https URLs are allowed\");\n if (process.env.ALLOW_PRIVATE_URLS !== \"0\") return u; // self-host default: localhost is fine\n const host = u.hostname.replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\" || host.endsWith(\".local\") || host.endsWith(\".internal\")) throw new Error(\"Private/local hosts are not allowed\");\n const addrs = net.isIP(host) ? [{ address: host }] : await dns.lookup(host, { all: true });\n for (const a of addrs) if (isPrivateIp(a.address)) throw new Error(\"Private/local hosts are not allowed\");\n return u;\n}\nasync function resolveSearxUrl(req: any): Promise<string> {\n const raw = String(req.body?.searxngUrl || req.headers[\"x-searxng-url\"] || \"\").trim();\n if (!raw) return SEARXNG_URL;\n try {\n const u = await assertPublicUrl(raw);\n return (u.origin + u.pathname).replace(/\\/$/, \"\");\n } catch (e: any) {\n console.warn(\"[SearXNG] user URL rejected:\", e?.message);\n return SEARXNG_URL;\n }\n}\n\nasync function searchSearXNGGeneral(query: string, count: number): Promise<RawSearchResult[]> {\n return searchSearXNG(query, count, \"general\");\n}\n\n// ============================================================================\n// Image search helpers (SearXNG categories=images) + image proxy\n// ============================================================================\ninterface ImageResult {\n title: string;\n src: string;\n thumb: string;\n page: string;\n}\n\n// ============================================================================\n// MCP \u2014 file-based config (mcp.json), server.ts as bridge\n// Format: Claude Code style { \"mcpServers\": { name: {type, command, args, url, headers, env, enabled} } }\n// Also supports opencode style { \"mcp\": { ... } } / { \"mcp\": { \"servers\": { ... } } }\n// Web can't spawn processes, so server.ts bridges via MCP SDK\n// Security: only read config from file on server; never accept command/url from client\n// ============================================================================\nfunction stripJsonc(s: string): string {\n // Remove // and /* */ comments but keep them inside strings (e.g. \"https://...\")\n return s.replace(/(\"(?:\\\\.|[^\"\\\\])*\")|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm, (_m, str) => str ?? \"\");\n}\nfunction isLocalRequest(req: any): boolean {\n const ip = String(req.socket?.remoteAddress || \"\");\n const loop = ip === \"127.0.0.1\" || ip === \"::1\" || ip === \"::ffff:127.0.0.1\";\n return loop && !req.headers[\"x-forwarded-for\"]; // tunnels (ngrok) add x-forwarded-for\n}\nfunction mcpAdminGuard(req: any, res: any, next: any) {\n const token = process.env.ADMIN_TOKEN;\n if (!token) return next(); // no ADMIN_TOKEN set = open (personal instance), same as before\n if (req.headers[\"x-admin-token\"] === token) return next();\n return res.status(403).json({ error: \"Admin only: send header x-admin-token matching ADMIN_TOKEN.\" });\n}\nfunction resolveEnvVars(str: string): string {\n if (typeof str !== \"string\") return str;\n return str.replace(/\\$\\{([^}]+)\\}/g, (_, name) => {\n const n = String(name).trim();\n if (n === \"WORKSPACE\") return getWorkspace(); // current folder chosen in the UI\n return process.env[n] ?? \"\";\n });\n}\nfunction resolveEnvObject(obj: Record<string, string> | undefined): Record<string, string> | undefined {\n if (!obj || typeof obj !== \"object\") return obj;\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(obj)) {\n out[k] = typeof v === \"string\" ? resolveEnvVars(v) : v;\n }\n return out;\n}\n\ntype McpEntry = {\n client: Client | null;\n tools: any[];\n status: \"connected\" | \"failed\" | \"disabled\" | \"connecting\";\n error?: string;\n config: any;\n type: string;\n};\n\nconst mcp = new Map<string, McpEntry>();\n\nfunction normalizeMcpType(t: string): \"stdio\" | \"http\" {\n const low = (t || \"\").toLowerCase();\n if (low === \"http\" || low === \"remote\" || low === \"streamablehttp\" || low === \"sse\") return \"http\";\n return \"stdio\";\n}\n\nasync function connectMcp(name: string, cfg: any) {\n const explicitlyDisabled = cfg.enabled === false || cfg.disabled === true;\n if (explicitlyDisabled) {\n mcp.set(name, { client: null, tools: [], status: \"disabled\", config: cfg, type: normalizeMcpType(cfg.type) });\n return;\n }\n const type = normalizeMcpType(cfg.type || (cfg.url ? \"http\" : \"stdio\"));\n const entry: McpEntry = { client: null, tools: [], status: \"connecting\", config: cfg, type };\n mcp.set(name, entry);\n try {\n let client: Client;\n if (type === \"http\") {\n const rawUrl = cfg.url;\n if (!rawUrl) throw new Error(\"Missing url for http/remote MCP server\");\n const resolvedUrl = new URL(resolveEnvVars(String(rawUrl)));\n const headers = resolveEnvObject(cfg.headers) || {};\n const mk = () => new Client({ name: \"fanluc\", version: \"1.0.0\" } as any, { capabilities: {} } as any);\n try {\n client = mk();\n await client.connect(new StreamableHTTPClientTransport(resolvedUrl, { requestInit: { headers } } as any), { timeout: 30000 } as any);\n } catch (e1: any) {\n // Older servers only speak the legacy \"SSE\" transport: try that before giving up.\n try {\n client = mk();\n await client.connect(new SSEClientTransport(resolvedUrl, { requestInit: { headers } } as any), { timeout: 30000 } as any);\n } catch {\n throw e1;\n }\n }\n } else {\n let command: string | undefined = cfg.command;\n let args: string[] = Array.isArray(cfg.args) ? cfg.args : [];\n const userEnv = resolveEnvObject(cfg.env || cfg.environment) || {};\n if (Array.isArray(command)) {\n args = (command as string[]).slice(1);\n command = (command as string[])[0];\n }\n if (!command) throw new Error(\"Missing command for stdio/local MCP server\");\n // Allow \"npx -y pkg\" typed into the command box\n let resolvedCommand = resolveEnvVars(String(command)).trim();\n let resolvedArgs = args.map((a) => resolveEnvVars(String(a)));\n if (!resolvedArgs.length && /\\s/.test(resolvedCommand)) {\n const parts = resolvedCommand.split(/\\s+/);\n resolvedCommand = parts[0];\n resolvedArgs = parts.slice(1);\n }\n // Child gets the real environment (PATH, proxies, ...) minus this app's own secrets.\n const baseEnv: Record<string, string> = {};\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === \"string\" && ![\"GEMINI_API_KEY\", \"TOKEN\", \"ADMIN_TOKEN\", \"ACCESS_TOKEN\"].includes(k)) baseEnv[k] = v;\n }\n const cwd = cfg.cwd ? resolveEnvVars(String(cfg.cwd)) : getWorkspace();\n const transport = new StdioClientTransport({\n command: resolvedCommand,\n args: resolvedArgs,\n env: { ...baseEnv, ...userEnv },\n cwd,\n stderr: \"pipe\",\n } as any);\n let errTail = \"\";\n (transport as any).stderr?.on?.(\"data\", (d: Buffer) => {\n errTail = (errTail + d.toString()).slice(-1500);\n });\n client = new Client({ name: \"fanluc\", version: \"1.0.0\" } as any, { capabilities: {} } as any);\n try {\n // first `npx -y` run may download packages: allow 2 minutes\n await client.connect(transport, { timeout: 120000 } as any);\n } catch (e: any) {\n const tail = errTail.trim();\n throw new Error(`${e?.message || e}${tail ? `\\n--- server stderr ---\\n${tail}` : \"\"}`);\n }\n }\n const toolsRes: any = await client.listTools();\n const tools = Array.isArray(toolsRes?.tools) ? toolsRes.tools : [];\n const truncated = tools.map((t: any) => ({\n ...t,\n description: typeof t.description === \"string\" ? t.description : t.description,\n }));\n mcp.set(name, { client, tools: truncated, status: \"connected\", config: cfg, type });\n console.log(`[MCP] ${name} connected \u2014 ${truncated.length} tools`);\n } catch (e: any) {\n const msg = e?.message || String(e);\n console.warn(`[MCP] ${name} failed:`, msg);\n mcp.set(name, { client: null as any, tools: [], status: \"failed\", error: msg, config: cfg, type });\n }\n}\n\nfunction loadMcpConfigSync(): Record<string, any> {\n const candidates = [\n path.join(process.cwd(), \"mcp.json\"),\n path.join(process.cwd(), \"mcp.jsonc\"),\n ];\n for (const p of candidates) {\n try {\n if (fs.existsSync(p)) {\n const raw = fs.readFileSync(p, \"utf-8\");\n const cleaned = stripJsonc(raw);\n const j = JSON.parse(cleaned);\n if (j.mcpServers && typeof j.mcpServers === \"object\") return j.mcpServers;\n if (j.mcp && j.mcp.servers && typeof j.mcp.servers === \"object\") return j.mcp.servers;\n if (j.mcp && typeof j.mcp === \"object\" && !j.mcp.servers) {\n const maybe = j.mcp;\n const vals = Object.values(maybe) as any[];\n if (vals.length && vals.every((v: any) => v && typeof v.type === \"string\")) return maybe;\n }\n const topVals = Object.values(j) as any[];\n if (topVals.length && topVals.every((v: any) => v && typeof v.type === \"string\")) return j;\n return {};\n }\n } catch (e) {\n console.warn(`Failed to load MCP config from ${p}:`, e);\n }\n }\n return {};\n}\n\nasync function initMcpFromFile() {\n const cfgMap = loadMcpConfigSync();\n const entries = Object.entries(cfgMap);\n if (entries.length === 0) {\n console.log(\"[MCP] no mcp.json found or empty \u2014 skipping MCP init\");\n return;\n }\n console.log(`[MCP] loading ${entries.length} server(s) from mcp.json`);\n await Promise.all(entries.map(([name, cfg]) => connectMcp(name, cfg))); // in parallel: slow npx starts don't block each other\n}\n\nfunction getMcpToolsForModel(): any[] {\n const out: any[] = [];\n for (const [server, entry] of mcp.entries()) {\n if (entry.status !== \"connected\") continue;\n for (const t of entry.tools) {\n out.push({\n server,\n name: `${server}_${t.name}`,\n originalName: t.name,\n description: t.description || \"\",\n inputSchema: t.inputSchema,\n });\n }\n }\n return out;\n}\n\n\nasync function startServer() {\n const app = express();\n const portArgIdx = process.argv.indexOf(\"--port\");\n const cliPort = portArgIdx !== -1 && process.argv[portArgIdx + 1] ? Number(process.argv[portArgIdx + 1]) : null;\n const PORT = cliPort || (process.env.APP_PORT ? Number(process.env.APP_PORT) : 3000);\n\n app.use(express.json({ limit: \"2gb\" }));\n\n // No sandbox in this edition => the API only answers requests coming from this machine\n // (loopback + Host header check against DNS-rebinding). ALLOW_REMOTE_EXEC=1 turns this off.\n app.use(\"/api\", (req, res, next) => (req.path === \"/health\" ? next() : requireLocal(req, res, next)));\n\n // Stdio MCP servers that use ${WORKSPACE} must restart when the user picks another folder.\n onWorkspaceChange(() => {\n for (const [name, entry] of mcp.entries()) {\n if (entry.status === \"disabled\") continue;\n // The Colab bridge is paired with a browser tab by token; restarting it would break that pairing.\n if (/colab-mcp|StudioMCP|Roblox.mcp\\.bat/i.test(JSON.stringify(entry.config || {}))) continue;\n if (JSON.stringify(entry.config || {}).includes(\"${WORKSPACE}\") || (entry.type === \"stdio\" && !entry.config?.cwd)) {\n const old = entry.client;\n connectMcp(name, entry.config).finally(() => {\n try {\n old?.close();\n } catch {}\n });\n }\n }\n });\n\n // Init MCP servers from mcp.json (non-blocking, log errors)\n initMcpFromFile().catch((e) => console.warn(\"[MCP] init failed:\", e));\n\n // API Proxy endpoint to solve CORS issues with ngrok / custom REST APIs (Google Colab, Kaggle, Local)\n app.post(\"/api/proxy-chat\", async (req, res) => {\n try {\n const { apiUrl, apiKey, body, customHeaders } = req.body;\n\n if (!apiUrl) {\n return res.status(400).json({ error: \"Missing apiUrl parameter\" });\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"ngrok-skip-browser-warning\": \"true\",\n \"User-Agent\": \"fanluc/2.4.0\",\n \"Authorization\": `Bearer ${apiKey || \"\"}`,\n ...(customHeaders || {}),\n };\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 300000); // 300 second (5 min) timeout\n\n const response = await fetch(apiUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const responseText = await response.text();\n return res.status(response.status).send(responseText);\n }\n\n if (body?.stream && response.body) {\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(Buffer.from(value));\n }\n } catch (streamErr) {\n console.warn(\"Proxy stream pipe interrupted:\", streamErr);\n } finally {\n res.end();\n }\n return;\n }\n\n const responseText = await response.text();\n try {\n const data = JSON.parse(responseText);\n return res.json(data);\n } catch {\n return res.send(responseText);\n }\n } catch (error: any) {\n console.error(\"Proxy error:\", error);\n if (error?.name === \"AbortError\") {\n return res.status(504).json({\n error: \"API response timed out (>5 min) or instance disconnected.\",\n });\n }\n return res.status(500).json({ error: error?.message || \"Internal Proxy Error\" });\n }\n });\n\n // Web Search endpoint \u2014 tuned for running on the user's own machine.\n // Engines (parallel, each with a timeout + health tracking): SearXNG (optional),\n // Bing (this PC's language), Mojeek, Wikipedia, Yahoo JP (DuckDuckGo removed: captcha-walls scrapers). Results are fused with\n // reciprocal-rank fusion, filtered, cached for 10 min. Route name kept for frontend compat.\n app.post(\"/api/yahoo-search\", async (req, res) => {\n try {\n const { query, count = 7 } = req.body;\n if (!query || typeof query !== \"string\") {\n return res.status(400).json({ error: \"Missing query parameter\" });\n }\n const maxCount = Math.min(15, Math.max(1, parseInt(count) || 7));\n const searxUrl = await resolveSearxUrl(req);\n const key = `web:${LOCALE}:${searxUrl}:${query.toLowerCase().trim()}:${maxCount}`;\n\n const payload = await cached(\n key,\n 10 * 60 * 1000,\n async () => {\n const per = Math.min(20, maxCount + 6);\n const lists = await raceUntilEnough<RawSearchResult>(\n [\n searxUrl ? runEngine(\"searxng\", () => searchSearXNG(query, per, \"general\", searxUrl), 4000) : Promise.resolve([] as RawSearchResult[]),\n runEngine(\"bing\", () => searchBingLocal(query, per) as Promise<RawSearchResult[]>, 4000),\n runEngine(\"mojeek\", () => searchMojeek(query, per) as Promise<RawSearchResult[]>, 4000),\n runEngine(\"wikipedia\", () => searchWikipedia(query, 5) as Promise<RawSearchResult[]>, 4000),\n runEngine(\"yahoo\", () => searchYahooJP(query, per), 4000),\n ],\n (c) => c.reduce((n, a) => n + a.length, 0) >= maxCount,\n 4500\n );\n const fused = fuseResults(lists as any) as RawSearchResult[];\n let results = mergeAndFilterResults(fused, maxCount);\n if (results.length === 0) results = fused.slice(0, maxCount).map((r) => ({ url: r.url, snippet: r.snippet || r.title || r.url }));\n results = injectDocsResult(query, results, maxCount);\n const names = [\"searxng\", \"bing\", \"mojeek\", \"wikipedia\", \"yahoo\"].filter((_, i) => lists[i].length > 0);\n const formattedText =\n results.length > 0\n ? `${results.length} results:\\n` + results.map((r) => `${r.url}: ${r.snippet}`).join(\"\\n\")\n : `0 results:\\n(no results found for \"${query}\")`;\n return { count: results.length, results, formattedText, engine: names.join(\"+\") || \"none\" };\n },\n (v) => v.count > 0\n );\n return res.json(payload);\n } catch (error: any) {\n console.error(\"Web search error:\", error);\n return res.status(500).json({ error: error?.message || \"Web search failed\" });\n }\n });\n\n // Which search engines are healthy right now (debug / settings panel)\n app.get(\"/api/search-status\", (_req, res) => {\n res.json({ locale: LOCALE, searxng: SEARXNG_URL || null, engines: engineStatus() });\n });\n\n // Dedicated SearXNG search (optional direct access)\n app.post(\"/api/searxng-search\", async (req, res) => {\n try {\n const { query, count = 7, categories = \"general\" } = req.body;\n if (!query || typeof query !== \"string\") return res.status(400).json({ error: \"Missing query\" });\n const maxCount = Math.min(15, Math.max(1, parseInt(count) || 7));\n const cat = categories === \"images\" ? \"images\" : \"general\";\n const raw = await searchSearXNG(query, maxCount, cat as any, await resolveSearxUrl(req));\n let results: any[] = [];\n if (cat === \"images\") {\n // Return image-mapped results\n const filtered = raw.slice(0, maxCount).map((r: any) => ({\n title: r.title,\n src: (r as any)._img_src || r.url,\n thumb: (r as any)._thumb || (r as any)._img_src || r.url,\n page: r.url,\n url: r.url,\n }));\n return res.json({ count: filtered.length, results: filtered, formattedText: filtered.length ? `${filtered.length} images:${filtered.map((x:any)=>\" \"+x.src).join(\",\")}` : \"0 images\" });\n } else {\n results = mergeAndFilterResults(raw, maxCount);\n if (results.length === 0) results = raw.slice(0, maxCount).map((r) => ({ url: r.url, snippet: r.snippet }));\n const formattedText = results.length ? `${results.length} results:\\n` + results.map((r:any)=>`${r.url}: ${r.snippet}`).join(\"\\n\") : `0 results\\n(no results)`;\n return res.json({ count: results.length, results, formattedText });\n }\n } catch (e:any){ return res.status(500).json({error:e?.message});}\n });\n\n // Image search: works WITHOUT SearXNG (Bing + Wikimedia Commons +\n // Openverse). SearXNG is only an extra source when SEARXNG_URL / the settings URL is set.\n app.post(\"/api/image-search\", async (req, res) => {\n try {\n const { query, count = 6 } = req.body;\n if (!query || typeof query !== \"string\") return res.status(400).json({ error: \"Missing query\" });\n const maxCount = Math.min(12, Math.max(1, parseInt(count) || 6));\n const hits = await searchImages(query, maxCount, await resolveSearxUrl(req));\n const images: ImageResult[] = hits.map((h) => ({ title: h.title || query, src: h.src, thumb: h.thumb, page: h.page }));\n const formattedText = images.length ? `Showing ${images.length} images for \"${query}\"` : `No images found for \"${query}\"`;\n return res.json({ count: images.length, images, formattedText });\n } catch (e: any) {\n console.error(\"Image search error:\", e);\n return res.status(500).json({ error: e?.message || \"Image search failed\" });\n }\n });\n\n // Image proxy (to avoid hotlink blocking)\n app.get(\"/api/image-proxy\", async (req, res) => {\n try {\n const url = String(req.query.url || \"\");\n if (!url || !url.startsWith(\"http\")) return res.status(400).send(\"Missing url\");\n const parsed = new URL(url);\n if (isBlockedHost(parsed.hostname)) return res.status(403).send(\"Blocked host\");\n let resp: Response | null = null;\n let cur = url;\n for (let hop = 0; hop < 4; hop++) {\n const h = new URL(cur).hostname;\n if (isBlockedHost(h)) return res.status(403).send(\"Blocked host\");\n resp = await fetch(cur, { redirect: \"manual\", headers: { \"User-Agent\": DESKTOP_UA, \"Accept\": \"image/*,*/*\", \"Referer\": new URL(cur).origin + \"/\" } } as any);\n const loc = resp.headers.get(\"location\");\n if (resp.status >= 300 && resp.status < 400 && loc) { cur = new URL(loc, cur).toString(); resp = null; continue; }\n break;\n }\n if (!resp) return res.status(508).send(\"Too many redirects\");\n if (!resp.ok) return res.status(resp.status).send(\"Fetch failed\");\n const ct = resp.headers.get(\"content-type\") || \"image/jpeg\";\n if (!ct.startsWith(\"image/\")) return res.status(415).send(\"Not an image\");\n res.setHeader(\"Content-Type\", ct);\n res.setHeader(\"Cache-Control\", \"public, max-age=86400\");\n if (resp.body) {\n const reader = resp.body.getReader();\n // stream\n res.flushHeaders?.();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(Buffer.from(value));\n }\n res.end();\n } else {\n const buf = Buffer.from(await resp.arrayBuffer());\n res.send(buf);\n }\n } catch (e:any){ return res.status(500).send(e?.message); }\n });\n\n // ==========================================================================\n // MCP endpoints\n // Security: config only from file; client never sends command/url\n // ==========================================================================\n app.get(\"/api/mcp/status\", (_req, res) => {\n const list = [...mcp.entries()].map(([name, v]) => ({\n name,\n type: v.type, // stdio / http\n status: v.status, // connected / failed / disabled / connecting\n tools: v.tools,\n toolCount: v.tools.length,\n error: v.error || null,\n command: v.config?.command || \"\",\n args: Array.isArray(v.config?.args) ? v.config.args.join(\" \") : (v.config?.args || \"\"),\n url: v.config?.url || \"\",\n headers: v.config?.headers || undefined,\n }));\n // Also include tools for model (prefixed)\n const modelTools = getMcpToolsForModel();\n res.json({ servers: list, modelTools, count: list.length });\n });\n\n app.get(\"/api/mcp/tools\", (_req, res) => {\n // For model injection: only enabled connected servers, truncated\n res.json({ tools: getMcpToolsForModel() });\n });\n\n app.post(\"/api/mcp/call\", async (req, res) => {\n try {\n const { server, tool, args, arguments: altArgs } = req.body || {};\n const toolName = tool;\n const toolArgs = args ?? altArgs ?? {};\n if (!server || !toolName) return res.status(400).json({ error: \"Missing server or tool\" });\n const entry = mcp.get(server);\n if (!entry) return res.status(404).json({ error: `MCP server \"${server}\" not found` });\n if (entry.status !== \"connected\" || !entry.client) return res.status(400).json({ error: `MCP server \"${server}\" not connected (${entry.status})${entry.error ? \": \"+entry.error : \"\"}` });\n // Validate tool exists on this server (or with prefix)\n const actualTool = toolName.includes(\"_\") && toolName.startsWith(server + \"_\")\n ? toolName.slice(server.length + 1)\n : toolName;\n const callOpts = { timeout: 180000 } as any;\n let result: any;\n try {\n result = await entry.client.callTool({ name: actualTool, arguments: toolArgs }, undefined, callOpts);\n } catch (err: any) {\n // server process died / connection dropped: reconnect once and retry\n if (/closed|not connected|EPIPE|terminated|ECONNRESET|fetch failed/i.test(String(err?.message || err))) {\n await connectMcp(server, entry.config);\n const again = mcp.get(server);\n if (again?.status === \"connected\" && again.client) {\n result = await again.client.callTool({ name: actualTool, arguments: toolArgs }, undefined, callOpts);\n } else throw err;\n } else throw err;\n }\n return res.json(result);\n } catch (e:any){\n console.error(\"MCP call error:\", e);\n return res.status(500).json({ error: e?.message || \"MCP call failed\" });\n }\n });\n\n // ---- Browser-configured MCP (http only, stateless: connect per request) ----\n async function withUserMcp<T>(cfg: any, fn: (c: Client) => Promise<T>): Promise<T> {\n const u = await assertPublicUrl(String(cfg?.url || \"\"));\n const headers: Record<string, string> = {};\n if (cfg?.headers && typeof cfg.headers === \"object\") {\n for (const [k, v] of Object.entries(cfg.headers)) if (typeof v === \"string\" && /^[\\w-]+$/.test(k)) headers[k] = v;\n }\n const transport = new StreamableHTTPClientTransport(u, { requestInit: { headers } } as any);\n const client = new Client({ name: \"fanluc\", version: \"1.0.0\" } as any, { capabilities: {} } as any);\n let timer: any;\n try {\n const run = (async () => { await client.connect(transport); return fn(client); })();\n return await Promise.race([run, new Promise<never>((_, rej) => { timer = setTimeout(() => rej(new Error(\"MCP timeout (20s)\")), 20000); })]);\n } finally {\n clearTimeout(timer);\n try { await client.close(); } catch {}\n }\n }\n\n app.post(\"/api/mcp/user/probe\", async (req, res) => {\n const list = Array.isArray(req.body?.servers) ? req.body.servers.slice(0, 8) : [];\n const out = await Promise.all(list.map(async (s: any) => {\n const name = String(s?.name || \"\").replace(/[^a-zA-Z0-9_-]/g, \"_\").slice(0, 40);\n try {\n const tools = await withUserMcp(s, async (c) => { const r: any = await c.listTools(); return Array.isArray(r?.tools) ? r.tools : []; });\n const t = tools.map((x: any) => ({ ...x, description: typeof x.description === \"string\" ? x.description : x.description }));\n return { name, type: \"http\", status: \"connected\", tools: t, toolCount: t.length, error: null, source: \"browser\" };\n } catch (e: any) {\n return { name, type: \"http\", status: \"failed\", tools: [], toolCount: 0, error: e?.message || String(e), source: \"browser\" };\n }\n }));\n res.json({ servers: out });\n });\n\n app.post(\"/api/mcp/user/call\", async (req, res) => {\n try {\n const { server, tool, args } = req.body || {};\n if (!server || !tool) return res.status(400).json({ error: \"Missing server or tool\" });\n const name = String(server.name || \"\");\n const actual = String(tool).startsWith(name + \"_\") ? String(tool).slice(name.length + 1) : String(tool);\n const r = await withUserMcp(server, (c) => c.callTool({ name: actual, arguments: args && typeof args === \"object\" ? args : {} }));\n return res.json(r);\n } catch (e: any) {\n return res.status(500).json({ error: e?.message || \"MCP call failed\" });\n }\n });\n\n app.post(\"/api/mcp/reconnect\", mcpAdminGuard, async (req, res) => {\n try {\n const { server } = req.body || {};\n if (!server) return res.status(400).json({ error: \"Missing server\" });\n const cfgMap = loadMcpConfigSync();\n const cfg = cfgMap[server];\n if (!cfg) return res.status(404).json({ error: \"Server not found in mcp.json\" });\n // Close old client if exists\n const old = mcp.get(server);\n try { await (old?.client as any)?.close?.(); } catch {}\n await connectMcp(server, cfg);\n const entry = mcp.get(server)!;\n return res.json({ name: server, status: entry.status, toolCount: entry.tools.length, error: entry.error || null });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n app.post(\"/api/mcp/toggle\", mcpAdminGuard, async (req, res) => {\n try {\n const { server, enabled } = req.body || {};\n if (!server) return res.status(400).json({ error: \"Missing server\" });\n const cfgMap = loadMcpConfigSync();\n // If server not in file, check memory\n let cfg = cfgMap[server];\n if (!cfg) {\n const mem = mcp.get(server);\n if (!mem) return res.status(404).json({ error: \"Server not found\" });\n cfg = mem.config;\n }\n const newEnabled = enabled !== undefined ? !!enabled : mcp.get(server)?.status === \"disabled\";\n const newCfg = { ...cfg, enabled: newEnabled, disabled: !newEnabled };\n if (newEnabled) {\n await connectMcp(server, newCfg);\n } else {\n const old = mcp.get(server);\n try { await (old?.client as any)?.close?.(); } catch {}\n mcp.set(server, { client: null, tools: [], status: \"disabled\", config: newCfg, type: normalizeMcpType(newCfg.type) });\n }\n // Persist back to mcp.json? For now only in-memory + file remains unchanged \u2014 tell client\n // Optionally write back: disabled servers keep enabled:false in memory only.\n const entry = mcp.get(server)!;\n return res.json({ name: server, status: entry.status, enabled: newEnabled });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n app.post(\"/api/mcp/add\", mcpAdminGuard, async (req, res) => {\n try {\n const { name, type, command, args, url, headers, env, enabled = true } = req.body || {};\n if (!name || typeof name !== \"string\") return res.status(400).json({ error: \"Missing name\" });\n const cleanName = name.trim().replace(/[^a-zA-Z0-9_-]/g, \"_\");\n if (!cleanName) return res.status(400).json({ error: \"Invalid name\" });\n // Security: only allow server-side file write; validate inputs\n const newCfg: any = { type: type || (url ? \"http\" : \"stdio\"), enabled: !!enabled };\n if (newCfg.type === \"http\" || newCfg.type === \"remote\") {\n if (!url || !String(url).startsWith(\"http\")) return res.status(400).json({ error: \"Invalid url for http server\" });\n newCfg.url = String(url);\n if (headers && typeof headers === \"object\") newCfg.headers = headers;\n } else {\n if (!command || typeof command !== \"string\") return res.status(400).json({ error: \"Missing command for stdio server\" });\n newCfg.command = String(command);\n if (Array.isArray(args) && args.length) newCfg.args = args.map(String);\n else if (typeof args === \"string\" && args.trim()) newCfg.args = String(args).trim().split(/\\s+/);\n if (env && typeof env === \"object\") newCfg.env = env;\n }\n // Persist to mcp.json\n const mcpPath = path.join(process.cwd(), \"mcp.json\");\n let existing: any = {};\n try {\n if (fs.existsSync(mcpPath)) {\n const raw = fs.readFileSync(mcpPath, \"utf-8\");\n const j = JSON.parse(stripJsonc(raw));\n if (j.mcpServers) existing = j.mcpServers;\n else if (j.mcp && j.mcp.servers) existing = j.mcp.servers;\n else if (j.mcp && typeof j.mcp === \"object\") existing = j.mcp;\n else existing = j;\n }\n } catch (e: any) {\n return res.status(500).json({ error: \"mcp.json is invalid, refusing to overwrite: \" + (e?.message || e) });\n }\n existing[cleanName] = newCfg;\n const toWrite = { mcpServers: existing };\n fs.writeFileSync(mcpPath, JSON.stringify(toWrite, null, 2));\n await connectMcp(cleanName, newCfg);\n const entry = mcp.get(cleanName)!;\n return res.json({ name: cleanName, status: entry.status, toolCount: entry.tools.length, error: entry.error || null });\n } catch (e:any){ return res.status(500).json({ error: e?.message });}\n });\n\n app.post(\"/api/mcp/edit\", mcpAdminGuard, async (req, res) => {\n try {\n const { oldName, name, type, command, args, url, headers, env, enabled = true } = req.body || {};\n if (!oldName || typeof oldName !== \"string\") return res.status(400).json({ error: \"Missing oldName\" });\n if (!name || typeof name !== \"string\") return res.status(400).json({ error: \"Missing name\" });\n const cleanOldName = oldName.trim();\n const cleanName = name.trim().replace(/[^a-zA-Z0-9_-]/g, \"_\");\n if (!cleanName) return res.status(400).json({ error: \"Invalid name\" });\n\n const newCfg: any = { type: type || (url ? \"http\" : \"stdio\"), enabled: !!enabled };\n if (newCfg.type === \"http\" || newCfg.type === \"remote\") {\n if (!url || !String(url).startsWith(\"http\")) return res.status(400).json({ error: \"Invalid url for http server\" });\n newCfg.url = String(url);\n if (headers && typeof headers === \"object\") newCfg.headers = headers;\n } else {\n if (!command || typeof command !== \"string\") return res.status(400).json({ error: \"Missing command for stdio server\" });\n newCfg.command = String(command);\n if (Array.isArray(args) && args.length) newCfg.args = args.map(String);\n else if (typeof args === \"string\" && args.trim()) newCfg.args = String(args).trim().split(/\\s+/);\n if (env && typeof env === \"object\") newCfg.env = env;\n }\n\n const mcpPath = path.join(process.cwd(), \"mcp.json\");\n let existing: any = {};\n try {\n if (fs.existsSync(mcpPath)) {\n const raw = fs.readFileSync(mcpPath, \"utf-8\");\n const j = JSON.parse(stripJsonc(raw));\n if (j.mcpServers) existing = j.mcpServers;\n else if (j.mcp && j.mcp.servers) existing = j.mcp.servers;\n else if (j.mcp && typeof j.mcp === \"object\") existing = j.mcp;\n else existing = j;\n }\n } catch (e: any) {\n return res.status(500).json({ error: \"mcp.json is invalid, refusing to overwrite: \" + (e?.message || e) });\n }\n\n // Close old client if name changed or reconnecting\n if (cleanOldName !== cleanName || mcp.has(cleanOldName)) {\n delete existing[cleanOldName];\n const old = mcp.get(cleanOldName);\n try { await (old?.client as any)?.close?.(); } catch {}\n mcp.delete(cleanOldName);\n }\n\n existing[cleanName] = newCfg;\n fs.writeFileSync(mcpPath, JSON.stringify({ mcpServers: existing }, null, 2));\n\n if (newCfg.enabled) {\n await connectMcp(cleanName, newCfg);\n } else {\n mcp.set(cleanName, { client: null, tools: [], status: \"disabled\", config: newCfg, type: normalizeMcpType(newCfg.type) });\n }\n\n const entry = mcp.get(cleanName);\n return res.json({ name: cleanName, status: entry?.status || \"disabled\", toolCount: entry?.tools?.length || 0, error: entry?.error || null });\n } catch (e: any) { return res.status(500).json({ error: e?.message }); }\n });\n\n app.post(\"/api/mcp/delete\", mcpAdminGuard, async (req, res) => {\n try {\n const { name } = req.body || {};\n if (!name || typeof name !== \"string\") return res.status(400).json({ error: \"Missing name\" });\n const cleanName = name.trim();\n\n const mcpPath = path.join(process.cwd(), \"mcp.json\");\n let existing: any = {};\n if (fs.existsSync(mcpPath)) {\n try {\n const raw = fs.readFileSync(mcpPath, \"utf-8\");\n const j = JSON.parse(stripJsonc(raw));\n if (j.mcpServers) existing = j.mcpServers;\n else if (j.mcp && j.mcp.servers) existing = j.mcp.servers;\n else if (j.mcp && typeof j.mcp === \"object\") existing = j.mcp;\n else existing = j;\n } catch {}\n }\n\n delete existing[cleanName];\n fs.writeFileSync(mcpPath, JSON.stringify({ mcpServers: existing }, null, 2));\n\n const old = mcp.get(cleanName);\n try { await (old?.client as any)?.close?.(); } catch {}\n mcp.delete(cleanName);\n\n return res.json({ success: true });\n } catch (e: any) { return res.status(500).json({ error: e?.message }); }\n });\n\n\n // Fetch URL endpoint - extracts clean article text via Readability instead\n // of dumping the whole stripped-tag page (nav/ads/footer/comment junk).\n app.post(\"/api/fetch-url\", async (req, res) => {\n const errorFallback = \"you entered an incorrect URL, are missing characters, or the website no longer exists\";\n try {\n const { url, length = 1100 } = req.body;\n if (!url || typeof url !== \"string\") {\n return res.json({\n url: url || \"\",\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n // Extract valid URL even if AI attached trailing titles, colons or spaces\n const urlMatch = url.match(/https?:\\/\\/[^\\s\"']+/);\n let targetUrl = urlMatch ? urlMatch[0] : url.trim();\n if (/^(?:fanluc|mondk-msh)\\.docs(?:[\\/?#]|$)/i.test(targetUrl)) targetUrl = \"https://\" + targetUrl;\n\n try {\n new URL(targetUrl);\n } catch {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n targetUrl = applyDomainRewrite(targetUrl);\n\n let hostname = \"\";\n try {\n hostname = new URL(targetUrl).hostname.toLowerCase();\n } catch {\n // already validated above, shouldn't happen\n }\n\n if (hostname === DOCS_VIRTUAL_HOST || hostname === MONDK_MSH_VIRTUAL_HOST) {\n const pathname = new URL(targetUrl).pathname;\n const doc =\n hostname === MONDK_MSH_VIRTUAL_HOST ? await readMondkMshPage(pathname) : await readVirtualDocsPage(pathname);\n return res.json({\n url: targetUrl,\n title: doc.title,\n text: doc.text,\n formattedText: `fetched url: ${targetUrl}\\ntitle: ${doc.title}\\ntext: ${doc.text}`,\n });\n }\n\n if (isBlockedHost(hostname)) {\n const blockedMsg = `This site (${hostname}) blocks automated crawling or requires login, so its content cannot be reliably extracted. Try a different, publicly accessible source instead.`;\n return res.json({\n url: targetUrl,\n text: blockedMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${blockedMsg}`,\n });\n }\n\n if (looksLikeNonHtmlFile(targetUrl)) {\n const fileMsg = \"This URL points to a non-HTML file (document, image, archive, or media) and cannot be read as article text.\";\n return res.json({\n url: targetUrl,\n text: fileMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${fileMsg}`,\n });\n }\n\n const cleanLength = Math.min(10000, Math.max(100, parseInt(length) || 1100));\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 20000); // 20s timeout\n\n let fetchResult: { ok: boolean; status: number; contentType: string; body: string };\n try {\n fetchResult = await fetchWithByteLimit(targetUrl, controller.signal, MAX_FETCH_BYTES);\n } finally {\n clearTimeout(timeoutId);\n }\n\n if (!fetchResult.ok) {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n if (fetchResult.contentType && !/text\\/html|application\\/xhtml/i.test(fetchResult.contentType)) {\n const nonHtmlMsg = `This URL returned non-HTML content (${fetchResult.contentType.split(\";\")[0]}) and cannot be read as article text.`;\n return res.json({\n url: targetUrl,\n text: nonHtmlMsg,\n formattedText: `fetched url: ${targetUrl}\\ntext: ${nonHtmlMsg}`,\n });\n }\n\n const { title, text: extractedFull } = extractReadableContent(fetchResult.body, targetUrl);\n\n if (!extractedFull) {\n return res.json({\n url: targetUrl,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n\n const extracted = extractedFull.slice(0, cleanLength);\n const titlePart = title ? `title: ${title}\\n` : \"\";\n const formattedText = `fetched url: ${targetUrl}\\n${titlePart}text: ${extracted}`;\n\n return res.json({\n url: targetUrl,\n title,\n text: extracted,\n formattedText,\n });\n } catch (error: any) {\n console.error(\"Fetch URL error:\", error);\n return res.json({\n url: req.body?.url,\n text: errorFallback,\n formattedText: errorFallback,\n });\n }\n });\n\n // Read doc from /docs endpoint\n app.post(\"/api/read-doc\", async (req, res) => {\n try {\n const { name } = req.body;\n if (!name || typeof name !== \"string\") {\n return res.status(400).json({ error: \"Missing name parameter\" });\n }\n\n const cleanName = name.trim().toLowerCase().replace(/^['\"`]|['\"`]$/g, \"\");\n const docsDir = path.join(process.cwd(), \"docs\");\n\n try {\n const files = await fs.promises.readdir(docsDir);\n let targetFile = files.find(\n (f) => f.toLowerCase() === cleanName || f.toLowerCase() === `${cleanName}.md`\n );\n\n if (!targetFile) {\n if (cleanName.includes(\"fanluc\")) targetFile = files.find((f) => f.includes(\"fanluc\"));\n else if (cleanName.includes(\"guide\")) targetFile = files.find((f) => f.includes(\"guide\"));\n else if (cleanName.includes(\"mondk\")) targetFile = files.find((f) => f.includes(\"mondk\"));\n else if (cleanName.includes(\"msh\")) targetFile = files.find((f) => f.includes(\"msh\"));\n else targetFile = files.find((f) => f.toLowerCase().includes(cleanName));\n }\n\n if (targetFile) {\n const content = await fs.promises.readFile(path.join(docsDir, targetFile), \"utf-8\");\n return res.json({\n found: true,\n fileName: targetFile,\n content,\n formattedText: `doc: ${targetFile}\\ncontent:\\n${content}`,\n });\n }\n\n return res.json({\n found: false,\n fileName: name,\n content: `Doc '${name}' not found in /docs/`,\n formattedText: `Doc '${name}' not found in /docs/`,\n });\n } catch (err: any) {\n return res.json({\n found: false,\n fileName: name,\n content: `Error reading docs directory: ${err?.message}`,\n formattedText: `Error reading docs directory: ${err?.message}`,\n });\n }\n } catch (error: any) {\n return res.status(500).json({ error: error?.message || \"Failed to read doc\" });\n }\n });\n\n // Translation endpoint using google-translate-api-x\n app.post(\"/api/translate\", async (req, res) => {\n try {\n const { text, to = \"en\", from = \"auto\" } = req.body;\n if (!text || typeof text !== \"string\") {\n return res.status(400).json({ error: \"Missing text parameter\" });\n }\n\n const cleanText = text.trim();\n if (!cleanText) {\n return res.status(400).json({ error: \"Empty text parameter\" });\n }\n\n const result = await translate(cleanText, {\n to: to || \"en\",\n from: from || \"auto\",\n });\n\n const translatedText = typeof result?.text === \"string\" ? result.text : String(result?.text ?? \"\");\n const detectedFrom = result?.from?.language?.iso || from || \"auto\";\n\n return res.json({\n translatedText,\n detectedFrom,\n originalText: cleanText,\n targetLang: to,\n formattedText: `translated \"${cleanText}\" (${detectedFrom} -> ${to}): \"${translatedText}\"`,\n });\n } catch (error: any) {\n console.error(\"Translation API error:\", error);\n return res.status(500).json({\n error: error?.message || \"Translation failed\",\n translatedText: \"\",\n detectedFrom: req.body?.from || \"auto\",\n formattedText: `translation failed: ${error?.message || \"error\"}`,\n });\n }\n });\n\n // Weather endpoint for show_weather\n app.get(\"/api/weather\", async (req, res) => {\n try {\n const { lat, lon, city } = req.query;\n let finalLat = lat;\n let finalLon = lon;\n let locationName = \"Unknown Location\";\n\n if (city && city !== \"auto\") {\n // Geocode city using Open-Meteo\n const geoRes = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(String(city))}&count=1&language=en&format=json`);\n const geoData = await geoRes.json();\n if (geoData.results && geoData.results.length > 0) {\n finalLat = geoData.results[0].latitude;\n finalLon = geoData.results[0].longitude;\n locationName = geoData.results[0].name + (geoData.results[0].country ? `, ${geoData.results[0].country}` : \"\");\n } else {\n return res.status(404).json({ error: \"City not found\" });\n }\n } else if (lat && lon) {\n // Reverse geocode for name using BigDataCloud free client API\n try {\n const revGeoRes = await fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lon}&localityLanguage=en`);\n const revGeoData = await revGeoRes.json();\n locationName = revGeoData.city || revGeoData.locality || revGeoData.principalSubdivision || \"Your Location\";\n } catch (e) {\n locationName = \"Your Location\";\n }\n } else {\n return res.status(400).json({ error: \"Provide lat/lon or city\" });\n }\n\n // Fetch weather using Open-Meteo\n const weatherRes = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${finalLat}&longitude=${finalLon}¤t_weather=true`);\n const weatherData = await weatherRes.json();\n\n if (!weatherData.current_weather) {\n return res.status(500).json({ error: \"Weather data not available\" });\n }\n\n const current = weatherData.current_weather;\n // Map WMO weather code to condition\n const code = current.weathercode;\n let condition = \"Clear\";\n if (code === 0) condition = \"Sunny\"; // Clear sky\n else if (code === 1 || code === 2 || code === 3) condition = \"Cloudy\"; // Mainly clear, partly cloudy, and overcast\n else if (code === 45 || code === 48) condition = \"Fog\";\n else if (code >= 51 && code <= 67) condition = \"Rainy\"; // Drizzle and Rain\n else if (code >= 71 && code <= 77) condition = \"Snow\";\n else if (code >= 80 && code <= 82) condition = \"Rainy\"; // Rain showers\n else if (code >= 85 && code <= 86) condition = \"Snow\"; // Snow showers\n else if (code >= 95 && code <= 99) condition = \"Stormy\"; // Thunderstorm\n\n // Determine if Windy based on windspeed (rough estimation)\n if (current.windspeed > 20 && (condition === \"Sunny\" || condition === \"Cloudy\" || condition === \"Clear\")) {\n condition = \"Windy\";\n }\n\n res.json({\n location: locationName,\n temperature: current.temperature,\n condition,\n isDay: current.is_day === 1,\n time: current.time,\n });\n } catch (error: any) {\n console.error(\"Weather API error:\", error);\n res.status(500).json({ error: \"Failed to fetch weather\" });\n }\n });\n\n // run_cmd / background jobs / workspace picker / workspace files: see localExec.ts\n registerLocalRoutes(app);\n\n app.get(\"/api/health\", (_req, res) => {\n res.json({ status: \"ok\" });\n });\n\n if (process.env.NODE_ENV !== \"production\") {\n const vite = await createViteServer({\n server: { middlewareMode: true, hmr: false },\n appType: \"spa\",\n });\n app.use(vite.middlewares);\n } else {\n const distPath = path.join(process.cwd(), \"dist\");\n app.use(express.static(distPath));\n app.get(\"*\", (_req, res) => {\n res.sendFile(path.join(distPath, \"index.html\"));\n });\n }\n\n const HOST = process.env.HOST || \"127.0.0.1\"; // loopback only by default (there is no sandbox!)\n app.listen(PORT, HOST, () => {\n console.log(`Server running on http://localhost:${PORT} (bound to ${HOST})`);\n console.log(`Workspace: ${getWorkspace()} | shell: ${SHELL.label}`);\n if (![\"127.0.0.1\", \"localhost\", \"::1\"].includes(HOST)) {\n console.warn(\"[security] HOST is not loopback. Commands run WITHOUT a sandbox: anyone who can reach this port can run commands on this PC.\");\n }\n });\n}\n\n// Close MCP child processes on exit so servers like colab-mcp don't linger as orphans.\nlet shuttingDown = false;\nfunction closeAllMcp() {\n if (shuttingDown) return;\n shuttingDown = true;\n for (const entry of mcp.values()) {\n try {\n entry.client?.close();\n } catch {}\n }\n}\nprocess.on(\"SIGINT\", () => { closeAllMcp(); setTimeout(() => process.exit(0), 300); });\nprocess.on(\"SIGTERM\", () => { closeAllMcp(); setTimeout(() => process.exit(0), 300); });\nprocess.on(\"exit\", closeAllMcp);\n\nstartServer();\n", "// ============================================================================\n// localExec.ts \u2014 SELF-HOST edition: NO sandbox.\n//\n// * Commands run directly on THIS machine, as the user who started the server,\n// with the real PATH / HOME / python / node / git (nothing is jailed).\n// * The working folder (\"workspace\") is chosen by the user at runtime\n// (like opencode web) and remembered in ~/.fanluc/config.json.\n// * Because there is no sandbox, the API is only reachable from this machine\n// (loopback + Host-header check, see requireLocal). Set ALLOW_REMOTE_EXEC=1\n// ONLY if you understand that it gives remote shell access to this PC.\n//\n// Env:\n// WORKSPACE_DIR force a workspace at startup (overrides saved one)\n// FANLUC_HOME where config.json lives (default ~/.fanluc)\n// FANLUC_SHELL shell binary override (bash / pwsh / powershell / cmd)\n// FANLUC_UNRESTRICTED=1 also disable the tiny \"catastrophic command\" guard\n// ALLOW_REMOTE_EXEC=1 disable the local-only guard (dangerous)\n// ALLOWED_HOSTS extra Host header values allowed, comma separated\n// STRIP_ENV extra env var names hidden from commands (comma sep.)\n// ============================================================================\nimport type { Express, Request, Response, NextFunction } from \"express\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { pipeline } from \"stream/promises\";\nimport { evaluatePermission, registerPermissionRoutes, removeOversizeNewFiles } from \"./permissions\";\nimport { spawn, execFileSync, ChildProcess } from \"child_process\";\n\n// ---------------------------------------------------------------------------\n// Config + workspace state\n// ---------------------------------------------------------------------------\nconst HOME_DIR = process.env.FANLUC_HOME || path.join(os.homedir(), \".fanluc\");\nconst CONFIG_FILE = path.join(HOME_DIR, \"config.json\");\n\ninterface LocalConfig {\n workspace?: string;\n recent?: string[];\n}\n\nfunction readConfig(): LocalConfig {\n try {\n return JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf-8\")) || {};\n } catch {\n return {};\n }\n}\n\nfunction writeConfig(cfg: LocalConfig) {\n try {\n fs.mkdirSync(HOME_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), \"utf-8\");\n } catch (e: any) {\n console.warn(\"[workspace] could not save config:\", e?.message || e);\n }\n}\n\nfunction isDir(p: string): boolean {\n try {\n return fs.statSync(p).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction pickInitialWorkspace(): string {\n const forced = process.env.WORKSPACE_DIR || process.env.WORKSPACE;\n if (forced && isDir(forced)) return path.resolve(forced);\n const saved = readConfig().workspace;\n if (saved && isDir(saved)) return path.resolve(saved);\n const fallback = path.join(process.cwd(), \"workspace\");\n try {\n fs.mkdirSync(fallback, { recursive: true });\n } catch {}\n return fallback;\n}\n\nlet currentWorkspace = pickInitialWorkspace();\n\nexport function getWorkspace(): string {\n return currentWorkspace;\n}\n\nconst workspaceListeners: Array<(dir: string) => void> = [];\n/** Register a callback fired after the user picks another workspace folder. */\nexport function onWorkspaceChange(cb: (dir: string) => void) {\n workspaceListeners.push(cb);\n}\n\nexport function setWorkspace(dir: string): { ok: true; workspace: string } | { ok: false; error: string } {\n if (!dir || typeof dir !== \"string\") return { ok: false, error: \"Missing path\" };\n const abs = path.resolve(dir.trim().replace(/^~(?=$|[\\\\/])/, os.homedir()));\n if (!isDir(abs)) return { ok: false, error: `Folder does not exist: ${abs}` };\n try {\n fs.accessSync(abs, fs.constants.R_OK | fs.constants.W_OK);\n } catch {\n return { ok: false, error: `No read/write permission: ${abs}` };\n }\n currentWorkspace = abs;\n const cfg = readConfig();\n const recent = [abs, ...(cfg.recent || []).filter((r) => r !== abs)].filter(isDir).slice(0, 10);\n writeConfig({ workspace: abs, recent });\n console.log(`[workspace] now: ${abs}`);\n for (const cb of workspaceListeners) {\n try {\n cb(abs);\n } catch {}\n }\n return { ok: true, workspace: abs };\n}\n\n/** Resolve a user/AI supplied relative path inside the workspace; null if it escapes. */\nexport function resolveInWorkspace(rel: string): string | null {\n const clean = String(rel || \"\").trim().replace(/^(\\.\\/|\\/|\\\\)+/, \"\");\n const abs = path.resolve(currentWorkspace, clean);\n if (abs === currentWorkspace) return abs;\n return abs.startsWith(currentWorkspace + path.sep) ? abs : null;\n}\n\nfunction agentDir(workspaceId: unknown): string {\n if (!workspaceId || typeof workspaceId !== \"string\") return currentWorkspace;\n const safeId = workspaceId.replace(/[^a-zA-Z0-9_-]/g, \"\").slice(0, 64);\n if (!safeId) return currentWorkspace;\n const dir = path.join(currentWorkspace, \".fanluc\", \"agents\", safeId);\n try {\n fs.mkdirSync(dir, { recursive: true });\n } catch {}\n return dir;\n}\n\n// ---------------------------------------------------------------------------\n// Shell detection (Linux / macOS / Windows)\n// ---------------------------------------------------------------------------\ninterface ShellInfo {\n bin: string;\n kind: \"posix\" | \"powershell\" | \"cmd\";\n label: string;\n args: (cmd: string) => string[];\n}\n\nfunction which(name: string): string | null {\n try {\n const finder = process.platform === \"win32\" ? \"where\" : \"which\";\n const out = execFileSync(finder, [name], { stdio: [\"ignore\", \"pipe\", \"ignore\"] }).toString().split(/\\r?\\n/)[0].trim();\n return out || null;\n } catch {\n return null;\n }\n}\n\nfunction shellFromBinary(bin: string): ShellInfo {\n const base = path.basename(bin).toLowerCase();\n if (base.includes(\"pwsh\") || base.includes(\"powershell\")) {\n return {\n bin,\n kind: \"powershell\",\n label: base.includes(\"pwsh\") ? \"PowerShell 7 (pwsh)\" : \"Windows PowerShell\",\n args: (cmd) => [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-ExecutionPolicy\", \"Bypass\", \"-Command\", cmd],\n };\n }\n if (base === \"cmd.exe\" || base === \"cmd\") {\n return { bin, kind: \"cmd\", label: \"cmd.exe\", args: (cmd) => [\"/d\", \"/s\", \"/c\", cmd] };\n }\n return { bin, kind: \"posix\", label: base.includes(\"bash\") ? \"bash\" : base, args: (cmd) => [\"-c\", cmd] };\n}\n\nfunction detectShell(): ShellInfo {\n const override = process.env.FANLUC_SHELL;\n if (override) return shellFromBinary(override);\n if (process.platform === \"win32\") {\n const pf = process.env.ProgramFiles || \"C:\\\\Program Files\";\n const pf86 = process.env[\"ProgramFiles(x86)\"] || \"C:\\\\Program Files (x86)\";\n const local = process.env.LOCALAPPDATA || \"\";\n const gitBash = [\n path.join(pf, \"Git\", \"bin\", \"bash.exe\"),\n path.join(pf86, \"Git\", \"bin\", \"bash.exe\"),\n local && path.join(local, \"Programs\", \"Git\", \"bin\", \"bash.exe\"),\n ].filter(Boolean) as string[];\n for (const c of gitBash) if (fs.existsSync(c)) return { ...shellFromBinary(c), label: \"Git Bash\" };\n const pwsh = which(\"pwsh\");\n if (pwsh) return shellFromBinary(pwsh);\n return shellFromBinary(which(\"powershell\") || \"powershell.exe\");\n }\n const bash = which(\"bash\");\n return shellFromBinary(bash || \"/bin/sh\");\n}\n\nexport const SHELL: ShellInfo = detectShell();\n\nexport function systemInfo() {\n return {\n platform: process.platform,\n arch: process.arch,\n os: `${os.type()} ${os.release()}`,\n shell: SHELL.label,\n shellKind: SHELL.kind,\n home: os.homedir(),\n workspace: currentWorkspace,\n node: process.version,\n python: which(\"python3\") ? \"python3\" : which(\"python\") ? \"python\" : null,\n git: !!which(\"git\"),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Environment for commands: the REAL environment, minus this app's own secrets\n// ---------------------------------------------------------------------------\nconst STRIP_ENV = new Set(\n [\"GEMINI_API_KEY\", \"TOKEN\", \"ADMIN_TOKEN\", \"ACCESS_TOKEN\", ...(process.env.STRIP_ENV || \"\").split(\",\").map((s) => s.trim())].filter(Boolean)\n);\n\nfunction buildEnv(): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const [k, v] of Object.entries(process.env)) if (!STRIP_ENV.has(k)) env[k] = v;\n return {\n ...env,\n PYTHONIOENCODING: \"utf-8\",\n PYTHONUTF8: \"1\",\n NO_COLOR: \"1\",\n FORCE_COLOR: \"0\",\n GIT_TERMINAL_PROMPT: \"0\", // fail instead of hanging on a credential prompt\n GIT_PAGER: \"cat\",\n PAGER: \"cat\",\n npm_config_yes: \"true\",\n DEBIAN_FRONTEND: \"noninteractive\",\n MPLBACKEND: env.MPLBACKEND || \"Agg\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tiny guard against catastrophic accidents (NOT a sandbox).\n// Everything else (sudo, .env, curl|sh, pip, npm, docker...) is allowed.\n// ---------------------------------------------------------------------------\nconst CATASTROPHIC: { pattern: RegExp; reason: string }[] = [\n { pattern: /\\brm\\s+(-[a-z]*\\s+)*-[a-z]*[rf][a-z]*\\s+(-[a-z]+\\s+)*(--no-preserve-root\\s+)?(\\/|~|\\$HOME|\\/\\*|~\\/\\*)\\s*(;|&|\\||$)/i, reason: \"recursive delete of / or home\" },\n { pattern: /\\bmkfs(\\.\\w+)?\\b/i, reason: \"formatting a filesystem\" },\n { pattern: /\\bdd\\b[^\\n]*\\bof=\\/dev\\/(sd|nvme|hd|disk|mmcblk)/i, reason: \"writing raw to a disk device\" },\n { pattern: /:\\(\\)\\s*\\{\\s*:\\s*\\|\\s*:\\s*&?\\s*\\}\\s*;/, reason: \"fork bomb\" },\n { pattern: /\\bformat\\s+[a-z]:/i, reason: \"formatting a drive\" },\n { pattern: /\\b(rd|rmdir)\\s+\\/s\\s+(\\/q\\s+)?[a-z]:\\\\?\\s*$/i, reason: \"deleting a whole drive\" },\n { pattern: /\\bRemove-Item\\b[^\\n]*-Recurse[^\\n]*\\s[a-z]:\\\\?\\s*$/i, reason: \"deleting a whole drive\" },\n];\n\nexport function findBlocked(command: string): string | null {\n if (process.env.FANLUC_UNRESTRICTED === \"1\") return null;\n for (const { pattern, reason } of CATASTROPHIC) if (pattern.test(command)) return reason;\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Process helpers\n// ---------------------------------------------------------------------------\nfunction killTree(child: ChildProcess) {\n const pid = child.pid;\n if (!pid) return;\n try {\n if (process.platform === \"win32\") {\n spawn(\"taskkill\", [\"/pid\", String(pid), \"/T\", \"/F\"], { stdio: \"ignore\", windowsHide: true });\n } else {\n try {\n process.kill(-pid, \"SIGTERM\");\n } catch {\n child.kill(\"SIGTERM\");\n }\n setTimeout(() => {\n try {\n process.kill(-pid, \"SIGKILL\");\n } catch {\n try {\n child.kill(\"SIGKILL\");\n } catch {}\n }\n }, 2000).unref?.();\n }\n } catch {}\n}\n\nconst CAN_ULIMIT = process.platform !== \"win32\" && SHELL.kind === \"posix\";\n\nfunction spawnShell(command: string, cwd: string): ChildProcess {\n return spawn(SHELL.bin, SHELL.args(command), {\n cwd,\n env: buildEnv(),\n stdio: [\"ignore\", \"pipe\", \"pipe\"], // no stdin: interactive prompts fail fast instead of hanging\n detached: process.platform !== \"win32\", // own process group so we can kill the whole tree\n windowsHide: true,\n });\n}\n\ninterface RunResult {\n stdout: string;\n stderr: string;\n exitCode: number | null;\n timedOut: boolean;\n truncated: boolean;\n}\n\nconst MAX_CAPTURE = 2 * 1024 * 1024;\nconst MAX_RETURN = Number(process.env.FANLUC_MAX_RETURN) > 0 ? Number(process.env.FANLUC_MAX_RETURN) : 100000; // chars returned to the model per stream (tail)\n\nfunction runCommand(command: string, cwd: string, timeoutMs: number): Promise<RunResult> {\n return new Promise((resolve) => {\n let child: ChildProcess;\n try {\n child = spawnShell(command, cwd);\n } catch (e: any) {\n return resolve({ stdout: \"\", stderr: `Failed to start shell (${SHELL.bin}): ${e?.message || e}`, exitCode: 127, timedOut: false, truncated: false });\n }\n let stdout = \"\";\n let stderr = \"\";\n let truncated = false;\n let timedOut = false;\n const add = (which: \"o\" | \"e\", d: Buffer) => {\n const s = d.toString(\"utf-8\");\n if (which === \"o\") stdout += s;\n else stderr += s;\n if (stdout.length + stderr.length > MAX_CAPTURE) {\n truncated = true;\n stdout = stdout.slice(-MAX_CAPTURE / 2);\n stderr = stderr.slice(-MAX_CAPTURE / 2);\n }\n };\n child.stdout?.on(\"data\", (d) => add(\"o\", d));\n child.stderr?.on(\"data\", (d) => add(\"e\", d));\n const timer = setTimeout(() => {\n timedOut = true;\n killTree(child);\n }, timeoutMs);\n child.on(\"error\", (err) => {\n clearTimeout(timer);\n resolve({ stdout, stderr: stderr + `\\n[spawn error: ${err.message}]`, exitCode: 127, timedOut, truncated });\n });\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n resolve({ stdout, stderr, exitCode: code, timedOut, truncated });\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Background jobs\n// ---------------------------------------------------------------------------\ninterface BgJob {\n id: string;\n command: string;\n child: ChildProcess;\n log: string;\n truncated: boolean;\n status: \"running\" | \"exited\" | \"killed\" | \"error\";\n exitCode: number | null;\n startedAt: number;\n endedAt: number | null;\n}\nconst BG_JOBS = new Map<string, BgJob>();\nconst BG_MAX_LOG = 300000;\nconst BG_MAX_CONCURRENT = 20;\nconst BG_EVICT_MS = 30 * 60 * 1000;\nlet bgSeq = 0;\n\nfunction bgAppend(job: BgJob, chunk: string) {\n if (!chunk) return;\n job.log += chunk;\n if (job.log.length > BG_MAX_LOG) {\n job.log = job.log.slice(job.log.length - BG_MAX_LOG);\n job.truncated = true;\n }\n}\nfunction bgStatus(job: BgJob): string {\n if (job.status === \"exited\") return `exited (code ${job.exitCode})`;\n return job.status;\n}\nfunction lastLine(text: string): string {\n const lines = text.split(\"\\n\").map((l) => l.trimEnd());\n for (let i = lines.length - 1; i >= 0; i--) if (lines[i].trim()) return lines[i];\n return \"(no output yet)\";\n}\nfunction bgEvictLater(job: BgJob) {\n setTimeout(() => {\n if (BG_JOBS.get(job.id) === job) BG_JOBS.delete(job.id);\n }, BG_EVICT_MS).unref?.();\n}\n\n// Kill every running job when the server exits so dev servers don't linger.\nfunction killAllJobs() {\n for (const j of BG_JOBS.values()) if (j.status === \"running\") killTree(j.child);\n}\nprocess.on(\"exit\", killAllJobs);\nfor (const sig of [\"SIGINT\", \"SIGTERM\"] as const) {\n process.on(sig, () => {\n killAllJobs();\n process.exit(0);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Local-only guard (because there is no sandbox)\n// ---------------------------------------------------------------------------\nfunction isLoopbackAddr(ip: string): boolean {\n return ip === \"127.0.0.1\" || ip === \"::1\" || ip === \"::ffff:127.0.0.1\";\n}\n\nexport function requireLocal(req: Request, res: Response, next: NextFunction) {\n if (process.env.ALLOW_REMOTE_EXEC === \"1\") return next();\n const ip = String(req.socket?.remoteAddress || \"\");\n const viaProxy = !!req.headers[\"x-forwarded-for\"] || !!req.headers[\"x-forwarded-host\"]; // ngrok/cloudflared add these\n // Host header check blocks DNS-rebinding attacks from web pages the user visits.\n const host = String(req.headers.host || \"\").replace(/:\\d+$/, \"\").replace(/^\\[|\\]$/g, \"\").toLowerCase();\n const extra = (process.env.ALLOWED_HOSTS || \"\").split(\",\").map((s) => s.trim().toLowerCase()).filter(Boolean);\n const hostOk = host === \"localhost\" || host === \"127.0.0.1\" || host === \"::1\" || host.endsWith(\".localhost\") || extra.includes(host);\n if (isLoopbackAddr(ip) && !viaProxy && hostOk) return next();\n return res.status(403).json({\n error: \"Local only: running commands / browsing folders is allowed only from the machine running the server (open http://localhost:PORT). Set ALLOW_REMOTE_EXEC=1 to override (dangerous).\",\n formattedText: \"Blocked: this request did not come from localhost.\",\n });\n}\n\n// ---------------------------------------------------------------------------\n// Workspace file listing (metadata + capped inline content)\n// ---------------------------------------------------------------------------\nconst SKIP_DIRS = new Set([\n \"node_modules\", \".git\", \".hg\", \".svn\", \"dist\", \"build\", \"out\", \".next\", \".nuxt\", \".cache\", \".venv\", \"venv\", \"env\",\n \"__pycache__\", \".pytest_cache\", \".mypy_cache\", \"target\", \"vendor\", \".gradle\", \".idea\", \".vscode\", \"coverage\", \".turbo\", \".fanluc\",\n]);\nconst BINARY_EXT = new Set([\n \"zip\", \"gz\", \"tar\", \"tgz\", \"rar\", \"7z\", \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"bmp\", \"ico\", \"pdf\", \"exe\", \"dll\", \"so\", \"dylib\", \"bin\", \"apk\", \"iso\",\n \"mp3\", \"mp4\", \"mkv\", \"avi\", \"mov\", \"wav\", \"flac\", \"ogg\", \"woff\", \"woff2\", \"ttf\", \"otf\", \"class\", \"jar\", \"pyc\", \"sqlite\", \"db\",\n]);\nconst MAX_FILES = 5000;\nconst envNum = (k: string, d: number) => { const n = Number(process.env[k]); return Number.isFinite(n) && n > 0 ? n : d; };\nconst VIEW_LIMIT = 70 * 1024 * 1024; // non-HTML files above this are not sent to the viewer (download instead)\nconst MAX_INLINE_FILE = 256 * 1024 * 1024; // technical guard only (Node cannot hold bigger strings); no user-facing cap\n\nasync function listWorkspaceFiles(root: string) {\n const files: Record<string, any> = {};\n let count = 0;\n let truncated = false;\n\n async function walk(dir: string, rel: string) {\n if (truncated) return;\n let entries: fs.Dirent[] = [];\n try {\n entries = await fs.promises.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const entry of entries) {\n if (truncated) return;\n const name = entry.name;\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(name) || name.startsWith(\".\")) continue;\n await walk(path.join(dir, name), rel ? `${rel}/${name}` : name);\n } else if (entry.isFile()) {\n if (name.startsWith(\".\")) continue;\n if (count >= MAX_FILES) {\n truncated = true;\n return;\n }\n const full = path.join(dir, name);\n const relPath = rel ? `${rel}/${name}` : name;\n let st: fs.Stats;\n try {\n st = await fs.promises.stat(full);\n } catch {\n continue;\n }\n const ext = name.split(\".\").pop()?.toLowerCase() || \"\";\n let content: string;\n if (BINARY_EXT.has(ext)) content = `[Binary File: ${name} (${(st.size / 1024).toFixed(1)} KB)]`;\n else if (st.size > MAX_INLINE_FILE || (st.size > VIEW_LIMIT && !/\\.html?$/i.test(name)))\n content = `[Large File: ${(st.size / 1024).toFixed(1)} KB \u2014 read it with run_cmd (cat / sed -n)]`;\n else {\n try {\n content = await fs.promises.readFile(full, \"utf-8\");\n } catch {\n content = `[Unreadable File: ${(st.size / 1024).toFixed(1)} KB]`;\n }\n }\n files[relPath] = { path: relPath, name, content, size: st.size, language: ext, updatedAt: st.mtimeMs };\n count++;\n }\n }\n }\n await walk(root, \"\");\n return { files, truncated, count };\n}\n\n\n// ---- on-disk key/value store (replaces the browser's localStorage) ------------------------\nconst KV_FILE = path.join(os.homedir(), \".fanluc\", \"state.json\");\nlet kvCache: Record<string, string> | null = null;\nfunction kvLoad(): Record<string, string> {\n if (kvCache) return kvCache;\n try {\n kvCache = JSON.parse(fs.readFileSync(KV_FILE, \"utf-8\")) || {};\n } catch {\n kvCache = {};\n }\n return kvCache!;\n}\nlet kvTimer: NodeJS.Timeout | null = null;\nfunction kvSave(data: Record<string, string>) {\n kvCache = data;\n if (kvTimer) return;\n kvTimer = setTimeout(() => {\n kvTimer = null;\n try {\n fs.mkdirSync(path.dirname(KV_FILE), { recursive: true });\n const tmp = KV_FILE + \".tmp\";\n fs.writeFileSync(tmp, JSON.stringify(kvCache), { mode: 0o600 });\n fs.renameSync(tmp, KV_FILE);\n } catch (e) {\n console.warn(\"[kv] save failed:\", e);\n }\n }, 300);\n}\nprocess.on(\"exit\", () => {\n if (kvTimer) {\n try {\n fs.mkdirSync(path.dirname(KV_FILE), { recursive: true });\n fs.writeFileSync(KV_FILE, JSON.stringify(kvCache), { mode: 0o600 });\n } catch {}\n }\n});\n\n// ---------------------------------------------------------------------------\n// Routes\n// ---------------------------------------------------------------------------\nfunction clampTimeout(v: unknown): number {\n const n = Number(v);\n if (!Number.isFinite(n) || n <= 0) return 120000;\n return Math.min(600000, Math.max(1000, n));\n}\n\nfunction listRoots(): { name: string; path: string }[] {\n const roots: { name: string; path: string }[] = [];\n if (process.platform === \"win32\") {\n for (let c = 65; c <= 90; c++) {\n const d = `${String.fromCharCode(c)}:\\\\`;\n try {\n if (fs.existsSync(d)) roots.push({ name: d, path: d });\n } catch {}\n }\n } else {\n roots.push({ name: \"/\", path: \"/\" });\n }\n return roots;\n}\n\nexport function registerLocalRoutes(app: Express) {\n registerPermissionRoutes(app, requireLocal);\n // ---- workspace -----------------------------------------------------------\n app.get(\"/api/workspace\", requireLocal, (_req, res) => {\n const cfg = readConfig();\n res.json({\n workspace: currentWorkspace,\n name: path.basename(currentWorkspace) || currentWorkspace,\n recent: (cfg.recent || []).filter(isDir),\n home: os.homedir(),\n roots: listRoots(),\n system: systemInfo(),\n });\n });\n\n app.post(\"/api/workspace/set\", requireLocal, (req, res) => {\n const r = setWorkspace(String(req.body?.path || \"\"));\n if (!r.ok) return res.status(400).json(r);\n return res.json({ ok: true, workspace: r.workspace, name: path.basename(r.workspace) || r.workspace });\n });\n\n // Folder browser for the picker (directories only)\n app.get(\"/api/fs/browse\", requireLocal, async (req, res) => {\n try {\n const raw = String(req.query.path || \"\").trim();\n const target = path.resolve(raw ? raw.replace(/^~(?=$|[\\\\/])/, os.homedir()) : os.homedir());\n if (!isDir(target)) return res.status(404).json({ error: `Not a folder: ${target}` });\n const showHidden = req.query.hidden === \"1\";\n let entries: fs.Dirent[] = [];\n try {\n entries = await fs.promises.readdir(target, { withFileTypes: true });\n } catch (e: any) {\n return res.status(403).json({ error: e?.message || \"Cannot read folder\" });\n }\n const dirs = entries\n .filter((e) => {\n if (!e.isDirectory() && !(e.isSymbolicLink() && isDir(path.join(target, e.name)))) return false;\n return showHidden || !e.name.startsWith(\".\");\n })\n .map((e) => e.name)\n .sort((a, b) => a.localeCompare(b));\n const parent = path.dirname(target);\n res.json({\n path: target,\n parent: parent === target ? null : parent,\n dirs,\n fileCount: entries.filter((e) => e.isFile()).length,\n roots: listRoots(),\n });\n } catch (e: any) {\n res.status(500).json({ error: e?.message || \"browse failed\" });\n }\n });\n\n app.post(\"/api/fs/mkdir\", requireLocal, async (req, res) => {\n try {\n const parent = path.resolve(String(req.body?.parent || \"\"));\n const name = String(req.body?.name || \"\").trim();\n if (!name || /[\\\\/:*?\"<>|]/.test(name) || name === \".\" || name === \"..\") return res.status(400).json({ error: \"Invalid folder name\" });\n if (!isDir(parent)) return res.status(404).json({ error: \"Parent folder not found\" });\n const full = path.join(parent, name);\n await fs.promises.mkdir(full, { recursive: false });\n res.json({ ok: true, path: full });\n } catch (e: any) {\n res.status(500).json({ error: e?.message || \"mkdir failed\" });\n }\n });\n\n app.get(\"/api/system-info\", requireLocal, (_req, res) => res.json(systemInfo()));\n\n // ---- run_cmd ---------------------------------------------------------------\n app.post(\"/api/run-cmd\", requireLocal, async (req, res) => {\n if (process.env.DISABLE_RUN_CMD === \"1\") {\n const msg = \"run_cmd is disabled on this server (DISABLE_RUN_CMD=1).\";\n return res.json({ stdout: \"\", stderr: msg, formattedText: msg, blocked: true });\n }\n const { command, workspaceId, timeoutMs } = req.body || {};\n if (!command || typeof command !== \"string\" || !command.trim()) {\n return res.status(400).json({ error: \"Missing command\", formattedText: \"Error: missing command\" });\n }\n const trimmed = command.trim();\n const blocked = findBlocked(trimmed);\n if (blocked) {\n const msg = `Command blocked as catastrophic: ${blocked}. (Set FANLUC_UNRESTRICTED=1 to disable this guard.)`;\n return res.json({ stdout: \"\", stderr: msg, formattedText: msg, blocked: true });\n }\n const cwd = agentDir(workspaceId);\n const limit = clampTimeout(timeoutMs);\n const ev = await evaluatePermission(trimmed, cwd, { canUlimit: CAN_ULIMIT });\n if (!ev.ok) {\n return res.json({ stdout: \"\", stderr: ev.message, formattedText: `$ ${trimmed}\\n${ev.message}`, blocked: true });\n }\n const startedAt = Date.now();\n const toRun = ev.ulimitMb ? `ulimit -f ${Math.max(1, Math.floor(ev.ulimitMb * 1024))}; ${trimmed}` : trimmed;\n const r = await runCommand(toRun, cwd, limit);\n const out = r.stdout.slice(-MAX_RETURN);\n const errOut = r.stderr.slice(-MAX_RETURN);\n const notes: string[] = [];\n if (r.truncated || r.stdout.length > MAX_RETURN || r.stderr.length > MAX_RETURN) notes.push(\"[output truncated \u2014 showing the end]\");\n if (ev.ulimitMb && r.exitCode === 153) notes.push(\"[stopped: a file would exceed the user's max file-size limit (permission settings)]\");\n if (ev.scanBytes) {\n const removed = await removeOversizeNewFiles(cwd, startedAt, ev.scanBytes);\n if (removed.length) notes.push(`[removed new files over the user's max file-size limit: ${removed.join(\", \")}]`);\n }\n if (r.timedOut) notes.push(`[timed out after ${Math.round(limit / 1000)}s and was killed \u2014 use run_cmd_bg for long-running commands]`);\n const body = `${out}${errOut ? (out ? \"\\n\" : \"\") + errOut : \"\"}`.trim() || \"(no output)\";\n const formattedText = `$ ${trimmed}\\n${body}${notes.length ? \"\\n\" + notes.join(\"\\n\") : \"\"}${\n !r.timedOut && r.exitCode ? `\\n[exit code ${r.exitCode}]` : \"\"\n }`;\n return res.json({ stdout: out, stderr: errOut, exitCode: r.exitCode, timedOut: r.timedOut, formattedText });\n });\n\n // ---- background jobs ---------------------------------------------------------\n app.post(\"/api/run-cmd-bg\", requireLocal, async (req, res) => {\n if (process.env.DISABLE_RUN_CMD === \"1\") {\n return res.json({ id: null, formattedText: \"run_cmd_bg is disabled on this server.\", blocked: true });\n }\n const { command, workspaceId } = req.body || {};\n if (!command || typeof command !== \"string\" || !command.trim()) {\n return res.status(400).json({ error: \"Missing command\", formattedText: \"Error: missing command\" });\n }\n const trimmed = command.trim();\n const blocked = findBlocked(trimmed);\n if (blocked) return res.json({ id: null, formattedText: `Command blocked as catastrophic: ${blocked}.`, blocked: true });\n const ev = await evaluatePermission(trimmed, agentDir(workspaceId), { canUlimit: CAN_ULIMIT });\n if (!ev.ok) return res.json({ id: null, formattedText: `$ ${trimmed}\\n${ev.message}`, blocked: true });\n const running = [...BG_JOBS.values()].filter((j) => j.status === \"running\").length;\n if (running >= BG_MAX_CONCURRENT) {\n return res.json({ id: null, formattedText: `Too many background commands running (max ${BG_MAX_CONCURRENT}). Kill one with kill_cmd_bg first.`, blocked: true });\n }\n let child: ChildProcess;\n try {\n child = spawnShell(ev.ulimitMb ? `ulimit -f ${Math.max(1, Math.floor(ev.ulimitMb * 1024))}; ${trimmed}` : trimmed, agentDir(workspaceId));\n } catch (e: any) {\n return res.json({ id: null, formattedText: `Failed to start background command: ${e?.message || e}`, blocked: true });\n }\n const id = `bg${(++bgSeq).toString(36)}${Date.now().toString(36).slice(-4)}`;\n const job: BgJob = { id, command: trimmed, child, log: \"\", truncated: false, status: \"running\", exitCode: null, startedAt: Date.now(), endedAt: null };\n BG_JOBS.set(id, job);\n child.stdout?.on(\"data\", (d) => bgAppend(job, d.toString()));\n child.stderr?.on(\"data\", (d) => bgAppend(job, d.toString()));\n child.on(\"error\", (err) => {\n bgAppend(job, `\\n[process error: ${err.message}]\\n`);\n job.status = \"error\";\n job.endedAt = Date.now();\n bgEvictLater(job);\n });\n child.on(\"exit\", (code, signal) => {\n job.exitCode = code;\n job.endedAt = Date.now();\n if (job.status === \"running\") job.status = \"exited\";\n if (signal) bgAppend(job, `\\n[terminated by signal ${signal}]\\n`);\n bgEvictLater(job);\n });\n return res.json({ id, formattedText: `Started background command ${id}: ${trimmed}` });\n });\n\n app.post(\"/api/kill-cmd-bg\", requireLocal, (req, res) => {\n const { id } = req.body || {};\n const job = id && BG_JOBS.get(id);\n if (!job) return res.json({ formattedText: `No background command with id \"${id}\" (it may have finished and been cleaned up).` });\n if (job.status !== \"running\") return res.json({ formattedText: `${id} is not running (status: ${bgStatus(job)}).` });\n job.status = \"killed\";\n killTree(job.child);\n return res.json({ formattedText: `Killed ${id} (${job.command}).` });\n });\n\n app.post(\"/api/read-cmd-bg-log\", requireLocal, (req, res) => {\n const { id, offset, limit } = req.body || {};\n const job = id && BG_JOBS.get(id);\n if (!job) return res.json({ formattedText: `No background command with id \"${id}\" (it may have finished and been cleaned up).` });\n const lines = job.log.split(\"\\n\");\n const off = Math.max(1, parseInt(offset, 10) || 1);\n const lim = Math.max(1, Math.min(2000, parseInt(limit, 10) || 200));\n const slice = lines.slice(off - 1, off - 1 + lim);\n const header = `[${id}] status: ${bgStatus(job)} | command: ${job.command} | log lines: ${lines.length}${job.truncated ? \" (older lines were trimmed)\" : \"\"}`;\n return res.json({ formattedText: `${header}\\n${slice.join(\"\\n\") || \"(nothing at this offset)\"}` });\n });\n\n app.post(\"/api/list-cmd-bg\", requireLocal, (_req, res) => {\n const jobs = [...BG_JOBS.values()].sort((a, b) => a.startedAt - b.startedAt);\n if (!jobs.length) return res.json({ formattedText: \"No background commands.\", jobs: [] });\n const rows = jobs.map((j) => ({ id: j.id, command: j.command, status: bgStatus(j), lastLogLine: lastLine(j.log) }));\n return res.json({ formattedText: rows.map((r) => `- ${r.id} | ${r.status} | ${r.command}\\n last: ${r.lastLogLine}`).join(\"\\n\"), jobs: rows });\n });\n\n // ---- per-agent folders (inside <workspace>/.fanluc/agents/<id>) ----------------\n app.post(\"/api/agent-workspace-export\", requireLocal, async (req, res) => {\n const safeId = typeof req.body?.workspaceId === \"string\" ? req.body.workspaceId.replace(/[^a-zA-Z0-9_-]/g, \"\").slice(0, 64) : \"\";\n if (!safeId) return res.status(400).json({ error: \"Missing workspaceId\" });\n const dir = path.join(currentWorkspace, \".fanluc\", \"agents\", safeId);\n if (!fs.existsSync(dir)) return res.status(404).json({ error: \"This agent has no workspace files yet.\" });\n try {\n // Zip with JSZip (already a dependency) so it works on every OS without zip/python.\n const { default: JSZip } = await import(\"jszip\");\n const zip = new JSZip();\n const walk = async (d: string, rel: string) => {\n for (const e of await fs.promises.readdir(d, { withFileTypes: true })) {\n const p = path.join(d, e.name);\n const r = rel ? `${rel}/${e.name}` : e.name;\n if (e.isDirectory()) await walk(p, r);\n else if (e.isFile()) zip.file(r, await fs.promises.readFile(p));\n }\n };\n await walk(dir, \"\");\n const buf = await zip.generateAsync({ type: \"nodebuffer\", compression: \"DEFLATE\" });\n res.setHeader(\"Content-Type\", \"application/zip\");\n res.setHeader(\"Content-Disposition\", `attachment; filename=\"agent-${safeId}-workspace.zip\"`);\n res.send(buf);\n } catch (e: any) {\n res.status(500).json({ error: e?.message || String(e) });\n }\n });\n\n app.post(\"/api/agent-workspace-clear\", requireLocal, (req, res) => {\n const safeId = typeof req.body?.workspaceId === \"string\" ? req.body.workspaceId.replace(/[^a-zA-Z0-9_-]/g, \"\").slice(0, 64) : \"\";\n if (!safeId) return res.status(400).json({ error: \"Missing workspaceId\" });\n const dir = path.join(currentWorkspace, \".fanluc\", \"agents\", safeId);\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n fs.mkdirSync(dir, { recursive: true });\n res.json({ ok: true, formattedText: `Cleared workspace for agent ${safeId}.` });\n } catch (e: any) {\n res.status(500).json({ error: e?.message || String(e) });\n }\n });\n\n // install_pack_v1 is gone in the self-host edition (there is no sandbox to prepare).\n app.post(\"/api/install-pack\", (_req, res) => {\n res.json({\n ok: true,\n formattedText:\n \"[INSTALL_PACK_V1 STATUS: SUCCESS]\\nThis build runs commands directly on the user's machine. There is nothing to install automatically: use run_cmd with the tool's own installer (pip install X, npm i X, winget/brew/apt) when something is missing.\",\n });\n });\n\n // ---- workspace files (UI panel) --------------------------------------------------\n app.post(\"/api/upload-workspace-file\", requireLocal, async (req, res) => {\n try {\n const { name, content, encoding = \"utf-8\" } = req.body || {};\n if (!name || typeof name !== \"string\") return res.status(400).json({ error: \"Missing file name\" });\n const filePath = resolveInWorkspace(name);\n if (!filePath || filePath === currentWorkspace) return res.status(403).json({ error: \"Invalid file path outside workspace\" });\n await fs.promises.mkdir(path.dirname(filePath), { recursive: true });\n let buffer: Buffer;\n if ((encoding === \"base64\" || name.toLowerCase().endsWith(\".zip\")) && typeof content === \"string\") {\n buffer = Buffer.from(content.includes(\",\") ? content.split(\",\")[1] : content, \"base64\");\n } else if (typeof content === \"string\") {\n buffer = Buffer.from(content, \"utf-8\");\n } else {\n buffer = Buffer.from(\"\");\n }\n await fs.promises.writeFile(filePath, buffer);\n const st = await fs.promises.stat(filePath);\n return res.json({ success: true, path: path.relative(currentWorkspace, filePath).split(path.sep).join(\"/\"), name: path.basename(filePath), size: st.size, updatedAt: st.mtimeMs });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Failed to upload workspace file\" });\n }\n });\n\n app.post(\"/api/delete-workspace-file\", requireLocal, async (req, res) => {\n try {\n const p = req.body?.path;\n if (!p || typeof p !== \"string\") return res.status(400).json({ error: \"Missing file path\" });\n const target = resolveInWorkspace(p);\n if (!target || target === currentWorkspace) return res.status(403).json({ error: \"Invalid file path outside workspace\" });\n if (fs.existsSync(target)) await fs.promises.rm(target, { recursive: true, force: true });\n return res.json({ success: true, path: p });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Failed to delete workspace file\" });\n }\n });\n\n\n // ---- raw upload: streamed straight to disk, NO size limit, no base64 --------------------\n app.post(\"/api/workspace/upload-raw\", requireLocal, async (req, res) => {\n try {\n const rel = String(req.query.path || \"\");\n if (!rel) return res.status(400).json({ error: \"Missing path\" });\n const target = resolveInWorkspace(rel);\n if (!target || target === currentWorkspace) return res.status(403).json({ error: \"Invalid file path outside workspace\" });\n await fs.promises.mkdir(path.dirname(target), { recursive: true });\n await pipeline(req, fs.createWriteStream(target));\n const st = await fs.promises.stat(target);\n return res.json({ success: true, path: path.relative(currentWorkspace, target).split(path.sep).join(\"/\"), size: st.size, updatedAt: st.mtimeMs });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Upload failed\" });\n }\n });\n\n // ---- reveal a workspace file in the OS file manager (the app runs on the user's own machine) ----\n app.post(\"/api/workspace/reveal\", requireLocal, async (req, res) => {\n try {\n const target = resolveInWorkspace(String(req.body?.path || \"\"));\n if (!target || !fs.existsSync(target)) return res.status(404).json({ error: \"Not found\" });\n let bin: string;\n let args: string[];\n if (process.platform === \"win32\") {\n bin = \"explorer.exe\";\n args = [`/select,${target}`];\n } else if (process.platform === \"darwin\") {\n bin = \"open\";\n args = [\"-R\", target];\n } else {\n bin = \"xdg-open\";\n args = [path.dirname(target)];\n }\n const child = spawn(bin, args, { detached: true, stdio: \"ignore\", windowsHide: false });\n child.on(\"error\", () => {});\n child.unref();\n return res.json({ ok: true });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Could not open folder\" });\n }\n });\n\n // ---- raw download of any workspace file (any size) ---------------------------------------\n app.get(\"/api/workspace/file\", requireLocal, async (req, res) => {\n try {\n const target = resolveInWorkspace(String(req.query.path || \"\"));\n if (!target || target === currentWorkspace || !fs.existsSync(target)) return res.status(404).json({ error: \"Not found\" });\n const st = await fs.promises.stat(target);\n if (!st.isFile()) return res.status(400).json({ error: \"Not a file\" });\n res.setHeader(\"Content-Type\", \"application/octet-stream\");\n res.setHeader(\"Content-Length\", String(st.size));\n res.setHeader(\"Content-Disposition\", `attachment; filename*=UTF-8''${encodeURIComponent(path.basename(target))}`);\n fs.createReadStream(target).on(\"error\", () => res.destroy()).pipe(res);\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Download failed\" });\n }\n });\n\n // ---- settings / chats / memories: saved on disk instead of the browser's localStorage ------\n app.get(\"/api/kv\", requireLocal, (_req, res) => res.json({ data: kvLoad() }));\n app.post(\"/api/kv\", requireLocal, (req, res) => {\n const { set, remove } = req.body || {};\n const data = kvLoad();\n if (set && typeof set === \"object\") for (const [k, v] of Object.entries(set)) if (typeof v === \"string\") data[k] = v;\n if (Array.isArray(remove)) for (const k of remove) delete data[String(k)];\n kvSave(data);\n return res.json({ ok: true });\n });\n\n app.get(\"/api/workspace-files\", requireLocal, async (_req, res) => {\n try {\n const { files, truncated, count } = await listWorkspaceFiles(currentWorkspace);\n return res.json({ files, truncated, count, workspace: currentWorkspace });\n } catch (err: any) {\n return res.status(500).json({ error: err?.message || \"Failed to list workspace files\" });\n }\n });\n}\n", "// Permissions for run_cmd / run_cmd_bg.\n//\n// IMPORTANT (honest limits): this works by READING THE COMMAND TEXT. It understands the common\n// shell tools (rm, mv, cp, mkdir, zip, tar, sed -i, npm/pip/apt install, redirections like `> file`...).\n// It can NOT see what a script does inside (python build.py, node x.js, make, npm run ...).\n// Those unknown commands are treated as allowed.\n//\n// Max file size when creating is enforced by the OS (`ulimit -f`) on Linux/macOS, and by a\n// post-run scan that removes oversized new files on Windows.\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport type { Express, RequestHandler } from \"express\";\n\nexport type Mode = \"allow\" | \"ask\" | \"deny\";\nexport type Cat = \"create\" | \"move\" | \"delete\" | \"archive\" | \"install\" | \"edit\";\n\nexport interface PermConfig {\n modes: Record<Cat, Mode>;\n /** strings so the UI text boxes can stay empty (\"\" = no limit) */\n limits: { maxCreateMB: string; maxDeleteMB: string; maxInstallMB: string; maxToolCalls: string };\n}\n\nconst DEFAULTS: PermConfig = {\n modes: { create: \"ask\", move: \"allow\", delete: \"ask\", archive: \"allow\", install: \"ask\", edit: \"allow\" },\n limits: { maxCreateMB: \"\", maxDeleteMB: \"\", maxInstallMB: \"\", maxToolCalls: \"\" },\n};\n\nconst LABEL: Record<Cat, string> = {\n create: \"create file/folder\",\n move: \"move/rename\",\n delete: \"delete\",\n archive: \"zip/unzip\",\n install: \"install/uninstall libraries\",\n edit: \"edit file\",\n};\n\nconst FILE = path.join(os.homedir(), \".fanluc\", \"permissions.json\");\nlet cache: PermConfig | null = null;\n\nexport function getPerms(): PermConfig {\n if (cache) return cache;\n let raw: any = {};\n try {\n raw = JSON.parse(fs.readFileSync(FILE, \"utf-8\"));\n } catch {}\n cache = sanitize(raw);\n return cache;\n}\n\nfunction sanitize(raw: any): PermConfig {\n const out: PermConfig = JSON.parse(JSON.stringify(DEFAULTS));\n for (const k of Object.keys(DEFAULTS.modes) as Cat[]) {\n const v = raw?.modes?.[k];\n if (v === \"allow\" || v === \"ask\" || v === \"deny\") out.modes[k] = v;\n }\n for (const k of Object.keys(DEFAULTS.limits) as (keyof PermConfig[\"limits\"])[]) {\n const v = raw?.limits?.[k];\n if (typeof v === \"string\" || typeof v === \"number\") out.limits[k] = String(v).trim().replace(/[^0-9.]/g, \"\").slice(0, 12);\n }\n return out;\n}\n\nexport function setPerms(raw: any): PermConfig {\n cache = sanitize(raw);\n try {\n fs.mkdirSync(path.dirname(FILE), { recursive: true });\n fs.writeFileSync(FILE, JSON.stringify(cache, null, 2), { mode: 0o600 });\n } catch (e) {\n console.warn(\"[permissions] save failed:\", e);\n }\n return cache;\n}\n\nfunction limitBytes(s: string): number | null {\n const n = parseFloat(s);\n return Number.isFinite(n) && n > 0 ? n * 1024 * 1024 : null;\n}\nconst fmt = (b: number) => (b >= 1024 * 1024 ? `${(b / 1024 / 1024).toFixed(1)} MB` : `${Math.max(1, Math.round(b / 1024))} KB`);\n\n// ===========================================================================\n// Command parsing\n// ===========================================================================\ninterface Seg {\n tokens: string[];\n redirects: string[]; // file targets of > / >>\n}\n\nconst WIN = process.platform === \"win32\";\n\nfunction splitCommand(cmd: string): Seg[] {\n const segs: Seg[] = [];\n let tokens: string[] = [];\n let redirects: string[] = [];\n let cur = \"\";\n let has = false; // current word exists (even if empty quotes)\n let heredocEnd: string | null = null;\n const pendingHeredocs: { marker: string; strip: boolean }[] = [];\n\n const endWord = () => {\n if (has) tokens.push(cur);\n cur = \"\";\n has = false;\n };\n const endSeg = () => {\n endWord();\n if (tokens.length || redirects.length) segs.push({ tokens, redirects });\n tokens = [];\n redirects = [];\n };\n const readWord = (i: number): { word: string; next: number } => {\n while (i < cmd.length && (cmd[i] === \" \" || cmd[i] === \"\\t\")) i++;\n let w = \"\";\n let q: string | null = null;\n while (i < cmd.length) {\n const c = cmd[i];\n if (q) {\n if (c === q) q = null;\n else w += c;\n } else if (c === \"'\" || c === '\"') q = c;\n else if (/[\\s;&|<>()]/.test(c)) break;\n else w += c;\n i++;\n }\n return { word: w, next: i };\n };\n\n let i = 0;\n let quote: string | null = null;\n while (i < cmd.length) {\n const c = cmd[i];\n if (quote) {\n if (c === quote) quote = null;\n else if (c === \"\\\\\" && quote === '\"' && !WIN && i + 1 < cmd.length) {\n cur += cmd[++i];\n } else cur += c;\n i++;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n quote = c;\n has = true;\n i++;\n continue;\n }\n if (c === \"\\\\\" && !WIN && i + 1 < cmd.length) {\n cur += cmd[i + 1];\n has = true;\n i += 2;\n continue;\n }\n if (c === \"\\n\") {\n endSeg();\n i++;\n // heredoc bodies are data, not commands\n if (pendingHeredocs.length) {\n for (const h of pendingHeredocs) {\n while (i < cmd.length) {\n let e = cmd.indexOf(\"\\n\", i);\n if (e < 0) e = cmd.length;\n const line = cmd.slice(i, e);\n i = Math.min(cmd.length, e + 1);\n if ((h.strip ? line.trim() : line.replace(/\\r$/, \"\")) === h.marker) break;\n }\n }\n pendingHeredocs.length = 0;\n }\n continue;\n }\n if (c === \";\" || c === \"|\" || c === \"&\") {\n // \"2>&1\" / \">&2\" are handled in the '>' branch, so a bare & here is a separator\n if ((c === \"&\" || c === \"|\") && cmd[i + 1] === c) i++;\n endSeg();\n i++;\n continue;\n }\n if (c === \"(\" || c === \")\") {\n endSeg();\n i++;\n continue;\n }\n if (c === \"<\") {\n if (cmd[i + 1] === \"<\" && cmd[i + 2] !== \"<\") {\n let j = i + 2;\n let strip = false;\n if (cmd[j] === \"-\") {\n strip = true;\n j++;\n }\n const { word, next } = readWord(j);\n if (word) pendingHeredocs.push({ marker: word, strip });\n i = next;\n } else {\n const { next } = readWord(i + (cmd[i + 1] === \"<\" ? 3 : 1));\n i = next;\n }\n continue;\n }\n if (c === \">\") {\n // fd prefix like 2> / 1>\n let fd = \"\";\n if (has && /^\\d+$/.test(cur)) {\n fd = cur;\n cur = \"\";\n has = false;\n } else endWord();\n let j = i + 1;\n if (cmd[j] === \">\") j++;\n if (cmd[j] === \"&\") {\n const r = readWord(j + 1);\n i = r.next;\n continue;\n }\n const r = readWord(j);\n i = r.next;\n if (fd !== \"2\" && r.word) redirects.push(r.word);\n continue;\n }\n if (c === \" \" || c === \"\\t\" || c === \"\\r\") {\n endWord();\n i++;\n continue;\n }\n cur += c;\n has = true;\n i++;\n }\n endSeg();\n void heredocEnd;\n return segs;\n}\n\nconst base = (s: string) =>\n path\n .basename(s.replace(/\\\\/g, \"/\"))\n .toLowerCase()\n .replace(/\\.(exe|cmd|bat|ps1|com)$/, \"\");\n\ninterface InstallInfo {\n mgr: string;\n uninstall: boolean;\n pkgs: string[];\n explicit: boolean; // pkgs list is complete (not \"install from package.json / requirements\")\n global: boolean;\n}\ninterface Finding {\n cat: Cat;\n targets?: string[]; // delete targets (raw tokens)\n dynamic?: boolean; // targets can't be known from the text\n install?: InstallInfo;\n}\n\nconst NPM_INST: Record<string, { inst: string[]; un: string[] }> = {\n npm: { inst: [\"install\", \"i\", \"in\", \"ins\", \"inst\", \"add\", \"ci\", \"update\", \"up\", \"upgrade\", \"link\", \"ln\", \"rebuild\", \"dedupe\"], un: [\"uninstall\", \"remove\", \"rm\", \"r\", \"un\", \"unlink\"] },\n cnpm: { inst: [\"install\", \"i\", \"add\", \"update\"], un: [\"uninstall\", \"remove\", \"rm\"] },\n pnpm: { inst: [\"add\", \"install\", \"i\", \"update\", \"up\", \"upgrade\", \"link\", \"ln\", \"import\", \"dlx\"], un: [\"remove\", \"rm\", \"uninstall\", \"un\", \"unlink\"] },\n yarn: { inst: [\"add\", \"install\", \"upgrade\", \"up\", \"global\", \"dlx\", \"link\", \"\"], un: [\"remove\"] },\n bun: { inst: [\"add\", \"install\", \"i\", \"update\", \"link\", \"x\"], un: [\"remove\", \"rm\", \"unlink\"] },\n};\nconst SYS_PM = new Set([\"apt\", \"apt-get\", \"aptitude\", \"dnf\", \"yum\", \"zypper\", \"pacman\", \"apk\", \"brew\", \"choco\", \"winget\", \"scoop\", \"snap\", \"flatpak\", \"nix-env\", \"port\", \"pkg\", \"emerge\", \"xbps-install\"]);\nconst SYS_INST = new Set([\"install\", \"add\", \"upgrade\", \"dist-upgrade\", \"full-upgrade\", \"reinstall\", \"update-all\"]);\nconst SYS_UN = new Set([\"remove\", \"uninstall\", \"purge\", \"autoremove\", \"del\", \"erase\"]);\nconst PIP_VALUE_FLAGS = new Set([\"-r\", \"--requirement\", \"-e\", \"--editable\", \"-c\", \"--constraint\", \"-i\", \"--index-url\", \"--extra-index-url\", \"-t\", \"--target\", \"--prefix\", \"-f\", \"--find-links\", \"--python\", \"--root\", \"--src\", \"--cache-dir\", \"--proxy\"]);\n\nfunction pkgArgs(args: string[], valueFlags: Set<string>): { pkgs: string[]; explicit: boolean } {\n const pkgs: string[] = [];\n let explicit = true;\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a.startsWith(\"-\")) {\n if (a === \"-r\" || a === \"--requirement\" || a === \"-e\" || a === \"--editable\" || a === \"-c\" || a === \"--constraint\") explicit = false;\n if (valueFlags.has(a)) i++;\n continue;\n }\n pkgs.push(a);\n }\n return { pkgs, explicit };\n}\n\nfunction installInfo(name: string, args: string[]): InstallInfo | null {\n const global = args.some((a) => a === \"-g\" || a === \"--global\" || a === \"global\");\n const subIdx = args.findIndex((a) => !a.startsWith(\"-\"));\n const sub = subIdx >= 0 ? args[subIdx].toLowerCase() : \"\";\n const after = subIdx >= 0 ? args.slice(subIdx + 1) : [];\n\n if (NPM_INST[name]) {\n const t = NPM_INST[name];\n const un = t.un.includes(sub);\n if (!un && !t.inst.includes(sub)) return null;\n if (name === \"yarn\" && sub === \"\" && args.length > 0 && !args.every((a) => a.startsWith(\"-\"))) return null;\n const p = pkgArgs(after.filter((a) => a !== \"global\"), new Set([\"--prefix\", \"--registry\", \"-w\", \"--workspace\", \"--cwd\"]));\n const noPkgsMeansAll = !un && p.pkgs.length === 0;\n return { mgr: name, uninstall: un, pkgs: p.pkgs, explicit: !noPkgsMeansAll && p.explicit, global };\n }\n if (name === \"npx\" || name === \"pnpx\" || name === \"bunx\") {\n const p = args.filter((a) => !a.startsWith(\"-\"))[0];\n return { mgr: \"npm\", uninstall: false, pkgs: p ? [p] : [], explicit: !!p, global: false };\n }\n if (name === \"pip\" || name === \"pip3\" || name === \"pipx\" || name === \"pip3.11\" || name === \"pip3.12\") {\n const un = sub === \"uninstall\";\n const inst = sub === \"install\" || sub === \"download\" || (name === \"pipx\" && (sub === \"run\" || sub === \"inject\" || sub === \"upgrade\"));\n if (!un && !inst) return null;\n const p = pkgArgs(after, PIP_VALUE_FLAGS);\n return { mgr: \"pip\", uninstall: un, pkgs: p.pkgs, explicit: p.explicit && p.pkgs.length > 0, global: false };\n }\n if (/^python(\\d(\\.\\d+)?)?$|^py$/.test(name)) {\n const m = args.indexOf(\"-m\");\n if (m >= 0 && args[m + 1] === \"pip\") return installInfo(\"pip\", args.slice(m + 2));\n return null;\n }\n if (name === \"uv\") {\n if (sub === \"pip\") return installInfo(\"pip\", after);\n if (sub === \"add\") return { mgr: \"pip\", uninstall: false, ...(() => { const p = pkgArgs(after, new Set()); return { pkgs: p.pkgs, explicit: p.explicit && p.pkgs.length > 0 }; })(), global: false };\n if (sub === \"remove\") return { mgr: \"pip\", uninstall: true, pkgs: after.filter((a) => !a.startsWith(\"-\")), explicit: false, global: false };\n if (sub === \"sync\" || sub === \"lock\") return { mgr: \"pip\", uninstall: false, pkgs: [], explicit: false, global: false };\n if (sub === \"tool\") {\n const s2 = after.find((a) => !a.startsWith(\"-\"));\n if (s2 === \"install\" || s2 === \"upgrade\") return { mgr: \"pip\", uninstall: false, pkgs: [], explicit: false, global: true };\n if (s2 === \"uninstall\") return { mgr: \"pip\", uninstall: true, pkgs: [], explicit: false, global: true };\n }\n return null;\n }\n if (name === \"uvx\") return { mgr: \"pip\", uninstall: false, pkgs: [], explicit: false, global: false };\n if (name === \"poetry\" || name === \"pdm\" || name === \"pipenv\") {\n if ([\"add\", \"install\", \"update\", \"sync\"].includes(sub)) return { mgr: \"pip\", uninstall: false, pkgs: [], explicit: false, global: false };\n if (sub === \"remove\") return { mgr: \"pip\", uninstall: true, pkgs: [], explicit: false, global: false };\n return null;\n }\n if (name === \"conda\" || name === \"mamba\" || name === \"micromamba\") {\n if ([\"install\", \"update\", \"upgrade\"].includes(sub)) return { mgr: name, uninstall: false, pkgs: [], explicit: false, global: false };\n if ([\"remove\", \"uninstall\"].includes(sub)) return { mgr: name, uninstall: true, pkgs: [], explicit: false, global: false };\n return null;\n }\n if (SYS_PM.has(name)) {\n const first = args[0] || \"\";\n if (name === \"pacman\") {\n if (/^-S/.test(first) && !/^-Ss|^-Si|^-Sq/.test(first)) return { mgr: name, uninstall: false, pkgs: [], explicit: false, global: true };\n if (/^-R/.test(first)) return { mgr: name, uninstall: true, pkgs: [], explicit: false, global: true };\n return null;\n }\n if (SYS_INST.has(sub)) return { mgr: name, uninstall: false, pkgs: after.filter((a) => !a.startsWith(\"-\")), explicit: false, global: true };\n if (SYS_UN.has(sub)) return { mgr: name, uninstall: true, pkgs: after.filter((a) => !a.startsWith(\"-\")), explicit: false, global: true };\n return null;\n }\n if (name === \"cargo\") {\n if (sub === \"install\" || sub === \"add\") return { mgr: name, uninstall: false, pkgs: [], explicit: false, global: sub === \"install\" };\n if (sub === \"uninstall\" || sub === \"remove\") return { mgr: name, uninstall: true, pkgs: [], explicit: false, global: sub === \"uninstall\" };\n return null;\n }\n if (name === \"go\" && (sub === \"install\" || sub === \"get\")) return { mgr: name, uninstall: false, pkgs: [], explicit: false, global: false };\n if (name === \"gem\" || name === \"bundle\" || name === \"composer\" || name === \"dotnet\" || name === \"pecl\") {\n if ([\"install\", \"add\", \"require\", \"update\"].includes(sub) || (name === \"dotnet\" && sub === \"tool\")) return { mgr: name, uninstall: false, pkgs: [], explicit: false, global: false };\n if ([\"uninstall\", \"remove\"].includes(sub)) return { mgr: name, uninstall: true, pkgs: [], explicit: false, global: false };\n return null;\n }\n if (/^install-(module|package|script|packageprovider)$/.test(name)) return { mgr: \"ps\", uninstall: false, pkgs: [], explicit: false, global: true };\n if (/^uninstall-(module|package|script)$/.test(name)) return { mgr: \"ps\", uninstall: true, pkgs: [], explicit: false, global: true };\n return null;\n}\n\nconst NULL_TARGETS = /^(\\/dev\\/(null|stdout|stderr|tty|fd\\/\\d+)|nul|\\$null|&\\d+)$/i;\nconst WRAPPERS = new Set([\"sudo\", \"doas\", \"time\", \"nohup\", \"command\", \"exec\", \"nice\", \"ionice\", \"stdbuf\", \"env\", \"builtin\"]);\nconst SHELLS = new Set([\"bash\", \"sh\", \"zsh\", \"dash\", \"ksh\", \"fish\"]);\n\nfunction classify(cmd: string, cwd: string, depth = 0): Finding[] {\n const out: Finding[] = [];\n if (depth > 3 || !cmd.trim()) return out;\n\n // command substitutions are commands too\n for (const m of cmd.matchAll(/\\$\\(([^()]*)\\)/g)) out.push(...classify(m[1], cwd, depth + 1));\n for (const m of cmd.matchAll(/`([^`]*)`/g)) out.push(...classify(m[1], cwd, depth + 1));\n\n for (const seg of splitCommand(cmd)) {\n let t = seg.tokens.slice();\n let viaXargs = false;\n while (t.length) {\n if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0])) {\n t.shift();\n continue;\n }\n const n = base(t[0]);\n if (WRAPPERS.has(n)) {\n t.shift();\n while (t.length && (t[0].startsWith(\"-\") || /^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0]))) t.shift();\n continue;\n }\n if (n === \"xargs\") {\n viaXargs = true;\n t.shift();\n while (t.length && t[0].startsWith(\"-\")) t.shift();\n continue;\n }\n break;\n }\n\n if (t.length) {\n const name = base(t[0]);\n const args = t.slice(1);\n const nonFlag = args.filter((a) => !a.startsWith(\"-\"));\n const sub = (nonFlag[0] || \"\").toLowerCase();\n const has = (re: RegExp) => args.some((a) => re.test(a));\n\n // ---- nested shells ----\n if (SHELLS.has(name)) {\n const i = args.findIndex((a) => /^-[a-z]*c$/.test(a));\n if (i >= 0 && args[i + 1]) out.push(...classify(args[i + 1], cwd, depth + 1));\n } else if (name === \"powershell\" || name === \"pwsh\") {\n const i = args.findIndex((a) => /^-(c|command)$/i.test(a));\n if (i >= 0) out.push(...classify(args.slice(i + 1).join(\" \"), cwd, depth + 1));\n } else if (name === \"cmd\") {\n const i = args.findIndex((a) => /^\\/(c|k)$/i.test(a));\n if (i >= 0) out.push(...classify(args.slice(i + 1).join(\" \"), cwd, depth + 1));\n }\n\n // ---- delete ----\n const flagLikeWin = (a: string) => WIN && /^\\/[a-z?]$/i.test(a);\n if ([\"rm\", \"rmdir\", \"del\", \"erase\", \"rd\", \"unlink\", \"shred\", \"trash\", \"trash-put\", \"remove-item\", \"ri\"].includes(name)) {\n const targets: string[] = [];\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (/^-(path|literalpath)$/i.test(a)) {\n if (args[i + 1]) targets.push(args[++i]);\n continue;\n }\n if (a.startsWith(\"-\") || flagLikeWin(a)) continue;\n targets.push(a);\n }\n out.push({ cat: \"delete\", targets, dynamic: viaXargs || targets.length === 0 });\n } else if (name === \"git\" && sub === \"clean\") {\n out.push({ cat: \"delete\", dynamic: true });\n } else if (name === \"git\" && sub === \"rm\") {\n out.push({ cat: \"delete\", targets: nonFlag.slice(1), dynamic: nonFlag.length < 2 });\n } else if (name === \"find\" && (args.includes(\"-delete\") || (args.includes(\"-exec\") && /(^|\\/)(rm|rmdir)$/.test(args[args.indexOf(\"-exec\") + 1] || \"\")))) {\n out.push({ cat: \"delete\", dynamic: true });\n }\n\n // ---- move / rename ----\n if ([\"mv\", \"move\", \"ren\", \"rename\", \"move-item\", \"mi\", \"rename-item\", \"rni\"].includes(name) || (name === \"git\" && sub === \"mv\")) {\n out.push({ cat: \"move\" });\n }\n\n // ---- archive ----\n if ([\"zip\", \"unzip\", \"tar\", \"7z\", \"7za\", \"7zr\", \"7zz\", \"gzip\", \"gunzip\", \"bzip2\", \"bunzip2\", \"xz\", \"unxz\", \"zstd\", \"unzstd\", \"rar\", \"unrar\", \"compress-archive\", \"expand-archive\"].includes(name)) {\n out.push({ cat: \"archive\" });\n } else if (/^python(\\d(\\.\\d+)?)?$|^py$/.test(name) && args[0] === \"-m\" && (args[1] === \"zipfile\" || args[1] === \"tarfile\")) {\n out.push({ cat: \"archive\" });\n }\n\n // ---- install / uninstall ----\n const inst = installInfo(name, args);\n if (inst) out.push({ cat: \"install\", install: inst });\n\n // ---- create ----\n if ([\"mkdir\", \"md\", \"touch\", \"new-item\", \"ni\", \"mkfifo\", \"cp\", \"copy\", \"copy-item\", \"cpi\", \"xcopy\", \"robocopy\", \"ln\", \"fallocate\", \"virtualenv\"].includes(name)) {\n out.push({ cat: \"create\" });\n } else if (name === \"git\" && (sub === \"clone\" || sub === \"init\" || sub === \"worktree\")) {\n out.push({ cat: \"create\" });\n } else if (name === \"curl\" && has(/^(-[a-zA-Z]*[oOJ][a-zA-Z]*|--output|--remote-name|--create-dirs)$/)) {\n out.push({ cat: \"create\" });\n } else if (name === \"wget\" && !(args.includes(\"-O-\") || args.some((a, i) => a === \"-O\" && args[i + 1] === \"-\") || has(/^-\\w*O-$/))) {\n out.push({ cat: \"create\" });\n } else if (name === \"dd\" && has(/^of=/)) {\n out.push({ cat: \"create\" });\n } else if (name === \"cargo\" && (sub === \"new\" || sub === \"init\")) {\n out.push({ cat: \"create\" });\n } else if (name === \"dotnet\" && sub === \"new\") {\n out.push({ cat: \"create\" });\n } else if ((name === \"npm\" || name === \"pnpm\" || name === \"yarn\" || name === \"bun\") && (sub === \"init\" || sub === \"create\")) {\n out.push({ cat: \"create\" });\n } else if (name === \"uv\" && (sub === \"venv\" || sub === \"init\")) {\n out.push({ cat: \"create\" });\n } else if (/^python(\\d(\\.\\d+)?)?$|^py$/.test(name) && args[0] === \"-m\" && args[1] === \"venv\") {\n out.push({ cat: \"create\" });\n } else if (name === \"tee\") {\n for (const f of nonFlag) pushWriteTarget(out, f, cwd);\n }\n\n // ---- edit ----\n if (name === \"sed\" && has(/^(-[a-zA-Z]*i[a-zA-Z.]*|--in-place(=.*)?)$/)) out.push({ cat: \"edit\" });\n else if (name === \"perl\" && has(/^-[a-zA-Z]*i[a-zA-Z.]*$/)) out.push({ cat: \"edit\" });\n else if (name === \"awk\" && args.some((a, i) => a === \"-i\" && /inplace/.test(args[i + 1] || \"\"))) out.push({ cat: \"edit\" });\n else if ([\"set-content\", \"sc\", \"add-content\", \"ac\", \"out-file\", \"clear-content\", \"patch\", \"sponge\", \"dos2unix\", \"unix2dos\", \"truncate\"].includes(name)) out.push({ cat: \"edit\" });\n else if (name === \"git\" && [\"apply\", \"am\", \"restore\"].includes(sub)) out.push({ cat: \"edit\" });\n else if (name === \"git\" && sub === \"reset\" && args.includes(\"--hard\")) out.push({ cat: \"edit\" });\n }\n\n for (const r of seg.redirects) pushWriteTarget(out, r, cwd);\n }\n return out;\n}\n\nfunction pushWriteTarget(out: Finding[], target: string, cwd: string) {\n if (!target || NULL_TARGETS.test(target)) return;\n if (/[$`]/.test(target)) {\n out.push({ cat: \"edit\" });\n return;\n }\n const abs = resolveToken(target, cwd);\n out.push({ cat: fs.existsSync(abs) ? \"edit\" : \"create\" });\n}\n\nfunction resolveToken(tok: string, cwd: string): string {\n let t = tok;\n if (t === \"~\" || t.startsWith(\"~/\") || t.startsWith(\"~\\\\\")) t = path.join(os.homedir(), t.slice(1));\n return path.resolve(cwd, t);\n}\n\n// ===========================================================================\n// Sizes\n// ===========================================================================\ninterface SizeResult {\n bytes: number;\n exists: boolean;\n complete: boolean;\n}\n\nasync function sizeOf(p: string, budget = { n: 300000 }): Promise<SizeResult> {\n let st: fs.Stats;\n try {\n st = await fs.promises.lstat(p);\n } catch {\n return { bytes: 0, exists: false, complete: true };\n }\n if (!st.isDirectory()) return { bytes: st.size, exists: true, complete: true };\n let bytes = 0;\n let complete = true;\n let entries: string[] = [];\n try {\n entries = await fs.promises.readdir(p);\n } catch {\n return { bytes: 0, exists: true, complete: false };\n }\n for (const e of entries) {\n if (--budget.n < 0) {\n complete = false;\n break;\n }\n const r = await sizeOf(path.join(p, e), budget);\n bytes += r.bytes;\n if (!r.complete) complete = false;\n }\n return { bytes, exists: true, complete };\n}\n\n/** Resolve delete targets (one-level globs supported). unknown=true when we can't tell. */\nasync function expandTargets(tokens: string[], cwd: string): Promise<{ paths: string[]; unknown: boolean }> {\n const paths: string[] = [];\n let unknown = false;\n for (const tok of tokens) {\n if (/[$`]/.test(tok)) {\n unknown = true;\n continue;\n }\n const abs = resolveToken(tok, cwd);\n const dir = path.dirname(abs);\n const leaf = path.basename(abs);\n if (/[*?[]/.test(dir)) {\n unknown = true;\n continue;\n }\n if (/[*?[]/.test(leaf)) {\n try {\n const re = new RegExp(\n \"^\" +\n leaf\n .replace(/[.+^${}()|\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\") +\n \"$\"\n );\n for (const f of await fs.promises.readdir(dir)) if (re.test(f) && !(f.startsWith(\".\") && !leaf.startsWith(\".\"))) paths.push(path.join(dir, f));\n } catch {\n unknown = true;\n }\n } else paths.push(abs);\n }\n return { paths, unknown };\n}\n\nasync function fetchJson(url: string, ms = 6000): Promise<any | null> {\n const ac = new AbortController();\n const t = setTimeout(() => ac.abort(), ms);\n try {\n const r = await fetch(url, { signal: ac.signal, headers: { accept: \"application/json\" } });\n if (!r.ok) return null;\n return await r.json();\n } catch {\n return null;\n } finally {\n clearTimeout(t);\n }\n}\n\n/** Lower-bound estimate (named packages only, not their dependencies). null = can't tell. */\nasync function estimateInstallBytes(info: InstallInfo): Promise<number | null> {\n if (!info.explicit || info.pkgs.length === 0) return null;\n let total = 0;\n for (const spec of info.pkgs) {\n if (/^(\\.|\\/|file:|git|http|github:|[a-z]:\\\\)/i.test(spec) || (spec.includes(\"/\") && !spec.startsWith(\"@\"))) return null;\n if (info.mgr === \"npm\" || NPM_INST[info.mgr]) {\n const m = spec.match(/^(@?[^@]+)(?:@(.+))?$/);\n if (!m) return null;\n const name = m[1];\n const ver = m[2] && /^\\d[\\w.\\-+]*$/.test(m[2]) ? m[2] : \"latest\";\n const j = await fetchJson(`https://registry.npmjs.org/${name.replace(\"/\", \"%2F\")}/${ver}`);\n const sz = j?.dist?.unpackedSize;\n if (typeof sz !== \"number\") return null;\n total += sz;\n } else if (info.mgr === \"pip\") {\n const m = spec.match(/^([A-Za-z0-9_.\\-]+)(?:\\[[^\\]]*\\])?(?:==([\\w.\\-+]+))?/);\n if (!m) return null;\n const j = await fetchJson(m[2] ? `https://pypi.org/pypi/${m[1]}/${m[2]}/json` : `https://pypi.org/pypi/${m[1]}/json`);\n const files: any[] = j?.urls || [];\n if (!files.length) return null;\n const wheels = files.filter((f) => f.packagetype === \"bdist_wheel\");\n const pool = wheels.length ? wheels : files;\n total += Math.min(...pool.map((f) => Number(f.size) || Infinity));\n } else return null;\n }\n return Number.isFinite(total) ? total : null;\n}\n\n// ===========================================================================\n// Approval queue\n// ===========================================================================\nexport interface PendingApproval {\n id: string;\n command: string;\n cwd: string;\n categories: string[];\n reasons: string[];\n createdAt: number;\n}\ninterface Decision {\n allow: boolean;\n remember: boolean;\n}\nconst pending = new Map<string, { info: PendingApproval; resolve: (d: Decision) => void }>();\nlet seq = 0;\nconst APPROVAL_TIMEOUT_MS = 10 * 60 * 1000;\n\nfunction requestApproval(info: Omit<PendingApproval, \"id\" | \"createdAt\">): Promise<Decision & { timedOut?: boolean }> {\n return new Promise((resolve) => {\n const id = `ap${(++seq).toString(36)}${Date.now().toString(36).slice(-4)}`;\n const timer = setTimeout(() => {\n pending.delete(id);\n resolve({ allow: false, remember: false, timedOut: true });\n }, APPROVAL_TIMEOUT_MS);\n pending.set(id, {\n info: { ...info, id, createdAt: Date.now() },\n resolve: (d) => {\n clearTimeout(timer);\n pending.delete(id);\n resolve(d);\n },\n });\n });\n}\n\n// ===========================================================================\n// Evaluate\n// ===========================================================================\nexport interface EvalResult {\n ok: boolean;\n message?: string;\n ulimitMb?: number;\n scanBytes?: number;\n}\n\nexport async function evaluatePermission(command: string, cwd: string, opts: { canUlimit: boolean }): Promise<EvalResult> {\n const cfg = getPerms();\n const findings = classify(command, cwd);\n const cats = new Set<Cat>(findings.map((f) => f.cat));\n\n for (const c of cats) {\n if (cfg.modes[c] === \"deny\") {\n return { ok: false, message: `Blocked by the user's permission settings: \"${LABEL[c]}\" is set to DENY. Don't retry this; use a different approach or tell the user.` };\n }\n }\n\n const askCats = new Set<Cat>([...cats].filter((c) => cfg.modes[c] === \"ask\"));\n const modeAsk = new Set(askCats); // categories that asked only because of the mode (eligible for \"remember\")\n const reasons: string[] = [];\n\n // ---- delete limit (files, folders, uninstalled libraries) ----\n const delLimit = limitBytes(cfg.limits.maxDeleteMB);\n if (delLimit) {\n let total = 0;\n for (const f of findings) {\n if (f.cat === \"delete\") {\n if (f.dynamic) {\n askCats.add(\"delete\");\n reasons.push(\"can't tell from the command how much will be deleted\");\n continue;\n }\n const { paths, unknown } = await expandTargets(f.targets || [], cwd);\n if (unknown) {\n askCats.add(\"delete\");\n reasons.push(\"some delete targets can't be resolved (variables / complex globs)\");\n }\n for (const p of paths) {\n const s = await sizeOf(p);\n total += s.bytes;\n if (!s.complete) {\n askCats.add(\"delete\");\n reasons.push(`${path.basename(p)} is too large to measure fully`);\n }\n }\n } else if (f.cat === \"install\" && f.install?.uninstall) {\n const i = f.install;\n if (i.global || !(NPM_INST[i.mgr] || i.mgr === \"npm\") || i.pkgs.length === 0) {\n askCats.add(\"install\");\n reasons.push(\"can't measure how much the uninstall removes\");\n } else {\n for (const p of i.pkgs) {\n const s = await sizeOf(path.join(cwd, \"node_modules\", p.replace(/@[^/]+$/, \"\")));\n total += s.bytes;\n }\n }\n }\n }\n if (total > delLimit) {\n return { ok: false, message: `Blocked: this would delete about ${fmt(total)}, over the user's limit of ${cfg.limits.maxDeleteMB} MB. Don't retry; tell the user.` };\n }\n }\n\n // ---- install limit ----\n const insLimit = limitBytes(cfg.limits.maxInstallMB);\n if (insLimit) {\n let total = 0;\n let unknown = false;\n let any = false;\n for (const f of findings) {\n if (f.cat === \"install\" && f.install && !f.install.uninstall) {\n any = true;\n const b = await estimateInstallBytes(f.install);\n if (b == null) unknown = true;\n else total += b;\n }\n }\n if (any && total > insLimit) {\n return { ok: false, message: `Blocked: the named packages alone are about ${fmt(total)}, over the user's install limit of ${cfg.limits.maxInstallMB} MB. Don't retry; tell the user.` };\n }\n if (any && unknown) {\n askCats.add(\"install\");\n reasons.push(\"install size can't be verified beforehand\");\n }\n }\n\n // ---- ask the user ----\n if (askCats.size > 0) {\n const d = await requestApproval({ command, cwd, categories: [...askCats].map((c) => LABEL[c]), reasons: [...new Set(reasons)] });\n if (!d.allow) {\n return {\n ok: false,\n message: d.timedOut\n ? \"The user did not answer the permission prompt in time, so the command was NOT run. Ask them first, then retry.\"\n : \"The user denied this command. Don't retry it; tell the user what you wanted to do or choose another approach.\",\n };\n }\n if (d.remember) {\n const next = getPerms();\n for (const c of modeAsk) next.modes[c] = \"allow\";\n setPerms(next);\n }\n }\n\n // ---- create-size limit ----\n const crLimit = limitBytes(cfg.limits.maxCreateMB);\n if (crLimit && !cats.has(\"install\")) {\n return opts.canUlimit ? { ok: true, ulimitMb: crLimit / 1024 / 1024 } : { ok: true, scanBytes: crLimit };\n }\n return { ok: true };\n}\n\n// Windows (no ulimit): remove files created during the run that exceed the limit.\nconst SKIP_DIRS = new Set([\"node_modules\", \".git\", \".venv\", \"venv\", \"__pycache__\", \"dist\", \"build\", \".next\", \"target\"]);\nexport async function removeOversizeNewFiles(root: string, sinceMs: number, limit: number): Promise<string[]> {\n const removed: string[] = [];\n let visits = 0;\n async function walk(dir: string) {\n let ents: fs.Dirent[] = [];\n try {\n ents = await fs.promises.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of ents) {\n if (++visits > 60000) return;\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (!SKIP_DIRS.has(e.name)) await walk(full);\n } else if (e.isFile()) {\n try {\n const st = await fs.promises.stat(full);\n if (st.size > limit && st.birthtimeMs >= sinceMs - 1000) {\n await fs.promises.rm(full, { force: true });\n removed.push(`${path.relative(root, full)} (${fmt(st.size)})`);\n }\n } catch {}\n }\n }\n }\n await walk(root);\n return removed;\n}\n\n// ===========================================================================\n// Routes\n// ===========================================================================\nexport function registerPermissionRoutes(app: Express, requireLocal: RequestHandler) {\n app.get(\"/api/permissions\", requireLocal, (_req, res) => res.json(getPerms()));\n app.post(\"/api/permissions\", requireLocal, (req, res) => res.json(setPerms(req.body)));\n app.get(\"/api/permissions/pending\", requireLocal, (_req, res) => res.json({ pending: [...pending.values()].map((p) => p.info) }));\n app.post(\"/api/permissions/decide\", requireLocal, (req, res) => {\n const { id, allow, remember } = req.body || {};\n const p = pending.get(String(id));\n if (!p) return res.status(404).json({ error: \"No such pending request (maybe it already timed out)\" });\n p.resolve({ allow: !!allow, remember: !!remember && !!allow });\n return res.json({ ok: true });\n });\n}\n\n// exported for tests\nexport const __test = { classify, splitCommand };\n", "// ============================================================================\n// localSearch.ts \u2014 search helpers tuned for running on the user's OWN machine.\n//\n// Why localhost helps: requests leave from a normal home/office IP instead of a\n// datacenter IP, so Bing / Mojeek rarely show CAPTCHAs, and\n// language / region come from this PC. What we add on top of the raw engines:\n// * hard per-engine timeouts (one hanging engine can't stall the tool)\n// * health tracking: an engine that keeps failing is skipped for a few minutes\n// * short result cache (same query within 10 min = instant)\n// * reciprocal-rank fusion (a URL found by several engines ranks higher)\n// * image search WITHOUT SearXNG: Bing images + Wikimedia\n// Commons + Openverse (open APIs) as a safety net. SearXNG stays optional.\n// ============================================================================\n\nexport interface WebHit {\n url: string;\n title: string;\n snippet: string;\n engine: string;\n}\n\nexport interface ImageHit {\n title: string;\n src: string;\n thumb: string;\n page: string;\n engine: string;\n}\n\nconst UA =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\";\n\n// ---- locale taken from this machine (override: SEARCH_LANG=vi-VN) -----------\nfunction detectLocale(): string {\n const env = process.env.SEARCH_LANG;\n if (env) return env;\n try {\n return Intl.DateTimeFormat().resolvedOptions().locale || \"en-US\";\n } catch {\n return \"en-US\";\n }\n}\nexport const LOCALE = detectLocale(); // e.g. \"vi-VN\"\nconst LANG = LOCALE.split(\"-\")[0] || \"en\";\nconst REGION = (LOCALE.split(\"-\")[1] || \"US\").toUpperCase();\nexport const ACCEPT_LANGUAGE = `${LOCALE},${LANG};q=0.9,en;q=0.8`;\n\n// ---- small utils --------------------------------------------------------------\nexport function decodeEntities(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/�?39;|'/g, \"'\")\n .replace(/ /g, \" \")\n .replace(/&#x([0-9a-f]+);/gi, (_m, h) => String.fromCodePoint(parseInt(h, 16)))\n .replace(/&#(\\d+);/g, (_m, d) => String.fromCodePoint(parseInt(d, 10)));\n}\nfunction stripTags(s: string): string {\n return decodeEntities(s.replace(/<[^>]*>/g, \" \")).replace(/\\s+/g, \" \").trim();\n}\n\nasync function getText(url: string, ms: number, headers: Record<string, string> = {}): Promise<string> {\n const resp = await fetch(url, {\n headers: { \"User-Agent\": UA, \"Accept-Language\": ACCEPT_LANGUAGE, ...headers },\n signal: AbortSignal.timeout(ms),\n });\n if (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n return await resp.text();\n}\n\nasync function getJson(url: string, ms: number, headers: Record<string, string> = {}): Promise<any> {\n const resp = await fetch(url, {\n headers: { \"User-Agent\": UA, Accept: \"application/json\", \"Accept-Language\": ACCEPT_LANGUAGE, ...headers },\n signal: AbortSignal.timeout(ms),\n });\n if (!resp.ok) throw new Error(`HTTP ${resp.status}`);\n return await resp.json();\n}\n\n// ---- engine health (circuit breaker) --------------------------------------------\ninterface Health {\n fails: number;\n until: number;\n lastError?: string;\n}\nconst health = new Map<string, Health>();\n\nexport function engineStatus(): Record<string, { ok: boolean; fails: number; retryInSec: number; lastError?: string }> {\n const out: Record<string, any> = {};\n const now = Date.now();\n for (const [k, h] of health) out[k] = { ok: h.until <= now, fails: h.fails, retryInSec: Math.max(0, Math.round((h.until - now) / 1000)), lastError: h.lastError };\n return out;\n}\n\n/** Run one engine with timeout + health tracking. Never throws. */\nexport async function runEngine<T>(name: string, fn: () => Promise<T[]>, timeoutMs = 5000): Promise<T[]> {\n const h = health.get(name);\n if (h && h.until > Date.now()) return [];\n try {\n const res = await Promise.race([\n fn(),\n new Promise<T[]>((_r, rej) => setTimeout(() => rej(new Error(`timeout ${timeoutMs}ms`)), timeoutMs).unref?.()),\n ]);\n if (res.length === 0) {\n // 0 results is suspicious (captcha page) but can also be a rare query: soft penalty only\n const cur = health.get(name) || { fails: 0, until: 0 };\n cur.fails += 0.5;\n if (cur.fails >= 3) cur.until = Date.now() + 2 * 60 * 1000;\n health.set(name, cur);\n } else {\n health.delete(name);\n }\n return res;\n } catch (e: any) {\n const cur = health.get(name) || { fails: 0, until: 0 };\n cur.fails += 1;\n cur.lastError = e?.message || String(e);\n if (cur.fails >= 2) cur.until = Date.now() + Math.min(30, 2 ** (cur.fails - 1)) * 60 * 1000; // 2,4,8..30 min\n health.set(name, cur);\n return [];\n }\n}\n\n// ---- tiny TTL cache ---------------------------------------------------------------\nconst cache = new Map<string, { exp: number; value: any }>();\nexport async function cached<T>(key: string, ttlMs: number, fn: () => Promise<T>, shouldCache: (v: T) => boolean = () => true): Promise<T> {\n const hit = cache.get(key);\n if (hit && hit.exp > Date.now()) return hit.value as T;\n const value = await fn();\n if (shouldCache(value)) {\n cache.set(key, { exp: Date.now() + ttlMs, value });\n if (cache.size > 300) cache.delete(cache.keys().next().value as string);\n }\n return value;\n}\n\n// ---- reciprocal rank fusion -----------------------------------------------------------\nfunction dedupeKey(url: string): string {\n try {\n const u = new URL(url);\n return (u.hostname.replace(/^www\\./, \"\") + u.pathname.replace(/\\/$/, \"\")).toLowerCase();\n } catch {\n return url.toLowerCase();\n }\n}\n\n/** A page returned by several engines scores higher; ties keep the better single rank. */\nexport function fuseResults(lists: WebHit[][]): WebHit[] {\n const K = 60;\n const map = new Map<string, { hit: WebHit; score: number }>();\n for (const list of lists) {\n list.forEach((hit, i) => {\n const key = dedupeKey(hit.url);\n const add = 1 / (K + i + 1);\n const cur = map.get(key);\n if (cur) {\n cur.score += add;\n if ((hit.snippet || \"\").length > (cur.hit.snippet || \"\").length) cur.hit = { ...cur.hit, snippet: hit.snippet };\n cur.hit.engine += `+${hit.engine}`;\n } else map.set(key, { hit: { ...hit }, score: add });\n });\n }\n return [...map.values()].sort((a, b) => b.score - a.score).map((x) => x.hit);\n}\n\n// ===========================================================================\n// Web engines (new ones; Bing/DDG/Yahoo already live in server.ts)\n// ===========================================================================\n\n/** Mojeek: independent index, plain HTML, very tolerant of scraping. */\nexport async function searchMojeek(query: string, count: number): Promise<WebHit[]> {\n const html = await getText(`https://www.mojeek.com/search?q=${encodeURIComponent(query.trim())}&lb=${LANG}`, 5000);\n const out: WebHit[] = [];\n const re = /<li[^>]*>\\s*<h2>\\s*<a[^>]+href=\"(https?:\\/\\/[^\"]+)\"[^>]*class=\"title\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<\\/li>/gi;\n const re2 = /<a[^>]+class=\"title\"[^>]+href=\"(https?:\\/\\/[^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>([\\s\\S]*?)(?=<a[^>]+class=\"title\"|<\\/ul>)/gi;\n let m: RegExpExecArray | null;\n while ((m = re2.exec(html)) !== null && out.length < count * 2) {\n const title = stripTags(m[2]);\n const sn = m[3].match(/<p[^>]*class=\"s\"[^>]*>([\\s\\S]*?)<\\/p>/i);\n const snippet = sn ? stripTags(sn[1]) : title;\n if (title) out.push({ url: decodeEntities(m[1]), title, snippet, engine: \"mojeek\" });\n }\n void re;\n return out;\n}\n\n/** Bing with this machine's language/region (the existing Bing engine is hard-wired to en-US). */\nexport async function searchBingLocal(query: string, count: number): Promise<WebHit[]> {\n const html = await getText(\n `https://www.bing.com/search?q=${encodeURIComponent(query.trim())}&count=${Math.min(30, count * 3)}&setlang=${encodeURIComponent(LOCALE)}&cc=${REGION}`,\n 5000\n );\n if (/captcha|unusual traffic|verify you are a human|\\/ck\\/a\\?!&&p=.*challenge/i.test(html) && !/class=\"b_algo\"/.test(html)) throw new Error(\"bing captcha\");\n const out: WebHit[] = [];\n const re = /<li class=\"b_algo\"[^>]*>[\\s\\S]*?<h2[^>]*>[\\s\\S]*?<a href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>[\\s\\S]*?<\\/h2>([\\s\\S]*?)<\\/li>/gi;\n let m: RegExpExecArray | null;\n while ((m = re.exec(html)) !== null && out.length < count * 2) {\n const url = decodeEntities(m[1]);\n if (!url.startsWith(\"http\")) continue;\n const title = stripTags(m[2]);\n const p = m[3].match(/<p[^>]*>([\\s\\S]*?)<\\/p>/i) || m[3].match(/<div class=\"b_caption\"[^>]*>([\\s\\S]*?)<\\/div>/i);\n out.push({ url, title, snippet: p ? stripTags(p[1]) : title, engine: \"bing\" });\n }\n return out;\n}\n\n\n/** Wikipedia (official open API, no key). Great for facts; the AI's own language first, then English. */\nexport async function searchWikipedia(query: string, count: number): Promise<WebHit[]> {\n const langs = LANG === \"en\" ? [\"en\"] : [LANG, \"en\"];\n const lists = await Promise.all(\n langs.map(async (lg) => {\n try {\n const j = await getJson(\n `https://${lg}.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query.trim())}&srlimit=${Math.min(5, count)}&format=json&utf8=1`,\n 4000\n );\n return ((j?.query?.search || []) as any[]).map((r) => ({\n url: `https://${lg}.wikipedia.org/wiki/${encodeURIComponent(String(r.title).replace(/ /g, \"_\"))}`,\n title: String(r.title),\n snippet: stripTags(String(r.snippet || r.title)),\n engine: \"wikipedia\",\n })) as WebHit[];\n } catch {\n return [] as WebHit[];\n }\n })\n );\n return lists.flat().slice(0, count);\n}\n\n/**\n * Run engines in parallel but DON'T wait for the slowest: resolve as soon as `enough(results)` is true\n * (plus a short grace so a fast second engine can still contribute), or at `deadlineMs`.\n */\nexport async function raceUntilEnough<T>(\n tasks: Promise<T[]>[],\n enough: (collected: T[][]) => boolean,\n deadlineMs = 4500,\n graceMs = 350\n): Promise<T[][]> {\n const collected: T[][] = tasks.map(() => []);\n return new Promise((resolve) => {\n let done = false;\n let graceTimer: NodeJS.Timeout | null = null;\n let pending = tasks.length;\n const finish = () => {\n if (done) return;\n done = true;\n clearTimeout(deadline);\n if (graceTimer) clearTimeout(graceTimer);\n resolve(collected.map((c) => c.slice()));\n };\n const deadline = setTimeout(finish, deadlineMs);\n tasks.forEach((t, i) => {\n t.then((r) => {\n collected[i] = r;\n })\n .catch(() => {})\n .finally(() => {\n pending--;\n if (pending === 0) return finish();\n if (!done && !graceTimer && enough(collected)) graceTimer = setTimeout(finish, graceMs);\n });\n });\n if (tasks.length === 0) finish();\n });\n}\n\n\n// ---- strict keyword match (used for low-diversity sources: Wikimedia / Openverse) ----------\nconst STOP = new Set([\"a\",\"an\",\"the\",\"of\",\"and\",\"or\",\"in\",\"on\",\"for\",\"to\",\"with\",\"image\",\"images\",\"photo\",\"photos\",\"picture\",\"pictures\",\"pic\",\"anh\",\"hinh\"]);\nfunction norm(s: string): string {\n return s.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").replace(/\\u0111/g, \"d\").replace(/\\u0110/g, \"D\").toLowerCase();\n}\n/** True only if EVERY meaningful query word appears as a whole word in `text` (so \"claude logo\" never matches \"Claude Monet\"). */\nexport function matchesAllKeywords(query: string, text: string): boolean {\n const toks = norm(query).split(/[^a-z0-9\\u0080-\\uffff]+/).filter((t) => t && !STOP.has(t));\n if (toks.length === 0) return false;\n const hay = norm(text);\n return toks.every((t) => {\n if (/[^\\x00-\\x7f]/.test(t)) return hay.includes(t); // CJK etc.\n return new RegExp(`(^|[^a-z0-9])${t.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}(s|es)?($|[^a-z0-9])`).test(hay);\n });\n}\n\n// ===========================================================================\n// Image engines\n// ===========================================================================\n\n/** SearXNG images (optional). */\nexport async function imagesSearxng(baseUrl: string, query: string, count: number): Promise<ImageHit[]> {\n if (!baseUrl) return [];\n const params = new URLSearchParams({ q: query.trim(), format: \"json\", categories: \"images\", pageno: \"1\" });\n const j = await getJson(`${baseUrl.replace(/\\/$/, \"\")}/search?${params}`, 4000);\n const out: ImageHit[] = [];\n for (const x of Array.isArray(j.results) ? j.results : []) {\n const src = String(x.img_src || \"\");\n if (!/^https?:\\/\\//i.test(src)) continue;\n out.push({ title: String(x.title || x.content || query), src, thumb: String(x.thumbnail_src || x.thumbnail || src), page: String(x.url || src), engine: \"searxng\" });\n if (out.length >= count * 2) break;\n }\n return out;\n}\n\n/** Bing Images (HTML fragment endpoint; each tile carries JSON in the m=\"\" attribute). */\nexport async function imagesBing(query: string, count: number): Promise<ImageHit[]> {\n const html = await getText(\n `https://www.bing.com/images/async?q=${encodeURIComponent(query.trim())}&first=0&count=${Math.min(35, count * 3)}&mmasync=1&setlang=${encodeURIComponent(LOCALE)}`,\n 6000\n );\n const out: ImageHit[] = [];\n const tagRe = /<a\\b[^>]*\\bclass=\"[^\"]*\\biusc\\b[^\"]*\"[^>]*>/gi;\n let t: RegExpExecArray | null;\n while ((t = tagRe.exec(html)) !== null && out.length < count * 2) {\n const mm = t[0].match(/\\bm=\"([^\"]*)\"/) || t[0].match(/\\bm='([^']*)'/);\n if (!mm) continue;\n try {\n const j = JSON.parse(decodeEntities(mm[1]));\n const src = String(j.murl || \"\");\n if (!/^https?:\\/\\//i.test(src)) continue;\n out.push({ title: decodeEntities(String(j.t || j.desc || query)).replace(/<[^>]*>/g, \"\"), src, thumb: String(j.turl || src), page: String(j.purl || src), engine: \"bing-img\" });\n } catch {}\n }\n return out;\n}\n\n/** Wikimedia Commons: free, no key, great for places / animals / history / science. */\nexport async function imagesWikimedia(query: string, count: number): Promise<ImageHit[]> {\n const params = new URLSearchParams({\n action: \"query\", format: \"json\", generator: \"search\", gsrnamespace: \"6\", gsrlimit: String(Math.min(20, count * 2)),\n gsrsearch: query.trim(), prop: \"imageinfo\", iiprop: \"url|mime\", iiurlwidth: \"480\", origin: \"*\",\n });\n const j = await getJson(`https://commons.wikimedia.org/w/api.php?${params}`, 5000);\n const pages: any[] = Object.values(j?.query?.pages || {});\n pages.sort((a, b) => (a.index || 0) - (b.index || 0));\n const out: ImageHit[] = [];\n for (const p of pages) {\n const ii = p.imageinfo?.[0];\n if (!ii || !/^image\\/(jpeg|png|webp|gif)$/.test(ii.mime || \"\")) continue;\n // Commons is narrow: only accept a file whose title contains ALL the keywords.\n if (!matchesAllKeywords(query, String(p.title || \"\").replace(/^File:/, \"\"))) continue;\n out.push({ title: String(p.title || query).replace(/^File:/, \"\"), src: ii.url, thumb: ii.thumburl || ii.url, page: ii.descriptionurl || ii.url, engine: \"wikimedia\" });\n }\n return out;\n}\n\n/** Openverse: Creative-Commons images, anonymous access (rate-limited per IP, fine as a fallback). */\nexport async function imagesOpenverse(query: string, count: number): Promise<ImageHit[]> {\n const j = await getJson(`https://api.openverse.org/v1/images/?q=${encodeURIComponent(query.trim())}&page_size=${Math.min(20, count * 2)}`, 6000);\n const out: ImageHit[] = [];\n for (const x of Array.isArray(j.results) ? j.results : []) {\n const src = String(x.url || \"\");\n if (!/^https?:\\/\\//i.test(src)) continue;\n // Same strictness: title + tags must contain ALL the keywords.\n const text = `${x.title || \"\"} ${(Array.isArray(x.tags) ? x.tags : []).map((t: any) => t?.name || \"\").join(\" \")}`;\n if (!matchesAllKeywords(query, text)) continue;\n out.push({ title: String(x.title || query), src, thumb: String(x.thumbnail || src), page: String(x.foreign_landing_url || src), engine: \"openverse\" });\n }\n return out;\n}\n\n/**\n * Image search chain:\n * Bing + Wikimedia Commons + Openverse (+ SearXNG if configured), all in parallel, no API key.\n * Returns as soon as enough images are in, never waits for the slowest engine.\n */\nexport async function searchImages(query: string, count: number, searxUrl = \"\"): Promise<ImageHit[]> {\n const key = `img:${LOCALE}:${searxUrl}:${query.toLowerCase().trim()}:${count}`;\n return cached(\n key,\n 10 * 60 * 1000,\n async () => {\n const seen = new Set<string>();\n const merged: ImageHit[] = [];\n const push = (list: ImageHit[]) => {\n for (const h of list) {\n const k = h.src.split(\"?\")[0].toLowerCase();\n if (seen.has(k)) continue;\n seen.add(k);\n merged.push(h);\n }\n };\n const lists = await raceUntilEnough(\n [\n searxUrl ? runEngine(\"img:searxng\", () => imagesSearxng(searxUrl, query, count), 4000) : Promise.resolve([] as ImageHit[]),\n runEngine(\"img:bing\", () => imagesBing(query, count), 4000),\n runEngine(\"img:wikimedia\", () => imagesWikimedia(query, count), 4000),\n runEngine(\"img:openverse\", () => imagesOpenverse(query, count), 4000),\n ],\n (c) => c.reduce((n, a) => n + a.length, 0) >= count,\n 4500\n );\n // Bing/SearXNG lead (interleaved); the strict-filtered Commons/Openverse hits only fill the tail.\n const main = [lists[0], lists[1]];\n const maxLen = Math.max(...main.map((a) => a.length), 0);\n for (let i = 0; i < maxLen; i++) for (const a of main) if (a[i]) push([a[i]]);\n push(lists[2]);\n push(lists[3]);\n return merged.slice(0, count);\n },\n (v) => v.length > 0\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_path", "import_fs", "import_promises", "import_fs", "import_os", "import_path", "path", "os", "fs", "i", "r", "requireLocal", "path", "os", "fs", "base", "which", "SKIP_DIRS", "fs", "SKIP_DIRS", "path", "os", "cache", "pending", "dotenv", "dedupeKey", "path", "fs", "url", "net", "dns", "path", "fs", "express", "responseText", "createViteServer"]
|
|
7
7
|
}
|