@kianwoon/modelweaver 0.3.16 → 0.3.18

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.
@@ -9,7 +9,7 @@ ${"\u2500".repeat(56)}
9
9
  `)&&(e+=`
10
10
  `);let i=[];for(let s of o){let r=s.envKey.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=new RegExp(`^${r}=.*$`,"m"),u=s.apiKey.includes('"')?s.apiKey.includes("'")?`'${s.apiKey.replace(/'/g,"'\\''")}'`:`'${s.apiKey}'`:`"${s.apiKey}"`;a.test(e)?e=e.replace(a,`${s.envKey}=${u}`):i.push(`${s.envKey}=${u}`)}oe(n,e+i.join(`
11
11
  `)+(i.length>0?`
12
- `:""),{mode:384})}async function Ie(){process.stdin.isTTY||(console.error("Error: modelweaver init --quick requires an interactive terminal."),process.exit(1));let{peekConfig:o}=await import("./config-P34YQCFG.js"),t=o(),n=t?.providers??new Map,e=t?.modelRouting??new Map,i=[],s=[],r,a,u=E(1,!0),l=!1;for(;;)try{j(),console.log(`
12
+ `:""),{mode:384})}async function Ie(){process.stdin.isTTY||(console.error("Error: modelweaver init --quick requires an interactive terminal."),process.exit(1));let{peekConfig:o}=await import("./config-ZAAEWZUJ.js"),t=o(),n=t?.providers??new Map,e=t?.modelRouting??new Map,i=[],s=[],r,a,u=E(1,!0),l=!1;for(;;)try{j(),console.log(`
13
13
  ${x}${m}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2500
14
14
  \u2502 Welcome to ModelWeaver! \u2501 Quick Setup \u2502
15
15
  \u2502 \u2502
@@ -24,7 +24,7 @@ ${x} Generated configuration:${d}
24
24
  `));let{confirm:b}=await p({type:"confirm",name:"confirm",message:`[Step 2 of ${u}] Write this configuration?`,initial:!0},g);if(b)break;console.log(`
25
25
  Restarting quick setup...
26
26
  `)}catch(c){if(c instanceof I){l||(console.log(`
27
- Setup cancelled. No files were changed.`),process.exit(0));continue}throw c}await ue(i,s,r,a,u,!0,!!t)}async function ue(o,t,n,e,i,s,r){let a=O(process.env.HOME||process.env.USERPROFILE||"",".modelweaver");ie(a,{recursive:!0});let u=O(a,"config.yaml");ne(u)&&r?M(`Updating existing config at ${u}`):M(`Writing new config to ${u}`),oe(u,e),Ae(o);try{let{readPidFile:c,isProcessAlive:f}=await import("./daemon-27GXX25D.js"),b=await c();if(b&&f(b)){if(process.platform!=="win32")try{process.kill(b,"SIGUSR1")}catch{}else console.log(" Windows does not support SIGUSR1 \u2014 run 'modelweaver reload' to pick up new config.");M("ModelWeaver daemon reloaded with new config")}}catch{}let l=await Ee(t);if(l){let c=n.host==="localhost"?`http://localhost:${n.port}`:`http://${n.host}:${n.port}`;J()&&console.log(" Backed up existing settings to settings.json.bak");let b=V(),v=Q(b,{baseUrl:c,defaultModel:l.defaultModel,availableModels:l.availableModels});X(v),M(`Claude Code settings updated at ${z()}`),console.log(` Proxy endpoint: ${c}`),console.log(` Default model: ${l.defaultModel}`),console.log(` Available models: ${l.availableModels.join(", ")}`),console.log(),console.log(` ${re}Restart Claude Code to apply changes.${d}`)}return l}var N=0,F=1,D=2,te=3;async function He(o){if(o?.quick)return Ie();process.stdin.isTTY||(console.error("Error: modelweaver init requires an interactive terminal."),process.exit(1));let{peekConfig:t}=await import("./config-P34YQCFG.js"),n=t(),e=n?.providers??new Map,i=n?.modelRouting??new Map,s=e.size>0,r=[],a=[],u=[],l={port:3456,host:"localhost"},c,f=null,b=s,v=N;for(;;)try{if(v<=N){if(j(),console.log(`
27
+ Setup cancelled. No files were changed.`),process.exit(0));continue}throw c}await ue(i,s,r,a,u,!0,!!t)}async function ue(o,t,n,e,i,s,r){let a=O(process.env.HOME||process.env.USERPROFILE||"",".modelweaver");ie(a,{recursive:!0});let u=O(a,"config.yaml");ne(u)&&r?M(`Updating existing config at ${u}`):M(`Writing new config to ${u}`),oe(u,e),Ae(o);try{let{readPidFile:c,isProcessAlive:f}=await import("./daemon-2JXEJR35.js"),b=await c();if(b&&f(b)){if(process.platform!=="win32")try{process.kill(b,"SIGUSR1")}catch{}else console.log(" Windows does not support SIGUSR1 \u2014 run 'modelweaver reload' to pick up new config.");M("ModelWeaver daemon reloaded with new config")}}catch{}let l=await Ee(t);if(l){let c=n.host==="localhost"?`http://localhost:${n.port}`:`http://${n.host}:${n.port}`;J()&&console.log(" Backed up existing settings to settings.json.bak");let b=V(),v=Q(b,{baseUrl:c,defaultModel:l.defaultModel,availableModels:l.availableModels});X(v),M(`Claude Code settings updated at ${z()}`),console.log(` Proxy endpoint: ${c}`),console.log(` Default model: ${l.defaultModel}`),console.log(` Available models: ${l.availableModels.join(", ")}`),console.log(),console.log(` ${re}Restart Claude Code to apply changes.${d}`)}return l}var N=0,F=1,D=2,te=3;async function He(o){if(o?.quick)return Ie();process.stdin.isTTY||(console.error("Error: modelweaver init requires an interactive terminal."),process.exit(1));let{peekConfig:t}=await import("./config-ZAAEWZUJ.js"),n=t(),e=n?.providers??new Map,i=n?.modelRouting??new Map,s=e.size>0,r=[],a=[],u=[],l={port:3456,host:"localhost"},c,f=null,b=s,v=N;for(;;)try{if(v<=N){if(j(),console.log(`
28
28
  ${x}${m}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\u2500
29
29
  \u2551 Welcome to ModelWeaver! \u2551
30
30
  \u2551 \u2551
@@ -61,4 +61,4 @@ ${f?`\u2551 Claude Code settings have been updated. \u2551
61
61
  \u2551 claude \u2551`}
62
62
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${d}
63
63
  `)}export{He as runInit,Z as testApiKey};
64
- //# sourceMappingURL=init-2GWQ546N.js.map
64
+ //# sourceMappingURL=init-WPWG2GL3.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kianwoon/modelweaver",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Multi-provider model orchestration proxy for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import{existsSync as k,readFileSync as I}from"fs";import{readFile as x,stat as j,access as E}from"fs/promises";import{join as P}from"path";import{parse as C}from"yaml";import{z as e}from"zod";import{Agent as $}from"undici";var A={failureThreshold:3,windowSeconds:60,cooldownSeconds:30},b=class{state="closed";failureTimestamps=[];openedAt=null;halfOpenInProgress=!1;halfOpenProbeId=null;nextProbeId=0;config;constructor(t={}){this.config={...A,...t}}canProceed(){if(this.state==="closed")return{allowed:!0,probeId:0};if(this.state==="open"){if(this.openedAt&&Date.now()-this.openedAt>=this.config.cooldownSeconds*1e3){this.state="half-open";let t=this.nextProbeId++;return this.halfOpenInProgress=!0,this.halfOpenProbeId=t,{allowed:!0,probeId:t}}return{allowed:!1,probeId:0}}if(!this.halfOpenInProgress){let t=this.nextProbeId++;return this.halfOpenInProgress=!0,this.halfOpenProbeId=t,{allowed:!0,probeId:t}}return{allowed:!1,probeId:0}}recordResult(t,n){if(this.halfOpenInProgress&&(n===void 0||n===this.halfOpenProbeId)&&(this.halfOpenInProgress=!1,this.halfOpenProbeId=null),t>=200&&t<300){this.state="closed",this.failureTimestamps=[],this.openedAt=null;return}if(t!==429&&t<500)return;let i=Date.now();if(this.failureTimestamps.push(i),this.pruneOldFailures(i),this.state==="half-open"){this.state="open",this.openedAt=i;return}this.failureTimestamps.length>=this.config.failureThreshold&&(this.state="open",this.openedAt=i)}getState(){return this.state}getStatus(){return{state:this.state,failures:this.failureTimestamps.length,lastFailure:this.failureTimestamps.length>0?this.failureTimestamps[this.failureTimestamps.length-1]:null}}pruneOldFailures(t){let n=t-this.config.windowSeconds*1e3;this.failureTimestamps=this.failureTimestamps.filter(i=>i>=n)}};var B=e.object({maxOutputTokens:e.number().int().positive()}).optional(),U=e.object({baseUrl:e.string().url().refine(r=>/^https?:\/\//.test(r),"baseUrl must use http:// or https://"),apiKey:e.string().min(1,"apiKey is required"),timeout:e.number().positive().default(3e4),ttfbTimeout:e.number().positive().default(15e3),stallTimeout:e.number().positive().default(3e4),authType:e.enum(["anthropic","bearer"]).default("anthropic"),modelLimits:B,concurrentLimit:e.number().int().min(1).optional(),poolSize:e.number().int().min(1).max(100).optional(),circuitBreaker:e.object({failureThreshold:e.number().int().min(1).optional(),windowSeconds:e.number().int().min(1).optional(),cooldownSeconds:e.number().int().min(1).optional()}).optional()}),R=e.object({provider:e.string(),model:e.string().optional()}),M=e.object({server:e.object({port:e.number().int().min(1).max(65535).default(3456),host:e.string().default("localhost")}).default({port:3456,host:"localhost"}),providers:e.record(e.string(),U),routing:e.record(e.string(),e.array(R)).default({}),tierPatterns:e.record(e.string(),e.array(e.string())).default({}),modelRouting:e.record(e.string(),e.array(R)).default({})});function L(r){return r.replace(/\$\{([^}]+)\}/g,(t,n)=>{let i=process.env[n];if(i===void 0)throw new Error(`Missing environment variable: ${n}`);return i})}function S(r){if(typeof r=="string")return L(r);if(Array.isArray(r))return r.map(S);if(r!==null&&typeof r=="object"){let t={};for(let[n,i]of Object.entries(r))t[n]=S(i);return t}return r}function T(r=process.cwd(),{skipGlobal:t=!1}={}){let n=P(r,"modelweaver.yaml");if(k(n))return n;if(!t){let i=P(process.env.HOME||process.env.USERPROFILE||"",".modelweaver","config.yaml");if(k(i))return i}return null}function G(r){let t=T(r);if(!t)return null;let n=I(t,"utf-8"),i=C(n),w=i?.providers??{},d=new Map;for(let[c,u]of Object.entries(w)){let y=String(u.apiKey??"").match(/^\$\{([^}]+)\}$/),s=y?y[1]:"";d.set(c,{baseUrl:String(u.baseUrl??""),envKey:s,authType:String(u.authType??"anthropic"),timeout:Number(u.timeout??3e4)})}let a=i?.server,p=a?{port:Number(a.port??3456),host:String(a.host??"localhost")}:null,f=new Map,m=i?.modelRouting??{};for(let[c,u]of Object.entries(m))Array.isArray(u)&&f.set(c,u.map(g=>({provider:String(g.provider??""),model:String(g.model??c)})));return{configPath:t,providers:d,server:p,modelRouting:f}}async function F(r,t){let n=null;if(r)try{await E(r),(await j(r)).isDirectory()?n=T(r):n=r}catch{n=r}if(n||(n=T(t)),!n)throw new Error("No config file found. Create modelweaver.yaml in your project root or ~/.modelweaver/config.yaml");let i=await x(n,"utf-8"),w=C(i,{customTags:[]}),d=S(w),a=M.parse(d),p=new Set(Object.keys(a.providers));for(let[s,o]of Object.entries(a.routing)){for(let l of o)if(!p.has(l.provider))throw new Error(`Routing tier "${s}" references unknown provider "${l.provider}". Available: ${[...p].join(", ")}`);if(!a.tierPatterns[s])throw new Error(`Routing tier "${s}" has no entry in tierPatterns. Add patterns for this tier.`)}for(let[s,o]of Object.entries(a.modelRouting))for(let l of o)if(!p.has(l.provider))throw new Error(`modelRouting for model "${s}" references unknown provider "${l.provider}". Available: ${[...p].join(", ")}`);let f=new Map;for(let[s,o]of Object.entries(a.providers)){let l={name:s,baseUrl:o.baseUrl,apiKey:o.apiKey,timeout:o.timeout,ttfbTimeout:o.ttfbTimeout,stallTimeout:o.stallTimeout,authType:o.authType,modelLimits:o.modelLimits?{maxOutputTokens:o.modelLimits.maxOutputTokens}:void 0,concurrentLimit:o.concurrentLimit};try{let v=new URL(o.baseUrl);l._cachedHost=v.host,l._cachedOrigin=`${v.protocol}//${v.host}`,l._cachedPathname=v.pathname.replace(/\/+$/,"")}catch{}let O=o.poolSize;l._agent=new $({keepAliveTimeout:3e4,keepAliveMaxTimeout:6e4,connections:O??10,allowH2:!0}),l.poolSize=O??10;let h=o.circuitBreaker;l._circuitBreaker=new b(h?{failureThreshold:h.failureThreshold,windowSeconds:h.windowSeconds,cooldownSeconds:h.cooldownSeconds}:void 0),f.set(s,l)}let m=new Map;for(let[s,o]of Object.entries(a.routing))m.set(s,o);let c=new Map;for(let[s,o]of Object.entries(a.tierPatterns))c.set(s,o);let u=new Map;if(a.modelRouting)for(let[s,o]of Object.entries(a.modelRouting))u.set(s,o);return{config:{server:{port:a.server.port,host:a.server.host},providers:f,routing:m,tierPatterns:c,modelRouting:u},configPath:n}}async function Y(r){let{config:t}=await F(r);return t}export{L as a,T as b,G as c,F as d,Y as e};
3
- //# sourceMappingURL=chunk-ZF23JS2D.js.map
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import{a,b,c,d,e}from"./chunk-ZF23JS2D.js";export{b as findConfigFile,d as loadConfig,c as peekConfig,e as reloadConfig,a as resolveEnvVars};
3
- //# sourceMappingURL=config-P34YQCFG.js.map