@killingjacky/claude-code-router 2.1.0 → 2.2.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 +53 -19
- package/dist/cli.js +234 -238
- package/dist/main/cli.js +8896 -0
- package/dist/main/fusion-tool-fallback-mcp.js +5 -0
- package/dist/main/fusion-vision-mcp.js +10 -0
- package/dist/main/gateway-bootstrap.js +2 -0
- package/dist/main/local-agent-auth-provider-hook.js +294 -0
- package/dist/main/media-tools-proxy-mcp.js +6 -0
- package/dist/main/request-log-worker.js +951 -0
- package/dist/main/route-script-worker.js +61 -0
- package/dist/main/toolhub-mcp.js +48 -0
- package/dist/main/upstream-header-sanitizer.js +1 -0
- package/dist/models.json +657155 -0
- package/dist/renderer/assets/assets/anthropic-CJYB5ODC.png +0 -0
- package/dist/renderer/assets/assets/bailian-6RH6ASGG.ico +0 -0
- package/dist/renderer/assets/assets/claude-code-WX35JWK4.png +0 -0
- package/dist/renderer/assets/assets/claudeapi-A6VUG2I3.png +0 -0
- package/dist/renderer/assets/assets/code0-XF6QJ6WD.png +0 -0
- package/dist/renderer/assets/assets/codex-3X2KBXKY.png +0 -0
- package/dist/renderer/assets/assets/deepseek-ZIDCDTQF.ico +0 -0
- package/dist/renderer/assets/assets/fenno-XFKUO3XQ.jpg +0 -0
- package/dist/renderer/assets/assets/gemini-7QB7T63T.svg +1 -0
- package/dist/renderer/assets/assets/grok-RUIG6CO6.ico +0 -0
- package/dist/renderer/assets/assets/infistar-ai-QGWTTUZK.jpg +0 -0
- package/dist/renderer/assets/assets/kilo-WKXQUJ25.svg +13 -0
- package/dist/renderer/assets/assets/logo-IPLFWCDN.png +0 -0
- package/dist/renderer/assets/assets/mascot-transition-DUBPNIIV.svg +100 -0
- package/dist/renderer/assets/assets/minimax-5TL6POE3.ico +0 -0
- package/dist/renderer/assets/assets/mistral-2RFSC6K3.webp +0 -0
- package/dist/renderer/assets/assets/moonshot-FNEXMLNW.ico +0 -0
- package/dist/renderer/assets/assets/nvidia-CCRWBFBH.svg +1 -0
- package/dist/renderer/assets/assets/openai-2EIP7LI2.png +0 -0
- package/dist/renderer/assets/assets/opencode-CEWXDOQI.ico +0 -0
- package/dist/renderer/assets/assets/openrouter-CZIFREDB.ico +0 -0
- package/dist/renderer/assets/assets/pi-O6OOC4YY.svg +21 -0
- package/dist/renderer/assets/assets/qiniu-ai-A5VJAOJ6.png +0 -0
- package/dist/renderer/assets/assets/runapi-UAX35AOL.jpg +0 -0
- package/dist/renderer/assets/assets/siliconflow-QCZUQAH2.png +0 -0
- package/dist/renderer/assets/assets/teamorouter-3LCEETRZ.png +0 -0
- package/dist/renderer/assets/assets/tray-cyan-C3U4WBE7.png +0 -0
- package/dist/renderer/assets/assets/tray-orange-VUJTRHBB.png +0 -0
- package/dist/renderer/assets/assets/tray-violet-EGMLZ2GB.png +0 -0
- package/dist/renderer/assets/assets/unity2-QCJYG2D6.jpg +0 -0
- package/dist/renderer/assets/assets/workbuddy-LBUELROU.png +0 -0
- package/dist/renderer/assets/assets/xiaomi-mimo-LQ6RRXCR.png +0 -0
- package/dist/renderer/assets/assets/zai-global-coding-OMCES3LL.svg +219 -0
- package/dist/renderer/assets/assets/zai-global-general-OMCES3LL.svg +219 -0
- package/dist/renderer/assets/assets/zcode-Z7V7YY2Q.png +0 -0
- package/dist/renderer/assets/assets/zhipu-cn-coding-7BBWPUTC.png +0 -0
- package/dist/renderer/assets/assets/zhipu-cn-general-7BBWPUTC.png +0 -0
- package/dist/renderer/assets/browser.js +408 -0
- package/dist/renderer/assets/log-body.worker.js +3 -0
- package/dist/renderer/assets/main.css +2 -0
- package/dist/renderer/assets/main.js +103 -0
- package/dist/renderer/assets/tray.js +8 -0
- package/dist/renderer/assets/web-client-bridge.js +1 -0
- package/dist/renderer/pages/browser/index.html +13 -0
- package/dist/renderer/pages/home/index.html +18 -0
- package/dist/renderer/pages/tray/index.html +17 -0
- package/package.json +6 -2
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";var y="2024-11-05",d=k(),J=new Set(d.map(n=>n.name)),s=Buffer.alloc(0);process.stdin.on("data",n=>{s=Buffer.concat([s,Buffer.isBuffer(n)?n:Buffer.from(n)]),R().catch(e=>{c(a(null,-32603,p(e)))})});process.stdin.resume();async function R(){for(;;){let n=s.indexOf(`\r
|
|
2
|
+
\r
|
|
3
|
+
`);if(n<0)return;let t=s.subarray(0,n).toString("utf8").match(/content-length:\s*(\d+)/i);if(!t){s=s.subarray(n+4),c(a(null,-32600,"Missing Content-Length header."));continue}let i=Number(t[1]),r=n+4,o=r+i;if(s.length<o)return;let h=s.subarray(r,o).toString("utf8");s=s.subarray(o);let g;try{g=JSON.parse(h)}catch(b){c(a(null,-32700,`Invalid JSON-RPC request: ${p(b)}`));continue}let m=await w(g);m&&c(m)}}async function w(n){if(!l(n))return a(null,-32600,"JSON-RPC request must be an object.");let e=n,t=e.id??null;if(!(e.id===void 0&&e.method?.startsWith("notifications/"))){if(e.jsonrpc!=="2.0"||!e.method)return a(t,-32600,"Invalid JSON-RPC 2.0 request.");try{switch(e.method){case"initialize":return u(t,{capabilities:{tools:{}},protocolVersion:y,serverInfo:{name:"ccr-fusion-tool-fallback",title:"CCR Fusion Tool Fallback",version:"1.0.0"}});case"ping":return u(t,{});case"tools/list":return u(t,{tools:d});case"tools/call":return u(t,S(e.params));default:return a(t,-32601,`Unsupported MCP method: ${e.method}`)}}catch(i){return a(t,-32603,p(i))}}}function S(n){let t=(l(n)&&typeof n.name=="string"?n.name.trim():"")||"unknown",i=d.find(o=>o.name===t),r=J.has(t)?"":" The requested tool was not in the fallback catalog.";return{content:[{text:i?.unavailableMessage||`Fusion MCP tool "${t}" is temporarily unavailable. CCR registered a fallback definition because the real MCP server did not provide the tool during discovery. Check the Fusion MCP server logs and retry.${r}`,type:"text"}],isError:!0}}function k(){let n=v("FUSION_FALLBACK_TOOLS_JSON");if(!n)return[];let e;try{e=JSON.parse(n)}catch{return[]}if(!Array.isArray(e))return[];let t=new Set,i=[];for(let r of e){if(!l(r))continue;let o=f(r.name);!o||t.has(o)||(t.add(o),i.push({description:f(r.description)||`Fallback registration for Fusion MCP tool "${o}". The real MCP server should handle successful calls.`,inputSchema:l(r.inputSchema)?r.inputSchema:C({}),name:o,unavailableMessage:f(r.unavailableMessage)}))}return i}function C(n,e=[]){return{additionalProperties:!0,properties:n,...e.length?{required:e}:{},type:"object"}}function u(n,e){return{id:n,jsonrpc:"2.0",result:e}}function a(n,e,t){return{error:{code:e,message:t},id:n,jsonrpc:"2.0"}}function c(n){let e=JSON.stringify(n);process.stdout.write(`Content-Length: ${Buffer.byteLength(e,"utf8")}\r
|
|
4
|
+
\r
|
|
5
|
+
${e}`)}function v(n){return process.env[n]?.trim()??""}function f(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function l(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function p(n){return n instanceof Error?n.message:String(n)}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";var ne=require("node:crypto"),re=require("node:fs/promises"),se=require("node:path"),me="2024-11-05",ge="https://api.openai.com/v1",de="gpt-4o-mini",ie=3e4,pe=9999,W=20*1024*1024,fe="ccr.fusion-usage.v1",he=100,ye=15e3,X=3,Se=5e3,k=new Set,J=!1,Q=!1,$=st(o("FUSION_BUILTIN_TOOL_KIND")),h=o("FUSION_TOOL_NAME")||o("FUSION_VISION_TOOL_NAME")||($==="web_search"?"web_search":"vision_understand"),oe=o("FUSION_TOOL_TITLE")||o("FUSION_VISION_TOOL_TITLE")||($==="web_search"?"Fusion Web Search":"Fusion Vision Understand"),we={description:"Analyze one or more images with this Fusion profile's configured OpenAI-compatible vision model.",inputSchema:K({detail:{enum:["auto","low","high"],type:"string"},imageBase64:{description:"Single raw base64 image payload or data URL.",type:"string"},imagePath:{description:"Single local image path.",type:"string"},imageUrl:{description:"Single HTTP(S) image URL, data URL, or bare base64 payload.",type:"string"},images:{items:K({base64:{type:"string"},label:{type:"string"},mimeType:{type:"string"},path:{type:"string"},url:{type:"string"}}),type:"array"},prompt:{description:"Task instruction for image analysis.",type:"string"},systemPrompt:{type:"string"},timeoutMs:{minimum:100,type:"number"}},["prompt"]),name:h,title:oe},_e={description:"Search the web with this Fusion profile's configured search provider.",inputSchema:K({allowedDomains:{items:{type:"string"},type:"array"},allowed_domains:{items:{type:"string"},type:"array"},blockedDomains:{items:{type:"string"},type:"array"},blocked_domains:{items:{type:"string"},type:"array"},count:{maximum:20,minimum:1,type:"number"},country:{type:"string"},excludeDomains:{items:{type:"string"},type:"array"},freshness:{enum:["day","week","month"],type:"string"},includeDomains:{items:{type:"string"},type:"array"},includeRaw:{type:"boolean"},language:{type:"string"},prompt:{description:"Natural-language search query.",type:"string"},safeSearch:{enum:["off","moderate","strict"],type:"string"},timeoutMs:{minimum:100,type:"number"}},["prompt"]),name:h,title:oe},be=$==="web_search"?_e:we,p=Buffer.alloc(0);process.stdin.on("data",e=>{p=Buffer.concat([p,Buffer.isBuffer(e)?e:Buffer.from(e)]),Pe().catch(t=>{C(b(null,-32603,S(t)))})});process.stdin.resume();process.once("SIGINT",()=>{ae(130)});process.once("SIGTERM",()=>{ae(143)});async function Pe(){for(;;){let e=p.indexOf(`\r
|
|
2
|
+
\r
|
|
3
|
+
`);if(e<0)return;let n=p.subarray(0,e).toString("utf8").match(/content-length:\s*(\d+)/i);if(!n){p=p.subarray(e+4),C(b(null,-32600,"Missing Content-Length header."));continue}let r=Number(n[1]),s=e+4,i=s+r;if(p.length<i)return;let c=p.subarray(s,i).toString("utf8");p=p.subarray(i);let u;try{u=JSON.parse(c)}catch(g){C(b(null,-32700,`Invalid JSON-RPC request: ${S(g)}`));continue}let d=await Re(u);d&&C(d)}}async function Re(e){if(!a(e))return b(null,-32600,"JSON-RPC request must be an object.");let t=e,n=t.id??null;if(!(t.id===void 0&&t.method?.startsWith("notifications/"))){if(t.jsonrpc!=="2.0"||!t.method)return b(n,-32600,"Invalid JSON-RPC 2.0 request.");try{switch(t.method){case"initialize":return U(n,{capabilities:{tools:{}},protocolVersion:me,serverInfo:{name:"ccr-fusion-builtins",title:"CCR Fusion Builtins",version:"1.0.0"}});case"ping":return U(n,{});case"tools/list":return U(n,{tools:[be]});case"tools/call":return U(n,await Ee(t.params));default:return b(n,-32601,`Unsupported MCP method: ${t.method}`)}}catch(r){return b(n,-32603,S(r))}}}async function Ee(e){if(!a(e)||typeof e.name!="string")throw new Error("tools/call params must include a tool name.");if(e.name!==h)throw new Error(`Unknown fusion tool: ${e.name}`);let t=a(e.arguments)?e.arguments:{};try{let n=$==="web_search"?await ve(t):await Ae(t);return te(n)}catch(n){return{...te(S(n)),isError:!0}}}async function Ae(e){let t=l(e.prompt);if(!t)throw new Error(`${h} requires prompt.`);let n=o("VISION_GATEWAY_BASE_URL"),r=n||o("VISION_BASE_URL")||o("OPENAI_BASE_URL")||ge,s=n?o("VISION_GATEWAY_API_KEY"):o("VISION_API_KEY")||o("OPENAI_API_KEY");if(!n&&!s)throw new Error("Missing vision API key. Set VISION_API_KEY.");let i=o("VISION_MODEL")||o("OPENAI_MODEL")||de,c=O(m(o("VISION_RETRY_COUNT"))??0,0,pe),u=F([i,...Te("VISION_FALLBACK_MODELS_JSON")]),d=Oe(u.length?u:[i],c),g=l(e.detail),I=await He(e,g==="low"||g==="high"?g:"auto");if(I.length===0)throw new Error(`${h} requires imageUrl, imagePath, imageBase64, or images.`);let Y=l(e.systemPrompt),ue=[...Y?[{role:"system",content:Y}]:[],{role:"user",content:[{type:"text",text:t},...I]}],le=O(m(e.timeoutMs)??m(o("VISION_TIMEOUT_MS"))??ie,100,6e5),v=[],G;for(let x=0;x<d.length;x+=1){let N=d[x],H=Date.now(),f,z=!1;try{f=await fetch(nt(r),{body:JSON.stringify({model:N,messages:ue}),headers:{...s?{authorization:`Bearer ${s}`}:{},"content-type":"application/json"},method:"POST",signal:AbortSignal.timeout(le)});let w=await f.text(),D=q(w);if(Z({durationMs:Date.now()-H,gatewayRuntime:!!n,model:N,payload:D,response:f}),z=!0,!f.ok)throw new Error(`Vision request failed (${f.status}): ${ce(w,D)}`);return rt(D)||w}catch(w){if(z||Z({durationMs:Date.now()-H,gatewayRuntime:!!n,model:N,response:f,statusCode:Ue(w)}),G=w,v.push({error:S(w),model:N,...f?{statusCode:f.status}:{}}),x<d.length-1){await j(xe(f,v.length-1));continue}}}Me(G,v)}function Z(e){let t=o("CCR_FUSION_USAGE_SYNC_ENDPOINT"),n=o("CCR_FUSION_USAGE_SYNC_HEADER"),r=o("CCR_FUSION_USAGE_SYNC_TOKEN");if(!t||!n||!r)return;let s=e.gatewayRuntime?Ve(e.model):{model:e.model},i=e.response?.status??e.statusCode??502,c={billing:{cost:{total:Le(e.response,e.payload)},usage:Ce(e.response,e.payload)},emittedAt:new Date().toISOString(),eventId:(0,ne.randomUUID)(),outcome:{status:$e(i),statusCode:i},performance:{latency_ms:e.durationMs},route:{method:"POST",url:"/v1/chat/completions"},schema:fe,source:{adapterKey:"openai_chat",provider:"fusion_vision"},target:s},u=Ie(t,n,r,c);k.add(u),u.then(()=>k.delete(u),()=>k.delete(u))}async function Ie(e,t,n,r){let s;for(let i=1;i<=X;i+=1)try{let c=await fetch(e,{body:JSON.stringify(r),headers:{[t]:n,"content-type":"application/json"},method:"POST",signal:AbortSignal.timeout(Se)}),u=await c.text();if(!c.ok)throw new L(c.status);let d=u?q(u):void 0;if(a(d)&&d.applied===!1)throw new V;J=!1;return}catch(c){if(s=c,i>=X||!ke(c))break;await j(he*2**(i-1))}J||(J=!0,console.warn(`[fusion-vision] Failed to publish lightweight usage event: ${S(s)}`))}var L=class extends Error{constructor(n){super(`HTTP ${n}`);this.statusCode=n;this.name="FusionUsageSyncHttpError",this.retryable=n===408||n===409||n===425||n===429||n>=500}statusCode;retryable},V=class extends Error{retryable=!1;constructor(){super("Usage sync endpoint rejected the event."),this.name="FusionUsageSyncRejectedError"}};function ke(e){return!(e instanceof V)&&(!(e instanceof L)||e.retryable)}async function ae(e){if(Q)return;Q=!0;let t=Date.now()+ye;for(;k.size>0&&Date.now()<t;){let n=Math.max(1,t-Date.now());await Promise.race([Promise.allSettled([...k]),j(n)])}process.exit(e)}function j(e){return new Promise(t=>setTimeout(t,e))}function Te(e){let t=o(e);if(!t)return[];try{let n=JSON.parse(t);return _(n)}catch{return[]}}function Oe(e,t){let n=[];for(let r of e)for(let s=0;s<=t;s+=1)n.push(r);return n}function xe(e,t){let n=Ne(e?.headers.get("retry-after")??null);if(n!==void 0&&n>0)return O(n,1,6e4);let r=Math.min(10,Math.max(0,t));return Math.min(3e4,1e3*2**r)}function Ne(e){let t=e?.trim();if(!t)return;let n=Number(t);if(Number.isFinite(n)&&n>=0)return n*1e3;let r=Date.parse(t);return Number.isFinite(r)?Math.max(0,r-Date.now()):void 0}function Ue(e){let t=e instanceof Error?e.name:"";return t==="AbortError"||t==="TimeoutError"?504:502}function Me(e,t){throw t.length<=1?e instanceof Error?e:new Error(S(e)):new Error(`Vision request failed after ${t.length} attempts. ${Be(t)} Last error: ${S(e)}`)}function Be(e){return`Failures: ${e.map(t=>`${t.model} ${t.statusCode?`HTTP ${t.statusCode}`:"network"}`).join("; ")}.`}function Ce(e,t){let n=a(t)?t:{},r=a(n.usage)?n.usage:{},s=a(r.input_tokens_details)?r.input_tokens_details:a(r.prompt_tokens_details)?r.prompt_tokens_details:{},i=c=>m(e?.headers.get(c));return{cache_read_tokens:i("x-gateway-billing-cache-read-tokens")??m(r.cache_read_tokens)??m(r.cache_read_input_tokens)??m(s.cached_tokens),cache_write_tokens:i("x-gateway-billing-cache-write-tokens")??m(r.cache_write_tokens)??m(r.cache_creation_input_tokens)??m(s.cache_creation_tokens),input_tokens:i("x-gateway-billing-input-tokens")??m(r.input_tokens)??m(r.prompt_tokens),output_tokens:i("x-gateway-billing-output-tokens")??m(r.output_tokens)??m(r.completion_tokens),total_tokens:i("x-gateway-billing-total-tokens")??m(r.total_tokens)}}function Le(e,t){let n=m(e?.headers.get("x-gateway-billing-total-cost"));if(n!==void 0)return n;let r=a(t)?t:{},s=a(r.billing)?r.billing:{},i=a(s.cost)?s.cost:{};return m(i.total)}function Ve(e){let t=e.indexOf("/"),n=t>0?e.slice(0,t).trim():void 0,r=t>0&&t<e.length-1?e.slice(t+1).trim():e,s=n?.split("::").find(i=>i.startsWith("cred:"))?.slice(5).trim();return{...s?{credentialId:s}:{},model:r,...n?{providerName:n}:{}}}function $e(e){return e>=200&&e<400?"success":e===429?"rate-limited":e===408||e===504?"timeout":"error"}async function ve(e){let t=l(e.prompt);if(!t)throw new Error(`${h} requires prompt.`);let n=it(),r=O(m(e.count)??m(o("SEARCH_RESULT_COUNT"))??5,1,20),s=O(m(e.timeoutMs)??m(o("SEARCH_TIMEOUT_MS"))??ie,100,6e5),i={count:r,country:l(e.country),excludeDomains:F([..._(e.excludeDomains),..._(e.blockedDomains),..._(e.blocked_domains)]),freshness:l(e.freshness),includeDomains:F([..._(e.includeDomains),..._(e.allowedDomains),..._(e.allowed_domains)]),includeRaw:e.includeRaw===!0,language:l(e.language),prompt:t,safeSearch:l(e.safeSearch),timeoutMs:s},c=await De(n,i);return c.length===0?`Search provider: ${n}
|
|
4
|
+
No results.`:[`Search provider: ${n}`,...c.slice(0,r).map((u,d)=>[`${d+1}. ${u.title||u.url||"Untitled"}`,u.url?`URL: ${u.url}`:"",u.snippet?`Snippet: ${u.snippet}`:""].filter(Boolean).join(`
|
|
5
|
+
`))].join(`
|
|
6
|
+
|
|
7
|
+
`)}async function De(e,t){return e==="brave"?Je(t):e==="bing"?Fe(t):e==="google_cse"?Ke(t):e==="serper"?je(t):e==="serpapi"?qe(t):e==="tavily"?Ye(t):Ge(t)}async function Je(e){let t=y("BRAVE_SEARCH_API_KEY","Brave Search API key"),n=new URL(o("BRAVE_SEARCH_ENDPOINT")||"https://api.search.brave.com/res/v1/web/search");n.searchParams.set("q",R(e)),n.searchParams.set("count",String(e.count)),e.country&&n.searchParams.set("country",e.country),e.language&&n.searchParams.set("search_lang",e.language),e.safeSearch&&n.searchParams.set("safesearch",e.safeSearch);let r=await P(n.toString(),{headers:{"x-subscription-token":t},signal:AbortSignal.timeout(e.timeoutMs)});return(a(r)&&a(r.web)&&Array.isArray(r.web.results)?r.web.results:[]).map(i=>E(i,"title","url","description")).filter(A)}async function Fe(e){let t=y("BING_SEARCH_API_KEY","Bing Web Search API key"),n=new URL(o("BING_SEARCH_ENDPOINT")||"https://api.bing.microsoft.com/v7.0/search");n.searchParams.set("q",R(e)),n.searchParams.set("count",String(e.count)),(e.country||e.language)&&n.searchParams.set("mkt",[e.language,e.country].filter(Boolean).join("-")),e.safeSearch&&n.searchParams.set("safeSearch",e.safeSearch);let r=await P(n.toString(),{headers:{"ocp-apim-subscription-key":t},signal:AbortSignal.timeout(e.timeoutMs)});return(a(r)&&a(r.webPages)&&Array.isArray(r.webPages.value)?r.webPages.value:[]).map(i=>E(i,"name","url","snippet")).filter(A)}async function Ke(e){let t=y("GOOGLE_SEARCH_API_KEY","Google Programmable Search API key"),n=y("GOOGLE_SEARCH_CX","Google Programmable Search Engine ID"),r=new URL(o("GOOGLE_SEARCH_ENDPOINT")||"https://www.googleapis.com/customsearch/v1");r.searchParams.set("key",t),r.searchParams.set("cx",n),r.searchParams.set("q",R(e)),r.searchParams.set("num",String(Math.min(e.count,10))),e.country&&r.searchParams.set("gl",e.country),e.language&&r.searchParams.set("hl",e.language);let s=await P(r.toString(),{signal:AbortSignal.timeout(e.timeoutMs)});return(a(s)&&Array.isArray(s.items)?s.items:[]).map(c=>E(c,"title","link","snippet")).filter(A)}async function je(e){let t=y("SERPER_API_KEY","Serper API key"),n=await P(o("SERPER_SEARCH_ENDPOINT")||"https://google.serper.dev/search",{body:JSON.stringify({gl:e.country,hl:e.language,num:e.count,q:R(e),tbs:ct(e.freshness)}),headers:{"content-type":"application/json","x-api-key":t},method:"POST",signal:AbortSignal.timeout(e.timeoutMs)});return(a(n)&&Array.isArray(n.organic)?n.organic:[]).map(s=>E(s,"title","link","snippet")).filter(A)}async function qe(e){let t=y("SERPAPI_API_KEY","SerpAPI key"),n=new URL(o("SERPAPI_SEARCH_ENDPOINT")||"https://serpapi.com/search.json");n.searchParams.set("api_key",t),n.searchParams.set("engine","google"),n.searchParams.set("q",R(e)),n.searchParams.set("num",String(e.count)),e.country&&n.searchParams.set("gl",e.country),e.language&&n.searchParams.set("hl",e.language),e.safeSearch&&n.searchParams.set("safe",e.safeSearch==="off"?"off":"active");let r=await P(n.toString(),{signal:AbortSignal.timeout(e.timeoutMs)});return(a(r)&&Array.isArray(r.organic_results)?r.organic_results:[]).map(i=>E(i,"title","link","snippet")).filter(A)}async function Ye(e){let t=y("TAVILY_API_KEY","Tavily API key"),n=await P(o("TAVILY_SEARCH_ENDPOINT")||"https://api.tavily.com/search",{body:JSON.stringify({api_key:t,include_raw_content:e.includeRaw,max_results:e.count,query:R(e),search_depth:"basic"}),headers:{"content-type":"application/json"},method:"POST",signal:AbortSignal.timeout(e.timeoutMs)});return(a(n)&&Array.isArray(n.results)?n.results:[]).map(s=>E(s,"title","url","content")).filter(A)}async function Ge(e){let t=y("EXA_API_KEY","Exa API key"),n=await P(o("EXA_SEARCH_ENDPOINT")||"https://api.exa.ai/search",{body:JSON.stringify({numResults:e.count,query:R(e)}),headers:{authorization:`Bearer ${t}`,"content-type":"application/json"},method:"POST",signal:AbortSignal.timeout(e.timeoutMs)});return(a(n)&&Array.isArray(n.results)?n.results:[]).map(s=>E(s,"title","url","text")).filter(A)}async function He(e,t){let n=[],r=l(e.imageUrl),s=l(e.imagePath),i=l(e.imageBase64);r&&n.push({url:r}),s&&n.push({path:s}),i&&n.push({base64:i,mimeType:l(e.mimeType)});let c=Array.isArray(e.images)?e.images:[];for(let g of c)a(g)&&n.push({base64:l(g.base64),label:l(g.label),mimeType:l(g.mimeType),path:l(g.path),url:l(g.url)});let u=[],d=[];for(let g of n){let I=await ze(g);if("skip"in I){d.push(I.skip);continue}g.label&&u.push({text:`Image: ${g.label}`,type:"text"}),u.push({image_url:{detail:t,url:I.url},type:"image_url"})}if(u.length===0)throw d.length===0?new Error(`${h} requires imageUrl, imagePath, imageBase64, or images.`):new Error(`${h} found no usable image. Skipped: ${d.join("; ")}.`);return u}async function ze(e){if(e.url){let r=e.url.trim();if(/^https?:\/\//i.test(r))return{url:r};if(r.startsWith("data:"))return ee(r,e.mimeType);let s=M(r);return s?B(s,"image/png"):{skip:`imageUrl is neither an HTTP(S) URL, a data URL, nor base64 (${T(r)})`}}if(e.base64){let r=e.base64.trim();if(r.startsWith("data:"))return ee(r,e.mimeType);let s=M(r);return s?B(s,e.mimeType):{skip:"imageBase64 is not usable base64"}}if(!e.path)return{skip:"image entry has no url, base64, or path"};let t=await(0,re.readFile)(e.path);if(t.byteLength>W)throw new Error(`Local image exceeds ${W} bytes: ${e.path}`);let n=M(t.toString("base64"));return n?B(n,e.mimeType||tt(e.path)):{skip:`file at ${T(e.path)} is not usable image data`}}var We=new Set(["image/jpeg","image/png","image/gif","image/webp"]);function ee(e,t){let n=e.indexOf(",");if(n<1)return{skip:`malformed data URL (${T(e)})`};let r=e.slice(5,n);if(!/;base64/i.test(r))return{skip:`data URL is not base64 (${T(e)})`};let s=r.split(";")[0]||void 0,i=M(e.slice(n+1));return i?B(i,s||t):{skip:`data URL payload is not usable base64 (${T(e)})`}}var Xe=/^[A-Za-z0-9+/]*={0,2}$/,Qe=/^(?:\uFEFF)?\s*(?:<\?xml|<svg)/i;function M(e){if(!e||!Xe.test(e)||e.length%4===1)return;let t=e.padEnd(e.length+(4-e.length%4)%4,"="),n=Buffer.from(t,"base64");if(n.byteLength!==0)return{payload:t,svg:Qe.test(n.subarray(0,64).toString("utf8")),sniffedType:Ze(n)}}function Ze(e){if(e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255)return"image/jpeg";if(e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71)return"image/png";if(e.length>=6&&e[0]===71&&e[1]===73&&e[2]===70&&e[3]===56&&(e[4]===55||e[4]===57)&&e[5]===97)return"image/gif";if(e.length>=12&&e.subarray(0,4).toString("latin1")==="RIFF"&&e.subarray(8,12).toString("latin1")==="WEBP")return"image/webp"}function et(e,t){let n=e?.trim().toLowerCase();return n&&We.has(n)?n:t.sniffedType??"image/png"}function B(e,t){return e.svg?{skip:"SVG/XML image payload is not supported by the vision upstream (supported: image/jpeg, image/png, image/gif, image/webp)"}:{url:`data:${et(t,e)};base64,${e.payload}`}}function T(e){return JSON.stringify(e.length>40?`${e.slice(0,37)}\u2026`:e)}function tt(e){let t=(0,se.extname)(e).toLowerCase();return t===".jpg"||t===".jpeg"?"image/jpeg":t===".webp"?"image/webp":t===".gif"?"image/gif":"image/png"}function nt(e){let t=e.trim().replace(/\/+$/,"");return t.endsWith("/chat/completions")?t:`${t}/chat/completions`}function rt(e){if(!a(e))return;let t=Array.isArray(e.choices)?e.choices:[],n=a(t[0])?t[0]:void 0,s=(a(n?.message)?n.message:void 0)?.content;return typeof s=="string"?s:Array.isArray(s)?s.map(c=>a(c)?l(c.text):void 0).filter(c=>!!c).join(`
|
|
8
|
+
`)||void 0:l(e.output_text)}function ce(e,t){if(a(t)){let n=t.error;if(typeof n=="string")return n;if(a(n)&&typeof n.message=="string")return n.message;if(typeof t.message=="string")return t.message}return e.slice(0,500)}function q(e){try{return JSON.parse(e)}catch{throw new Error(`Invalid JSON from provider: ${e.slice(0,500)}`)}}function st(e){return e==="web_search"?"web_search":"vision"}function it(){let e=ot(o("SEARCH_PROVIDER"))??"auto";if(e!=="auto")return e;let n=["brave","bing","google_cse","serper","serpapi","tavily","exa"].find(at);if(!n)throw new Error("No search provider configured. Set SEARCH_PROVIDER and its API key.");return n}function ot(e){if(e==="auto"||e==="brave"||e==="bing"||e==="google_cse"||e==="serper"||e==="serpapi"||e==="tavily"||e==="exa")return e}function at(e){return e==="brave"?!!o("BRAVE_SEARCH_API_KEY"):e==="bing"?!!o("BING_SEARCH_API_KEY"):e==="google_cse"?!!(o("GOOGLE_SEARCH_API_KEY")&&o("GOOGLE_SEARCH_CX")):e==="serper"?!!o("SERPER_API_KEY"):e==="serpapi"?!!o("SERPAPI_API_KEY"):e==="tavily"?!!o("TAVILY_API_KEY"):!!o("EXA_API_KEY")}function y(e,t){let n=o(e);if(!n)throw new Error(`Missing ${t}. Set ${e}.`);return n}async function P(e,t){let n=await fetch(e,t),r=await n.text(),s=r?q(r):{};if(!n.ok)throw new Error(`Search request failed (${n.status}): ${ce(r,s)}`);return s}function R(e){let t=e.includeDomains.map(r=>`site:${r}`).join(" "),n=e.excludeDomains.map(r=>`-site:${r}`).join(" ");return[e.prompt,t,n].filter(Boolean).join(" ")}function ct(e){if(e==="day")return"qdr:d";if(e==="week")return"qdr:w";if(e==="month")return"qdr:m"}function E(e,t,n,r){return a(e)?{snippet:l(e[r]),title:l(e[t]),url:l(e[n])}:{}}function A(e){return!!(e.title||e.url||e.snippet)}function _(e){return typeof e=="string"?e.split(",").map(t=>t.trim()).filter(Boolean):Array.isArray(e)?e.map(l).filter(t=>!!t):[]}function F(e){return[...new Set(e.filter(Boolean))]}function te(e){return{content:[{text:e,type:"text"}]}}function K(e,t=[]){return{additionalProperties:!1,properties:e,required:t,type:"object"}}function U(e,t){return{id:e,jsonrpc:"2.0",result:t}}function b(e,t,n,r){return{error:{code:t,...r===void 0?{}:{data:r},message:n},id:e,jsonrpc:"2.0"}}function C(e){let t=JSON.stringify(e);process.stdout.write(`Content-Length: ${Buffer.byteLength(t,"utf8")}\r
|
|
9
|
+
\r
|
|
10
|
+
${t}`)}function a(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function l(e){return typeof e=="string"&&e.trim()?e.trim():void 0}function m(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"&&e.trim()){let t=Number(e);return Number.isFinite(t)?t:void 0}}function O(e,t,n){return Math.min(n,Math.max(t,Math.trunc(e)))}function o(e){return l(process.env[e])}function S(e){return e instanceof Error?e.message:String(e)}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var k=Object.create;var w=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var C=(n,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of E(e))!h.call(n,o)&&o!==r&&w(n,o,{get:()=>e[o],enumerable:!(s=b(e,o))||s.enumerable});return n};var G=(n,e,r)=>(r=n!=null?k(F(n)):{},C(e||!n||!n.__esModule?w(r,"default",{value:n,enumerable:!0}):r,n));var d=require("node:module"),a=G(require("node:path")),l=(0,d.createRequire)(__filename),c=a.default.resolve(process.cwd(),`.ccr-gateway-config-${process.pid}`),f=!1;process.once("disconnect",()=>{process.exit(0)});process.on("message",n=>{if(!f)try{let e=x(n);f=!0,R(e.config),process.env.GATEWAY_CONFIG_PATH=c,l(e.gatewayEntry),process.send?.({protocolVersion:1,type:"gateway:config-accepted"})}catch(e){console.error(`[gateway-bootstrap] ${V(e)}`),process.exit(1)}});function R(n){let e=l("node:fs"),r=`${JSON.stringify(n)}
|
|
2
|
+
`,s=e.existsSync.bind(e),o=e.readFileSync.bind(e),p=e.renameSync.bind(e),m=e.writeFileSync.bind(e);e.existsSync=t=>u(t)||s(t),e.readFileSync=(t,i)=>u(t)?M(i)?r:Buffer.from(r,"utf8"):o(t,i),e.writeFileSync=(t,i,S)=>{if(y(t))throw new Error("Gateway configuration is managed by Claude Code Router.");m(t,i,S)},e.renameSync=(t,i)=>{if(y(t)||y(i))throw new Error("Gateway configuration is managed by Claude Code Router.");p(t,i)}}function x(n){if(!g(n)||n.type!=="gateway:start"||n.protocolVersion!==1)throw new Error("Invalid gateway start message.");if(!g(n.config))throw new Error("Gateway start message does not include a configuration object.");if(typeof n.gatewayEntry!="string"||!n.gatewayEntry.trim())throw new Error("Gateway start message does not include a runtime entry.");return{config:n.config,gatewayEntry:a.default.resolve(n.gatewayEntry),protocolVersion:1,type:"gateway:start"}}function M(n){return typeof n=="string"?!!n:g(n)&&typeof n.encoding=="string"&&!!n.encoding}function u(n){return typeof n=="string"&&a.default.resolve(n)===c}function y(n){if(typeof n!="string")return!1;let e=a.default.resolve(n);return e===c||e.startsWith(`${c}.`)}function g(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function V(n){return n instanceof Error?n.stack||n.message:String(n)}
|