@kianwoon/modelweaver 0.3.13 → 0.3.14
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/dist/chunk-SCUI4R77.js +7 -0
- package/dist/chunk-SCUI4R77.js.map +1 -0
- package/dist/{daemon-57XX5JCT.js → daemon-27GXX25D.js} +2 -2
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/{init-BWJF5P6D.js → init-VLTKSOZN.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-DIRPR744.js +0 -7
- package/dist/chunk-DIRPR744.js.map +0 -1
- /package/dist/{daemon-57XX5JCT.js.map → daemon-27GXX25D.js.map} +0 -0
- /package/dist/{init-BWJF5P6D.js.map → init-VLTKSOZN.js.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{spawn as L,execFile as W,execFileSync as I}from"child_process";import{access as N,readFile as E,writeFile as M,unlink as y,mkdir as G}from"fs/promises";import{join as g}from"path";import{dirname as U}from"path";import{fileURLToPath as _}from"url";import{createServer as K}from"net";function d(){return process.platform==="win32"}var p=g(process.env.HOME||process.env.USERPROFILE||"",".modelweaver"),v=null;function Q(n){v=n}function k(){return g(p,"modelweaver.pid")}function u(){return g(p,"modelweaver.log")}async function R(){try{await N(p)}catch{await G(p,{recursive:!0})}}async function Y(n){await R();try{await M(k(),`${n}
|
|
3
|
+
`,{flag:"wx"})}catch(t){if(t.code==="EEXIST")return;throw t}}async function h(){let n=k();try{let t=await E(n,"utf-8"),e=parseInt(t.trim(),10);return isNaN(e)?null:e}catch{return null}}async function f(){let n=k();try{await y(n)}catch{}}function b(){return g(p,"modelweaver.worker.pid")}async function Z(n){await R(),await M(b(),`${n}
|
|
4
|
+
`)}async function w(){let n=b();try{let t=await E(n,"utf-8"),e=parseInt(t.trim(),10);return isNaN(e)?null:e}catch{return null}}async function m(){let n=b();try{await y(n)}catch{}}function s(n){try{return process.kill(n,0),!0}catch{return!1}}function S(n){return new Promise(t=>{if(d()){try{W("netstat",["-ano"],{encoding:"utf-8",timeout:3e3},(e,o)=>{if(e){t([]);return}let r=[];for(let i of(o||"").split(`
|
|
5
|
+
`))if(i.includes("LISTENING")&&i.includes(`:${n}`)){let l=i.trim().split(/\s+/),a=parseInt(l[l.length-1],10);!isNaN(a)&&a>0&&r.push(a)}t(r)})}catch{t([]);return}return}W("lsof",["-ti",`:${n}`,"-sTCP:LISTEN"],{encoding:"utf-8",timeout:3e3},(e,o)=>{if(e){t([]);return}let r=(o||"").trim();t(r?r.split(`
|
|
6
|
+
`).map(Number).filter(i=>!isNaN(i)):[])})})}async function D(n){if(v!==null)return v;try{let{loadConfig:t}=await import("./config-P34YQCFG.js"),{config:e}=await t(n??void 0);return e.server.port}catch{return 3456}}async function $(n,t=5e3){for(let o of n)try{process.kill(-o,"SIGTERM")}catch{try{process.kill(o,"SIGTERM")}catch{}}let e=Date.now()+t;for(;Date.now()<e;){if(n.every(o=>!s(o)))return!0;await new Promise(o=>setTimeout(o,200))}for(let o of n)if(d())try{I("taskkill",["/F","/PID",String(o),"/T"],{stdio:"ignore"})}catch{}else try{process.kill(-o,"SIGKILL")}catch{try{process.kill(o,"SIGKILL")}catch{}}return!0}async function O(n){let t=await h();if(t===null){let e=n??await D();if(e!==null&&e>0){let o=await S(e);if(o.length>0){let r=o.filter(i=>s(i));if(r.length>0)return{running:!0,pid:r[0],message:`ModelWeaver is running (PID ${r[0]}, detected on port ${e}; PID file missing)`}}}return{running:!1,message:"ModelWeaver is not running (no PID file found)"}}return s(t)?{running:!0,pid:t,message:`ModelWeaver is running (PID ${t})`}:(await f(),{running:!1,message:"ModelWeaver is not running (stale PID file cleaned up)"})}function C(n){return new Promise(t=>{let e=K();e.once("error",o=>{o.code==="EADDRINUSE"?t(!0):t(!1)}),e.once("listening",()=>{e.close(()=>t(!1))}),e.listen(n)})}async function ee(n,t,e){let o=await O(t);if(o.running)return{success:!1,pid:o.pid,message:`ModelWeaver is already running (PID ${o.pid})`,logPath:u()};let r=t??await D()??3456;if(await C(r))return{success:!1,message:`Port ${r} is already in use. Is ModelWeaver or another process running on it?`,logPath:u()};let i=_(import.meta.url),l=U(i),c=[g(l,"index.js"),"--monitor"];n&&c.push("--config",n),t&&c.push("--port",String(t)),e&&c.push("--verbose"),L(process.execPath,c,{detached:!0,stdio:"ignore",env:{...process.env}}).unref();let P;for(let x=0;x<20;x++){let T=await h();if(T!==null){P=T;break}await new Promise(F=>setTimeout(F,100))}return P?{success:!0,pid:P,message:`ModelWeaver started in background (PID ${P})`,logPath:u()}:{success:!1,message:"Daemon started but PID file was not created. Check logs at "+u(),logPath:u()}}async function A(n){let t=await h();if(t===null){let r=n??await D();if(r!==null&&r>0){let l=(await S(r)).filter(a=>s(a));if(l.length>0){let a=await w(),c=[...l];return a!==null&&s(a)&&!c.includes(a)&&c.push(a),await $(c),await m(),{success:!0,message:`ModelWeaver stopped (found on port ${r}, PIDs ${l.join(", ")}; PID file was missing)`}}}return{success:!1,message:"ModelWeaver is not running (no PID file found)"}}if(!s(t)){let r=await w();return r!==null&&s(r)&&(await $([r]),await m()),await f(),{success:!1,message:"ModelWeaver is not running (stale PID file cleaned up)"}}let e=await w();if(e!==null&&s(e))try{process.kill(e,"SIGTERM")}catch{}try{process.kill(t,"SIGTERM")}catch{return{success:!1,message:`Failed to stop daemon (PID ${t})`}}let o=Date.now()+5e3;for(;Date.now()<o;){let r=!s(t),i=e===null||!s(e);if(r&&i)return await f(),await m(),{success:!0,message:`ModelWeaver stopped (monitor PID ${t}, worker PID ${e})`};await new Promise(l=>setTimeout(l,100))}if(e!==null&&s(e))try{d()?I("taskkill",["/F","/PID",String(e),"/T"],{stdio:"ignore"}):process.kill(e,"SIGKILL")}catch{}if(s(t))try{d()?I("taskkill",["/F","/PID",String(t),"/T"],{stdio:"ignore"}):process.kill(t,"SIGKILL")}catch{}return await f(),await m(),{success:!0,message:`ModelWeaver force-stopped (monitor PID ${t}, worker PID ${e})`}}async function j(){let n=u();try{await y(n)}catch{}}async function te(){let n=await A();return await j(),await m(),{success:n.success||n.message.includes("not running"),message:n.success?"ModelWeaver stopped and cleaned up (PID file + log file removed)":n.message.includes("not running")?"ModelWeaver is not running. Log file cleaned up.":n.message}}async function ne(n){let t=await h();if(t===null){let e=n??await D();if(e!==null&&e>0){let r=(await S(e)).filter(i=>s(i));if(r.length>0){for(let i of r)try{d()?console.log(` Windows detected \u2014 reload signal not supported for PID ${i}. Use 'modelweaver stop && modelweaver start' instead.`):process.kill(i,"SIGHUP")}catch{}console.log(` Sent reload signal to ${r.length} process(es) on port ${e}.`);return}}console.log(" Daemon is not running.");return}if(!s(t)){await f(),console.log(" Daemon is not running (stale PID file cleaned up).");return}try{if(d()){let e=await w();e!==null?(process.kill(e,"SIGTERM"),console.log(` Killed worker (PID ${e}) on Windows \u2014 monitor will restart it.`)):console.log(" No worker PID file found \u2014 cannot reload.")}else process.kill(t,"SIGHUP"),console.log(` Sent reload signal to daemon (PID ${t}).`)}catch{console.log(" Failed to send reload signal \u2014 daemon may not be running.")}}function re(n,t=300){let e=null;return{reload(){e&&clearTimeout(e),e=setTimeout(()=>{e=null,n()},t)},dispose(){e&&(clearTimeout(e),e=null)}}}export{Q as a,k as b,u as c,R as d,Y as e,h as f,f as g,b as h,Z as i,w as j,m as k,s as l,S as m,D as n,O as o,C as p,ee as q,A as r,j as s,te as t,ne as u,re as v};
|
|
7
|
+
//# sourceMappingURL=chunk-SCUI4R77.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon.ts"],"sourcesContent":["// src/daemon.ts — Daemon lifecycle management for background mode\nimport { spawn, execFile, execFileSync } from \"node:child_process\";\nimport { access, readFile, writeFile, unlink, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { createServer } from \"node:net\";\n\nfunction isWindows(): boolean {\n return process.platform === \"win32\";\n}\n\n// ---------------------------------------------------------------------------\n// Paths\n// ---------------------------------------------------------------------------\n\nconst MODELWEAVER_DIR = join(\n process.env.HOME || process.env.USERPROFILE || \"\",\n \".modelweaver\"\n);\n\n/** Override for getConfigPort — used by tests to prevent port scanning */\nlet _configPortOverride: number | null = null;\n\n/** Set a config port override (0 = skip port-based discovery). Used by tests. */\nexport function _setConfigPortOverride(port: number | null): void {\n _configPortOverride = port;\n}\n\nexport function getPidPath(): string {\n return join(MODELWEAVER_DIR, \"modelweaver.pid\");\n}\n\nexport function getLogPath(): string {\n return join(MODELWEAVER_DIR, \"modelweaver.log\");\n}\n\n// ---------------------------------------------------------------------------\n// Directory & PID helpers\n// ---------------------------------------------------------------------------\n\nexport async function ensureDir(): Promise<void> {\n try {\n await access(MODELWEAVER_DIR);\n } catch {\n await mkdir(MODELWEAVER_DIR, { recursive: true });\n }\n}\n\nexport async function writePidFile(pid: number): Promise<void> {\n await ensureDir();\n try {\n await writeFile(getPidPath(), `${pid}\\n`, { flag: 'wx' });\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') {\n // PID file already exists — another instance is likely running\n return;\n }\n throw err;\n }\n}\n\nexport async function readPidFile(): Promise<number | null> {\n const pidPath = getPidPath();\n try {\n const content = await readFile(pidPath, \"utf-8\");\n const pid = parseInt(content.trim(), 10);\n return isNaN(pid) ? null : pid;\n } catch {\n return null;\n }\n}\n\nexport async function removePidFile(): Promise<void> {\n const pidPath = getPidPath();\n try {\n await unlink(pidPath);\n } catch {\n // File doesn't exist — nothing to do\n }\n}\n\n// ---------------------------------------------------------------------------\n// Worker PID helpers (used by monitor to track daemon child)\n// ---------------------------------------------------------------------------\n\nexport function getWorkerPidPath(): string {\n return join(MODELWEAVER_DIR, \"modelweaver.worker.pid\");\n}\n\nexport async function writeWorkerPidFile(pid: number): Promise<void> {\n await ensureDir();\n await writeFile(getWorkerPidPath(), `${pid}\\n`);\n}\n\nexport async function readWorkerPidFile(): Promise<number | null> {\n const pidPath = getWorkerPidPath();\n try {\n const content = await readFile(pidPath, \"utf-8\");\n const pid = parseInt(content.trim(), 10);\n return isNaN(pid) ? null : pid;\n } catch {\n return null;\n }\n}\n\nexport async function removeWorkerPidFile(): Promise<void> {\n const pidPath = getWorkerPidPath();\n try {\n await unlink(pidPath);\n } catch {\n // File doesn't exist — nothing to do\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0); // Signal 0 = check existence without sending signal\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Port-based process discovery (fallback when PID file is missing)\n// ---------------------------------------------------------------------------\n\n/** Find PIDs of processes listening on the given TCP port via lsof (async).\n * NOTE: lsof is unavailable on Windows — port-based discovery silently skips on that platform.\n */\nexport function findPidsOnPort(port: number): Promise<number[]> {\n return new Promise((resolve) => {\n if (isWindows()) {\n try {\n execFile(\"netstat\", [\"-ano\"], { encoding: \"utf-8\", timeout: 3000 }, (err, out) => {\n if (err) { resolve([]); return; }\n const pids: number[] = [];\n for (const line of (out || \"\").split(\"\\n\")) {\n if (line.includes(\"LISTENING\") && line.includes(`:${port}`)) {\n const parts = line.trim().split(/\\s+/);\n const pid = parseInt(parts[parts.length - 1], 10);\n if (!isNaN(pid) && pid > 0) pids.push(pid);\n }\n }\n resolve(pids);\n });\n } catch {\n resolve([]);\n return;\n }\n return;\n }\n execFile(\"lsof\", [\"-ti\", `:${port}`, \"-sTCP:LISTEN\"], {\n encoding: \"utf-8\",\n timeout: 3000,\n }, (err, out) => {\n if (err) {\n // lsof returns non-zero when nothing is listening on the port\n resolve([]);\n return;\n }\n const trimmed = (out || \"\").trim();\n resolve(trimmed ? trimmed.split(\"\\n\").map(Number).filter((n) => !isNaN(n)) : []);\n });\n });\n}\n\n/** Attempt to load the configured port from the config file (dynamic import to avoid circular deps). */\nexport async function getConfigPort(configPath?: string | null): Promise<number | null> {\n if (_configPortOverride !== null) return _configPortOverride;\n try {\n const { loadConfig } = await import(\"./config.js\");\n const { config } = await loadConfig(configPath ?? undefined);\n return config.server.port;\n } catch {\n // Config file missing or invalid — fall back to default\n return 3456;\n }\n}\n\n/**\n * Kill a process tree: send SIGTERM, wait up to `timeoutMs`, then SIGKILL.\n * Handles the process and any known child (worker PID file).\n */\nasync function killProcessTree(pids: number[], timeoutMs: number = 5000): Promise<boolean> {\n for (const pid of pids) {\n try {\n // Try process group kill first (kills all children)\n process.kill(-pid, \"SIGTERM\");\n } catch {\n // Fall back to individual kill if process group doesn't exist\n try { process.kill(pid, \"SIGTERM\"); } catch { /* already dead */ }\n }\n }\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (pids.every((p) => !isProcessAlive(p))) return true;\n await new Promise((r) => setTimeout(r, 200));\n }\n // Force kill anything still alive\n for (const pid of pids) {\n if (isWindows()) {\n try {\n execFileSync(\"taskkill\", [\"/F\", \"/PID\", String(pid), \"/T\"], { stdio: \"ignore\" });\n } catch {\n // taskkill may fail if process already exited\n }\n } else {\n try {\n process.kill(-pid, \"SIGKILL\");\n } catch {\n // Fall back to individual kill if process group doesn't exist\n try { process.kill(pid, \"SIGKILL\"); } catch { /* already dead */ }\n }\n }\n }\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// Daemon status\n// ---------------------------------------------------------------------------\n\nexport interface DaemonStatus {\n running: boolean;\n pid?: number;\n message: string;\n}\n\nexport async function statusDaemon(portOverride?: number): Promise<DaemonStatus> {\n const pid = await readPidFile();\n if (pid === null) {\n // PID file missing — try to find the process by configured port\n const port = portOverride ?? await getConfigPort();\n if (port !== null && port > 0) {\n const portPids = await findPidsOnPort(port);\n if (portPids.length > 0) {\n const livePids = portPids.filter((p) => isProcessAlive(p));\n if (livePids.length > 0) {\n return {\n running: true,\n pid: livePids[0],\n message: `ModelWeaver is running (PID ${livePids[0]}, detected on port ${port}; PID file missing)`,\n };\n }\n }\n }\n return { running: false, message: \"ModelWeaver is not running (no PID file found)\" };\n }\n if (isProcessAlive(pid)) {\n return { running: true, pid, message: `ModelWeaver is running (PID ${pid})` };\n }\n // Stale PID file — process is dead but file remains\n await removePidFile();\n return { running: false, message: `ModelWeaver is not running (stale PID file cleaned up)` };\n}\n\n// ---------------------------------------------------------------------------\n// Daemon start\n// ---------------------------------------------------------------------------\n\nexport interface DaemonStartResult {\n success: boolean;\n pid?: number;\n message: string;\n logPath: string;\n}\n\nexport function isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n server.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(true);\n } else {\n resolve(false);\n }\n });\n server.once(\"listening\", () => {\n server.close(() => resolve(false));\n });\n server.listen(port);\n });\n}\n\nexport async function startDaemon(\n configPath?: string,\n port?: number,\n verbose?: boolean,\n): Promise<DaemonStartResult> {\n // Check if already running (now uses port-based fallback too)\n const currentStatus = await statusDaemon(port);\n if (currentStatus.running) {\n return {\n success: false,\n pid: currentStatus.pid,\n message: `ModelWeaver is already running (PID ${currentStatus.pid})`,\n logPath: getLogPath(),\n };\n }\n\n // Check if port is already in use\n const effectivePort = port ?? await getConfigPort() ?? 3456;\n if (await isPortInUse(effectivePort)) {\n return {\n success: false,\n message: `Port ${effectivePort} is already in use. Is ModelWeaver or another process running on it?`,\n logPath: getLogPath(),\n };\n }\n\n // Resolve the entry script path\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n // Use dist/index.js (built output) — works with both npx and direct node\n const entryScript = join(__dirname, \"index.js\");\n\n // Build args — spawn a monitor process; monitor spawns the actual daemon child\n const childArgs: string[] = [entryScript, \"--monitor\"];\n if (configPath) childArgs.push(\"--config\", configPath);\n if (port) childArgs.push(\"--port\", String(port));\n if (verbose) childArgs.push(\"--verbose\");\n\n const child = spawn(process.execPath, childArgs, {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env },\n });\n\n // Allow parent to exit independently\n child.unref();\n\n // Wait briefly for child to start and write PID file\n // (child process writes PID file in its startup sequence)\n let pid: number | undefined;\n for (let i = 0; i < 20; i++) {\n const checkPid = await readPidFile();\n if (checkPid !== null) {\n pid = checkPid;\n break;\n }\n // Sleep 100ms\n await new Promise(r => setTimeout(r, 100));\n }\n\n if (!pid) {\n return {\n success: false,\n message: \"Daemon started but PID file was not created. Check logs at \" + getLogPath(),\n logPath: getLogPath(),\n };\n }\n\n return {\n success: true,\n pid,\n message: `ModelWeaver started in background (PID ${pid})`,\n logPath: getLogPath(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Daemon stop\n// ---------------------------------------------------------------------------\n\nexport interface DaemonStopResult {\n success: boolean;\n message: string;\n}\n\nexport async function stopDaemon(portOverride?: number): Promise<DaemonStopResult> {\n const pid = await readPidFile();\n if (pid === null) {\n // PID file missing — try to find the process by configured port\n const port = portOverride ?? await getConfigPort();\n if (port !== null && port > 0) {\n const portPids = await findPidsOnPort(port);\n const livePids = portPids.filter((p) => isProcessAlive(p));\n if (livePids.length > 0) {\n // Also include the worker PID file if present\n const workerPid = await readWorkerPidFile();\n const pidsToKill = [...livePids];\n if (workerPid !== null && isProcessAlive(workerPid) && !pidsToKill.includes(workerPid)) {\n pidsToKill.push(workerPid);\n }\n await killProcessTree(pidsToKill);\n await removeWorkerPidFile();\n return {\n success: true,\n message: `ModelWeaver stopped (found on port ${port}, PIDs ${livePids.join(\", \")}; PID file was missing)`,\n };\n }\n }\n return { success: false, message: \"ModelWeaver is not running (no PID file found)\" };\n }\n\n if (!isProcessAlive(pid)) {\n // Monitor is dead — check for orphaned worker and kill it\n const workerPid = await readWorkerPidFile();\n if (workerPid !== null && isProcessAlive(workerPid)) {\n await killProcessTree([workerPid]);\n await removeWorkerPidFile();\n }\n await removePidFile();\n return { success: false, message: \"ModelWeaver is not running (stale PID file cleaned up)\" };\n }\n\n // Kill worker first (holds port + connection pool)\n const workerPid = await readWorkerPidFile();\n if (workerPid !== null && isProcessAlive(workerPid)) {\n try { process.kill(workerPid, \"SIGTERM\"); } catch { /* already dead */ }\n }\n // Then kill monitor\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n return { success: false, message: `Failed to stop daemon (PID ${pid})` };\n }\n // Wait for BOTH to die\n const deadline = Date.now() + 5000;\n while (Date.now() < deadline) {\n const monitorDead = !isProcessAlive(pid);\n const workerDead = workerPid === null || !isProcessAlive(workerPid);\n if (monitorDead && workerDead) {\n await removePidFile();\n await removeWorkerPidFile();\n return { success: true, message: `ModelWeaver stopped (monitor PID ${pid}, worker PID ${workerPid})` };\n }\n await new Promise(r => setTimeout(r, 100));\n }\n\n // Force kill anything still running\n if (workerPid !== null && isProcessAlive(workerPid)) {\n try {\n if (isWindows()) {\n execFileSync(\"taskkill\", [\"/F\", \"/PID\", String(workerPid), \"/T\"], { stdio: \"ignore\" });\n } else {\n process.kill(workerPid, \"SIGKILL\");\n }\n } catch { /* already dead */ }\n }\n if (isProcessAlive(pid)) {\n try {\n if (isWindows()) {\n execFileSync(\"taskkill\", [\"/F\", \"/PID\", String(pid), \"/T\"], { stdio: \"ignore\" });\n } else {\n process.kill(pid, \"SIGKILL\");\n }\n } catch { /* already dead */ }\n }\n\n await removePidFile();\n await removeWorkerPidFile();\n return { success: true, message: `ModelWeaver force-stopped (monitor PID ${pid}, worker PID ${workerPid})` };\n}\n\n// ---------------------------------------------------------------------------\n// Remove (stop + cleanup)\n// ---------------------------------------------------------------------------\n\nexport async function removeLogFile(): Promise<void> {\n const logPath = getLogPath();\n try {\n await unlink(logPath);\n } catch {\n // File doesn't exist — nothing to do\n }\n}\n\nexport async function removeDaemon(): Promise<DaemonStopResult> {\n const stopResult = await stopDaemon();\n await removeLogFile();\n await removeWorkerPidFile();\n return {\n success: stopResult.success || stopResult.message.includes(\"not running\"),\n message: stopResult.success\n ? \"ModelWeaver stopped and cleaned up (PID file + log file removed)\"\n : stopResult.message.includes(\"not running\")\n ? \"ModelWeaver is not running. Log file cleaned up.\"\n : stopResult.message,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Daemon reload (SIGHUP to monitor → restart worker with fresh code)\n// ---------------------------------------------------------------------------\n\nexport async function reloadDaemon(portOverride?: number): Promise<void> {\n const pid = await readPidFile();\n if (pid === null) {\n // PID file missing — try to find the process by configured port\n const port = portOverride ?? await getConfigPort();\n if (port !== null && port > 0) {\n const portPids = await findPidsOnPort(port);\n const livePids = portPids.filter((p) => isProcessAlive(p));\n if (livePids.length > 0) {\n for (const p of livePids) {\n try {\n if (isWindows()) {\n // SIGHUP not available on Windows — just inform user\n console.log(` Windows detected — reload signal not supported for PID ${p}. Use 'modelweaver stop && modelweaver start' instead.`);\n } else {\n process.kill(p, \"SIGHUP\");\n }\n } catch { /* ignore */ }\n }\n console.log(` Sent reload signal to ${livePids.length} process(es) on port ${port}.`);\n return;\n }\n }\n console.log(\" Daemon is not running.\");\n return;\n }\n\n if (!isProcessAlive(pid)) {\n await removePidFile();\n console.log(\" Daemon is not running (stale PID file cleaned up).\");\n return;\n }\n\n try {\n if (isWindows()) {\n // Windows has no SIGHUP — kill the worker directly so monitor restarts it\n const workerPid = await readWorkerPidFile();\n if (workerPid !== null) {\n process.kill(workerPid, \"SIGTERM\");\n console.log(` Killed worker (PID ${workerPid}) on Windows — monitor will restart it.`);\n } else {\n console.log(\" No worker PID file found — cannot reload.\");\n }\n } else {\n process.kill(pid, \"SIGHUP\");\n console.log(` Sent reload signal to daemon (PID ${pid}).`);\n }\n } catch {\n console.log(\" Failed to send reload signal — daemon may not be running.\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Debounced watcher\n// ---------------------------------------------------------------------------\n\nexport function createDebouncedReload(\n callback: () => void,\n debounceMs: number = 300,\n): { reload: () => void; dispose: () => void } {\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n return {\n reload() {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n callback();\n }, debounceMs);\n },\n dispose() {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n },\n };\n}\n"],"mappings":"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","names":["spawn","execFile","execFileSync","access","readFile","writeFile","unlink","mkdir","join","dirname","fileURLToPath","createServer","isWindows","MODELWEAVER_DIR","_configPortOverride","_setConfigPortOverride","port","getPidPath","getLogPath","ensureDir","writePidFile","pid","err","readPidFile","pidPath","content","removePidFile","getWorkerPidPath","writeWorkerPidFile","readWorkerPidFile","removeWorkerPidFile","isProcessAlive","findPidsOnPort","resolve","out","pids","line","parts","trimmed","n","getConfigPort","configPath","loadConfig","config","killProcessTree","timeoutMs","deadline","p","r","statusDaemon","portOverride","portPids","livePids","isPortInUse","server","startDaemon","verbose","currentStatus","effectivePort","__filename","__dirname","childArgs","i","checkPid","stopDaemon","workerPid","pidsToKill","monitorDead","workerDead","removeLogFile","logPath","removeDaemon","stopResult","reloadDaemon","createDebouncedReload","callback","debounceMs","timer"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v}from"./chunk-
|
|
3
|
-
//# sourceMappingURL=daemon-
|
|
2
|
+
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v}from"./chunk-SCUI4R77.js";export{a as _setConfigPortOverride,v as createDebouncedReload,d as ensureDir,m as findPidsOnPort,n as getConfigPort,c as getLogPath,b as getPidPath,h as getWorkerPidPath,p as isPortInUse,l as isProcessAlive,f as readPidFile,j as readWorkerPidFile,u as reloadDaemon,t as removeDaemon,s as removeLogFile,g as removePidFile,k as removeWorkerPidFile,q as startDaemon,o as statusDaemon,r as stopDaemon,e as writePidFile,i as writeWorkerPidFile};
|
|
3
|
+
//# sourceMappingURL=daemon-27GXX25D.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as Z}from"./chunk-OMWFRIHF.js";import{d as ee}from"./chunk-ZF23JS2D.js";import{b as te,e as ne,g as B,k as oe}from"./chunk-DIRPR744.js";import{serve as ve}from"@hono/node-server";import{readFileSync as nt}from"fs";import{Hono as He}from"hono";var q=new Map;function re(){q.clear()}function ke(t,e){for(let[o,n]of e)for(let d of n)if(t.includes(d))return o;return null}function Se(t,e){return e.get(t)||[]}function se(t,e,o,n){let d=q.get(t);if(d)return q.delete(t),q.set(t,d),{requestId:e,model:t,tier:d.tier,providerChain:d.providerChain,startTime:Date.now(),rawBody:n};let c,i,r=o.modelRouting.get(t);if(r&&r.length>0)c="(modelRouting)",i=r;else{let u=ke(t,o.tierPatterns);if(!u)return null;c=u,i=Se(c,o.routing)}if(q.size>=200){let u=q.keys().next().value;u!==void 0&&q.delete(u)}return q.set(t,{tier:c,providerChain:i}),{requestId:e,model:t,tier:c,providerChain:i,startTime:Date.now(),rawBody:n}}import{request as Ee}from"undici";import{PassThrough as Ie}from"stream";import pe from"fs";import me from"path";import Pe from"os";var U=class{samples=new Map;maxSize;MAX_PROVIDERS=50;constructor(e=20){this.maxSize=e}record(e,o){if(this.samples.size>=this.MAX_PROVIDERS&&!this.samples.has(e)){let d=this.samples.keys().next().value;d!==void 0&&this.samples.delete(d)}let n=this.samples.get(e);n||(n=[],this.samples.set(e,n)),n.push({ttfbMs:o,timestamp:Date.now()}),n.length>this.maxSize&&n.splice(0,n.length-this.maxSize)}getCV(e){let o=this.samples.get(e);if(!o||o.length<3)return 0;let n=o.map(i=>i.ttfbMs),d=n.reduce((i,r)=>i+r,0)/n.length;if(d===0)return 0;let c=n.reduce((i,r)=>i+(r-d)**2,0)/n.length;return Math.sqrt(c)/d}getStats(e){let o=this.samples.get(e);if(!o||o.length===0)return{count:0,mean:0,cv:0};let n=o.map(c=>c.ttfbMs),d=n.reduce((c,i)=>c+i,0)/n.length;return{count:n.length,mean:Math.round(d),cv:Math.round(this.getCV(e)*100)/100}}clear(e){this.samples.delete(e)}prune(e){let o=new Set(e);for(let n of this.samples.keys())o.has(n)||this.samples.delete(n)}},H=class{counts=new Map;increment(e){let o=(this.counts.get(e)??0)+1;return this.counts.set(e,o),o}decrement(e){let o=Math.max(0,(this.counts.get(e)??0)-1);return this.counts.set(e,o),o}get(e){return this.counts.get(e)??0}},$=new U,L=new H;function ie(t){let e=$.getCV(t.name),o=L.get(t.name),n=t.concurrentLimit??1,d=Math.max(1,n-o),c=Math.max(1,Math.floor(e*2+.5));return Math.min(c,d)}import{WebSocketServer as Re}from"ws";var Te=3e4,_e=2,ue=64*1024,Ce=500,Me=500,xe=1e4,ae=new WeakMap,z=null,le=0,ce=0;function de(t){let e=Date.now();e-ce>=xe&&(console.warn(`[ws] Backpressure: dropping ${t} events (total dropped stream events: ${le})`),ce=e)}function J(t,e){let o=new Re({server:t,path:"/ws"});z=o,o.on("connection",n=>{let c={type:"summary",data:e.getSummary()};n.send(JSON.stringify(c));let i,r=0,u=()=>n.readyState===n.OPEN,m=e.onRecord(f=>{if(u()){if(n.bufferedAmount>ue){a(),de("metrics");return}setImmediate(()=>{if(!u())return;let g={type:"request",data:f};n.send(JSON.stringify(g))}),a()}});function a(){i||(i=setTimeout(()=>{if(i=void 0,!u())return;let f={type:"summary",data:e.getSummary()};n.send(JSON.stringify(f))},Ce))}let s=setInterval(()=>{if(!u()){clearInterval(s);return}if(r>=_e){l(),n.terminate();return}n.ping(),r++},Te);n.on("pong",()=>{r=0});let p=!1,l=()=>{p||(p=!0,clearInterval(s),i&&clearTimeout(i),m())};n.on("close",l),n.on("error",l)})}function I(t){if(!z)return;let e=JSON.stringify({type:"stream",data:t}),o=t.state==="streaming",n=t.state==="complete"||t.state==="error",d=Date.now();for(let c of z.clients)if(c.readyState===c.OPEN){if(o){let i=ae.get(c)??0;if(d-i<Me)continue;ae.set(c,d)}if(c.bufferedAmount>ue){if(n){let i=()=>{c.readyState===c.OPEN&&c.send(e)};c.once("drain",i),setTimeout(()=>{c.removeListener("drain",i),c.readyState===c.OPEN&&c.send(e)},5e3).unref();continue}le++,de("stream");continue}setImmediate(()=>{c.readyState===c.OPEN&&c.send(e)})}}var Ae=new Set(["anthropic-version","anthropic-beta","content-type","accept"]),Oe=/\/+/g,qe=/^https?:\/\/[^/]+/,F=/"model"\s*:\s*"([^"]*)"/,j=/"max_tokens"\s*:\s*(\d+)/,O=new TextEncoder,$e=3e3;function Ne(t){return t===429||t>=500}var Le=["context window","context_limit","token limit","prompt is too long","max tokens","input too large","too many tokens"];function Be(t,e){if(t!==400)return!1;let o=e.toLowerCase();return Le.some(n=>o.includes(n))}function De(t,e){if(!Be(t,e))return null;console.warn("[context-compact] Upstream context window limit detected");try{let n=me.join(Pe.homedir(),".claude","state");pe.mkdirSync(n,{recursive:!0}),pe.writeFileSync(me.join(n,"context-compact-needed"),Date.now().toString())}catch{}let o=JSON.stringify({type:"error",error:{type:"invalid_request_error",message:"Context window limit reached. Run /compact to reduce conversation size, then retry."}});return new Response(o,{status:400,headers:{"content-type":"application/json"}})}function je(t,e){let o="",n=t,d=t.indexOf("/",t.indexOf("//")+2);d!==-1&&(n=t.substring(0,d),o=t.substring(d));let c="",i=e,r=e.indexOf("?");r!==-1&&(i=e.substring(0,r),c=e.substring(r));let u;return o.endsWith("/v1")&&i.startsWith("/v1")?u=o+i.substring(3):u=o+i,u=u.replace(Oe,"/"),n+u+c}function We(t,e,o){let n=new Headers;for(let c of Ae){let i=t.get(c);i&&n.set(c,i)}e.authType==="bearer"?n.set("Authorization",`Bearer ${e.apiKey}`):n.set("x-api-key",e.apiKey),n.set("x-request-id",o);let d=e._cachedHost;if(d)n.set("host",d);else try{let c=new URL(e.baseUrl);n.set("host",c.host)}catch{}return n}function he(t){let e=t.messages;if(!Array.isArray(e))return;let o=new Set,n=new Set;for(let u=0;u<e.length;u++){let m=e[u];if(Array.isArray(m.content))for(let a of m.content)a.type==="tool_use"&&a.id?o.add(String(a.id)):a.type==="tool_result"&&a.tool_use_id&&n.add(String(a.tool_use_id))}let d=new Set,c=new Set;for(let u of o)n.has(u)||d.add(u);for(let u of n)o.has(u)||c.add(u);if(d.size===0&&c.size===0)return;let i=!1,r=e.map(u=>{if(!Array.isArray(u.content))return u;let m=u.content.filter(a=>!(a.type==="tool_use"&&d.has(String(a.id))||a.type==="tool_result"&&c.has(String(a.tool_use_id))));return m.length<u.content.length?(i=!0,{...u,content:m}):u});i&&(t.messages=r)}function Ue(t,e,o,n,d){if(d){let y=structuredClone(n);if(e.model&&(y.model=e.model),he(y),o.modelLimits){let{maxOutputTokens:M}=o.modelLimits,h=typeof y.max_tokens=="number"?y.max_tokens:M;(y.max_tokens===void 0||h>M)&&(y.max_tokens=Math.min(h,M))}return JSON.stringify(y)}let c=!!(e.model&&n.model!==e.model),i=!1,r=!1,u=0;if(o.modelLimits){u=o.modelLimits.maxOutputTokens;let y=j.exec(t);y?i=parseInt(y[1],10)>u:typeof n.max_tokens!="number"&&(r=!0)}if(!c&&!i&&!r)return t;if(r){let y={...n};return e.model&&(y.model=e.model),y.max_tokens=u,JSON.stringify(y)}let m=[];c&&m.push(F.source),i&&m.push(j.source);let a=new RegExp(m.join("|"),"g"),s=c?`"model":"${e.model}"`:null,p=i?`"max_tokens":${u}`:null,l=n.model,f=!1;return t.replace(a,y=>s&&F.test(y)?(F.lastIndex=0,!f&&l&&(console.warn(`Routing override: ${l} -> ${e.model} via ${o.name}`),f=!0),s):p&&j.test(y)?(j.lastIndex=0,p):y)}async function fe(t,e,o,n,d,c=0){let i=n.url.replace(qe,"");e.model&&(o.actualModel=e.model);let r=je(t.baseUrl,i),u;if((n.headers.get("content-type")||"").includes("application/json"))try{let h=o.parsedBody??JSON.parse(o.rawBody),w=!1;e.model&&h.model!==e.model&&(w=!0);let b=c>0;if(b&&(w=!0),t.modelLimits){let{maxOutputTokens:v}=t.modelLimits,T=typeof h.max_tokens=="number"?h.max_tokens:v;(h.max_tokens===void 0||T>v)&&(w=!0)}if(w)if(c===0&&!b)u=Ue(o.rawBody,e,t,h,!1);else{let v=structuredClone(h);if(e.model){let T=v.model;v.model=e.model,T&&T!==e.model&&console.warn(`Routing override: ${T} -> ${e.model} via ${t.name}`)}if(b&&he(v),t.modelLimits){let{maxOutputTokens:T}=t.modelLimits,P=typeof v.max_tokens=="number"?v.max_tokens:T;(v.max_tokens===void 0||P>T)&&(v.max_tokens=Math.min(P,T))}u=JSON.stringify(v)}else u=o.rawBody}catch{u=o.rawBody}else u=o.rawBody;let a=We(n.headers,t,o.requestId);a.set("content-length",Buffer.byteLength(u,"utf-8").toString());let s=new AbortController,p=setTimeout(()=>s.abort(),t.timeout),l=t.ttfbTimeout??15e3,f=!1,g=null,y=new Promise((h,w)=>{g=setTimeout(()=>{f=!0,s.abort(),w(new Error(`TTFB timeout after ${l}ms`))},l)}),M;if(d){if(d.aborted){clearTimeout(p),g&&clearTimeout(g);let w=JSON.stringify({type:"error",error:{type:"overloaded_error",message:`Provider "${t.name}" cancelled by race winner`}});return new Response(w,{status:502,headers:{"content-type":"application/json","content-length":O.encode(w).byteLength.toString()}})}let h=()=>{clearTimeout(p),g&&clearTimeout(g)};M=d.addEventListener("abort",h,{once:!0})}try{let h=await Promise.race([Ee(r,{method:"POST",headers:a,body:u,signal:s.signal,dispatcher:t._agent}),y]);g&&clearTimeout(g);let w=t.stallTimeout??3e4,b=new Ie,v=`Body stalled: no data after ${w}ms`,T=setTimeout(()=>{I({requestId:o.requestId,model:String(o.actualModel??e.model??""),tier:"",state:"error",message:v,timestamp:Date.now()}),b.destroy(new Error(v))},w);b.on("data",()=>{clearTimeout(T),T=setTimeout(()=>{I({requestId:o.requestId,model:String(o.actualModel??e.model??""),tier:"",state:"error",message:v,timestamp:Date.now()}),b.destroy(new Error(v))},w)}),b.on("end",()=>{clearTimeout(T)}),b.on("error",()=>{clearTimeout(T)}),h.body.pipe(b);let P=new Response(b,{status:h.statusCode,headers:h.headers});return clearTimeout(p),P}catch(h){clearTimeout(p),g&&clearTimeout(g);let w=f?`Provider "${t.name}" timed out waiting for first byte after ${l}ms`:h instanceof DOMException&&h.name==="AbortError"?`Provider "${t.name}" timed out after ${t.timeout}ms`:`Provider "${t.name}" connection failed: ${h.message}`,b=JSON.stringify({type:"error",error:{type:"overloaded_error",message:w}});return new Response(b,{status:502,headers:{"content-type":"application/json","content-length":O.encode(b).byteLength.toString()}})}finally{M?.()}}async function ge(t,e,o,n,d,c,i){let r=ie(t);if(r<=1){L.increment(t.name);let l=Date.now();try{let f=await fe(t,e,o,n,d,c);return $.record(t.name,Date.now()-l),f}finally{L.decrement(t.name)}}i?.warn("Hedging request",{requestId:o.requestId,provider:t.name,count:r,cv:Math.round($.getCV(t.name)*100)/100,inFlight:L.get(t.name),maxConcurrent:t.concurrentLimit});let u=Date.now(),m=[];for(let l=0;l<r;l++)L.increment(t.name),m.push(fe(t,e,o,n,d,c).finally(()=>L.decrement(t.name)));let a=m.map((l,f)=>l.then(g=>({response:g,hedgeIndex:f}))),s=new Set,p=[];try{for(;s.size<a.length;){let l=a.filter((g,y)=>!s.has(y));if(l.length===0)break;let f=await Promise.race(l);if(s.add(f.hedgeIndex),t._circuitBreaker&&t._circuitBreaker.recordResult(f.response.status),f.response.status>=200&&f.response.status<300){$.record(t.name,Date.now()-u);for(let g=0;g<a.length;g++)s.has(g)||(t._circuitBreaker&&t._circuitBreaker.recordResult(502),a[g].then(y=>{try{y.response.body?.cancel()}catch{}}));for(let g of p)try{g.body?.cancel()}catch{}return f.response}p.push(f.response)}for(let l of p)try{l.body?.cancel()}catch{}return p[0]??new Response(JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${t.name}" all hedged requests failed`}}),{status:502,headers:{"content-type":"application/json"}})}catch{for(let l of p)try{l.body?.cancel()}catch{}return p[0]??new Response(JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${t.name}" hedging failed`}}),{status:502,headers:{"content-type":"application/json"}})}}async function ye(t,e,o,n,d,c){if(e.length<=1){let s=e[0],p=t.get(s.provider);if(!p){let f=JSON.stringify({type:"error",error:{type:"api_error",message:`Unknown provider: ${s.provider}`}});return new Response(f,{status:502,headers:{"content-type":"application/json","content-length":O.encode(f).byteLength.toString()}})}if(p._circuitBreaker&&!p._circuitBreaker.canProceed().allowed){c?.warn("Provider skipped by circuit breaker",{requestId:o.requestId,provider:s.provider});let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${s.provider}" skipped by circuit breaker`}});return new Response(g,{status:502,headers:{"content-type":"application/json","content-length":O.encode(g).byteLength.toString()}})}return d?.(s.provider,0),await ge(p,s,o,n,void 0,0,c)}let i=new AbortController,r=new Set,u=[];async function m(s){let p=e[s],l=t.get(p.provider);if(!l){let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Unknown provider: ${p.provider}`}});return{response:new Response(g,{status:502,headers:{"content-type":"application/json","content-length":O.encode(g).byteLength.toString()}}),index:s}}let f;if(l._circuitBreaker){let g=l._circuitBreaker.canProceed();if(!g.allowed){c?.warn("Provider skipped by circuit breaker",{requestId:o.requestId,provider:p.provider});let y=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${p.provider}" skipped by circuit breaker`}});return{response:new Response(y,{status:502,headers:{"content-type":"application/json","content-length":O.encode(y).byteLength.toString()}}),index:s}}f=g.probeId}d?.(p.provider,s);try{return{response:await ge(l,p,o,n,i.signal,s,c),index:s}}catch{l._circuitBreaker&&l._circuitBreaker.recordResult(502,f);let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${p.provider}" failed`}});return{response:new Response(g,{status:502,headers:{"content-type":"application/json","content-length":O.encode(g).byteLength.toString()}}),index:s}}}let a=[];for(let s=0;s<e.length;s++)s===0?a.push(m(0)):a.push(new Promise(p=>{setTimeout(()=>{if(i.signal.aborted){let l=JSON.stringify({type:"error",error:{type:"api_error",message:"Cancelled by race winner"}});p({response:new Response(l,{status:502,headers:{"content-type":"application/json"}}),index:s});return}m(s).then(p)},$e)}));try{for(;r.size<a.length;){let p=a.filter((f,g)=>!r.has(g));if(p.length===0)break;let l=await Promise.race(p);if(r.add(l.index),l.response.status>=200&&l.response.status<300){i.abort();for(let f of u)try{f.response.body?.cancel()}catch{}return l.response}if(!Ne(l.response.status)){if(i.abort(),l.response.status===400&&l.response.body)try{let f=await l.response.text(),g=De(l.response.status,f);return g||new Response(f,{status:l.response.status,statusText:l.response.statusText,headers:l.response.headers})}catch{return l.response}return l.response}u.push(l)}if(i.abort(),u.length>0)return u[0].response;let s=JSON.stringify({type:"error",error:{type:"overloaded_error",message:"All providers failed"}});return new Response(s,{status:502,headers:{"content-type":"application/json","content-length":O.encode(s).byteLength.toString()}})}catch{i.abort();let s=JSON.stringify({type:"error",error:{type:"overloaded_error",message:"All providers failed"}});return new Response(s,{status:502,headers:{"content-type":"application/json","content-length":O.encode(s).byteLength.toString()}})}}import{randomUUID as ze}from"crypto";import{gzip as Je}from"zlib";import{promisify as Fe}from"util";var Ge=Fe(Je),G={"claude-opus-4-6":2e5,"claude-sonnet-4-6":2e5,"claude-haiku-4-5-20251001":2e5,"claude-3-5-sonnet":2e5,"claude-3-5-haiku":2e5,"glm-4.7":128e3,"glm-5-turbo":128e3};function K(t){if(G[t])return G[t];for(let[e,o]of Object.entries(G))if(t.startsWith(e))return o;return 0}function X(t,e,o){let n=o+t+e;return n<=0?0:Math.round(t/n*1e3)/10}function V(t,e,o,n,d){if(d<=0)return 0;let c=t+e+o+n;return Math.round(c/d*1e3)/10}function Q(t,e,o){return new Response(JSON.stringify({type:"error",error:{type:t,message:e}}),{status:502,headers:{"content-type":"application/json","x-request-id":o}})}function Ke(t){let e=t.message?.usage??t.usage;if(!e)return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0};let o=e.input_tokens??e.prompt_tokens??0,n=e.output_tokens??e.completion_tokens??0,d=e.cache_read_input_tokens??0,c=e.cache_creation_input_tokens??0;return{inputTokens:o,outputTokens:n,cacheReadTokens:d,cacheCreationTokens:c}}function Xe(t,e,o,n,d,c){let i=new TextDecoder,r={input:0,output:0,cacheRead:0,cacheCreation:0},u="",m="",a=4096,s=0,p=0,l=0,f=0,g="",y=null,M=250,h=0,w=!0,b="",v=100,T=S=>{for(let C of S.split(`
|
|
2
|
+
import{a as Z}from"./chunk-OMWFRIHF.js";import{d as ee}from"./chunk-ZF23JS2D.js";import{b as te,e as ne,g as B,k as re}from"./chunk-SCUI4R77.js";import{serve as ve}from"@hono/node-server";import{readFileSync as nt}from"fs";import{Hono as He}from"hono";var $=new Map;function oe(){$.clear()}function ke(t,e){for(let[r,n]of e)for(let d of n)if(t.includes(d))return r;return null}function Re(t,e){return e.get(t)||[]}function se(t,e,r,n){let d=$.get(t);if(d)return $.delete(t),$.set(t,d),{requestId:e,model:t,tier:d.tier,providerChain:d.providerChain,startTime:Date.now(),rawBody:n};let c,i,o=r.modelRouting.get(t);if(o&&o.length>0)c="(modelRouting)",i=o;else{let u=ke(t,r.tierPatterns);if(!u)return null;c=u,i=Re(c,r.routing)}if($.size>=200){let u=$.keys().next().value;u!==void 0&&$.delete(u)}return $.set(t,{tier:c,providerChain:i}),{requestId:e,model:t,tier:c,providerChain:i,startTime:Date.now(),rawBody:n}}import{request as Ee}from"undici";import{PassThrough as Ie}from"stream";import pe from"fs";import me from"path";import Pe from"os";var U=class{samples=new Map;maxSize;MAX_PROVIDERS=50;constructor(e=20){this.maxSize=e}record(e,r){if(this.samples.size>=this.MAX_PROVIDERS&&!this.samples.has(e)){let d=this.samples.keys().next().value;d!==void 0&&this.samples.delete(d)}let n=this.samples.get(e);n||(n=[],this.samples.set(e,n)),n.push({ttfbMs:r,timestamp:Date.now()}),n.length>this.maxSize&&n.splice(0,n.length-this.maxSize)}getCV(e){let r=this.samples.get(e);if(!r||r.length<3)return 0;let n=r.map(i=>i.ttfbMs),d=n.reduce((i,o)=>i+o,0)/n.length;if(d===0)return 0;let c=n.reduce((i,o)=>i+(o-d)**2,0)/n.length;return Math.sqrt(c)/d}getStats(e){let r=this.samples.get(e);if(!r||r.length===0)return{count:0,mean:0,cv:0};let n=r.map(c=>c.ttfbMs),d=n.reduce((c,i)=>c+i,0)/n.length;return{count:n.length,mean:Math.round(d),cv:Math.round(this.getCV(e)*100)/100}}clear(e){this.samples.delete(e)}prune(e){let r=new Set(e);for(let n of this.samples.keys())r.has(n)||this.samples.delete(n)}},H=class{counts=new Map;increment(e){let r=(this.counts.get(e)??0)+1;return this.counts.set(e,r),r}decrement(e){let r=Math.max(0,(this.counts.get(e)??0)-1);return this.counts.set(e,r),r}get(e){return this.counts.get(e)??0}},N=new U,L=new H;function ie(t){let e=N.getCV(t.name),r=L.get(t.name),n=t.concurrentLimit??1,d=Math.max(1,n-r),c=Math.max(1,Math.floor(e*2+.5));return Math.min(c,d)}import{WebSocketServer as Se}from"ws";var Te=3e4,_e=2,ue=64*1024,Ce=500,Me=500,xe=1e4,ae=new WeakMap,z=null,le=0,ce=0;function de(t){let e=Date.now();e-ce>=xe&&(console.warn(`[ws] Backpressure: dropping ${t} events (total dropped stream events: ${le})`),ce=e)}function J(t,e){let r=new Se({server:t,path:"/ws"});z=r,r.on("connection",n=>{let c={type:"summary",data:e.getSummary()};n.send(JSON.stringify(c));let i,o=0,u=()=>n.readyState===n.OPEN,m=e.onRecord(f=>{if(u()){if(n.bufferedAmount>ue){a(),de("metrics");return}setImmediate(()=>{if(!u())return;let g={type:"request",data:f};n.send(JSON.stringify(g))}),a()}});function a(){i||(i=setTimeout(()=>{if(i=void 0,!u())return;let f={type:"summary",data:e.getSummary()};n.send(JSON.stringify(f))},Ce))}let s=setInterval(()=>{if(!u()){clearInterval(s);return}if(o>=_e){l(),n.terminate();return}n.ping(),o++},Te);n.on("pong",()=>{o=0});let p=!1,l=()=>{p||(p=!0,clearInterval(s),i&&clearTimeout(i),m())};n.on("close",l),n.on("error",l)})}function P(t){if(!z)return;let e=JSON.stringify({type:"stream",data:t}),r=t.state==="streaming",n=t.state==="complete"||t.state==="error",d=Date.now();for(let c of z.clients)if(c.readyState===c.OPEN){if(r){let i=ae.get(c)??0;if(d-i<Me)continue;ae.set(c,d)}if(c.bufferedAmount>ue){if(n){let i=()=>{c.readyState===c.OPEN&&c.send(e)};c.once("drain",i),setTimeout(()=>{c.removeListener("drain",i),c.readyState===c.OPEN&&c.send(e)},5e3).unref();continue}le++,de("stream");continue}setImmediate(()=>{c.readyState===c.OPEN&&c.send(e)})}}var Ae=new Set(["anthropic-version","anthropic-beta","content-type","accept"]),Oe=/\/+/g,qe=/^https?:\/\/[^/]+/,F=/"model"\s*:\s*"([^"]*)"/,j=/"max_tokens"\s*:\s*(\d+)/,q=new TextEncoder,$e=3e3;function Ne(t){return t===429||t>=500}var Le=["context window","context_limit","token limit","prompt is too long","max tokens","input too large","too many tokens"];function Be(t,e){if(t!==400)return!1;let r=e.toLowerCase();return Le.some(n=>r.includes(n))}function De(t,e){if(!Be(t,e))return null;console.warn("[context-compact] Upstream context window limit detected");try{let n=me.join(Pe.homedir(),".claude","state");pe.mkdirSync(n,{recursive:!0}),pe.writeFileSync(me.join(n,"context-compact-needed"),Date.now().toString())}catch{}let r=JSON.stringify({type:"error",error:{type:"invalid_request_error",message:"Context window limit reached. Run /compact to reduce conversation size, then retry."}});return new Response(r,{status:400,headers:{"content-type":"application/json"}})}function je(t,e){let r="",n=t,d=t.indexOf("/",t.indexOf("//")+2);d!==-1&&(n=t.substring(0,d),r=t.substring(d));let c="",i=e,o=e.indexOf("?");o!==-1&&(i=e.substring(0,o),c=e.substring(o));let u;return r.endsWith("/v1")&&i.startsWith("/v1")?u=r+i.substring(3):u=r+i,u=u.replace(Oe,"/"),n+u+c}function We(t,e,r){let n=new Headers;for(let c of Ae){let i=t.get(c);i&&n.set(c,i)}e.authType==="bearer"?n.set("Authorization",`Bearer ${e.apiKey}`):n.set("x-api-key",e.apiKey),n.set("x-request-id",r);let d=e._cachedHost;if(d)n.set("host",d);else try{let c=new URL(e.baseUrl);n.set("host",c.host)}catch{}return n}function he(t){let e=t.messages;if(!Array.isArray(e))return;let r=new Set,n=new Set;for(let u=0;u<e.length;u++){let m=e[u];if(Array.isArray(m.content))for(let a of m.content)a.type==="tool_use"&&a.id?r.add(String(a.id)):a.type==="tool_result"&&a.tool_use_id&&n.add(String(a.tool_use_id))}let d=new Set,c=new Set;for(let u of r)n.has(u)||d.add(u);for(let u of n)r.has(u)||c.add(u);if(d.size===0&&c.size===0)return;let i=!1,o=e.map(u=>{if(!Array.isArray(u.content))return u;let m=u.content.filter(a=>!(a.type==="tool_use"&&d.has(String(a.id))||a.type==="tool_result"&&c.has(String(a.tool_use_id))));return m.length<u.content.length?(i=!0,{...u,content:m}):u});i&&(t.messages=o)}function Ue(t,e,r,n,d){if(d){let w=structuredClone(n);if(e.model&&(w.model=e.model),he(w),r.modelLimits){let{maxOutputTokens:_}=r.modelLimits,y=typeof w.max_tokens=="number"?w.max_tokens:_;(w.max_tokens===void 0||y>_)&&(w.max_tokens=Math.min(y,_))}return JSON.stringify(w)}let c=!!(e.model&&n.model!==e.model),i=!1,o=!1,u=0;if(r.modelLimits){u=r.modelLimits.maxOutputTokens;let w=j.exec(t);w?i=parseInt(w[1],10)>u:typeof n.max_tokens!="number"&&(o=!0)}if(!c&&!i&&!o)return t;if(o){let w={...n};return e.model&&(w.model=e.model),w.max_tokens=u,JSON.stringify(w)}let m=[];c&&m.push(F.source),i&&m.push(j.source);let a=new RegExp(m.join("|"),"g"),s=c?`"model":"${e.model}"`:null,p=i?`"max_tokens":${u}`:null,l=n.model,f=!1;return t.replace(a,w=>s&&F.test(w)?(F.lastIndex=0,!f&&l&&(console.warn(`Routing override: ${l} -> ${e.model} via ${r.name}`),f=!0),s):p&&j.test(w)?(j.lastIndex=0,p):w)}async function fe(t,e,r,n,d,c=0){let i=n.url.replace(qe,"");e.model&&(r.actualModel=e.model);let o=je(t.baseUrl,i),u;if((n.headers.get("content-type")||"").includes("application/json"))try{let h=r.parsedBody??JSON.parse(r.rawBody),b=!1;e.model&&h.model!==e.model&&(b=!0);let k=c>0;if(k&&(b=!0),t.modelLimits){let{maxOutputTokens:R}=t.modelLimits,C=typeof h.max_tokens=="number"?h.max_tokens:R;(h.max_tokens===void 0||C>R)&&(b=!0)}if(b)if(c===0&&!k)u=Ue(r.rawBody,e,t,h,!1);else{let R=structuredClone(h);if(e.model){let C=R.model;R.model=e.model,C&&C!==e.model&&console.warn(`Routing override: ${C} -> ${e.model} via ${t.name}`)}if(k&&he(R),t.modelLimits){let{maxOutputTokens:C}=t.modelLimits,M=typeof R.max_tokens=="number"?R.max_tokens:C;(R.max_tokens===void 0||M>C)&&(R.max_tokens=Math.min(M,C))}u=JSON.stringify(R)}else u=r.rawBody}catch{u=r.rawBody}else u=r.rawBody;let a=We(n.headers,t,r.requestId);a.set("content-length",Buffer.byteLength(u,"utf-8").toString());let s=new AbortController,p=setTimeout(()=>s.abort(),t.timeout),l=t.ttfbTimeout??15e3,f=!1,g=null,w=new Promise((h,b)=>{g=setTimeout(()=>{f=!0,s.abort(),b(new Error(`TTFB timeout after ${l}ms`))},l)}),_,y;if(d){if(d.aborted){clearTimeout(p),g&&clearTimeout(g);let b=JSON.stringify({type:"error",error:{type:"overloaded_error",message:`Provider "${t.name}" cancelled by race winner`}});return new Response(b,{status:502,headers:{"content-type":"application/json","content-length":q.encode(b).byteLength.toString()}})}let h=()=>{clearTimeout(p),g&&clearTimeout(g),setImmediate(()=>{if(y&&!y.destroyed)try{y.destroy()}catch{}})};d.addEventListener("abort",h,{once:!0}),_=()=>d.removeEventListener("abort",h)}try{let h=await Promise.race([Ee(o,{method:"POST",headers:a,body:u,signal:s.signal,dispatcher:t._agent}),w]);if(g&&clearTimeout(g),y=h.body,h.statusCode>=400){clearTimeout(p);let A=await h.body.text();return new Response(A,{status:h.statusCode,statusText:h.statusText,headers:h.headers})}let b=t.stallTimeout??3e4,k=new Ie,R=`Body stalled: no data after ${b}ms`,C=setTimeout(()=>{P({requestId:r.requestId,model:String(r.actualModel??e.model??""),tier:"",state:"error",message:R,timestamp:Date.now()}),k.destroy(new Error(R));try{y?.destroy(new Error(R))}catch{}},b);k.on("data",()=>{clearTimeout(C),C=setTimeout(()=>{P({requestId:r.requestId,model:String(r.actualModel??e.model??""),tier:"",state:"error",message:R,timestamp:Date.now()}),k.destroy(new Error(R));try{y?.destroy(new Error(R))}catch{}},b)}),k.on("end",()=>{clearTimeout(C)}),k.on("error",()=>{clearTimeout(C)}),h.body.pipe(k);let M=new Response(k,{status:h.statusCode,headers:h.headers});return clearTimeout(p),M}catch(h){clearTimeout(p),g&&clearTimeout(g);let b=f?`Provider "${t.name}" timed out waiting for first byte after ${l}ms`:h instanceof DOMException&&h.name==="AbortError"?`Provider "${t.name}" timed out after ${t.timeout}ms`:`Provider "${t.name}" connection failed: ${h.message}`,k=JSON.stringify({type:"error",error:{type:"overloaded_error",message:b}});return new Response(k,{status:502,headers:{"content-type":"application/json","content-length":q.encode(k).byteLength.toString()}})}finally{_?.()}}async function ge(t,e,r,n,d,c,i){let o=ie(t);if(o<=1){L.increment(t.name);let l=Date.now();try{let f=await fe(t,e,r,n,d,c);return N.record(t.name,Date.now()-l),f}finally{L.decrement(t.name)}}i?.warn("Hedging request",{requestId:r.requestId,provider:t.name,count:o,cv:Math.round(N.getCV(t.name)*100)/100,inFlight:L.get(t.name),maxConcurrent:t.concurrentLimit});let u=Date.now(),m=[];for(let l=0;l<o;l++)L.increment(t.name),m.push(fe(t,e,r,n,d,c).finally(()=>L.decrement(t.name)));let a=m.map((l,f)=>l.then(g=>({response:g,hedgeIndex:f}))),s=new Set,p=[];try{for(;s.size<a.length;){let l=a.filter((g,w)=>!s.has(w));if(l.length===0)break;let f=await Promise.race(l);if(s.add(f.hedgeIndex),t._circuitBreaker&&t._circuitBreaker.recordResult(f.response.status),f.response.status>=200&&f.response.status<300){N.record(t.name,Date.now()-u);for(let g=0;g<a.length;g++)s.has(g)||(t._circuitBreaker&&t._circuitBreaker.recordResult(502),a[g].then(w=>{try{w.response.body?.cancel()}catch{}}));for(let g of p)try{g.body?.cancel()}catch{}return f.response}p.push(f.response)}for(let l of p)try{l.body?.cancel()}catch{}return p[0]??new Response(JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${t.name}" all hedged requests failed`}}),{status:502,headers:{"content-type":"application/json"}})}catch{for(let l of p)try{l.body?.cancel()}catch{}return p[0]??new Response(JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${t.name}" hedging failed`}}),{status:502,headers:{"content-type":"application/json"}})}}async function ye(t,e,r,n,d,c){if(e.length<=1){let s=e[0],p=t.get(s.provider);if(!p){let f=JSON.stringify({type:"error",error:{type:"api_error",message:`Unknown provider: ${s.provider}`}});return new Response(f,{status:502,headers:{"content-type":"application/json","content-length":q.encode(f).byteLength.toString()}})}if(p._circuitBreaker&&!p._circuitBreaker.canProceed().allowed){c?.warn("Provider skipped by circuit breaker",{requestId:r.requestId,provider:s.provider});let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${s.provider}" skipped by circuit breaker`}});return new Response(g,{status:502,headers:{"content-type":"application/json","content-length":q.encode(g).byteLength.toString()}})}return d?.(s.provider,0),await ge(p,s,r,n,void 0,0,c)}let i=new AbortController,o=new Set,u=[];async function m(s){let p=e[s],l=t.get(p.provider);if(!l){let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Unknown provider: ${p.provider}`}});return{response:new Response(g,{status:502,headers:{"content-type":"application/json","content-length":q.encode(g).byteLength.toString()}}),index:s}}let f;if(l._circuitBreaker){let g=l._circuitBreaker.canProceed();if(!g.allowed){c?.warn("Provider skipped by circuit breaker",{requestId:r.requestId,provider:p.provider});let w=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${p.provider}" skipped by circuit breaker`}});return{response:new Response(w,{status:502,headers:{"content-type":"application/json","content-length":q.encode(w).byteLength.toString()}}),index:s}}f=g.probeId}d?.(p.provider,s);try{return{response:await ge(l,p,r,n,i.signal,s,c),index:s}}catch{l._circuitBreaker&&l._circuitBreaker.recordResult(502,f);let g=JSON.stringify({type:"error",error:{type:"api_error",message:`Provider "${p.provider}" failed`}});return{response:new Response(g,{status:502,headers:{"content-type":"application/json","content-length":q.encode(g).byteLength.toString()}}),index:s}}}let a=[];for(let s=0;s<e.length;s++)s===0?a.push(m(0)):a.push(new Promise(p=>{setTimeout(()=>{if(i.signal.aborted){let l=JSON.stringify({type:"error",error:{type:"api_error",message:"Cancelled by race winner"}});p({response:new Response(l,{status:502,headers:{"content-type":"application/json"}}),index:s});return}m(s).then(p)},$e)}));try{for(;o.size<a.length;){let p=a.filter((f,g)=>!o.has(g));if(p.length===0)break;let l=await Promise.race(p);if(o.add(l.index),l.response.status>=200&&l.response.status<300){i.abort();for(let f of u)try{f.response.body?.cancel()}catch{}return l.response}if(!Ne(l.response.status)){if(i.abort(),l.response.status===400&&l.response.body)try{let f=await l.response.text(),g=De(l.response.status,f);return g||new Response(f,{status:l.response.status,statusText:l.response.statusText,headers:l.response.headers})}catch{return l.response}return l.response}u.push(l)}if(i.abort(),u.length>0)return u[0].response;let s=JSON.stringify({type:"error",error:{type:"overloaded_error",message:"All providers failed"}});return new Response(s,{status:502,headers:{"content-type":"application/json","content-length":q.encode(s).byteLength.toString()}})}catch{i.abort();let s=JSON.stringify({type:"error",error:{type:"overloaded_error",message:"All providers failed"}});return new Response(s,{status:502,headers:{"content-type":"application/json","content-length":q.encode(s).byteLength.toString()}})}}import{randomUUID as ze}from"crypto";import{gzip as Je}from"zlib";import{promisify as Fe}from"util";var Ge=Fe(Je),G={"claude-opus-4-6":2e5,"claude-sonnet-4-6":2e5,"claude-haiku-4-5-20251001":2e5,"claude-3-5-sonnet":2e5,"claude-3-5-haiku":2e5,"glm-4.7":128e3,"glm-5-turbo":128e3};function K(t){if(G[t])return G[t];for(let[e,r]of Object.entries(G))if(t.startsWith(e))return r;return 0}function X(t,e,r){let n=r+t+e;return n<=0?0:Math.round(t/n*1e3)/10}function V(t,e,r,n,d){if(d<=0)return 0;let c=t+e+r+n;return Math.round(c/d*1e3)/10}function Q(t,e,r){return new Response(JSON.stringify({type:"error",error:{type:t,message:e}}),{status:502,headers:{"content-type":"application/json","x-request-id":r}})}function Ke(t){let e=t.message?.usage??t.usage;if(!e)return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0};let r=e.input_tokens??e.prompt_tokens??0,n=e.output_tokens??e.completion_tokens??0,d=e.cache_read_input_tokens??0,c=e.cache_creation_input_tokens??0;return{inputTokens:r,outputTokens:n,cacheReadTokens:d,cacheCreationTokens:c}}function Xe(t,e,r,n,d,c){let i=new TextDecoder,o={input:0,output:0,cacheRead:0,cacheCreation:0},u="",m="",a=4096,s=0,p=0,l=0,f=0,g="",w=null,_=250,y=0,h=!0,b="",k=100,R=S=>{for(let E of S.split(`
|
|
3
3
|
|
|
4
|
-
`)){if(!
|
|
5
|
-
`).find(
|
|
6
|
-
`).replace(/\\"/g,'"').replace(/\\\\/g,"\\");b+=D,b.length>
|
|
7
|
-
`).replace(/\\"/g,'"').replace(/\\\\/g,"\\");b+=
|
|
8
|
-
`);u=
|
|
9
|
-
`:"")+x;C&&m.trim()&&T(m);let R=Date.now();if(w||R-h>=M){h=R,w=!1;let x=K(t.actualModel||t.model);setImmediate(()=>{I({requestId:t.requestId,model:t.model,tier:t.tier,state:"streaming",outputTokens:r.output,timestamp:R,preview:b,cacheHitRate:X(r.cacheRead,r.cacheCreation,r.input),contextPercent:V(r.input,r.cacheRead,r.cacheCreation,r.output,x),contextWindowSize:x||void 0})})}C&&E(r.input,r.output,r.cacheRead,r.cacheCreation)}else{g+=S,g.length>a&&(g=g.slice(-a)),P(g);let _=Date.now();if(w||_-h>=M){h=_,w=!1;let R=K(t.actualModel||t.model);setImmediate(()=>{I({requestId:t.requestId,model:t.model,tier:t.tier,state:"streaming",outputTokens:f,timestamp:_,preview:b,cacheHitRate:X(p,l,s),contextPercent:V(s,p,l,f,R),contextWindowSize:R||void 0})})}C&&E(s,f,p,l)}};return new TransformStream({transform(S,C){C.enqueue(S),N(i.decode(S,{stream:!0}),!1)},flush(){N("",!0)}})}function be(t){let e=t._cachedOrigin,o=t.poolSize??10;return`${e??"unknown"}:${o}`}function Y(t,e,o){let n=t,d=Z(e),c=new He;return c.onError((i,r)=>(console.error(`[server] Unhandled error: ${i.message}`),r.json({type:"error",error:{type:"api_error",message:"Internal proxy error"}},{status:500,headers:{"content-type":"application/json"}}))),c.use("/api/*",async(i,r)=>{i.header("Access-Control-Allow-Origin","*"),await r()}),c.options("/api/*",i=>(i.header("Access-Control-Allow-Origin","*"),i.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),i.header("Access-Control-Allow-Headers","Content-Type, Authorization, anthropic-version, x-api-key"),i.body("",200))),c.post("/v1/messages",async i=>{let r=ze(),u,m;try{m=await i.req.text(),u=JSON.parse(m)}catch{return Q("invalid_request_error","Invalid JSON body",r)}let a=u.model;if(!a)return Q("invalid_request_error","Missing 'model' field in request body",r);let s=se(a,r,n,m);if(s&&(s.parsedBody=u),!s){d.info("No tier match",{requestId:r,model:a});let h=n.modelRouting.size>0?` Configured model routes: ${[...n.modelRouting.keys()].join(", ")}.`:"";return Q("invalid_request_error",`No route matches model "${a}". Configured tiers: ${[...n.tierPatterns.keys()].join(", ")}.${h}`,r)}d.info("Routing request",{requestId:r,model:a,tier:s.tier,providers:s.providerChain.map(h=>h.provider)}),I({requestId:r,model:a,tier:s.tier,state:"start",provider:s.providerChain[0]?.provider??"unknown",timestamp:Date.now()});let p="unknown",l;try{if(l=await ye(n.providers,s.providerChain,s,i.req.raw,(h,w)=>{d.info("Attempting provider",{requestId:r,provider:h,index:w,tier:s.tier}),p||(p=h)},d),l.status<400){let h=17;l.headers.forEach((w,b)=>{h+=b.length+w.length+4}),h+=2,setImmediate(()=>{I({requestId:r,model:a,tier:s.tier,state:"ttfb",status:l.status,headerSize:h,timestamp:Date.now()})})}}catch(h){let w=h instanceof Error?h.message:String(h);return d.error("Forward failed",{requestId:r,error:w}),setImmediate(()=>{I({requestId:r,model:a,tier:s.tier,state:"error",status:502,message:w,timestamp:Date.now()})}),i.json({type:"error",error:{type:"api_error",message:"Upstream request failed: "+w}},502)}l.status>=400&&setImmediate(()=>{I({requestId:r,model:a,tier:s.tier,state:"error",status:l.status,message:`HTTP ${l.status}`,timestamp:Date.now()})});let f=l.body;if(l.body&&l.status>=200&&l.status<300&&o){let h=s.providerChain.length>0?s.providerChain[0].provider:p,w=Xe(s,p,h,o,l.status,l.headers.get("content-type")||"");f=l.body.pipeThrough(w)}let g=new Headers(l.headers);g.set("x-request-id",r);let y=new Response(f,{status:l.status,statusText:l.statusText,headers:g}),M=Date.now()-s.startTime;return d.info("Request completed",{requestId:r,model:a,tier:s.tier,status:y.status,latencyMs:M}),y}),c.get("/api/metrics/summary",async i=>{if(!o)return i.json({error:"Metrics not enabled"},503);let r=o.getSummary(),u=JSON.stringify(r);if((i.req.header("accept-encoding")||"").includes("gzip")&&u.length>=1024){let a=await Ge(Buffer.from(u));return new Response(a,{status:200,headers:{"content-type":"application/json","content-encoding":"gzip",vary:"accept-encoding"}})}return i.json(r)}),c.get("/api/circuit-breaker",i=>{let r={};for(let[u,m]of n.providers){let a=m._circuitBreaker;if(a){let s=a.getStatus();r[u]={state:s.state,failures:s.failures,lastFailure:s.lastFailure?new Date(s.lastFailure).toISOString():null}}}return i.json(r)}),{app:c,getConfig:()=>n,setConfig:i=>{let r=new Map;for(let m of n.providers.values())m._agent&&r.set(be(m),m._agent);let u=new Set;for(let m of i.providers.values()){let a=be(m),s=r.get(a);s&&(m._agent=s,u.add(a))}for(let[m,a]of r)u.has(m)||a.close();n=i,re()}}}var W=class{buffer;maxSize;head=0;count=0;subscribers;createdAt;_totalInputTokens=0;_totalOutputTokens=0;_totalTokensPerSec=0;_totalCacheReadTokens=0;_totalCacheCreationTokens=0;_modelMap=new Map;_providerMap=new Map;constructor(e=1e3){this.buffer=new Array(e).fill(null),this.maxSize=e,this.subscribers=new Set,this.createdAt=Date.now()}recordRequest(e){let o=this.head%this.maxSize,n=this.count>=this.maxSize?this.buffer[o]:null;if(n!==null){this._totalInputTokens-=n.inputTokens??0,this._totalOutputTokens-=n.outputTokens??0,this._totalTokensPerSec-=n.tokensPerSec??0,this._totalCacheReadTokens-=n.cacheReadTokens??0,this._totalCacheCreationTokens-=n.cacheCreationTokens??0;let r=n.model,u=this._modelMap.get(r);u&&(u.count--,u.count<=0&&this._modelMap.delete(r));let m=n.targetProvider??n.provider,a=this._providerMap.get(m)??0;a<=1?this._providerMap.delete(m):this._providerMap.set(m,a-1)}this._totalInputTokens+=e.inputTokens??0,this._totalOutputTokens+=e.outputTokens??0,this._totalTokensPerSec+=e.tokensPerSec??0,this._totalCacheReadTokens+=e.cacheReadTokens??0,this._totalCacheCreationTokens+=e.cacheCreationTokens??0;let d=e.model,c=this._modelMap.get(d);c?(c.count++,e.timestamp>c.lastSeen&&(c.lastSeen=e.timestamp),c.actualModel=e.actualModel):this._modelMap.set(d,{actualModel:e.actualModel,count:1,lastSeen:e.timestamp});let i=e.targetProvider??e.provider;this._providerMap.set(i,(this._providerMap.get(i)??0)+1),this.buffer[o]=e,this.head++,this.count<this.maxSize&&this.count++;for(let r of this.subscribers)try{r(e)}catch{}}getSummary(){let e=this.getRecentRequests(),o=[...this._modelMap.entries()].map(([i,{actualModel:r,count:u,lastSeen:m}])=>({model:i,actualModel:r,count:u,lastSeen:m})).sort((i,r)=>r.count-i.count),n=[...this._providerMap.entries()].map(([i,r])=>({provider:i,count:r})).sort((i,r)=>r.count-i.count),d=0,c=0;for(let i of e){let r=(i.inputTokens??0)+(i.cacheReadTokens??0)+(i.cacheCreationTokens??0);r>0&&(i.cacheReadTokens??0)>0&&(d+=i.cacheReadTokens/r*100,c++)}return{totalRequests:this.count,totalInputTokens:this._totalInputTokens,totalOutputTokens:this._totalOutputTokens,avgTokensPerSec:this.count>0?Math.round(this._totalTokensPerSec/this.count*10)/10:0,totalCacheReadTokens:this._totalCacheReadTokens,totalCacheCreationTokens:this._totalCacheCreationTokens,avgCacheHitRate:c>0?Math.round(d/c*10)/10:0,activeModels:o,providerDistribution:n,recentRequests:e,uptimeSeconds:Math.floor((Date.now()-this.createdAt)/1e3)}}onRecord(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}getRecentRequests(){if(this.count===0)return[];let e=Math.min(this.count,50),o=[];for(let n=0;n<e;n++){let d=((this.head-1-n)%this.maxSize+this.maxSize)%this.maxSize,c=this.buffer[d];c!==null&&o.push(c)}return o.reverse(),o}};import{spawn as Ve}from"child_process";import{existsSync as Qe,unlinkSync as Ye}from"fs";import{dirname as Ze,join as et}from"path";import{fileURLToPath as tt}from"url";async function we(t){let e=te();Qe(e)&&Ye(e),await ne(process.pid);let o=process.argv[1]||et(Ze(tt(import.meta.url)),"index.js");process.on("uncaughtException",f=>{console.error(`[monitor] Uncaught exception: ${f.message}`)}),process.on("unhandledRejection",f=>{console.error(`[monitor] Unhandled rejection: ${f}`)});let n=10,d=1e3,c=3e4,i=6e4,r=0,u=null,m=null,a=!1,s=!1,p=null;function l(){let f=[o,"--daemon"];t.config&&f.push("--config",t.config),t.port&&f.push("--port",String(t.port)),t.verbose&&f.push("--verbose"),p=Ve(process.execPath,f,{detached:!0,stdio:"ignore",env:{...process.env}}),u&&clearTimeout(u),u=setTimeout(()=>{r>0&&console.error(`[monitor] Worker stable for ${i}ms, resetting restart counter`),r=0,u=null},i),p.on("exit",async g=>{p=null,u&&(clearTimeout(u),u=null),await oe(),g===0&&!s&&(await B(),process.exit(0)),s=!1,a&&(console.error("[monitor] Worker exited during shutdown, monitor exiting"),await B(),process.exit(0));let y=r;y>=n&&(console.error(`[monitor] Max restart attempts exhausted (${n}), monitor exiting`),await B(),process.exit(1));let M=Math.min(d*2**y,c);r++,console.error(`[monitor] Worker died (code ${g}), restarting in ${M}ms (attempt ${r}/${n})`),m=setTimeout(l,M)})}process.on("SIGTERM",()=>{if(a=!0,m&&(clearTimeout(m),m=null),u&&(clearTimeout(u),u=null),p){try{p.kill("SIGTERM")}catch{}setTimeout(()=>{console.error("[monitor] Child did not exit within 5 s, forcing exit"),process.exit(0)},5e3)}else B().then(()=>process.exit(0))}),process.on("SIGINT",()=>{if(a=!0,m&&(clearTimeout(m),m=null),u&&(clearTimeout(u),u=null),p){try{p.kill("SIGTERM")}catch{}setTimeout(()=>{console.error("[monitor] Child did not exit within 5 s, forcing exit"),process.exit(0)},5e3)}else B().then(()=>process.exit(0))}),process.on("SIGHUP",()=>{if(console.log("[monitor] Received reload signal, restarting worker..."),s=!0,m&&(clearTimeout(m),m=null),p)try{p.kill("SIGTERM")}catch{}r=0}),l()}var ot=JSON.parse(nt(new URL("../package.json",import.meta.url),"utf-8")).version;function rt(t){let e={verbose:!1,help:!1,daemon:!1,monitor:!1,gui:!1};for(let o=2;o<t.length;o++)switch(t[o]){case"-p":case"--port":let n=t[++o];(!n||isNaN(parseInt(n,10)))&&(console.error("Error: -p/--port requires a number"),process.exit(1)),e.port=parseInt(n,10);break;case"-c":case"--config":let d=t[++o];d||(console.error("Error: -c/--config requires a path"),process.exit(1)),e.config=d;break;case"-v":case"--verbose":e.verbose=!0;break;case"-h":case"--help":e.help=!0;break;case"--daemon":e.daemon=!0;break;case"--monitor":e.monitor=!0;break}return e}function st(){console.log(`
|
|
4
|
+
`)){if(!E)continue;let x=E.split(`
|
|
5
|
+
`).find(T=>T.startsWith("data:"));if(x)try{let T=JSON.parse(x.slice(5));if(x.includes('"usage"')){let v=Ke(T);v.inputTokens>o.input&&(o.input=v.inputTokens),v.outputTokens>o.output&&(o.output=v.outputTokens),v.cacheReadTokens>o.cacheRead&&(o.cacheRead=v.cacheReadTokens),v.cacheCreationTokens>o.cacheCreation&&(o.cacheCreation=v.cacheCreationTokens)}let I=T.delta;I&&typeof I.text=="string"&&(b+=I.text,b.length>k&&(b=b.slice(-k)));let O=T.choices;if(O?.[0]){let v=O[0].delta;v&&typeof v.content=="string"&&(b+=v.content,b.length>k&&(b=b.slice(-k)))}}catch{}}},C=S=>{if(!S.includes('"usage"')){let v=[...S.matchAll(/"text"\s*:\s*"((?:[^"\\]|\\.)*)"/g)];if(v.length>0){let D=v[v.length-1][1].replace(/\\n/g,`
|
|
6
|
+
`).replace(/\\"/g,'"').replace(/\\\\/g,"\\");b+=D,b.length>k&&(b=b.slice(-k))}return}let E=[...S.matchAll(/"(?:input_tokens|prompt_tokens)"\s*:\s*(\d+)/g)],x=[...S.matchAll(/"cache_read_input_tokens"\s*:\s*(\d+)/g)],T=[...S.matchAll(/"cache_creation_input_tokens"\s*:\s*(\d+)/g)],I=[...S.matchAll(/"(?:output_tokens|completion_tokens)"\s*:\s*(\d+)/g)];if(E.length>0){let v=parseInt(E[E.length-1][1],10);v>s&&(s=v)}if(x.length>0){let v=parseInt(x[x.length-1][1],10);v>p&&(p=v)}if(T.length>0){let v=parseInt(T[T.length-1][1],10);v>l&&(l=v)}if(I.length>0){let v=parseInt(I[I.length-1][1],10);v>f&&(f=v)}let O=[...S.matchAll(/"text"\s*:\s*"((?:[^"\\]|\\.)*)"/g)];if(O.length>0){let v=O[O.length-1][1].replace(/\\n/g,`
|
|
7
|
+
`).replace(/\\"/g,'"').replace(/\\\\/g,"\\");b+=v,b.length>k&&(b=b.slice(-k))}},M=(S,E,x=0,T=0)=>{try{let I=Date.now()-t.startTime,O=I/1e3,v=O>0?E/O:0;n.recordRequest({requestId:t.requestId,model:t.model,actualModel:t.actualModel||t.model,tier:t.tier,provider:e,targetProvider:r,status:d,inputTokens:S,outputTokens:E,latencyMs:I,tokensPerSec:Math.round(v*10)/10,timestamp:Date.now(),fallbackMode:t.fallbackMode,cacheReadTokens:x,cacheCreationTokens:T});let D=K(t.actualModel||t.model);setImmediate(()=>{P({requestId:t.requestId,model:t.model,tier:t.tier,state:"complete",status:d,latencyMs:Date.now()-t.startTime,inputTokens:S,outputTokens:E,tokensPerSec:Math.round(v*10)/10,timestamp:Date.now(),cacheReadTokens:x,cacheCreationTokens:T,cacheHitRate:X(x,T,S),contextPercent:V(S,x,T,E,D),contextWindowSize:D||void 0})})}catch{}},A=(S,E)=>{if(w===null&&(w=c.includes("text/event-stream")||S.startsWith("event:")),w){u+=S;let x=u.split(`
|
|
8
|
+
`);u=x.pop();for(let I of x)I===""?m&&(R(m),m=""):m+=(m?`
|
|
9
|
+
`:"")+I;E&&m.trim()&&R(m);let T=Date.now();if(h||T-y>=_){y=T,h=!1;let I=K(t.actualModel||t.model);setImmediate(()=>{P({requestId:t.requestId,model:t.model,tier:t.tier,state:"streaming",outputTokens:o.output,timestamp:T,preview:b,cacheHitRate:X(o.cacheRead,o.cacheCreation,o.input),contextPercent:V(o.input,o.cacheRead,o.cacheCreation,o.output,I),contextWindowSize:I||void 0})})}E&&M(o.input,o.output,o.cacheRead,o.cacheCreation)}else{g+=S,g.length>a&&(g=g.slice(-a)),C(g);let x=Date.now();if(h||x-y>=_){y=x,h=!1;let T=K(t.actualModel||t.model);setImmediate(()=>{P({requestId:t.requestId,model:t.model,tier:t.tier,state:"streaming",outputTokens:f,timestamp:x,preview:b,cacheHitRate:X(p,l,s),contextPercent:V(s,p,l,f,T),contextWindowSize:T||void 0})})}E&&M(s,f,p,l)}};return new TransformStream({transform(S,E){E.enqueue(S),A(i.decode(S,{stream:!0}),!1)},flush(){A("",!0)}})}function we(t){let e=t._cachedOrigin,r=t.poolSize??10;return`${e??"unknown"}:${r}`}function Y(t,e,r){let n=t,d=Z(e),c=new He;return c.onError((i,o)=>(console.error(`[server] Unhandled error: ${i.message}`),o.json({type:"error",error:{type:"api_error",message:"Internal proxy error"}},{status:500,headers:{"content-type":"application/json"}}))),c.use("/api/*",async(i,o)=>{i.header("Access-Control-Allow-Origin","*"),await o()}),c.options("/api/*",i=>(i.header("Access-Control-Allow-Origin","*"),i.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),i.header("Access-Control-Allow-Headers","Content-Type, Authorization, anthropic-version, x-api-key"),i.body("",200))),c.post("/v1/messages",async i=>{let o=ze(),u,m;try{m=await i.req.text(),u=JSON.parse(m)}catch{return Q("invalid_request_error","Invalid JSON body",o)}let a=u.model;if(!a)return Q("invalid_request_error","Missing 'model' field in request body",o);let s=se(a,o,n,m);if(s&&(s.parsedBody=u),!s){d.info("No tier match",{requestId:o,model:a});let y=n.modelRouting.size>0?` Configured model routes: ${[...n.modelRouting.keys()].join(", ")}.`:"";return Q("invalid_request_error",`No route matches model "${a}". Configured tiers: ${[...n.tierPatterns.keys()].join(", ")}.${y}`,o)}d.info("Routing request",{requestId:o,model:a,tier:s.tier,providers:s.providerChain.map(y=>y.provider)}),P({requestId:o,model:a,tier:s.tier,state:"start",provider:s.providerChain[0]?.provider??"unknown",timestamp:Date.now()});let p="unknown",l;try{if(l=await ye(n.providers,s.providerChain,s,i.req.raw,(y,h)=>{d.info("Attempting provider",{requestId:o,provider:y,index:h,tier:s.tier}),p||(p=y)},d),l.status<400){let y=17;l.headers.forEach((h,b)=>{y+=b.length+h.length+4}),y+=2,setImmediate(()=>{P({requestId:o,model:a,tier:s.tier,state:"ttfb",status:l.status,headerSize:y,timestamp:Date.now()})})}}catch(y){let h=y instanceof Error?y.message:String(y);return d.error("Forward failed",{requestId:o,error:h}),setImmediate(()=>{P({requestId:o,model:a,tier:s.tier,state:"error",status:502,message:h,timestamp:Date.now()})}),i.json({type:"error",error:{type:"api_error",message:"Upstream request failed: "+h}},502)}l.status>=400&&setImmediate(()=>{P({requestId:o,model:a,tier:s.tier,state:"error",status:l.status,message:`HTTP ${l.status}`,timestamp:Date.now()})});let f=l.body;if(l.body&&l.status>=200&&l.status<300&&r){let y=s.providerChain.length>0?s.providerChain[0].provider:p,h=Xe(s,p,y,r,l.status,l.headers.get("content-type")||"");f=l.body.pipeThrough(h)}let g=new Headers(l.headers);g.set("x-request-id",o);let w=new Response(f,{status:l.status,statusText:l.statusText,headers:g}),_=Date.now()-s.startTime;return d.info("Request completed",{requestId:o,model:a,tier:s.tier,status:w.status,latencyMs:_}),w}),c.get("/api/metrics/summary",async i=>{if(!r)return i.json({error:"Metrics not enabled"},503);let o=r.getSummary(),u=JSON.stringify(o);if((i.req.header("accept-encoding")||"").includes("gzip")&&u.length>=1024){let a=await Ge(Buffer.from(u));return new Response(a,{status:200,headers:{"content-type":"application/json","content-encoding":"gzip",vary:"accept-encoding"}})}return i.json(o)}),c.get("/api/circuit-breaker",i=>{let o={};for(let[u,m]of n.providers){let a=m._circuitBreaker;if(a){let s=a.getStatus();o[u]={state:s.state,failures:s.failures,lastFailure:s.lastFailure?new Date(s.lastFailure).toISOString():null}}}return i.json(o)}),{app:c,getConfig:()=>n,setConfig:i=>{let o=new Map;for(let m of n.providers.values())m._agent&&o.set(we(m),m._agent);let u=new Set;for(let m of i.providers.values()){let a=we(m),s=o.get(a);s&&(m._agent=s,u.add(a))}for(let[m,a]of o)u.has(m)||a.close();n=i,oe()}}}var W=class{buffer;maxSize;head=0;count=0;subscribers;createdAt;_totalInputTokens=0;_totalOutputTokens=0;_totalTokensPerSec=0;_totalCacheReadTokens=0;_totalCacheCreationTokens=0;_modelMap=new Map;_providerMap=new Map;constructor(e=1e3){this.buffer=new Array(e).fill(null),this.maxSize=e,this.subscribers=new Set,this.createdAt=Date.now()}recordRequest(e){let r=this.head%this.maxSize,n=this.count>=this.maxSize?this.buffer[r]:null;if(n!==null){this._totalInputTokens-=n.inputTokens??0,this._totalOutputTokens-=n.outputTokens??0,this._totalTokensPerSec-=n.tokensPerSec??0,this._totalCacheReadTokens-=n.cacheReadTokens??0,this._totalCacheCreationTokens-=n.cacheCreationTokens??0;let o=n.model,u=this._modelMap.get(o);u&&(u.count--,u.count<=0&&this._modelMap.delete(o));let m=n.targetProvider??n.provider,a=this._providerMap.get(m)??0;a<=1?this._providerMap.delete(m):this._providerMap.set(m,a-1)}this._totalInputTokens+=e.inputTokens??0,this._totalOutputTokens+=e.outputTokens??0,this._totalTokensPerSec+=e.tokensPerSec??0,this._totalCacheReadTokens+=e.cacheReadTokens??0,this._totalCacheCreationTokens+=e.cacheCreationTokens??0;let d=e.model,c=this._modelMap.get(d);c?(c.count++,e.timestamp>c.lastSeen&&(c.lastSeen=e.timestamp),c.actualModel=e.actualModel):this._modelMap.set(d,{actualModel:e.actualModel,count:1,lastSeen:e.timestamp});let i=e.targetProvider??e.provider;this._providerMap.set(i,(this._providerMap.get(i)??0)+1),this.buffer[r]=e,this.head++,this.count<this.maxSize&&this.count++;for(let o of this.subscribers)try{o(e)}catch{}}getSummary(){let e=this.getRecentRequests(),r=[...this._modelMap.entries()].map(([i,{actualModel:o,count:u,lastSeen:m}])=>({model:i,actualModel:o,count:u,lastSeen:m})).sort((i,o)=>o.count-i.count),n=[...this._providerMap.entries()].map(([i,o])=>({provider:i,count:o})).sort((i,o)=>o.count-i.count),d=0,c=0;for(let i of e){let o=(i.inputTokens??0)+(i.cacheReadTokens??0)+(i.cacheCreationTokens??0);o>0&&(i.cacheReadTokens??0)>0&&(d+=i.cacheReadTokens/o*100,c++)}return{totalRequests:this.count,totalInputTokens:this._totalInputTokens,totalOutputTokens:this._totalOutputTokens,avgTokensPerSec:this.count>0?Math.round(this._totalTokensPerSec/this.count*10)/10:0,totalCacheReadTokens:this._totalCacheReadTokens,totalCacheCreationTokens:this._totalCacheCreationTokens,avgCacheHitRate:c>0?Math.round(d/c*10)/10:0,activeModels:r,providerDistribution:n,recentRequests:e,uptimeSeconds:Math.floor((Date.now()-this.createdAt)/1e3)}}onRecord(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}getRecentRequests(){if(this.count===0)return[];let e=Math.min(this.count,50),r=[];for(let n=0;n<e;n++){let d=((this.head-1-n)%this.maxSize+this.maxSize)%this.maxSize,c=this.buffer[d];c!==null&&r.push(c)}return r.reverse(),r}};import{spawn as Ve}from"child_process";import{existsSync as Qe,unlinkSync as Ye}from"fs";import{dirname as Ze,join as et}from"path";import{fileURLToPath as tt}from"url";async function be(t){let e=te();Qe(e)&&Ye(e),await ne(process.pid);let r=process.argv[1]||et(Ze(tt(import.meta.url)),"index.js");process.on("uncaughtException",f=>{console.error(`[monitor] Uncaught exception: ${f.message}`)}),process.on("unhandledRejection",f=>{console.error(`[monitor] Unhandled rejection: ${f}`)});let n=10,d=1e3,c=3e4,i=6e4,o=0,u=null,m=null,a=!1,s=!1,p=null;async function l(){let f=await import("net");if(await new Promise(_=>{let y=f.createServer();y.once("error",()=>_(!0)),y.once("listening",()=>{y.close(()=>_(!1))}),y.listen(t.port??3456)})){console.error(`[monitor] Port ${t.port??3456} already in use, skipping worker spawn`);return}let w=[r,"--daemon"];t.config&&w.push("--config",t.config),t.port&&w.push("--port",String(t.port)),t.verbose&&w.push("--verbose"),p=Ve(process.execPath,w,{detached:!0,stdio:"ignore",env:{...process.env}}),u&&clearTimeout(u),u=setTimeout(()=>{o>0&&console.error(`[monitor] Worker stable for ${i}ms, resetting restart counter`),o=0,u=null},i),p.on("exit",async _=>{p=null,u&&(clearTimeout(u),u=null),await re(),_===0&&!s&&(await B(),process.exit(0)),s=!1,a&&(console.error("[monitor] Worker exited during shutdown, monitor exiting"),await B(),process.exit(0));let y=o;y>=n&&(console.error(`[monitor] Max restart attempts exhausted (${n}), monitor exiting`),await B(),process.exit(1));let h=Math.min(d*2**y,c);o++,console.error(`[monitor] Worker died (code ${_}), restarting in ${h}ms (attempt ${o}/${n})`),m=setTimeout(l,h)})}process.on("SIGTERM",()=>{if(a=!0,m&&(clearTimeout(m),m=null),u&&(clearTimeout(u),u=null),p){try{p.kill("SIGTERM")}catch{}setTimeout(()=>{console.error("[monitor] Child did not exit within 5 s, forcing exit"),process.exit(0)},5e3)}else B().then(()=>process.exit(0))}),process.on("SIGINT",()=>{if(a=!0,m&&(clearTimeout(m),m=null),u&&(clearTimeout(u),u=null),p){try{p.kill("SIGTERM")}catch{}setTimeout(()=>{console.error("[monitor] Child did not exit within 5 s, forcing exit"),process.exit(0)},5e3)}else B().then(()=>process.exit(0))}),process.on("SIGHUP",()=>{if(console.log("[monitor] Received reload signal, restarting worker..."),s=!0,m&&(clearTimeout(m),m=null),p)try{p.kill("SIGTERM")}catch{}o=0}),l()}var rt=JSON.parse(nt(new URL("../package.json",import.meta.url),"utf-8")).version;function ot(t){let e={verbose:!1,help:!1,daemon:!1,monitor:!1,gui:!1};for(let r=2;r<t.length;r++)switch(t[r]){case"-p":case"--port":let n=t[++r];(!n||isNaN(parseInt(n,10)))&&(console.error("Error: -p/--port requires a number"),process.exit(1)),e.port=parseInt(n,10);break;case"-c":case"--config":let d=t[++r];d||(console.error("Error: -c/--config requires a path"),process.exit(1)),e.config=d;break;case"-v":case"--verbose":e.verbose=!0;break;case"-h":case"--help":e.help=!0;break;case"--daemon":e.daemon=!0;break;case"--monitor":e.monitor=!0;break}return e}function st(){console.log(`
|
|
10
10
|
ModelWeaver \u2014 Multi-provider model orchestration proxy for Claude Code
|
|
11
11
|
|
|
12
12
|
Usage: modelweaver [command] [options]
|
|
@@ -31,8 +31,8 @@ Options:
|
|
|
31
31
|
Config locations (first found wins):
|
|
32
32
|
./modelweaver.yaml
|
|
33
33
|
~/.modelweaver/config.yaml
|
|
34
|
-
`)}async function it(){let t=
|
|
35
|
-
ModelWeaver v${
|
|
36
|
-
`),console.log(" Routes:");for(let[a,s]of e.routing){let p=s.map((l,f)=>`${l.provider}${f===0?" (primary)":" (fallback)"}`).join(", ");console.log(` ${a.padEnd(8)} \u2192 ${p}`)}if(console.log(),e.modelRouting.size>0){console.log(" Model Routes:");for(let[a,s]of e.modelRouting){let p=s.map((l,f)=>`${l.provider}${f===0?" (primary)":" (fallback)"}`).join(", ");console.log(` ${a.padEnd(20)} \u2192 ${p}`)}console.log()}let u=ve({fetch:
|
|
34
|
+
`)}async function it(){let t=ot(process.argv);try{let a=await import("dotenv"),{existsSync:s}=await import("fs"),{join:p}=await import("path"),l=process.env.HOME||process.env.USERPROFILE||"",f=[p(process.cwd(),".env"),p(l,".modelweaver",".env"),p(l,".env")];for(let g of f)if(s(g)){a.config({path:g});break}}catch{}if(process.argv[2]==="init"){let a=process.argv.includes("--quick")||process.argv.includes("-q"),{runInit:s}=await import("./init-VLTKSOZN.js");await s({quick:a}),process.exit(0)}if(process.argv[2]==="start"){let{startDaemon:a}=await import("./daemon-27GXX25D.js"),s=await a(t.config,t.port,t.verbose);console.log(` ${s.message}`),console.log(` Log file: ${s.logPath}`),process.exit(s.success?0:1)}if(process.argv[2]==="stop"){let{stopDaemon:a}=await import("./daemon-27GXX25D.js"),s=await a();console.log(` ${s.message}`),process.exit(s.success?0:1)}if(process.argv[2]==="status"){let{statusDaemon:a}=await import("./daemon-27GXX25D.js"),s=await a();console.log(` ${s.message}`);try{let{getService:p}=await import("./service-6EQTZJEG.js"),f=(await p()).isInstalled();console.log(f?" Service: installed":' Service: not installed (run "modelweaver install" to enable auto-start)')}catch(p){console.log(` Service: ${p instanceof Error?p.message:String(p)}`)}process.exit(0)}if(process.argv[2]==="remove"){let{removeDaemon:a}=await import("./daemon-27GXX25D.js"),s=await a();console.log(` ${s.message}`),process.exit(s.success?0:1)}if(process.argv[2]==="install"){try{let{getService:a}=await import("./service-6EQTZJEG.js");await(await a()).install()}catch(a){console.error(` Error: ${a instanceof Error?a.message:String(a)}`),process.exit(1)}process.exit(0)}if(process.argv[2]==="uninstall"){try{let{getService:a}=await import("./service-6EQTZJEG.js");(await a()).uninstall()}catch(a){console.error(` Error: ${a instanceof Error?a.message:String(a)}`),process.exit(1)}process.exit(0)}if(process.argv[2]==="gui"){let{launchGui:a}=await import("./gui-launcher-ZVOVTD6C.js");await a(),process.exit(0)}if(process.argv[2]==="reload"){let{reloadDaemon:a}=await import("./daemon-27GXX25D.js");await a(t.port),process.exit(0)}t.help&&(st(),process.exit(0));let e,r;try{let a=await ee(t.config);e=a.config,r=a.configPath}catch(a){console.error(`Config error: ${a.message}`),process.exit(1)}let n=t.port||e.server.port,d=e.server.host,c=t.verbose?"debug":"info",i=new W;if(t.monitor){await be(t);return}if(t.daemon){let{removeWorkerPidFile:a,writeWorkerPidFile:s,createDebouncedReload:p,getLogPath:l}=await import("./daemon-27GXX25D.js"),{reloadConfig:f}=await import("./config-P34YQCFG.js"),{createWriteStream:g,watch:w}=await import("fs"),{createLogger:_}=await import("./logger-UA2A2DVX.js"),y=_(c);process.on("uncaughtException",M=>{y.error("Uncaught exception (daemon survived)",{error:M.message,stack:M.stack})}),process.on("unhandledRejection",M=>{y.error("Unhandled rejection (daemon survived)",{reason:String(M)})}),await s(process.pid);let h=g(l(),{flags:"a"});h.on("error",()=>{}),process.stdout.write=h.write.bind(h),process.stderr.write=h.write.bind(h);let b=Y(e,c,i),k=null;if(r){let M=p(async()=>{try{let A=await f(r);b.setConfig(A),N.prune([...A.providers.keys()]),y.info("Config reloaded",{path:r})}catch(A){y.error("Config reload failed \u2014 keeping old config",{error:A.message})}},300);try{k=w(r,()=>{M.reload()}),k.on("error",()=>{k&&(k.close(),k=null)})}catch{}}process.on("SIGUSR1",async()=>{try{let M=await f(r);b.setConfig(M),N.prune([...M.providers.keys()]),y.info("Config reloaded (SIGUSR1)",{path:r})}catch(M){y.error("Config reload failed (SIGUSR1)",{error:M.message})}});let R=ve({fetch:b.app.fetch,hostname:d,port:n});J(R,i);let C=async()=>{k&&(k.close(),k=null),await a(),h.end(),process.exit(0)};process.on("SIGTERM",C),process.on("SIGINT",C);return}let o=Y(e,c,i);console.log(`
|
|
35
|
+
ModelWeaver v${rt}`),console.log(` Listening: http://${d}:${n}`),console.log(` Config: ${r}
|
|
36
|
+
`),console.log(" Routes:");for(let[a,s]of e.routing){let p=s.map((l,f)=>`${l.provider}${f===0?" (primary)":" (fallback)"}`).join(", ");console.log(` ${a.padEnd(8)} \u2192 ${p}`)}if(console.log(),e.modelRouting.size>0){console.log(" Model Routes:");for(let[a,s]of e.modelRouting){let p=s.map((l,f)=>`${l.provider}${f===0?" (primary)":" (fallback)"}`).join(", ");console.log(` ${a.padEnd(20)} \u2192 ${p}`)}console.log()}let u=ve({fetch:o.app.fetch,hostname:d,port:n});J(u,i);let m=()=>{console.log(`
|
|
37
37
|
Shutting down...`),process.exit(0)};process.on("SIGTERM",m),process.on("SIGINT",m)}it();
|
|
38
38
|
//# sourceMappingURL=index.js.map
|