@duckmind/dm-darwin-x64 0.49.9 → 0.50.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.
@@ -1,2 +1,2 @@
1
- import{getModels as Ij}from"@duckmind/dm-ai/compat";var C$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function v$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function q0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Qj=128000,zj=16000,qj={input:0,output:0,cacheRead:0,cacheWrite:0},Vj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function H$($){return Vj.some((j)=>j.test($))}var Mj=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function W$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function V0($,j){let J=(j??"").trim(),Y=$.match(/^([a-z0-9]+-)(.*)$/);if(Y)return J?`${J}-${Y[1]}`:Y[1];return $}function M0($,j){for(let[J,Y,Z]of Mj)if(J.has($))return{slug:W$(j,Y),api:Z};return{slug:W$(j,"misc"),api:"openai-completions"}}function Dj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function Y$($){return{id:$,name:Dj($),contextWindow:Qj,maxTokens:zj,reasoning:H$($),cost:{...qj}}}import{execSync as Ej}from"node:child_process";import{randomUUID as D0}from"node:crypto";import{chmodSync as N$,constants as Uj,copyFileSync as E0,existsSync as k$,linkSync as Rj,mkdirSync as U0,readFileSync as Gj,rmSync as f$,writeFileSync as _j}from"node:fs";import{homedir as g$}from"node:os";import{dirname as V$,join as M$}from"node:path";import{fileURLToPath as Oj}from"node:url";var q$=!1;function u$($){q$=$}var B={info(...$){if(!q$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!q$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!q$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!q$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var h$=M$(g$(),".dm","agent","dm-cliproxy"),C=M$(h$,"config.json"),Aj=[M$(g$(),".pi","agent","pi-cliproxyapi","config.json"),M$(g$(),".config","pi-cliproxyapi","config.json")];function nj(){return k$(M$(V$(Oj(import.meta.url)),"..",".git"))}function Wj($=Aj,j=C,J=nj()){if(k$(j))return;let Z=(typeof $==="string"?[$]:[...$]).find((z)=>k$(z));if(!Z)return;let X;try{U0(V$(j),{recursive:!0,mode:448}),N$(V$(j),448),X=`${j}.${process.pid}.${D0()}.tmp`,E0(Z,X,Uj.COPYFILE_EXCL),N$(X,384),Rj(X,j),f$(X),X=void 0,B.info("legacy config copied to",j)}catch(z){if(X)try{f$(X,{force:!0})}catch(Q){B.warn("failed to clean temporary config:",Q)}B.warn("failed to migrate legacy config:",z)}}var T$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function o(){if(Wj(),!k$(C))return B.debug("config not found, using defaults at",C),structuredClone(T$);try{let $=JSON.parse(Gj(C,"utf8"));return Hj($)}catch($){return B.error("failed to read config:",$,"— using defaults"),structuredClone(T$)}}function B$($){U0(V$(C),{recursive:!0,mode:448}),N$(V$(C),448);let j=`${C}.${process.pid}.${D0()}.tmp`;try{_j(j,JSON.stringify($,null,2)+`
2
- `,{encoding:"utf8",flag:"wx",mode:384}),E0(j,C),N$(C,384)}finally{f$(j,{force:!0})}B.info("config saved to",C)}function Hj($){if(!$||typeof $!=="object")return structuredClone(T$);let j=$,J=structuredClone(T$),Y=j.proxy??{};if(J.proxy.endpoint=typeof Y.endpoint==="string"?Y.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof Y.apiKey==="string"?Y.apiKey:"",typeof Y.usageKey==="string")J.proxy.usageKey=Y.usageKey;if(typeof Y.providerPrefix==="string"&&Y.providerPrefix.trim())J.proxy.providerPrefix=Y.providerPrefix.trim();if(j.builtinProviders&&typeof j.builtinProviders==="object")J.builtinProviders=j.builtinProviders;if(j.customProviders&&typeof j.customProviders==="object")J.customProviders=j.customProviders;if(Array.isArray(j.discoveryExcludes))J.discoveryExcludes=j.discoveryExcludes.filter((Z)=>typeof Z==="string");if(j.overrides&&typeof j.overrides==="object")J.overrides=j.overrides;if(typeof j.refreshIntervalMinutes==="number")J.refreshIntervalMinutes=j.refreshIntervalMinutes;if(typeof j.usageCacheTtlMs==="number")J.usageCacheTtlMs=j.usageCacheTtlMs;return J}function I($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Ej(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Y=J?.stderr?.toString?.()?.trim()??J.message;return B.warn(`failed to resolve "!" config value (${j}): ${Y}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{chmodSync as Nj,existsSync as b1,mkdirSync as kj,readFileSync as x1,writeFileSync as Tj}from"node:fs";import{dirname as R0,join as Bj}from"node:path";var p$=Bj(h$,"discovery-cache.json");function c$($){try{kj(R0(p$),{recursive:!0,mode:448}),Nj(R0(p$),448);let j={savedAt:Date.now(),discovery:$};Tj(p$,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){B.warn("failed to write discovery cache:",j.message)}}var Z$="dm-cliproxy/0.3.5",Fj=5000;async function O0($,j){let J=new AbortController,Y=setTimeout(()=>J.abort(Error("timeout")),Fj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Y)}}function Kj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function Lj($){let j=Kj($.proxy.endpoint),J;try{J=await O0(j,{headers:{"User-Agent":Z$,Accept:"application/json"}})}catch(Q){return B.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!J.ok)return B.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let Y;try{Y=await J.json()}catch{return B.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return B.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Z=[],X=Y.builtinProviders??{};for(let[Q,q]of Object.entries(X)){if(!q||!Array.isArray(q.models))continue;let V=q.models.map((D)=>({id:String(D.id),name:typeof D.name==="string"?D.name:String(D.id),reasoning:Boolean(D.reasoning??H$(String(D.id))),contextWindow:typeof D.contextWindow==="number"?D.contextWindow:200000,maxTokens:typeof D.maxTokens==="number"?D.maxTokens:16000,cost:D.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));Z.push({name:Q,api:q.api??"openai-responses",models:V})}let z=(Array.isArray(Y.customModelPool)?Y.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??H$(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:V0(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Y?.upstream?.upstreamVersion==="string"?Y.upstream.upstreamVersion:null,builtinProviders:Z,customPool:z,serverDiscoveryExcludes:Array.isArray(Y.discoveryExcludes)?Y.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Y?.counts?.upstreamTotal==="number"?Y.counts.upstreamTotal:0}}async function Sj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Y=await O0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":Z$}});if(!Y.ok)throw Error(`/v1/models returned ${Y.status}`);let Z=await Y.json();if(!Z?.data||!Array.isArray(Z.data))return[];return Z.data.map((X)=>({id:typeof X.id==="string"?X.id:"",owned_by:typeof X.owned_by==="string"?X.owned_by:""})).filter((X)=>X.id)}function Pj($,j){let J=j.discoveryExcludes,Y=new Map,Z=[],X=0;for(let z of $){if(X++,q0(z.id,J))continue;if(z.owned_by==="openai"){let D=Y$(z.id);G0(Y,"openai","openai-responses",_0(D));continue}if(z.owned_by==="anthropic"){let D=Y$(z.id);G0(Y,"anthropic","anthropic-messages",_0(D));continue}let{slug:Q,api:q}=M0(z.owned_by,j.proxy.providerPrefix),V=Y$(z.id);Z.push({id:z.id,name:V.name??z.id,reasoning:V.reasoning??!1,contextWindow:V.contextWindow??128000,maxTokens:V.maxTokens??16000,cost:V.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:q,suggestedProvider:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:Z,serverDiscoveryExcludes:[],upstreamTotal:X}}function G0($,j,J,Y){let Z=$.get(j);if(!Z)Z={name:j,api:J,models:[]},$.set(j,Z);Z.models.push(Y)}function _0($){return{id:$.id,name:$.name??$.id,reasoning:$.reasoning??!1,contextWindow:$.contextWindow??128000,maxTokens:$.maxTokens??16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function D$($,j){let J=await Lj($);if(J)return B.info(`discovery via /.well-known/pi: ${J.builtinProviders.length} builtin, ${J.customPool.length} custom`),c$(J),J;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await Sj($,j),Z=Pj(Y,$);return B.info(`discovery via /v1/models: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),c$(Z),Z}function A0($){let j=new Set;for(let J of $.builtinProviders)for(let Y of J.models)j.add(Y.id);for(let J of $.customPool)j.add(J.id);return j}async function E$($,j,J){let Y={registered:[],skipped:[]},Z=A0(J),X=I(j.proxy.apiKey);if(!X)return B.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),Y;let z=new Map;for(let q of J.builtinProviders)z.set(q.name,q.models.map((V)=>({id:V.id,name:V.name,reasoning:V.reasoning,contextWindow:V.contextWindow,maxTokens:V.maxTokens,cost:V.cost})));for(let[q,V]of Object.entries(j.builtinProviders)){if(!V?.enabled){Y.skipped.push({provider:q,reason:"disabled"});continue}if(!Array.isArray(V.models)||V.models.length===0){Y.skipped.push({provider:q,reason:"empty whitelist"});continue}let D=[];try{D=Ij(q)}catch{}let U=new Map(D.map((A)=>[A.id,A])),L=new Map((z.get(q)??[]).map((A)=>[A.id,A])),O=[];for(let A of V.models){if(!Z.has(A))continue;let H=U.get(A),P=L.get(A);if(H){O.push({id:H.id,name:H.name,reasoning:H.reasoning,contextWindow:H.contextWindow,maxTokens:H.maxTokens,cost:H.cost,input:H.input,api:H.api,thinkingLevelMap:H.thinkingLevelMap});continue}if(!P)continue;let p=q==="anthropic"?"anthropic-messages":V.apiOverride??"openai-responses";O.push({id:P.id,name:P.name,reasoning:P.reasoning,contextWindow:P.contextWindow,maxTokens:P.maxTokens,cost:P.cost,input:["text"],api:p})}if(O.length===0){Y.skipped.push({provider:q,reason:"no whitelisted models present on proxy"});continue}let _=V.apiOverride??O[0].api;if(!C$.has(_)){Y.skipped.push({provider:q,reason:`api "${_}" not in allowlist`});continue}let E=O.map((A)=>{let H=j.overrides[A.id]??{},P={id:A.id,name:typeof H.name==="string"?H.name:A.name,api:_,reasoning:typeof H.reasoning==="boolean"?H.reasoning:A.reasoning,input:A.input,cost:H.cost??A.cost,contextWindow:typeof H.contextWindow==="number"?H.contextWindow:A.contextWindow,maxTokens:typeof H.maxTokens==="number"?H.maxTokens:A.maxTokens};if(A.thinkingLevelMap)P.thinkingLevelMap=A.thinkingLevelMap;return P}),W={name:q,baseUrl:v$(_,j.proxy.endpoint),apiKey:X,authHeader:!0,api:_,models:E};$.registerProvider(q,W),Y.registered.push({provider:q,modelCount:E.length,api:_})}let Q=new Map(J.customPool.map((q)=>[q.id,q]));for(let[q,V]of Object.entries(j.customProviders)){if(!C$.has(V.api)){Y.skipped.push({provider:q,reason:`api "${V.api}" not in allowlist`});continue}let D=V.models.filter((O)=>Z.has(O.id));if(D.length===0){Y.skipped.push({provider:q,reason:"no configured models present on proxy"});continue}let U=D.map((O)=>{let _=Q.get(O.id),E=Y$(O.id),W=j.overrides[O.id]??{};return{id:O.id,name:O.name??_?.name??E.name??O.id,api:V.api,reasoning:bj(O.reasoning,_?.reasoning,E.reasoning,W.reasoning)??!1,input:["text"],cost:O.cost??_?.cost??E.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:n0(O.contextWindow,_?.contextWindow,E.contextWindow,W.contextWindow)??128000,maxTokens:n0(O.maxTokens,_?.maxTokens,E.maxTokens,W.maxTokens)??16000}}),L={name:q,baseUrl:v$(V.api,j.proxy.endpoint),apiKey:X,authHeader:!0,api:V.api,models:U};$.registerProvider(q,L),Y.registered.push({provider:q,modelCount:U.length,api:V.api})}return B.info(`applyAll: registered ${Y.registered.length} providers, skipped ${Y.skipped.length}`),Y}function n0(...$){for(let j of $)if(typeof j==="number")return j;return}function bj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var xj=15000,U$=null;function X$(){U$=null}async function W0($,j,J={}){if(!J.force&&U$&&Date.now()-U$.fetchedAt<$.usageCacheTtlMs)return U$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Y=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Z=new AbortController,X=setTimeout(()=>Z.abort(Error("timeout")),xj),z;try{z=await fetch(Y,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":Z$},signal:Z.signal})}finally{clearTimeout(X)}if(!z.ok)throw Error(`/api/usage returned ${z.status}`);let Q=await z.json();if(!Q||Q.schemaVersion!==1||!Array.isArray(Q.accounts))throw Error("/api/usage returned unexpected payload shape");return U$={fetchedAt:Date.now(),doc:Q},B.debug("usage fetched, accounts:",Q.accounts.length),Q}import{getKeybindings as A1,matchesKey as v}from"@duckmind/dm-tui";import{visibleWidth as m$}from"@duckmind/dm-tui";import{visibleWidth as H0}from"@duckmind/dm-tui";function F($,j){let J=H0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return l$($,j)}function l$($,j){if(j<=0)return"\x1B[0m";let J="",Y=0,Z=0;while(Z<$.length){let X=$[Z];if(X==="\x1B"&&$[Z+1]==="["){let Q=$.indexOf("m",Z+2);if(Q>=0){J+=$.slice(Z,Q+1),Z=Q+1;continue}}let z=H0(X);if(Y+z>j)break;J+=X,Y+=z,Z++}return`${J}\x1B[0m`}var yj="│",wj="╭",Cj="╮",vj="╰",uj="╯",R$="─";function i($,j){let J=Math.max(4,j.width);return[fj($,j.title,j.titleColor??"accent",J),...j.lines.map((Y)=>gj($,Y,J)),hj($,j.footer,J)]}function fj($,j,J,Y){let Z=j??"",X=m$(Z),z=Math.max(0,Y-3-X),Q=Z?$.bold($.fg(J,Z)):"",q=`${wj}${R$}${Q}${R$.repeat(z)}${Cj}`;return $.fg("borderAccent",q)}function gj($,j,J){let Y=Math.max(0,J-2),Z=$.fg("borderAccent",yj);return`${Z}${F(j,Y)}${Z}`}function hj($,j,J){let Y=`${vj}${R$}`,Z=`${uj}`,X=3;if(!j||!j.hint&&!j.badge){let _=Math.max(0,J-3);return $.fg("borderAccent",`${Y}${R$.repeat(_)}${Z}`)}let z=j.hint??"",Q=j.badge??"",q=m$(z),V=m$(Q),D=Math.max(0,J-3-q-V),U=$.fg("dim",z),L=Q?$.fg("muted",Q):"",O=R$.repeat(D);return`${$.fg("borderAccent",Y)}${U}${$.fg("borderAccent",O)}${L}${$.fg("borderAccent",Z)}`}function F$($){return Math.max(0,$-2)}import{existsSync as N0}from"node:fs";import{homedir as pj}from"node:os";import{getKeybindings as cj,Input as lj,matchesKey as mj}from"@duckmind/dm-tui";var rj=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:($)=>{try{if(!new URL($).pathname.endsWith("/v1"))return"must end with /v1";return null}catch{return"not a valid URL"}}},{label:"apiKey",hint:"CliProxyAPI bearer key. Accepts literal, $ENV_VAR, !cmd, or ~/path",required:!0},{label:"providerPrefix",hint:"Prefix for your custom provider names. Suggested groups become <prefix>-glm, <prefix>-gemini, etc. Use any short slug (letters/digits/dashes).",required:!0,validate:($)=>/^[a-z0-9][a-z0-9-]*$/i.test($)?null:"letters/digits/dashes only"},{label:"usageKey",hint:"Optional X-Plugin-Key for /api/usage. Leave blank to skip the Usage tab",required:!1}];async function G$($,j=!1){let J=o(),Y={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Z=!1;for(let z of rj){let Q=j?Y[z.label]??z.initialValue??"":Y[z.label]??"";if(!j&&Q)continue;let q=await oj($,z,Q||z.initialValue||"");if(q===void 0){Z=!0;break}let V=q.trim();if(!V){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Z=!0;break}Y[z.label]="";continue}Y[z.label]=z.label==="providerPrefix"||z.label==="endpoint"?V:sj(V)}if(Z)return!1;let X={...J};if(X.proxy={...J.proxy,endpoint:Y.endpoint??"",apiKey:Y.apiKey??"",providerPrefix:Y.providerPrefix??""},Y.usageKey)X.proxy.usageKey=Y.usageKey;else delete X.proxy.usageKey;return B$(X),$.ui.notify(`saved to ${C}`,"info"),!0}function sj($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,pj());return N0(j)?`!cat ${$}`:$}if($.startsWith("/"))return N0($)?`!cat ${$}`:$;return $}async function oj($,j,J){return $.ui.custom((Y,Z,X,z)=>ij(Y,Z,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function ij($,j,J,Y,Z){let X=new lj;X.setValue(Y),X.focused=!0;let z=null,Q=(q)=>{if(!q&&!J.required){Z("");return}if(!q&&J.required){z="required field",$.requestRender();return}if(J.validate){let V=q.trim();if(V&&!V.startsWith("!")&&!V.startsWith("$")){let D=J.validate(V);if(D){z=D,$.requestRender();return}}}Z(q)};return X.onSubmit=Q,X.onEscape=()=>Z(void 0),{render(q){let V=F$(q),D=X.render(V-4),U=["",` ${j.fg("dim",J.hint)}`,"",...D.map((L)=>` ${j.fg("accent",`❯ ${L}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return i(j,{width:q,title:` setup: ${J.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){X.invalidate()},handleInput(q){if(cj().matches(q,"tui.select.cancel")||mj(q,"escape")){Z(void 0);return}z=null,X.handleInput(q),$.requestRender()}}}import{visibleWidth as K$}from"@duckmind/dm-tui";function k0($,j,J,Y){let Z=$.fg("borderAccent","│"),X=j.map((z,Q)=>{let q=`${Q+1} ${z.label}`;return Q===J?$.bold($.fg("accent",` ${q} `)):$.fg("dim",` ${q} `)});return F(` ${X.join(Z)}`,Y)}function T0($,j,J){let Y=j.join($.fg("dim"," "));return F(` ${Y}`,J)}function B0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function d($,j,J){let Y=$.slice(j,j+J);while(Y.length<J)Y.push("");return Y}function L$($,j,J,Y,Z,X){if(Z<=Y)return 0;let z=Math.max(0,Z-Y);if(j<X)return 0;let Q=Math.max(0,Math.min(J,z)),q=Q+X;if($<q)Q=Math.max(0,$-X);let V=Q+Y-1;if(j>V)Q=Math.min(z,j-(Y-1));return Q}function S$($,j,J){let Y=Math.max(0,J-j);return Math.max(0,Math.min($,Y))}import{matchesKey as t}from"@duckmind/dm-tui";import{existsSync as dj,readFileSync as tj}from"node:fs";import{homedir as K0}from"node:os";import{join as L0}from"node:path";var aj=L0(K0(),".dm","models.json"),ej=L0(K0(),".dm","auth.json");function F0($){if(!dj($))return null;try{return JSON.parse(tj($,"utf8"))}catch{return null}}function S0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Y=F0(aj);if(Y&&typeof Y==="object"){for(let X of Object.keys(Y))if(J.has(X))j.push({kind:"models.json",provider:X,detail:`provider "${X}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Z=F0(ej);if(Z&&typeof Z==="object"){for(let X of Object.keys(Z))if(J.has(X))j.push({kind:"auth.json",provider:X,detail:`provider "${X}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function P0($){let{theme:j,cfg:J}=$,Y=0,Z=()=>{let Q=$.getDiscovery(),q=(_)=>j.fg("success",_),V=(_)=>j.fg("error",_),D=(_)=>j.fg("dim",_),U=[];U.push(`${D("endpoint")} ${J.proxy.endpoint||V("(unset)")}`),U.push(`${D("apiKey")} ${I(J.proxy.apiKey)?q("resolves"):V("empty after resolution")}`),U.push(`${D("usageKey")} ${J.proxy.usageKey?I(J.proxy.usageKey)?q("resolves"):V("set but empty"):D("not configured")}`),U.push(`${D("user-agent")} ${Z$}`),U.push(""),U.push(`${D("discovery")} source=${Q.source}`),U.push(`${D("upstream")} v=${Q.upstreamVersion??"(unknown)"} · ${Q.upstreamTotal} ids`);let L=Q.builtinProviders.map((_)=>`${_.name}=${_.models.length}`).join(", ")||D("(none)");U.push(`${D("built-in")} ${L}`),U.push(`${D("custom pool")} ${Q.customPool.length} models`);let O=S0(J);if(U.push(""),O.length===0)U.push(`${D("conflicts")} ${q("none")}`);else{U.push(`${D("conflicts")}`);for(let _ of O)U.push(` ${j.fg("warning",`[${_.kind}]`)} ${_.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(Q,q)=>{let V=Z();return Y=S$(Y,q,V.length),d(V,Y,q).map((D)=>F(` ${D}`,Q))},handleInput:(Q)=>{let q=Z().length;if(t(Q,"up")||t(Q,"k"))return Y=Math.max(0,Y-1),!0;if(t(Q,"down")||t(Q,"j"))return Y=Math.min(Math.max(0,q-1),Y+1),!0;if(t(Q,"pageUp")||t(Q,"b"))return Y=Math.max(0,Y-10),!0;if(t(Q,"pageDown")||t(Q,"f"))return Y=Math.min(Math.max(0,q-1),Y+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as k}from"@duckmind/dm-tui";function r$($){let j=new Map,J=new Map;for(let Z of $.builtinProviders){let X=[];for(let z of Z.models)j.set(z.id,{id:z.id,name:z.name,suggestedApi:Z.api,subtitle:z.name&&z.name!==z.id?z.name:void 0,ownedBy:Z.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost}),X.push(z.id);J.set(Z.name,X)}let Y=[];for(let Z of $.customPool){if(!j.has(Z.id))j.set(Z.id,{id:Z.id,name:Z.name,suggestedApi:Z.api,subtitle:Z.name&&Z.name!==Z.id?Z.name:void 0,origin:Z.suggestedProvider,ownedBy:Z.ownedBy,reasoning:Z.reasoning,contextWindow:Z.contextWindow,maxTokens:Z.maxTokens,cost:Z.cost});Y.push(Z.id)}return{byId:j,builtinModelIds:J,customPoolIds:Y}}function $1($){let j=new Map;for(let[J,Y]of Object.entries($.customProviders))for(let Z of Y.models)j.set(Z.id,J);return j}function $$($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function I0($,j,J){if(j.kind==="builtin"){let X=J.builtinModelIds.get(j.name)??[],z=new Set($$($,j));return X.filter((Q)=>!z.has(Q))}let Y=$1($),Z=new Set($$($,j));return J.customPoolIds.filter((X)=>{if(Z.has(X))return!1;let z=Y.get(X);return z===void 0||z===j.name})}function j1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function b0($,j,J){if(j.kind==="builtin"){let Z=$.builtinProviders[j.name]??{enabled:!0,models:[]},X=new Set(Z.models);X.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Z.apiOverride??null,models:Array.from(X).sort()};return}for(let[Z,X]of Object.entries($.customProviders)){if(Z===j.name)continue;let z=X.models.findIndex((Q)=>Q.id===J.id);if(z>=0)X.models.splice(z,1)}let Y=$.customProviders[j.name]??{api:j.api,models:[]};if(!Y.models.some((Z)=>Z.id===J.id))Y.models.push(j1(J));$.customProviders[j.name]=Y}function x0($,j,J){if(j.kind==="builtin"){let Z=$.builtinProviders[j.name];if(!Z)return;Z.models=Z.models.filter((X)=>X!==J),Z.enabled=Z.models.length>0;return}let Y=$.customProviders[j.name];if(!Y)return;Y.models=Y.models.filter((Z)=>Z.id!==J)}function s$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function y0($,j){let J=new Map;for(let Y of $){let Z=j.byId.get(Y),X=Z?.ownedBy||Z?.origin||"misc",z=J.get(X)??[];z.push(Y),J.set(X,z)}return Array.from(J.entries()).sort((Y,Z)=>Y[0].localeCompare(Z[0])).map(([Y,Z])=>({label:Y,ids:Z}))}function w0($,j,J){let Y=J.trim().toLowerCase();if(!Y)return $;return $.filter((Z)=>{if(Z.toLowerCase().includes(Y))return!0;let X=j.byId.get(Z)?.name;return X?X.toLowerCase().includes(Y):!1})}import{getModels as J1,getProviders as Y1}from"@duckmind/dm-ai/compat";function o$($,j){let J=[],Y=new Set(j.builtinModelIds.keys()),Z=new Set(Y1()),X=new Set([...Y,...Z]);for(let z of Array.from(X).sort()){let Q=j.builtinModelIds.get(z);if(!Q||Q.length===0)continue;let q;try{let D=J1(z).find((U)=>Q.includes(U.id));if(D)q=D.api}catch{}if(!q){let V=Q[0];q=j.byId.get(V)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:z,api:q,subtitle:`built-in · ${q}`}),!$.builtinProviders[z])$.builtinProviders[z]={enabled:!1,models:[]}}for(let z of Object.keys($.customProviders).sort()){let Q=$.customProviders[z];J.push({kind:"custom",name:z,api:Q.api,subtitle:`custom · ${Q.api}`})}return J}import{getKeybindings as Z1,matchesKey as Q$}from"@duckmind/dm-tui";async function C0($,j){return $.ui.custom((J,Y,Z,X)=>X1(Y,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",X),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function X1($,j,J,Y){return{render(Z){return i($,{width:Z,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Z){if(Z1().matches(Z,"tui.select.cancel")||Q$(Z,"escape")||Q$(Z,"n")||Q$(Z,"q")){Y(!1);return}if(Q$(Z,"y")||Q$(Z,"enter")||Q$(Z,"return")){Y(!0);return}}}}import{getKeybindings as Q1,Input as z1,matchesKey as q1}from"@duckmind/dm-tui";async function v0($,j){let J=W$(j,"group");return $.ui.custom((Y,Z,X,z)=>V1(Y,Z,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function V1($,j,J,Y){let Z=new z1;if(J)Z.setValue(J);Z.focused=!0;let X=null;return Z.onSubmit=(z)=>{let Q=z.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(Q)){X="letters / digits / dot / dash / underscore only",$.requestRender();return}Y(Q)},Z.onEscape=()=>Y(null),{render(z){let Q=F$(z),q=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",V=Z.render(Q-4),D=["",` ${j.fg("dim",q)}`,"",...V.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",X?` ${j.fg("error",`! ${X}`)}`:""];return i(j,{width:z,title:" new custom group ",lines:D,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(z){if(Q1().matches(z,"tui.select.cancel")||q1(z,"escape")){Y(null);return}X=null,Z.handleInput(z),$.requestRender()}}}import{visibleWidth as M1}from"@duckmind/dm-tui";function i$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function u0($,j){let J=M1($);if(J===j)return $;if(J>j)return l$($,j);return F($,j)}function f0($,j,J){let{theme:Y,width:Z,isCursor:X,isFocused:z}=J,Q=i$(Y,X,z),q=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,V=$.kind==="builtin"?Y.fg("accent","B"):Y.fg("warning","C"),D=`${Y.fg("dim","[")}${V}${Y.fg("dim","]")}`,U=q>0?Y.fg("success","●"):Y.fg("dim","○"),L=q>0?Y.fg("success",String(q).padStart(2)):Y.fg("dim"," 0"),O=X&&z?Y.bold(Y.fg("accent",$.name)):X?Y.bold($.name):$.name,_=Y.fg("dim",$.api),E=`${Q}${D} ${O} ${U}${L} ${_}`;return u0(E,Z)}function g0($,j,J,Y){let Z=i$($,j,J),X=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return F(`${Z}${X}`,Y)}function d$($,j,J,Y,Z){let{theme:X,width:z,isCursor:Q,isFocused:q}=Z,V=i$(X,Q,q),D=J==="assigned"?X.fg("success","☑"):X.fg("dim","☐"),U=Y?` ${X.fg("warning","⚠")}`:"",L=Q&&q?X.fg("accent",$):$,O=j?.reasoning?` ${X.fg("accent","✨")}`:"",_=j?X.fg("muted",` · ${j.suggestedApi}`):X.fg("error"," · not on proxy"),E=`${V}${D} ${L}${U}${O}${_}`;return u0(E,z)}function h0($,j,J){let Y=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return F(` ${Y}`,J)}function t$($,j,J){return F(` ${$.fg("dim",j)}`,J)}function p0($,j,J,Y){let Z=Y?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return F(`${Z}${j}`,J)}function c0($){let{tui:j,theme:J,ctx:Y,cfg:Z}=$,X=$.onChange??(()=>{}),z=r$($.getDiscovery()),Q=o$(Z,z),q="providers",V=0,D=0,U=0,L=0,O=0,_=0,E="",W=!1,A=()=>{if(Q.length===0)return null;let M=Math.max(0,Math.min(V,Q.length-1));return Q[M]??null},H=(M)=>{let n=w0(I0(Z,M,z),z,E);return y0(n,z)},P=(M)=>H(M).flatMap((n)=>n.ids),p=()=>{Q=o$(Z,z);let M=Math.max(0,Q.length);if(V>M)V=M;let n=A();if(n){let S=$$(Z,n).length,N=P(n).length;if(D>=S)D=Math.max(0,S-1);if(U>=N)U=Math.max(0,N-1)}},P$=()=>{z=r$($.getDiscovery()),p()},_$=(M)=>{let n=["providers","assigned","pool"],S=n.indexOf(q);q=M?n[(S-1+n.length)%n.length]:n[(S+1)%n.length]},G=(M)=>{if(q==="providers"){let N=Q.length+1;V=Math.max(0,Math.min(V+M,N-1));return}let n=A();if(!n)return;if(q==="assigned"){let N=$$(Z,n).length;if(N===0)return;D=Math.max(0,Math.min(D+M,N-1));return}let S=P(n).length;if(S===0)return;U=Math.max(0,Math.min(U+M,S-1))},b=async()=>{if(q==="providers"){if(V===Q.length){let N=await v0(Y,Z.proxy.providerPrefix);if(N&&!Z.customProviders[N]){if(Z.customProviders[N]={api:"openai-completions",models:[]},X(),p(),V=Q.findIndex((K)=>K.kind==="custom"&&K.name===N),V<0)V=Q.length-1;q="pool"}j.requestRender();return}q="pool";return}let M=A();if(!M)return;if(q==="assigned"){let N=$$(Z,M)[D];if(!N)return;x0(Z,M,N),X(),p();return}let n=P(M)[U];if(!n)return;let S=z.byId.get(n);if(!S)return;b0(Z,M,S),X(),p()},l=async()=>{if(q!=="providers")return;let M=A();if(!M||M.kind!=="custom")return;if(!await C0(Y,M.name)){j.requestRender();return}if(delete Z.customProviders[M.name],X(),p(),V>=Q.length)V=Math.max(0,Q.length-1);j.requestRender()},u=(M,n)=>h(M,n);function h(M,n){let S=Math.max(70,M),N=Math.min(56,Math.max(34,Math.floor(S*0.4))),K=S-N-1,m=Math.max(8,n),r=Math.max(5,Math.floor((m-1)/2)),a$=m-r,c=A(),z$=0,I$=0,b$=0,e$=0,x$=0,$0=0,a=[];a.push(j$(" providers ",N,q==="providers"));for(let T=0;T<Q.length;T++){let f=Q[T],w=q==="providers"&&T===V;if(w)z$=a.length,I$=z$;a.push(f0(f,Z,{theme:J,width:N,isCursor:w,isFocused:q==="providers"}))}{let T=q==="providers"&&V===Q.length;if(T)z$=a.length,I$=z$;a.push(g0(J,T,q==="providers",N))}let e=[],jj=c?`assigned to ${J.bold(c.name)} ${J.fg("dim",`· ${c.api}`)}`:J.fg("dim","no provider selected");if(e.push(j$(" assigned ",K,q==="assigned")),e.push(p0(J,jj,K,q==="assigned")),c){let T=$$(Z,c);if(T.length===0)e.push(t$(J,"(nothing assigned yet)",K));for(let f=0;f<T.length;f++){let w=T[f],g=z.byId.get(w),n$=q==="assigned"&&f===D;if(n$)b$=e.length,e$=b$;let J$=g?!s$(c.api,g.suggestedApi):!1;e.push(d$(w,g,"assigned",J$,{theme:J,width:K,isCursor:n$,isFocused:q==="assigned"}))}}let s=[];if(s.push(x(K,q==="pool")),c){let T=H(c);if(T.reduce((w,g)=>w+g.ids.length,0)===0)s.push(t$(J,E?`(no matches for "${E}")`:"(no models available)",K));else{let w=0;for(let g of T){let n$=s.length;s.push(h0(J,g.label,K));for(let J$=0;J$<g.ids.length;J$++){let Q0=g.ids[J$],w$=z.byId.get(Q0),z0=q==="pool"&&w===U;if(z0)x$=s.length,$0=J$===0?n$:x$;let Xj=w$?!s$(c.api,w$.suggestedApi):!1;s.push(d$(Q0,w$,"pool",Xj,{theme:J,width:K,isCursor:z0,isFocused:q==="pool"})),w++}}}}let Jj=Math.max(1,a$-1),j0=L$(I$,z$,L,m,a.length,1),J0=L$(q==="assigned"?e$:0,q==="assigned"?b$:0,O,r,e.length,2),Y0=L$(q==="pool"?$0:0,q==="pool"?x$:0,_,Jj,s.length,1);L=j0,O=J0,_=Y0;let Z0=d(a,j0,m),Yj=d(e,J0,r),Zj=d(s,Y0,a$),X0=J.fg("borderAccent","│"),y$=[];for(let T=0;T<m;T++){let f=F(Z0[T]??"",N),w=T<r?Yj[T]:Zj[T-r],g=F(w,K);y$.push(`${f}${X0}${g}`)}let A$=r;if(A$>0&&A$<m){let T=F(Z0[A$]??"",N),f=J.fg("borderAccent","─".repeat(K));y$[A$]=`${T}${X0}${f}`}return y$}function j$(M,n,S){let N=S?J.bold(J.fg("accent",M)):J.fg("muted",M),K=J.fg("borderAccent","─".repeat(Math.max(0,n-K$(M)-1)));return F(`${N}${K}`,n)}function x(M,n){let N=n?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),K="";if(W)K=`${J.fg("dim"," /")}${J.fg("accent",E)}${J.fg("accent","█")} `;else if(E)K=`${J.fg("dim"," /")}${J.fg("warning",E)} `;let m=K$(" available pool ")+K$(K),r=J.fg("borderAccent","─".repeat(Math.max(0,M-m-1)));return F(`${N}${K}${r}`,M)}function O$(M){if(W){if(k(M,"escape"))return E="",W=!1,U=0,!0;if(k(M,"enter")||k(M,"return"))return W=!1,!0;if(k(M,"backspace")||k(M,"delete"))return E=E.slice(0,-1),U=0,!0;if(M.length===1&&M>=" "&&M!=="")return E+=M,U=0,!0;return!0}if(k(M,"tab"))return _$(!1),!0;if(k(M,"shift+tab"))return _$(!0),!0;if(k(M,"/"))return q="pool",W=!0,!0;if(k(M,"enter")||k(M,"return")||k(M,"space"))return b().then(()=>!0);if(q==="providers"&&(k(M,"d")||k(M,"delete")||k(M,"backspace")))return l().then(()=>!0);if(k(M,"up")||k(M,"k"))return G(-1),!0;if(k(M,"down")||k(M,"j"))return G(1),!0;if(k(M,"pageUp")||k(M,"b"))return G(-8),!0;if(k(M,"pageDown")||k(M,"f"))return G(8),!0;if(k(M,"left")||k(M,"h"))return q="providers",!0;if(k(M,"right")||k(M,"l")){if(q==="providers")q="assigned";else if(q==="assigned")q="pool";return!0}return!1}function $j(){if(W)return" type to filter · ↵ apply · esc clear ";return" tab ↔ panel · ↑↓ nav · ↵ move · / filter · d remove group "}return{id:"models",label:"Models",render:u,handleInput:O$,footerHint:$j,rebuild:P$}}import{matchesKey as y}from"@duckmind/dm-tui";var R={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function l0($,j={}){let J=[],Y=new Map,Z=0;for(let X of $.accounts){if(!j.showDisabled&&X.disabled){Z++;continue}let z=Y.get(X.provider)??[];z.push(X),Y.set(X.provider,z)}if(J.push(`${R.dim}generated ${$.generatedAt}${R.reset}`),$.unsupportedProviders.length>0)J.push(`${R.dim}providers without quota lookup:${R.reset} ${$.unsupportedProviders.join(", ")}`);if(Z>0)J.push(`${R.dim}hidden disabled accounts:${R.reset} ${Z} ${R.dim2}(press d to show)${R.reset}`);for(let[X,z]of Array.from(Y.entries()).sort()){J.push(""),J.push(`${R.bold}${R.accent}▌ ${X}${R.reset}`);for(let Q of z){if(J.push(E1(Q)),!Q.supported){J.push(` ${R.dim2}(provider not quota-aware)${R.reset}`);continue}if(Q.error){if(j.verbose)for(let V of D1(Q.error,88))J.push(` ${R.red}${V}${R.reset}`);continue}let q=Q.groups??[];if(q.length===0){J.push(` ${R.dim2}(no active quota windows)${R.reset}`);continue}for(let V of q)J.push(R1(V))}}return J.push(""),J.push(`${R.dim}legend:${R.reset} ${m0} ok ${r0} error/unavailable ${s0} disabled ${R.green}✓N${R.reset}/${R.red}✗N${R.reset} request counters ${R.dim}v = verbose, d = show disabled${R.reset}`),J}function D1($,j){if($.length<=j)return[$];let J=[],Y=$;while(Y.length>j){let Z=Y.lastIndexOf(" ",j);if(Z<j*0.6)Z=j;J.push(Y.slice(0,Z)),Y=Y.slice(Z).replace(/^\s+/,"")}if(Y)J.push(Y);return J}function E1($){let j=U1($),J=`${R.green}✓${$.success}${R.reset} ${R.red}✗${$.failed}${R.reset}`,Y=d0($.label,36);return` ${j} ${R.bold}${Y}${R.reset} ${J}`}var m0=`${R.green}●${R.reset}`,r0=`${R.yellow}⚠${R.reset}`,s0=`${R.dim2}⊘${R.reset}`;function U1($){if($.disabled)return s0;if($.unavailable||$.error||$.status&&$.status!=="active")return r0;return m0}function R1($){let j=i0($.remainingFraction),J=Math.round(j*100),Y=G1(j),Z=$.resetTime?` ${R.dim}reset ${O1($.resetTime)}${R.reset}`:"",X=d0($.label,28).padEnd(28," ");return` ${Y} ${_1(J,j)} ${X}${Z}`}function G1($){let j=i0($),J=Math.round(j*18),Y=o0(j),Z=R.dim2,X="█".repeat(J),z="░".repeat(18-J);return`${Z}[${Y}${X}${Z}${z}]${R.reset}`}function _1($,j){return`${o0(j)}${String($).padStart(3)}%${R.reset}`}function o0($){if($>=0.4)return R.green;if($>=0.15)return R.yellow;return R.red}function O1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let Y=Math.round(J/60000);if(Y<60)return`${Y}m`;let Z=Math.round(Y/60);if(Z<48)return`${Z}h`;return`${Math.round(Z/24)}d`}function i0($){return Math.max(0,Math.min(1,$))}function d0($,j){if($.length<=j)return $;return`${$.slice(0,j-1)}…`}function t0($){let{tui:j,theme:J,cfg:Y}=$,Z="idle",X=null,z="",Q=0,q=!1,V=!1,D=(E)=>{Z="loading",j.requestRender();let W=I(Y.proxy.usageKey);W0(Y,W,{force:E}).then((A)=>{X=A,Z="ready",Q=0,j.requestRender()}).catch((A)=>{z=A.message,Z="error",j.requestRender()})},U=()=>{if(Z==="idle"||Z==="loading")return[J.fg("dim"," loading usage…")];if(Z==="error")return[J.fg("error",` usage failed: ${z}`)];if(!X)return[J.fg("dim"," (no data)")];return l0(X,{showDisabled:q,verbose:V})};return{id:"usage",label:"Usage",render:(E,W)=>{let A=U();return Q=S$(Q,W,A.length),d(A,Q,W).map((H)=>F(` ${H}`,E))},handleInput:(E)=>{if(y(E,"d"))return q=!q,Q=0,!0;if(y(E,"v"))return V=!V,Q=0,!0;let W=U().length;if(y(E,"up")||y(E,"k"))return Q=Math.max(0,Q-1),!0;if(y(E,"down")||y(E,"j"))return Q=Math.min(Math.max(0,W-1),Q+1),!0;if(y(E,"pageUp")||y(E,"b"))return Q=Math.max(0,Q-10),!0;if(y(E,"pageDown")||y(E,"f"))return Q=Math.min(Math.max(0,W-1),Q+10),!0;if(y(E,"home")||y(E,"g"))return Q=0,!0;if(y(E,"end")||y(E,"shift+g"))return Q=Math.max(0,W-1),!0;return!1},footerHint:()=>{let E=q?J.fg("success","[d disabled]"):"d disabled",W=V?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${E} · ${W} `},onActivate:()=>{if(Z==="idle")D(!1)},reload:()=>{if(X$(),Z!=="idle")D(!0)}}}function a0($){let{dm:j,ctx:J,tui:Y,theme:Z,cfg:X,done:z}=$,Q=$.discovery,q=!1,V="",D=c0({tui:Y,theme:Z,ctx:J,cfg:X,getDiscovery:()=>Q,onChange:()=>{q=!0,V=""}}),U=t0({tui:Y,theme:Z,cfg:X}),L=P0({theme:Z,cfg:X,getDiscovery:()=>Q}),O=[D,U,L],_=0,E=()=>O[_],W=(G)=>{if(G<0||G>=O.length||G===_)return;_=G,E().onActivate?.(),Y.requestRender()},A=()=>{V=Z.fg("dim","saving…"),B$(X),Y.requestRender(),E$(j,X,Q).then((G)=>{q=!1,V=Z.fg("success",`✓ settings saved · ${G.registered.length} registered, ${G.skipped.length} skipped`),Y.requestRender()}).catch((G)=>{V=Z.fg("error",`save failed: ${G.message}`),Y.requestRender()})},H=async()=>{V=Z.fg("dim","refreshing…"),Y.requestRender();try{let G=I(X.proxy.apiKey);Q=await D$(X,G),X$(),D.rebuild(),U.reload();let b=await E$(j,X,Q);V=Z.fg("success",`✓ refreshed · ${b.registered.length} providers (${Q.source})`)}catch(G){V=Z.fg("error",`refresh failed: ${G.message}`)}Y.requestRender()},P=async()=>{if(!await G$(J,!0)){Y.requestRender();return}let b=o();X.proxy={...X.proxy,...b.proxy},await H()},p=()=>{let G=X.proxy.endpoint||"(unset)",b=G.length>40?`…${G.slice(-39)}`:G,l=Boolean(I(X.proxy.apiKey)),u=0,h=0;for(let x of Object.values(X.builtinProviders)){if(x.enabled&&x.models.length>0)u++;h+=x.models.length}for(let x of Object.values(X.customProviders)){if(x.models.length>0)u++;h+=x.models.length}let j$=V?V:q?Z.fg("warning","● unsaved — press s to save"):Z.fg("dim","✓ saved");return[`${Z.fg("dim","endpoint")} ${b}`,`${Z.fg("dim","key")} ${l?Z.fg("success","✓"):Z.fg("error","✗")}`,`${Z.fg("dim","providers")} ${u}`,`${Z.fg("dim","models")} ${h}`,j$]},P$=(G)=>{let b=Y.rows??40,u=Math.max(16,Math.min(b-6,38))-2,h=Math.max(72,G-2),j$=Math.max(6,u-3),x=[];return x.push(T0(Z,p(),h)),x.push(k0(Z,O.map((O$)=>({id:O$.id,label:O$.label})),_,h)),x.push(B0(Z,h)),x.push(...E().render(h,j$)),i(Z,{width:G,title:" /cliproxy ",lines:x,footer:{hint:E().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},_$=(G)=>{if(A1().matches(G,"tui.select.cancel")||v(G,"q")||v(G,"escape"))return z(),!0;if(v(G,"]")||v(G,"tab"))return W((_+1)%O.length),!0;if(v(G,"[")||v(G,"shift+tab"))return W((_-1+O.length)%O.length),!0;if(v(G,"1"))return W(0),!0;if(v(G,"2"))return W(1),!0;if(v(G,"3"))return W(2),!0;if(v(G,"r"))return H().then(()=>!0);if(v(G,"e"))return P().then(()=>!0);if(v(G,"s"))return A(),!0;return!1};return{render:P$,invalidate(){},handleInput(G){let b=E().handleInput(G);if(b instanceof Promise){V="",b.then((u)=>{if(u)Y.requestRender()});return}if(b){V="",Y.requestRender();return}let l=_$(G);if(l instanceof Promise)l.then((u)=>{if(u)Y.requestRender()});else if(l)Y.requestRender()}}}async function e0($,j,J,Y){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Z=structuredClone(J);u$(!0);try{await j.ui.custom((X,z,Q,q)=>a0({dm:$,ctx:j,tui:X,theme:z,cfg:Z,discovery:Y,done:q}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{u$(!1)}}function HJ($){$.registerCommand("cliproxy",{description:"Manage proxy models, usage, and diagnostics in one hub overlay",handler:n1.bind(null,$)}),$.registerCommand("cliproxy-setup",{description:"Set endpoint, API key, and (optional) usage key for the proxy",handler:W1.bind(null,$)})}async function n1($,j,J){let Y=o();if(!Y.proxy.endpoint||!I(Y.proxy.apiKey)){if(J.ui.notify("endpoint or API key not set — launching setup first","info"),!await G$(J,!0))return}let Z=o(),X=I(Z.proxy.apiKey),z;try{z=await D$(Z,X)}catch(Q){J.ui.notify(`discovery failed: ${Q.message}`,"error");return}await e0($,J,Z,z)}async function W1($,j,J){if(!await G$(J,!0))return;let Z=o();try{let X=await D$(Z,I(Z.proxy.apiKey)),z=await E$($,Z,X);X$(),J.ui.notify(`setup ok · ${z.registered.length} providers registered (source=${X.source})`,"info")}catch(X){J.ui.notify(`setup saved, but apply failed: ${X.message}`,"warning")}}export{HJ as registerCommands};
1
+ import{getModels as sj}from"@duckmind/dm-ai/compat";var f$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function h$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function D0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Rj=128000,_j=16000,Aj={input:0,output:0,cacheRead:0,cacheWrite:0},Oj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function L$($){return Oj.some((j)=>j.test($))}var Hj=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function B$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function R0($,j){let J=(j??"").trim(),Z=$.match(/^([a-z0-9]+-)(.*)$/);if(Z)return J?`${J}-${Z[1]}`:Z[1];return $}function _0($,j){for(let[J,Z,Y]of Hj)if(J.has($))return{slug:B$(j,Z),api:Y};return{slug:B$(j,"misc"),api:"openai-completions"}}function Gj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function X$($){return{id:$,name:Gj($),contextWindow:Rj,maxTokens:_j,reasoning:L$($),cost:{...Aj}}}import{execSync as Nj}from"node:child_process";import{randomUUID as O0}from"node:crypto";import{chmodSync as l$,closeSync as A0,constants as Wj,copyFileSync as Tj,existsSync as V$,fsyncSync as kj,linkSync as Bj,mkdirSync as Lj,openSync as Fj,readFileSync as H0,renameSync as Kj,rmSync as c$,writeFileSync as Sj}from"node:fs";import{homedir as F$}from"node:os";import{dirname as S$,join as D$}from"node:path";import{fileURLToPath as Ij}from"node:url";var U$=!1;function p$($){U$=$}var F={info(...$){if(!U$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!U$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!U$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!U$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var m$=D$(F$(),".dm","agent","dm-cliproxy"),l=D$(m$,"config.json"),bj=[D$(F$(),".pi","agent","pi-cliproxyapi","config.json"),D$(F$(),".config","pi-cliproxyapi","config.json")];function R$($){Lj($,{recursive:!0,mode:448}),l$($,448)}function Q$($){if(V$($))l$($,384)}function Pj($){let j;try{j=JSON.parse(H0($,"utf8"))}catch{return}let J=j&&typeof j==="object"?j.proxy:void 0;for(let Z of[J?.apiKey,J?.usageKey]){if(typeof Z!=="string")continue;let Y=/^!cat\s+((?:~\/|\/)[^\s;&|`]+)$/.exec(Z.trim());if(!Y)continue;let X=Y[1].replace(/^~/,F$());Q$(X)}}function xj(){return V$(D$(S$(Ij(import.meta.url)),"..",".git"))}function nj($=bj,j=l,J=xj()){if(V$(j))return;let Y=(typeof $==="string"?[$]:[...$]).find((z)=>V$(z));if(!Y)return;let X;try{Q$(Y),Pj(Y),R$(S$(j)),X=`${j}.${process.pid}.${O0()}.tmp`,Tj(Y,X,Wj.COPYFILE_EXCL),l$(X,384),Bj(X,j),c$(X),X=void 0,F.info("legacy config copied to",j)}catch(z){if(X)try{c$(X,{force:!0})}catch(Q){F.warn("failed to clean temporary config:",Q)}F.warn("failed to migrate legacy config:",z)}}var K$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function r(){if(nj(),!V$(l))return F.debug("config not found, using defaults at",l),structuredClone(K$);try{R$(S$(l)),Q$(l);let $=JSON.parse(H0(l,"utf8"));return wj($)}catch($){return F.error("failed to read config:",$,"— using defaults"),structuredClone(K$)}}function yj($,j=l){R$(S$(j));let J=`${j}.${process.pid}.${O0()}.tmp`,Z;try{Z=Fj(J,"wx",384),Sj(Z,JSON.stringify($,null,2)+`
2
+ `,{encoding:"utf8"}),kj(Z),A0(Z),Z=void 0,Kj(J,j),Q$(j)}finally{if(Z!==void 0)A0(Z);c$(J,{force:!0})}}function I$($){yj($),F.info("config saved to",l)}function wj($){if(!$||typeof $!=="object")return structuredClone(K$);let j=$,J=structuredClone(K$),Z=j.proxy??{};if(J.proxy.endpoint=typeof Z.endpoint==="string"?Z.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof Z.apiKey==="string"?Z.apiKey:"",typeof Z.usageKey==="string")J.proxy.usageKey=Z.usageKey;if(typeof Z.providerPrefix==="string"&&Z.providerPrefix.trim())J.proxy.providerPrefix=Z.providerPrefix.trim();if(j.builtinProviders&&typeof j.builtinProviders==="object")J.builtinProviders=j.builtinProviders;if(j.customProviders&&typeof j.customProviders==="object")J.customProviders=j.customProviders;if(Array.isArray(j.discoveryExcludes))J.discoveryExcludes=j.discoveryExcludes.filter((Y)=>typeof Y==="string");if(j.overrides&&typeof j.overrides==="object")J.overrides=j.overrides;if(typeof j.refreshIntervalMinutes==="number")J.refreshIntervalMinutes=j.refreshIntervalMinutes;if(typeof j.usageCacheTtlMs==="number")J.usageCacheTtlMs=j.usageCacheTtlMs;return J}function x($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Nj(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Z=J?.status,Y=typeof Z==="number"?` (exit ${Z})`:"";return F.warn(`failed to resolve "!" config value${Y}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{createHash as Cj}from"node:crypto";import{existsSync as i1,readFileSync as r1,writeFileSync as vj}from"node:fs";import{dirname as uj,join as gj}from"node:path";var fj=gj(m$,"discovery-cache.json");function G0($,j){return Cj("sha256").update($.trim().replace(/\/+$/,"")).update("\x00").update(j).digest("hex")}function s$($,j,J=fj){try{R$(uj(J));let Z={savedAt:Date.now(),scope:j,discovery:$};vj(J,JSON.stringify(Z),{encoding:"utf8",mode:384}),Q$(J)}catch(Z){F.warn("failed to write discovery cache:",Z.message)}}var z$="dm-cliproxy/0.3.5",hj=5000;async function T0($,j){let J=new AbortController,Z=setTimeout(()=>J.abort(Error("timeout")),hj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Z)}}function pj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function cj($){let j=pj($.proxy.endpoint),J;try{J=await T0(j,{headers:{"User-Agent":z$,Accept:"application/json"}})}catch(Q){return F.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!J.ok)return F.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let Z;try{Z=await J.json()}catch{return F.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Z||Z.schemaVersion!==1)return F.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Y=[],X=Z.builtinProviders??{};for(let[Q,q]of Object.entries(X)){if(!q||!Array.isArray(q.models))continue;let E=q.models.map((M)=>({id:String(M.id),name:typeof M.name==="string"?M.name:String(M.id),reasoning:Boolean(M.reasoning??L$(String(M.id))),contextWindow:typeof M.contextWindow==="number"?M.contextWindow:200000,maxTokens:typeof M.maxTokens==="number"?M.maxTokens:16000,cost:M.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));Y.push({name:Q,api:q.api??"openai-responses",models:E})}let z=(Array.isArray(Z.customModelPool)?Z.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??L$(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:R0(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Z?.upstream?.upstreamVersion==="string"?Z.upstream.upstreamVersion:null,builtinProviders:Y,customPool:z,serverDiscoveryExcludes:Array.isArray(Z.discoveryExcludes)?Z.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Z?.counts?.upstreamTotal==="number"?Z.counts.upstreamTotal:0}}async function lj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Z=await T0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":z$}});if(!Z.ok)throw Error(`/v1/models returned ${Z.status}`);let Y=await Z.json();if(!Y?.data||!Array.isArray(Y.data))return[];return Y.data.map((X)=>({id:typeof X.id==="string"?X.id:"",owned_by:typeof X.owned_by==="string"?X.owned_by:""})).filter((X)=>X.id)}function mj($,j){let J=j.discoveryExcludes,Z=new Map,Y=[],X=0;for(let z of $){if(X++,D0(z.id,J))continue;if(z.owned_by==="openai"){let M=X$(z.id);N0(Z,"openai","openai-responses",W0(M));continue}if(z.owned_by==="anthropic"){let M=X$(z.id);N0(Z,"anthropic","anthropic-messages",W0(M));continue}let{slug:Q,api:q}=_0(z.owned_by,j.proxy.providerPrefix),E=X$(z.id);Y.push({id:z.id,name:E.name??z.id,reasoning:E.reasoning??!1,contextWindow:E.contextWindow??128000,maxTokens:E.maxTokens??16000,cost:E.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:q,suggestedProvider:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Z.values()),customPool:Y,serverDiscoveryExcludes:[],upstreamTotal:X}}function N0($,j,J,Z){let Y=$.get(j);if(!Y)Y={name:j,api:J,models:[]},$.set(j,Y);Y.models.push(Z)}function W0($){return{id:$.id,name:$.name??$.id,reasoning:$.reasoning??!1,contextWindow:$.contextWindow??128000,maxTokens:$.maxTokens??16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function _$($,j){let J=G0($.proxy.endpoint,j),Z=await cj($);if(Z)return F.info(`discovery via /.well-known/pi: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),s$(Z,J),Z;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await lj($,j),X=mj(Y,$);return F.info(`discovery via /v1/models: ${X.builtinProviders.length} builtin, ${X.customPool.length} custom`),s$(X,J),X}function k0($){let j=new Set;for(let J of $.builtinProviders)for(let Z of J.models)j.add(Z.id);for(let J of $.customPool)j.add(J.id);return j}var B0=new WeakMap,o$=new WeakMap;function A$($){let j=(o$.get($)??0)+1;return o$.set($,j),j}function b$($,j){return j===void 0||j===(o$.get($)??0)}function L0($,j,J){let Z=B0.get($)??new Set;for(let Y of Z){if(j.has(Y))continue;$.unregisterProvider(Y),J.unregistered.push(Y)}B0.set($,new Set(j))}async function O$($,j,J,Z){let Y={registered:[],skipped:[],unregistered:[]};if(!b$($,Z))return Y.skipped.push({provider:"*",reason:"stale refresh generation"}),Y;let X=new Set,z=k0(J),Q=x(j.proxy.apiKey);if(!Q)return F.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),L0($,X,Y),Y;let q=new Map;for(let M of J.builtinProviders)q.set(M.name,M.models.map((U)=>({id:U.id,name:U.name,reasoning:U.reasoning,contextWindow:U.contextWindow,maxTokens:U.maxTokens,cost:U.cost})));for(let[M,U]of Object.entries(j.builtinProviders)){if(!b$($,Z))return Y;if(!U?.enabled){Y.skipped.push({provider:M,reason:"disabled"});continue}if(!Array.isArray(U.models)||U.models.length===0){Y.skipped.push({provider:M,reason:"empty whitelist"});continue}let K=[];try{K=sj(M)}catch{}let k=new Map(K.map((N)=>[N.id,N])),O=new Map((q.get(M)??[]).map((N)=>[N.id,N])),D=[];for(let N of U.models){if(!z.has(N))continue;let G=k.get(N),n=O.get(N);if(G){D.push({id:G.id,name:G.name,reasoning:G.reasoning,contextWindow:G.contextWindow,maxTokens:G.maxTokens,cost:G.cost,input:G.input,api:G.api,thinkingLevelMap:G.thinkingLevelMap});continue}if(!n)continue;let J$=M==="anthropic"?"anthropic-messages":U.apiOverride??"openai-responses";D.push({id:n.id,name:n.name,reasoning:n.reasoning,contextWindow:n.contextWindow,maxTokens:n.maxTokens,cost:n.cost,input:["text"],api:J$})}if(D.length===0){Y.skipped.push({provider:M,reason:"no whitelisted models present on proxy"});continue}let A=U.apiOverride??D[0].api;if(!f$.has(A)){Y.skipped.push({provider:M,reason:`api "${A}" not in allowlist`});continue}let B=D.map((N)=>{let G=j.overrides[N.id]??{},n={id:N.id,name:typeof G.name==="string"?G.name:N.name,api:A,reasoning:typeof G.reasoning==="boolean"?G.reasoning:N.reasoning,input:N.input,cost:G.cost??N.cost,contextWindow:typeof G.contextWindow==="number"?G.contextWindow:N.contextWindow,maxTokens:typeof G.maxTokens==="number"?G.maxTokens:N.maxTokens};if(N.thinkingLevelMap)n.thinkingLevelMap=N.thinkingLevelMap;return n}),C={name:M,baseUrl:h$(A,j.proxy.endpoint),apiKey:Q,authHeader:!0,api:A,models:B};$.registerProvider(M,C),X.add(M),Y.registered.push({provider:M,modelCount:B.length,api:A})}let E=new Map(J.customPool.map((M)=>[M.id,M]));for(let[M,U]of Object.entries(j.customProviders)){if(!b$($,Z))return Y;if(!f$.has(U.api)){Y.skipped.push({provider:M,reason:`api "${U.api}" not in allowlist`});continue}let K=U.models.filter((D)=>z.has(D.id));if(K.length===0){Y.skipped.push({provider:M,reason:"no configured models present on proxy"});continue}let k=K.map((D)=>{let A=E.get(D.id),B=X$(D.id),C=j.overrides[D.id]??{};return{id:D.id,name:D.name??A?.name??B.name??D.id,api:U.api,reasoning:oj(D.reasoning,A?.reasoning,B.reasoning,C.reasoning)??!1,input:["text"],cost:D.cost??A?.cost??B.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:F0(D.contextWindow,A?.contextWindow,B.contextWindow,C.contextWindow)??128000,maxTokens:F0(D.maxTokens,A?.maxTokens,B.maxTokens,C.maxTokens)??16000}}),O={name:M,baseUrl:h$(U.api,j.proxy.endpoint),apiKey:Q,authHeader:!0,api:U.api,models:k};$.registerProvider(M,O),X.add(M),Y.registered.push({provider:M,modelCount:k.length,api:U.api})}if(b$($,Z))L0($,X,Y);return F.info(`applyAll: registered ${Y.registered.length} providers, skipped ${Y.skipped.length}, unregistered ${Y.unregistered.length}`),Y}function F0(...$){for(let j of $)if(typeof j==="number")return j;return}function oj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var ij=15000,H$=null;function q$(){H$=null}async function K0($,j,J={}){if(!J.force&&H$&&Date.now()-H$.fetchedAt<$.usageCacheTtlMs)return H$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Z=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Y=new AbortController,X=setTimeout(()=>Y.abort(Error("timeout")),ij),z;try{z=await fetch(Z,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":z$},signal:Y.signal})}finally{clearTimeout(X)}if(!z.ok)throw Error(`/api/usage returned ${z.status}`);let Q=await z.json();if(!Q||Q.schemaVersion!==1||!Array.isArray(Q.accounts))throw Error("/api/usage returned unexpected payload shape");return H$={fetchedAt:Date.now(),doc:Q},F.debug("usage fetched, accounts:",Q.accounts.length),Q}import{getKeybindings as n1,matchesKey as u}from"@duckmind/dm-tui";import{visibleWidth as r$}from"@duckmind/dm-tui";import{visibleWidth as S0}from"@duckmind/dm-tui";function S($,j){let J=S0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return i$($,j)}function i$($,j){if(j<=0)return"\x1B[0m";let J="",Z=0,Y=0;while(Y<$.length){let X=$[Y];if(X==="\x1B"&&$[Y+1]==="["){let Q=$.indexOf("m",Y+2);if(Q>=0){J+=$.slice(Y,Q+1),Y=Q+1;continue}}let z=S0(X);if(Z+z>j)break;J+=X,Z+=z,Y++}return`${J}\x1B[0m`}var rj="│",dj="╭",tj="╮",aj="╰",ej="╯",G$="─";function d($,j){let J=Math.max(4,j.width);return[$1($,j.title,j.titleColor??"accent",J),...j.lines.map((Z)=>j1($,Z,J)),J1($,j.footer,J)]}function $1($,j,J,Z){let Y=j??"",X=r$(Y),z=Math.max(0,Z-3-X),Q=Y?$.bold($.fg(J,Y)):"",q=`${dj}${G$}${Q}${G$.repeat(z)}${tj}`;return $.fg("borderAccent",q)}function j1($,j,J){let Z=Math.max(0,J-2),Y=$.fg("borderAccent",rj);return`${Y}${S(j,Z)}${Y}`}function J1($,j,J){let Z=`${aj}${G$}`,Y=`${ej}`,X=3;if(!j||!j.hint&&!j.badge){let O=Math.max(0,J-3);return $.fg("borderAccent",`${Z}${G$.repeat(O)}${Y}`)}let z=j.hint??"",Q=j.badge??"",q=r$(z),E=r$(Q),M=Math.max(0,J-3-q-E),U=$.fg("dim",z),K=Q?$.fg("muted",Q):"",k=G$.repeat(M);return`${$.fg("borderAccent",Z)}${U}${$.fg("borderAccent",k)}${K}${$.fg("borderAccent",Y)}`}function P$($){return Math.max(0,$-2)}import{existsSync as I0}from"node:fs";import{homedir as Y1}from"node:os";import{getKeybindings as Z1,Input as d$,matchesKey as X1}from"@duckmind/dm-tui";var Q1=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:($)=>{try{if(!new URL($).pathname.endsWith("/v1"))return"must end with /v1";return null}catch{return"not a valid URL"}}},{label:"apiKey",hint:"CliProxyAPI bearer key. Input is masked; blank keeps an existing key",required:!0,secret:!0},{label:"providerPrefix",hint:"Prefix for your custom provider names. Suggested groups become <prefix>-glm, <prefix>-gemini, etc. Use any short slug (letters/digits/dashes).",required:!0,validate:($)=>/^[a-z0-9][a-z0-9-]*$/i.test($)?null:"letters/digits/dashes only"},{label:"usageKey",hint:"Optional X-Plugin-Key for /api/usage. Input is masked; blank keeps it, '-' clears it",required:!1,secret:!0}];async function N$($,j=!1){let J=r(),Z={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Y=!1;for(let z of Q1){let Q=Z[z.label]??"",q=z.secret?"":j?Z[z.label]??z.initialValue??"":Z[z.label]??"";if(!j&&q)continue;let E=z.secret&&Q?{...z,required:!1}:z,M=await M1($,E,q||z.initialValue||"");if(M===void 0){Y=!0;break}let U=q1(z,Q,M);if(U===null){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Y=!0;break}}Z[z.label]=U??""}if(Y)return!1;let X={...J};if(X.proxy={...J.proxy,endpoint:Z.endpoint??"",apiKey:Z.apiKey??"",providerPrefix:Z.providerPrefix??""},Z.usageKey)X.proxy.usageKey=Z.usageKey;else delete X.proxy.usageKey;return I$(X),$.ui.notify(`saved to ${l}`,"info"),!0}function z1($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,Y1());return I0(j)?`!cat ${$}`:$}if($.startsWith("/"))return I0($)?`!cat ${$}`:$;return $}function q1($,j,J){let Z=J.trim();if(!Z){if($.secret&&j)return j;return $.required?null:""}if($.secret&&!$.required&&Z==="-")return"";return $.label==="providerPrefix"||$.label==="endpoint"?Z:z1(Z)}async function M1($,j,J){return $.ui.custom((Z,Y,X,z)=>E1(Z,Y,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}class b0{rawInput=new d$;displayInput=new d$;pasteActive=!1;get focused(){return this.rawInput.focused}set focused($){this.rawInput.focused=$,this.displayInput.focused=$}set onSubmit($){this.rawInput.onSubmit=$}set onEscape($){this.rawInput.onEscape=$}getValue(){return this.rawInput.getValue()}setValue($){this.rawInput.setValue($),this.displayInput.setValue("•".repeat($.length))}handleInput($){this.rawInput.handleInput($),this.displayInput.handleInput(this.maskInput($)),this.displayInput.setValue("•".repeat(this.rawInput.getValue().length))}render($){return this.displayInput.render($)}invalidate(){this.rawInput.invalidate(),this.displayInput.invalidate()}maskInput($){let j="";for(let J=0;J<$.length;){if($.startsWith("\x1B[200~",J)){this.pasteActive=!0,j+="\x1B[200~",J+=6;continue}if($.startsWith("\x1B[201~",J)){this.pasteActive=!1,j+="\x1B[201~",J+=6;continue}if(!this.pasteActive&&$.charCodeAt(J)===27)return $;let Z=$.codePointAt(J),Y=String.fromCodePoint(Z);j+=Z<32||Z===127?Y:"•",J+=Y.length}return j}}function E1($,j,J,Z,Y){let X=J.secret?new b0:new d$;X.setValue(Z),X.focused=!0;let z=null,Q=(q)=>{if(!q&&!J.required){Y("");return}if(!q&&J.required){z="required field",$.requestRender();return}if(J.validate){let E=q.trim();if(E&&!E.startsWith("!")&&!E.startsWith("$")){let M=J.validate(E);if(M){z=M,$.requestRender();return}}}Y(q)};return X.onSubmit=Q,X.onEscape=()=>Y(void 0),{render(q){let E=P$(q),M=X.render(E-4),U=["",` ${j.fg("dim",J.hint)}`,"",...M.map((K)=>` ${j.fg("accent",`❯ ${K}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return d(j,{width:q,title:` setup: ${J.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){X.invalidate()},handleInput(q){if(Z1().matches(q,"tui.select.cancel")||X1(q,"escape")){Y(void 0);return}z=null,X.handleInput(q),$.requestRender()}}}import{visibleWidth as x$}from"@duckmind/dm-tui";function P0($,j,J,Z){let Y=$.fg("borderAccent","│"),X=j.map((z,Q)=>{let q=`${Q+1} ${z.label}`;return Q===J?$.bold($.fg("accent",` ${q} `)):$.fg("dim",` ${q} `)});return S(` ${X.join(Y)}`,Z)}function x0($,j,J){let Z=j.join($.fg("dim"," "));return S(` ${Z}`,J)}function n0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function t($,j,J){let Z=$.slice(j,j+J);while(Z.length<J)Z.push("");return Z}function n$($,j,J,Z,Y,X){if(Y<=Z)return 0;let z=Math.max(0,Y-Z);if(j<X)return 0;let Q=Math.max(0,Math.min(J,z)),q=Q+X;if($<q)Q=Math.max(0,$-X);let E=Q+Z-1;if(j>E)Q=Math.min(z,j-(Z-1));return Q}function y$($,j,J){let Z=Math.max(0,J-j);return Math.max(0,Math.min($,Z))}import{matchesKey as a}from"@duckmind/dm-tui";import{existsSync as U1,readFileSync as V1}from"node:fs";import{homedir as w0}from"node:os";import{join as C0}from"node:path";var D1=C0(w0(),".dm","models.json"),R1=C0(w0(),".dm","auth.json");function y0($){if(!U1($))return null;try{return JSON.parse(V1($,"utf8"))}catch{return null}}function v0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Z=y0(D1);if(Z&&typeof Z==="object"){for(let X of Object.keys(Z))if(J.has(X))j.push({kind:"models.json",provider:X,detail:`provider "${X}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Y=y0(R1);if(Y&&typeof Y==="object"){for(let X of Object.keys(Y))if(J.has(X))j.push({kind:"auth.json",provider:X,detail:`provider "${X}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function u0($){let{theme:j,cfg:J}=$,Z=0,Y=()=>{let Q=$.getDiscovery(),q=(O)=>j.fg("success",O),E=(O)=>j.fg("error",O),M=(O)=>j.fg("dim",O),U=[];U.push(`${M("endpoint")} ${J.proxy.endpoint||E("(unset)")}`),U.push(`${M("apiKey")} ${x(J.proxy.apiKey)?q("resolves"):E("empty after resolution")}`),U.push(`${M("usageKey")} ${J.proxy.usageKey?x(J.proxy.usageKey)?q("resolves"):E("set but empty"):M("not configured")}`),U.push(`${M("user-agent")} ${z$}`),U.push(""),U.push(`${M("discovery")} source=${Q.source}`),U.push(`${M("upstream")} v=${Q.upstreamVersion??"(unknown)"} · ${Q.upstreamTotal} ids`);let K=Q.builtinProviders.map((O)=>`${O.name}=${O.models.length}`).join(", ")||M("(none)");U.push(`${M("built-in")} ${K}`),U.push(`${M("custom pool")} ${Q.customPool.length} models`);let k=v0(J);if(U.push(""),k.length===0)U.push(`${M("conflicts")} ${q("none")}`);else{U.push(`${M("conflicts")}`);for(let O of k)U.push(` ${j.fg("warning",`[${O.kind}]`)} ${O.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(Q,q)=>{let E=Y();return Z=y$(Z,q,E.length),t(E,Z,q).map((M)=>S(` ${M}`,Q))},handleInput:(Q)=>{let q=Y().length;if(a(Q,"up")||a(Q,"k"))return Z=Math.max(0,Z-1),!0;if(a(Q,"down")||a(Q,"j"))return Z=Math.min(Math.max(0,q-1),Z+1),!0;if(a(Q,"pageUp")||a(Q,"b"))return Z=Math.max(0,Z-10),!0;if(a(Q,"pageDown")||a(Q,"f"))return Z=Math.min(Math.max(0,q-1),Z+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as T}from"@duckmind/dm-tui";function t$($){let j=new Map,J=new Map;for(let Y of $.builtinProviders){let X=[];for(let z of Y.models)j.set(z.id,{id:z.id,name:z.name,suggestedApi:Y.api,subtitle:z.name&&z.name!==z.id?z.name:void 0,ownedBy:Y.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost}),X.push(z.id);J.set(Y.name,X)}let Z=[];for(let Y of $.customPool){if(!j.has(Y.id))j.set(Y.id,{id:Y.id,name:Y.name,suggestedApi:Y.api,subtitle:Y.name&&Y.name!==Y.id?Y.name:void 0,origin:Y.suggestedProvider,ownedBy:Y.ownedBy,reasoning:Y.reasoning,contextWindow:Y.contextWindow,maxTokens:Y.maxTokens,cost:Y.cost});Z.push(Y.id)}return{byId:j,builtinModelIds:J,customPoolIds:Z}}function _1($){let j=new Map;for(let[J,Z]of Object.entries($.customProviders))for(let Y of Z.models)j.set(Y.id,J);return j}function j$($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function g0($,j,J){if(j.kind==="builtin"){let X=J.builtinModelIds.get(j.name)??[],z=new Set(j$($,j));return X.filter((Q)=>!z.has(Q))}let Z=_1($),Y=new Set(j$($,j));return J.customPoolIds.filter((X)=>{if(Y.has(X))return!1;let z=Z.get(X);return z===void 0||z===j.name})}function A1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function f0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name]??{enabled:!0,models:[]},X=new Set(Y.models);X.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Y.apiOverride??null,models:Array.from(X).sort()};return}for(let[Y,X]of Object.entries($.customProviders)){if(Y===j.name)continue;let z=X.models.findIndex((Q)=>Q.id===J.id);if(z>=0)X.models.splice(z,1)}let Z=$.customProviders[j.name]??{api:j.api,models:[]};if(!Z.models.some((Y)=>Y.id===J.id))Z.models.push(A1(J));$.customProviders[j.name]=Z}function h0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name];if(!Y)return;Y.models=Y.models.filter((X)=>X!==J),Y.enabled=Y.models.length>0;return}let Z=$.customProviders[j.name];if(!Z)return;Z.models=Z.models.filter((Y)=>Y.id!==J)}function a$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function p0($,j){let J=new Map;for(let Z of $){let Y=j.byId.get(Z),X=Y?.ownedBy||Y?.origin||"misc",z=J.get(X)??[];z.push(Z),J.set(X,z)}return Array.from(J.entries()).sort((Z,Y)=>Z[0].localeCompare(Y[0])).map(([Z,Y])=>({label:Z,ids:Y}))}function c0($,j,J){let Z=J.trim().toLowerCase();if(!Z)return $;return $.filter((Y)=>{if(Y.toLowerCase().includes(Z))return!0;let X=j.byId.get(Y)?.name;return X?X.toLowerCase().includes(Z):!1})}import{getModels as O1,getProviders as H1}from"@duckmind/dm-ai/compat";function e$($,j){let J=[],Z=new Set(j.builtinModelIds.keys()),Y=new Set(H1()),X=new Set([...Z,...Y]);for(let z of Array.from(X).sort()){let Q=j.builtinModelIds.get(z);if(!Q||Q.length===0)continue;let q;try{let M=O1(z).find((U)=>Q.includes(U.id));if(M)q=M.api}catch{}if(!q){let E=Q[0];q=j.byId.get(E)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:z,api:q,subtitle:`built-in · ${q}`}),!$.builtinProviders[z])$.builtinProviders[z]={enabled:!1,models:[]}}for(let z of Object.keys($.customProviders).sort()){let Q=$.customProviders[z];J.push({kind:"custom",name:z,api:Q.api,subtitle:`custom · ${Q.api}`})}return J}import{getKeybindings as G1,matchesKey as M$}from"@duckmind/dm-tui";async function l0($,j){return $.ui.custom((J,Z,Y,X)=>N1(Z,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",X),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function N1($,j,J,Z){return{render(Y){return d($,{width:Y,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Y){if(G1().matches(Y,"tui.select.cancel")||M$(Y,"escape")||M$(Y,"n")||M$(Y,"q")){Z(!1);return}if(M$(Y,"y")||M$(Y,"enter")||M$(Y,"return")){Z(!0);return}}}}import{getKeybindings as W1,Input as T1,matchesKey as k1}from"@duckmind/dm-tui";async function m0($,j){let J=B$(j,"group");return $.ui.custom((Z,Y,X,z)=>B1(Z,Y,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function B1($,j,J,Z){let Y=new T1;if(J)Y.setValue(J);Y.focused=!0;let X=null;return Y.onSubmit=(z)=>{let Q=z.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(Q)){X="letters / digits / dot / dash / underscore only",$.requestRender();return}Z(Q)},Y.onEscape=()=>Z(null),{render(z){let Q=P$(z),q=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",E=Y.render(Q-4),M=["",` ${j.fg("dim",q)}`,"",...E.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",X?` ${j.fg("error",`! ${X}`)}`:""];return d(j,{width:z,title:" new custom group ",lines:M,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Y.invalidate()},handleInput(z){if(W1().matches(z,"tui.select.cancel")||k1(z,"escape")){Z(null);return}X=null,Y.handleInput(z),$.requestRender()}}}import{visibleWidth as L1}from"@duckmind/dm-tui";function $0($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function s0($,j){let J=L1($);if(J===j)return $;if(J>j)return i$($,j);return S($,j)}function o0($,j,J){let{theme:Z,width:Y,isCursor:X,isFocused:z}=J,Q=$0(Z,X,z),q=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,E=$.kind==="builtin"?Z.fg("accent","B"):Z.fg("warning","C"),M=`${Z.fg("dim","[")}${E}${Z.fg("dim","]")}`,U=q>0?Z.fg("success","●"):Z.fg("dim","○"),K=q>0?Z.fg("success",String(q).padStart(2)):Z.fg("dim"," 0"),k=X&&z?Z.bold(Z.fg("accent",$.name)):X?Z.bold($.name):$.name,O=Z.fg("dim",$.api),D=`${Q}${M} ${k} ${U}${K} ${O}`;return s0(D,Y)}function i0($,j,J,Z){let Y=$0($,j,J),X=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return S(`${Y}${X}`,Z)}function j0($,j,J,Z,Y){let{theme:X,width:z,isCursor:Q,isFocused:q}=Y,E=$0(X,Q,q),M=J==="assigned"?X.fg("success","☑"):X.fg("dim","☐"),U=Z?` ${X.fg("warning","⚠")}`:"",K=Q&&q?X.fg("accent",$):$,k=j?.reasoning?` ${X.fg("accent","✨")}`:"",O=j?X.fg("muted",` · ${j.suggestedApi}`):X.fg("error"," · not on proxy"),D=`${E}${M} ${K}${U}${k}${O}`;return s0(D,z)}function r0($,j,J){let Z=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return S(` ${Z}`,J)}function J0($,j,J){return S(` ${$.fg("dim",j)}`,J)}function d0($,j,J,Z){let Y=Z?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return S(`${Y}${j}`,J)}function t0($){let{tui:j,theme:J,ctx:Z,cfg:Y}=$,X=$.onChange??(()=>{}),z=t$($.getDiscovery()),Q=e$(Y,z),q="providers",E=0,M=0,U=0,K=0,k=0,O=0,D="",A=!1,B=()=>{if(Q.length===0)return null;let V=Math.max(0,Math.min(E,Q.length-1));return Q[V]??null},C=(V)=>{let H=c0(g0(Y,V,z),z,D);return p0(H,z)},N=(V)=>C(V).flatMap((H)=>H.ids),G=()=>{Q=e$(Y,z);let V=Math.max(0,Q.length);if(E>V)E=V;let H=B();if(H){let P=j$(Y,H).length,W=N(H).length;if(M>=P)M=Math.max(0,P-1);if(U>=W)U=Math.max(0,W-1)}},n=()=>{z=t$($.getDiscovery()),G()},J$=(V)=>{let H=["providers","assigned","pool"],P=H.indexOf(q);q=V?H[(P-1+H.length)%H.length]:H[(P+1)%H.length]},_=(V)=>{if(q==="providers"){let W=Q.length+1;E=Math.max(0,Math.min(E+V,W-1));return}let H=B();if(!H)return;if(q==="assigned"){let W=j$(Y,H).length;if(W===0)return;M=Math.max(0,Math.min(M+V,W-1));return}let P=N(H).length;if(P===0)return;U=Math.max(0,Math.min(U+V,P-1))},b=async()=>{if(q==="providers"){if(E===Q.length){let W=await m0(Z,Y.proxy.providerPrefix);if(W&&!Y.customProviders[W]){if(Y.customProviders[W]={api:"openai-completions",models:[]},X(),G(),E=Q.findIndex((I)=>I.kind==="custom"&&I.name===W),E<0)E=Q.length-1;q="pool"}j.requestRender();return}q="pool";return}let V=B();if(!V)return;if(q==="assigned"){let W=j$(Y,V)[M];if(!W)return;h0(Y,V,W),X(),G();return}let H=N(V)[U];if(!H)return;let P=z.byId.get(H);if(!P)return;f0(Y,V,P),X(),G()},p=async()=>{if(q!=="providers")return;let V=B();if(!V||V.kind!=="custom")return;if(!await l0(Z,V.name)){j.requestRender();return}if(delete Y.customProviders[V.name],X(),G(),E>=Q.length)E=Math.max(0,Q.length-1);j.requestRender()},g=(V,H)=>c(V,H);function c(V,H){let P=Math.max(70,V),W=Math.min(56,Math.max(34,Math.floor(P*0.4))),I=P-W-1,s=Math.max(8,H),o=Math.max(5,Math.floor((s-1)/2)),Y0=s-o,m=B(),E$=0,w$=0,C$=0,Z0=0,v$=0,X0=0,e=[];e.push(Y$(" providers ",W,q==="providers"));for(let L=0;L<Q.length;L++){let f=Q[L],v=q==="providers"&&L===E;if(v)E$=e.length,w$=E$;e.push(o0(f,Y,{theme:J,width:W,isCursor:v,isFocused:q==="providers"}))}{let L=q==="providers"&&E===Q.length;if(L)E$=e.length,w$=E$;e.push(i0(J,L,q==="providers",W))}let $$=[],Mj=m?`assigned to ${J.bold(m.name)} ${J.fg("dim",`· ${m.api}`)}`:J.fg("dim","no provider selected");if($$.push(Y$(" assigned ",I,q==="assigned")),$$.push(d0(J,Mj,I,q==="assigned")),m){let L=j$(Y,m);if(L.length===0)$$.push(J0(J,"(nothing assigned yet)",I));for(let f=0;f<L.length;f++){let v=L[f],h=z.byId.get(v),k$=q==="assigned"&&f===M;if(k$)C$=$$.length,Z0=C$;let Z$=h?!a$(m.api,h.suggestedApi):!1;$$.push(j0(v,h,"assigned",Z$,{theme:J,width:I,isCursor:k$,isFocused:q==="assigned"}))}}let i=[];if(i.push(y(I,q==="pool")),m){let L=C(m);if(L.reduce((v,h)=>v+h.ids.length,0)===0)i.push(J0(J,D?`(no matches for "${D}")`:"(no models available)",I));else{let v=0;for(let h of L){let k$=i.length;i.push(r0(J,h.label,I));for(let Z$=0;Z$<h.ids.length;Z$++){let U0=h.ids[Z$],g$=z.byId.get(U0),V0=q==="pool"&&v===U;if(V0)v$=i.length,X0=Z$===0?k$:v$;let Dj=g$?!a$(m.api,g$.suggestedApi):!1;i.push(j0(U0,g$,"pool",Dj,{theme:J,width:I,isCursor:V0,isFocused:q==="pool"})),v++}}}}let Ej=Math.max(1,Y0-1),Q0=n$(w$,E$,K,s,e.length,1),z0=n$(q==="assigned"?Z0:0,q==="assigned"?C$:0,k,o,$$.length,2),q0=n$(q==="pool"?X0:0,q==="pool"?v$:0,O,Ej,i.length,1);K=Q0,k=z0,O=q0;let M0=t(e,Q0,s),Uj=t($$,z0,o),Vj=t(i,q0,Y0),E0=J.fg("borderAccent","│"),u$=[];for(let L=0;L<s;L++){let f=S(M0[L]??"",W),v=L<o?Uj[L]:Vj[L-o],h=S(v,I);u$.push(`${f}${E0}${h}`)}let T$=o;if(T$>0&&T$<s){let L=S(M0[T$]??"",W),f=J.fg("borderAccent","─".repeat(I));u$[T$]=`${L}${E0}${f}`}return u$}function Y$(V,H,P){let W=P?J.bold(J.fg("accent",V)):J.fg("muted",V),I=J.fg("borderAccent","─".repeat(Math.max(0,H-x$(V)-1)));return S(`${W}${I}`,H)}function y(V,H){let W=H?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),I="";if(A)I=`${J.fg("dim"," /")}${J.fg("accent",D)}${J.fg("accent","█")} `;else if(D)I=`${J.fg("dim"," /")}${J.fg("warning",D)} `;let s=x$(" available pool ")+x$(I),o=J.fg("borderAccent","─".repeat(Math.max(0,V-s-1)));return S(`${W}${I}${o}`,V)}function W$(V){if(A){if(T(V,"escape"))return D="",A=!1,U=0,!0;if(T(V,"enter")||T(V,"return"))return A=!1,!0;if(T(V,"backspace")||T(V,"delete"))return D=D.slice(0,-1),U=0,!0;if(V.length===1&&V>=" "&&V!=="")return D+=V,U=0,!0;return!0}if(T(V,"tab"))return J$(!1),!0;if(T(V,"shift+tab"))return J$(!0),!0;if(T(V,"/"))return q="pool",A=!0,!0;if(T(V,"enter")||T(V,"return")||T(V,"space"))return b().then(()=>!0);if(q==="providers"&&(T(V,"d")||T(V,"delete")||T(V,"backspace")))return p().then(()=>!0);if(T(V,"up")||T(V,"k"))return _(-1),!0;if(T(V,"down")||T(V,"j"))return _(1),!0;if(T(V,"pageUp")||T(V,"b"))return _(-8),!0;if(T(V,"pageDown")||T(V,"f"))return _(8),!0;if(T(V,"left")||T(V,"h"))return q="providers",!0;if(T(V,"right")||T(V,"l")){if(q==="providers")q="assigned";else if(q==="assigned")q="pool";return!0}return!1}function qj(){if(A)return" type to filter · ↵ apply · esc clear ";return" tab ↔ panel · ↑↓ nav · ↵ move · / filter · d remove group "}return{id:"models",label:"Models",render:g,handleInput:W$,footerHint:qj,rebuild:n}}import{matchesKey as w}from"@duckmind/dm-tui";var R={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function a0($,j={}){let J=[],Z=new Map,Y=0;for(let X of $.accounts){if(!j.showDisabled&&X.disabled){Y++;continue}let z=Z.get(X.provider)??[];z.push(X),Z.set(X.provider,z)}if(J.push(`${R.dim}generated ${$.generatedAt}${R.reset}`),$.unsupportedProviders.length>0)J.push(`${R.dim}providers without quota lookup:${R.reset} ${$.unsupportedProviders.join(", ")}`);if(Y>0)J.push(`${R.dim}hidden disabled accounts:${R.reset} ${Y} ${R.dim2}(press d to show)${R.reset}`);for(let[X,z]of Array.from(Z.entries()).sort()){J.push(""),J.push(`${R.bold}${R.accent}▌ ${X}${R.reset}`);for(let Q of z){if(J.push(K1(Q)),!Q.supported){J.push(` ${R.dim2}(provider not quota-aware)${R.reset}`);continue}if(Q.error){if(j.verbose)for(let E of F1(Q.error,88))J.push(` ${R.red}${E}${R.reset}`);continue}let q=Q.groups??[];if(q.length===0){J.push(` ${R.dim2}(no active quota windows)${R.reset}`);continue}for(let E of q)J.push(I1(E))}}return J.push(""),J.push(`${R.dim}legend:${R.reset} ${e0} ok ${$j} error/unavailable ${jj} disabled ${R.green}✓N${R.reset}/${R.red}✗N${R.reset} request counters ${R.dim}v = verbose, d = show disabled${R.reset}`),J}function F1($,j){if($.length<=j)return[$];let J=[],Z=$;while(Z.length>j){let Y=Z.lastIndexOf(" ",j);if(Y<j*0.6)Y=j;J.push(Z.slice(0,Y)),Z=Z.slice(Y).replace(/^\s+/,"")}if(Z)J.push(Z);return J}function K1($){let j=S1($),J=`${R.green}✓${$.success}${R.reset} ${R.red}✗${$.failed}${R.reset}`,Z=Zj($.label,36);return` ${j} ${R.bold}${Z}${R.reset} ${J}`}var e0=`${R.green}●${R.reset}`,$j=`${R.yellow}⚠${R.reset}`,jj=`${R.dim2}⊘${R.reset}`;function S1($){if($.disabled)return jj;if($.unavailable||$.error||$.status&&$.status!=="active")return $j;return e0}function I1($){let j=Yj($.remainingFraction),J=Math.round(j*100),Z=b1(j),Y=$.resetTime?` ${R.dim}reset ${x1($.resetTime)}${R.reset}`:"",X=Zj($.label,28).padEnd(28," ");return` ${Z} ${P1(J,j)} ${X}${Y}`}function b1($){let j=Yj($),J=Math.round(j*18),Z=Jj(j),Y=R.dim2,X="█".repeat(J),z="░".repeat(18-J);return`${Y}[${Z}${X}${Y}${z}]${R.reset}`}function P1($,j){return`${Jj(j)}${String($).padStart(3)}%${R.reset}`}function Jj($){if($>=0.4)return R.green;if($>=0.15)return R.yellow;return R.red}function x1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let Z=Math.round(J/60000);if(Z<60)return`${Z}m`;let Y=Math.round(Z/60);if(Y<48)return`${Y}h`;return`${Math.round(Y/24)}d`}function Yj($){return Math.max(0,Math.min(1,$))}function Zj($,j){if($.length<=j)return $;return`${$.slice(0,j-1)}…`}function Xj($){let{tui:j,theme:J,cfg:Z}=$,Y="idle",X=null,z="",Q=0,q=!1,E=!1,M=(D)=>{Y="loading",j.requestRender();let A=x(Z.proxy.usageKey);K0(Z,A,{force:D}).then((B)=>{X=B,Y="ready",Q=0,j.requestRender()}).catch((B)=>{z=B.message,Y="error",j.requestRender()})},U=()=>{if(Y==="idle"||Y==="loading")return[J.fg("dim"," loading usage…")];if(Y==="error")return[J.fg("error",` usage failed: ${z}`)];if(!X)return[J.fg("dim"," (no data)")];return a0(X,{showDisabled:q,verbose:E})};return{id:"usage",label:"Usage",render:(D,A)=>{let B=U();return Q=y$(Q,A,B.length),t(B,Q,A).map((C)=>S(` ${C}`,D))},handleInput:(D)=>{if(w(D,"d"))return q=!q,Q=0,!0;if(w(D,"v"))return E=!E,Q=0,!0;let A=U().length;if(w(D,"up")||w(D,"k"))return Q=Math.max(0,Q-1),!0;if(w(D,"down")||w(D,"j"))return Q=Math.min(Math.max(0,A-1),Q+1),!0;if(w(D,"pageUp")||w(D,"b"))return Q=Math.max(0,Q-10),!0;if(w(D,"pageDown")||w(D,"f"))return Q=Math.min(Math.max(0,A-1),Q+10),!0;if(w(D,"home")||w(D,"g"))return Q=0,!0;if(w(D,"end")||w(D,"shift+g"))return Q=Math.max(0,A-1),!0;return!1},footerHint:()=>{let D=q?J.fg("success","[d disabled]"):"d disabled",A=E?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${D} · ${A} `},onActivate:()=>{if(Y==="idle")M(!1)},reload:()=>{if(q$(),Y!=="idle")M(!0)}}}function Qj($){let{dm:j,ctx:J,tui:Z,theme:Y,cfg:X,done:z}=$,Q=$.discovery,q=!1,E="",M=t0({tui:Z,theme:Y,ctx:J,cfg:X,getDiscovery:()=>Q,onChange:()=>{q=!0,E=""}}),U=Xj({tui:Z,theme:Y,cfg:X}),K=u0({theme:Y,cfg:X,getDiscovery:()=>Q}),k=[M,U,K],O=0,D=()=>k[O],A=(_)=>{if(_<0||_>=k.length||_===O)return;O=_,D().onActivate?.(),Z.requestRender()},B=()=>{E=Y.fg("dim","saving…"),I$(X),Z.requestRender();let _=A$(j);O$(j,X,Q,_).then((b)=>{q=!1,E=Y.fg("success",`✓ settings saved · ${b.registered.length} registered, ${b.skipped.length} skipped`),Z.requestRender()}).catch((b)=>{E=Y.fg("error",`save failed: ${b.message}`),Z.requestRender()})},C=async()=>{E=Y.fg("dim","refreshing…"),Z.requestRender();try{let _=A$(j),b=x(X.proxy.apiKey);Q=await _$(X,b),q$(),M.rebuild(),U.reload();let p=await O$(j,X,Q,_);E=Y.fg("success",`✓ refreshed · ${p.registered.length} providers (${Q.source})`)}catch(_){E=Y.fg("error",`refresh failed: ${_.message}`)}Z.requestRender()},N=async()=>{if(!await N$(J,!0)){Z.requestRender();return}let b=r();X.proxy={...X.proxy,...b.proxy},await C()},G=()=>{let _=X.proxy.endpoint||"(unset)",b=_.length>40?`…${_.slice(-39)}`:_,p=Boolean(x(X.proxy.apiKey)),g=0,c=0;for(let y of Object.values(X.builtinProviders)){if(y.enabled&&y.models.length>0)g++;c+=y.models.length}for(let y of Object.values(X.customProviders)){if(y.models.length>0)g++;c+=y.models.length}let Y$=E?E:q?Y.fg("warning","● unsaved — press s to save"):Y.fg("dim","✓ saved");return[`${Y.fg("dim","endpoint")} ${b}`,`${Y.fg("dim","key")} ${p?Y.fg("success","✓"):Y.fg("error","✗")}`,`${Y.fg("dim","providers")} ${g}`,`${Y.fg("dim","models")} ${c}`,Y$]},n=(_)=>{let b=Z.rows??40,g=Math.max(16,Math.min(b-6,38))-2,c=Math.max(72,_-2),Y$=Math.max(6,g-3),y=[];return y.push(x0(Y,G(),c)),y.push(P0(Y,k.map((W$)=>({id:W$.id,label:W$.label})),O,c)),y.push(n0(Y,c)),y.push(...D().render(c,Y$)),d(Y,{width:_,title:" /cliproxy ",lines:y,footer:{hint:D().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},J$=(_)=>{if(n1().matches(_,"tui.select.cancel")||u(_,"q")||u(_,"escape"))return z(),!0;if(u(_,"]")||u(_,"tab"))return A((O+1)%k.length),!0;if(u(_,"[")||u(_,"shift+tab"))return A((O-1+k.length)%k.length),!0;if(u(_,"1"))return A(0),!0;if(u(_,"2"))return A(1),!0;if(u(_,"3"))return A(2),!0;if(u(_,"r"))return C().then(()=>!0);if(u(_,"e"))return N().then(()=>!0);if(u(_,"s"))return B(),!0;return!1};return{render:n,invalidate(){},handleInput(_){let b=D().handleInput(_);if(b instanceof Promise){E="",b.then((g)=>{if(g)Z.requestRender()});return}if(b){E="",Z.requestRender();return}let p=J$(_);if(p instanceof Promise)p.then((g)=>{if(g)Z.requestRender()});else if(p)Z.requestRender()}}}async function zj($,j,J,Z){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Y=structuredClone(J);p$(!0);try{await j.ui.custom((X,z,Q,q)=>Qj({dm:$,ctx:j,tui:X,theme:z,cfg:Y,discovery:Z,done:q}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{p$(!1)}}function vJ($){$.registerCommand("cliproxy",{description:"Manage proxy models, usage, and diagnostics in one hub overlay",handler:y1.bind(null,$)}),$.registerCommand("cliproxy-setup",{description:"Set endpoint, API key, and (optional) usage key for the proxy",handler:w1.bind(null,$)})}async function y1($,j,J){let Z=r();if(!Z.proxy.endpoint||!x(Z.proxy.apiKey)){if(J.ui.notify("endpoint or API key not set — launching setup first","info"),!await N$(J,!0))return}let Y=r(),X=x(Y.proxy.apiKey),z;try{z=await _$(Y,X)}catch(Q){J.ui.notify(`discovery failed: ${Q.message}`,"error");return}await zj($,J,Y,z)}async function w1($,j,J){if(!await N$(J,!0))return;let Y=r();try{let X=A$($),z=await _$(Y,x(Y.proxy.apiKey)),Q=await O$($,Y,z,X);q$(),J.ui.notify(`setup ok · ${Q.registered.length} providers registered (source=${z.source})`,"info")}catch(X){J.ui.notify(`setup saved, but apply failed: ${X.message}`,"warning")}}export{vJ as registerCommands};
@@ -1,2 +1,2 @@
1
- import{execSync as w}from"node:child_process";import{randomUUID as L}from"node:crypto";import{chmodSync as V,constants as k,copyFileSync as B,existsSync as R,linkSync as v,mkdirSync as U,readFileSync as x,rmSync as E,writeFileSync as O}from"node:fs";import{homedir as D}from"node:os";import{dirname as z,join as Y}from"node:path";import{fileURLToPath as T}from"node:url";var M=!1;var b={info(...K){if(!M)console.log("[dm-cliproxy]",...K)},warn(...K){if(!M)console.warn("[dm-cliproxy]",...K)},error(...K){if(!M)console.error("[dm-cliproxy]",...K)},debug(...K){if(!M&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...K)}};var A=Y(D(),".dm","agent","dm-cliproxy"),X=Y(A,"config.json"),G=[Y(D(),".pi","agent","pi-cliproxyapi","config.json"),Y(D(),".config","pi-cliproxyapi","config.json")];function N(){return R(Y(z(T(import.meta.url)),"..",".git"))}function I(K=G,J=X,Q=N()){if(R(J))return;let $=(typeof K==="string"?[K]:[...K]).find((q)=>R(q));if(!$)return;let Z;try{U(z(J),{recursive:!0,mode:448}),V(z(J),448),Z=`${J}.${process.pid}.${L()}.tmp`,B($,Z,k.COPYFILE_EXCL),V(Z,384),v(Z,J),E(Z),Z=void 0,b.info("legacy config copied to",J)}catch(q){if(Z)try{E(Z,{force:!0})}catch(H){b.warn("failed to clean temporary config:",H)}b.warn("failed to migrate legacy config:",q)}}var j={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function s(){if(I(),!R(X))return b.debug("config not found, using defaults at",X),structuredClone(j);try{let K=JSON.parse(x(X,"utf8"));return _(K)}catch(K){return b.error("failed to read config:",K,"— using defaults"),structuredClone(j)}}function d(K){U(z(X),{recursive:!0,mode:448}),V(z(X),448);let J=`${X}.${process.pid}.${L()}.tmp`;try{O(J,JSON.stringify(K,null,2)+`
2
- `,{encoding:"utf8",flag:"wx",mode:384}),B(J,X),V(X,384)}finally{E(J,{force:!0})}b.info("config saved to",X)}function _(K){if(!K||typeof K!=="object")return structuredClone(j);let J=K,Q=structuredClone(j),W=J.proxy??{};if(Q.proxy.endpoint=typeof W.endpoint==="string"?W.endpoint:Q.proxy.endpoint,Q.proxy.apiKey=typeof W.apiKey==="string"?W.apiKey:"",typeof W.usageKey==="string")Q.proxy.usageKey=W.usageKey;if(typeof W.providerPrefix==="string"&&W.providerPrefix.trim())Q.proxy.providerPrefix=W.providerPrefix.trim();if(J.builtinProviders&&typeof J.builtinProviders==="object")Q.builtinProviders=J.builtinProviders;if(J.customProviders&&typeof J.customProviders==="object")Q.customProviders=J.customProviders;if(Array.isArray(J.discoveryExcludes))Q.discoveryExcludes=J.discoveryExcludes.filter(($)=>typeof $==="string");if(J.overrides&&typeof J.overrides==="object")Q.overrides=J.overrides;if(typeof J.refreshIntervalMinutes==="number")Q.refreshIntervalMinutes=J.refreshIntervalMinutes;if(typeof J.usageCacheTtlMs==="number")Q.usageCacheTtlMs=J.usageCacheTtlMs;return Q}function m(K){if(!K)return"";let J=K.trim();if(J.startsWith("!"))try{return w(J.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(Q){let W=Q?.stderr?.toString?.()?.trim()??Q.message;return b.warn(`failed to resolve "!" config value (${J}): ${W}`),""}if(J.startsWith("$"))return process.env[J.slice(1)]??"";return J}export{d as saveConfig,m as resolveConfigValue,I as migrateLegacyConfig,s as loadConfig,N as isLocalCheckout,G as LEGACY_CONFIG_PATHS,X as CONFIG_PATH,A as CONFIG_DIR};
1
+ import{execSync as G}from"node:child_process";import{randomUUID as k}from"node:crypto";import{chmodSync as B,closeSync as U,constants as N,copyFileSync as w,existsSync as Y,fsyncSync as A,linkSync as I,mkdirSync as _,openSync as D,readFileSync as O,renameSync as C,rmSync as L,writeFileSync as x}from"node:fs";import{homedir as V}from"node:os";import{dirname as q,join as $}from"node:path";import{fileURLToPath as v}from"node:url";var M=!1;var b={info(...K){if(!M)console.log("[dm-cliproxy]",...K)},warn(...K){if(!M)console.warn("[dm-cliproxy]",...K)},error(...K){if(!M)console.error("[dm-cliproxy]",...K)},debug(...K){if(!M&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...K)}};var S=$(V(),".dm","agent","dm-cliproxy"),z=$(S,"config.json"),F=[$(V(),".pi","agent","pi-cliproxyapi","config.json"),$(V(),".config","pi-cliproxyapi","config.json")];function H(K){_(K,{recursive:!0,mode:448}),B(K,448)}function R(K){if(Y(K))B(K,384)}function u(K){let J;try{J=JSON.parse(O(K,"utf8"))}catch{return}let W=J&&typeof J==="object"?J.proxy:void 0;for(let Q of[W?.apiKey,W?.usageKey]){if(typeof Q!=="string")continue;let X=/^!cat\s+((?:~\/|\/)[^\s;&|`]+)$/.exec(Q.trim());if(!X)continue;let Z=X[1].replace(/^~/,V());R(Z)}}function f(){return Y($(q(v(import.meta.url)),"..",".git"))}function p(K=F,J=z,W=f()){if(Y(J))return;let X=(typeof K==="string"?[K]:[...K]).find((E)=>Y(E));if(!X)return;let Z;try{R(X),u(X),H(q(J)),Z=`${J}.${process.pid}.${k()}.tmp`,w(X,Z,N.COPYFILE_EXCL),B(Z,384),I(Z,J),L(Z),Z=void 0,b.info("legacy config copied to",J)}catch(E){if(Z)try{L(Z,{force:!0})}catch(T){b.warn("failed to clean temporary config:",T)}b.warn("failed to migrate legacy config:",E)}}var j={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function c(){if(p(),!Y(z))return b.debug("config not found, using defaults at",z),structuredClone(j);try{H(q(z)),R(z);let K=JSON.parse(O(z,"utf8"));return m(K)}catch(K){return b.error("failed to read config:",K,"— using defaults"),structuredClone(j)}}function d(K,J=z){H(q(J));let W=`${J}.${process.pid}.${k()}.tmp`,Q;try{Q=D(W,"wx",384),x(Q,JSON.stringify(K,null,2)+`
2
+ `,{encoding:"utf8"}),A(Q),U(Q),Q=void 0,C(W,J),R(J)}finally{if(Q!==void 0)U(Q);L(W,{force:!0})}}function o(K){d(K),b.info("config saved to",z)}function m(K){if(!K||typeof K!=="object")return structuredClone(j);let J=K,W=structuredClone(j),Q=J.proxy??{};if(W.proxy.endpoint=typeof Q.endpoint==="string"?Q.endpoint:W.proxy.endpoint,W.proxy.apiKey=typeof Q.apiKey==="string"?Q.apiKey:"",typeof Q.usageKey==="string")W.proxy.usageKey=Q.usageKey;if(typeof Q.providerPrefix==="string"&&Q.providerPrefix.trim())W.proxy.providerPrefix=Q.providerPrefix.trim();if(J.builtinProviders&&typeof J.builtinProviders==="object")W.builtinProviders=J.builtinProviders;if(J.customProviders&&typeof J.customProviders==="object")W.customProviders=J.customProviders;if(Array.isArray(J.discoveryExcludes))W.discoveryExcludes=J.discoveryExcludes.filter((X)=>typeof X==="string");if(J.overrides&&typeof J.overrides==="object")W.overrides=J.overrides;if(typeof J.refreshIntervalMinutes==="number")W.refreshIntervalMinutes=J.refreshIntervalMinutes;if(typeof J.usageCacheTtlMs==="number")W.usageCacheTtlMs=J.usageCacheTtlMs;return W}function t(K){if(!K)return"";let J=K.trim();if(J.startsWith("!"))try{return G(J.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(W){let Q=W?.status,X=typeof Q==="number"?` (exit ${Q})`:"";return b.warn(`failed to resolve "!" config value${X}`),""}if(J.startsWith("$"))return process.env[J.slice(1)]??"";return J}export{d as saveConfigAtPath,o as saveConfig,t as resolveConfigValue,p as migrateLegacyConfig,c as loadConfig,f as isLocalCheckout,R as ensurePrivateFile,H as ensurePrivateDirectory,F as LEGACY_CONFIG_PATHS,z as CONFIG_PATH,S as CONFIG_DIR};
@@ -1 +1 @@
1
- function E(v,J){if(!v)return!0;for(let Z of J)if(new RegExp("^"+Z.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test(v))return!0;return!1}var F=128000,N=16000,_={input:0,output:0,cacheRead:0,cacheWrite:0},x=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function W(v){return x.some((J)=>J.test(v))}var h=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function L(v,J){let Z=(v??"").trim();return Z?`${Z}-${J}`:J}function B(v,J){let Z=(J??"").trim(),Y=v.match(/^([a-z0-9]+-)(.*)$/);if(Y)return Z?`${Z}-${Y[1]}`:Y[1];return v}function C(v,J){for(let[Z,Y,V]of h)if(Z.has(v))return{slug:L(J,Y),api:V};return{slug:L(J,"misc"),api:"openai-completions"}}function T(v){return v.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((J)=>J[0].toUpperCase()+J.slice(1)).join(" ")}function q(v){return{id:v,name:T(v),contextWindow:F,maxTokens:N,reasoning:W(v),cost:{..._}}}import{chmodSync as b,existsSync as v0,mkdirSync as f,readFileSync as J0,writeFileSync as u}from"node:fs";import{dirname as O,join as c}from"node:path";import{homedir as R}from"node:os";import{dirname as d,join as H}from"node:path";var K=!1;var D={info(...v){if(!K)console.log("[dm-cliproxy]",...v)},warn(...v){if(!K)console.warn("[dm-cliproxy]",...v)},error(...v){if(!K)console.error("[dm-cliproxy]",...v)},debug(...v){if(!K&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...v)}};var k=H(R(),".dm","agent","dm-cliproxy"),r=H(k,"config.json"),a=[H(R(),".pi","agent","pi-cliproxyapi","config.json"),H(R(),".config","pi-cliproxyapi","config.json")];var w=c(k,"discovery-cache.json");function A(v){try{f(O(w),{recursive:!0,mode:448}),b(O(w),448);let J={savedAt:Date.now(),discovery:v};u(w,JSON.stringify(J),{encoding:"utf8",mode:384})}catch(J){D.warn("failed to write discovery cache:",J.message)}}var G="dm-cliproxy/0.3.5",y=5000;async function I(v,J){let Z=new AbortController,Y=setTimeout(()=>Z.abort(Error("timeout")),y);try{return await fetch(v,{...J,signal:Z.signal})}finally{clearTimeout(Y)}}function P(v){return new URL("/.well-known/pi",new URL(v).origin).toString()}async function n(v){let J=P(v.proxy.endpoint),Z;try{Z=await I(J,{headers:{"User-Agent":G,Accept:"application/json"}})}catch(Q){return D.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!Z.ok)return D.warn(`well-known returned ${Z.status} — falling back to /v1/models`),null;let Y;try{Y=await Z.json()}catch{return D.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return D.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let V=[],j=Y.builtinProviders??{};for(let[Q,X]of Object.entries(j)){if(!X||!Array.isArray(X.models))continue;let M=X.models.map(($)=>({id:String($.id),name:typeof $.name==="string"?$.name:String($.id),reasoning:Boolean($.reasoning??W(String($.id))),contextWindow:typeof $.contextWindow==="number"?$.contextWindow:200000,maxTokens:typeof $.maxTokens==="number"?$.maxTokens:16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));V.push({name:Q,api:X.api??"openai-responses",models:M})}let z=(Array.isArray(Y.customModelPool)?Y.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??W(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:B(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",v.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Y?.upstream?.upstreamVersion==="string"?Y.upstream.upstreamVersion:null,builtinProviders:V,customPool:z,serverDiscoveryExcludes:Array.isArray(Y.discoveryExcludes)?Y.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Y?.counts?.upstreamTotal==="number"?Y.counts.upstreamTotal:0}}async function p(v,J){let Z=new URL("/v1/models",new URL(v.proxy.endpoint).origin).toString(),Y=await I(Z,{headers:{Authorization:`Bearer ${J}`,Accept:"application/json","User-Agent":G}});if(!Y.ok)throw Error(`/v1/models returned ${Y.status}`);let V=await Y.json();if(!V?.data||!Array.isArray(V.data))return[];return V.data.map((j)=>({id:typeof j.id==="string"?j.id:"",owned_by:typeof j.owned_by==="string"?j.owned_by:""})).filter((j)=>j.id)}function s(v,J){let Z=J.discoveryExcludes,Y=new Map,V=[],j=0;for(let z of v){if(j++,E(z.id,Z))continue;if(z.owned_by==="openai"){let $=q(z.id);U(Y,"openai","openai-responses",S($));continue}if(z.owned_by==="anthropic"){let $=q(z.id);U(Y,"anthropic","anthropic-messages",S($));continue}let{slug:Q,api:X}=C(z.owned_by,J.proxy.providerPrefix),M=q(z.id);V.push({id:z.id,name:M.name??z.id,reasoning:M.reasoning??!1,contextWindow:M.contextWindow??128000,maxTokens:M.maxTokens??16000,cost:M.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:X,suggestedProvider:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:V,serverDiscoveryExcludes:[],upstreamTotal:j}}function U(v,J,Z,Y){let V=v.get(J);if(!V)V={name:J,api:Z,models:[]},v.set(J,V);V.models.push(Y)}function S(v){return{id:v.id,name:v.name??v.id,reasoning:v.reasoning??!1,contextWindow:v.contextWindow??128000,maxTokens:v.maxTokens??16000,cost:v.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function D0(v,J){let Z=await n(v);if(Z)return D.info(`discovery via /.well-known/pi: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),A(Z),Z;if(!J)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await p(v,J),V=s(Y,v);return D.info(`discovery via /v1/models: ${V.builtinProviders.length} builtin, ${V.customPool.length} custom`),A(V),V}function M0(v){let J=new Set;for(let Z of v.builtinProviders)for(let Y of Z.models)J.add(Y.id);for(let Z of v.customPool)J.add(Z.id);return J}export{D0 as fetchDiscovery,M0 as discoveryToIdSet,G as PLUGIN_USER_AGENT};
1
+ function C(J,Z){if(!J)return!0;for(let $ of Z)if(new RegExp("^"+$.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test(J))return!0;return!1}var T=128000,x=16000,S={input:0,output:0,cacheRead:0,cacheWrite:0},b=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function H(J){return b.some((Z)=>Z.test(J))}var u=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function L(J,Z){let $=(J??"").trim();return $?`${$}-${Z}`:Z}function E(J,Z){let $=(Z??"").trim(),Y=J.match(/^([a-z0-9]+-)(.*)$/);if(Y)return $?`${$}-${Y[1]}`:Y[1];return J}function B(J,Z){for(let[$,Y,V]of u)if($.has(J))return{slug:L(Z,Y),api:V};return{slug:L(Z,"misc"),api:"openai-completions"}}function h(J){return J.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((Z)=>Z[0].toUpperCase()+Z.slice(1)).join(" ")}function v(J){return{id:J,name:h(J),contextWindow:T,maxTokens:x,reasoning:H(J),cost:{...S}}}import{createHash as n}from"node:crypto";import{existsSync as k0,readFileSync as A0,writeFileSync as p}from"node:fs";import{dirname as P,join as s}from"node:path";import{chmodSync as O,closeSync as a,constants as e,copyFileSync as J0,existsSync as f,fsyncSync as Y0,linkSync as Z0,mkdirSync as y,openSync as $0,readFileSync as Q0,renameSync as V0,rmSync as z0,writeFileSync as j0}from"node:fs";import{homedir as D}from"node:os";import{dirname as W0,join as R}from"node:path";var K=!1;var X={info(...J){if(!K)console.log("[dm-cliproxy]",...J)},warn(...J){if(!K)console.warn("[dm-cliproxy]",...J)},error(...J){if(!K)console.error("[dm-cliproxy]",...J)},debug(...J){if(!K&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var k=R(D(),".dm","agent","dm-cliproxy"),H0=R(k,"config.json"),v0=[R(D(),".pi","agent","pi-cliproxyapi","config.json"),R(D(),".config","pi-cliproxyapi","config.json")];function w(J){y(J,{recursive:!0,mode:448}),O(J,448)}function U(J){if(f(J))O(J,384)}var g=s(k,"discovery-cache.json");function G(J,Z){return n("sha256").update(J.trim().replace(/\/+$/,"")).update("\x00").update(Z).digest("hex")}function A(J,Z,$=g){try{w(P($));let Y={savedAt:Date.now(),scope:Z,discovery:J};p($,JSON.stringify(Y),{encoding:"utf8",mode:384}),U($)}catch(Y){X.warn("failed to write discovery cache:",Y.message)}}var _="dm-cliproxy/0.3.5",d=5000;async function F(J,Z){let $=new AbortController,Y=setTimeout(()=>$.abort(Error("timeout")),d);try{return await fetch(J,{...Z,signal:$.signal})}finally{clearTimeout(Y)}}function l(J){return new URL("/.well-known/pi",new URL(J).origin).toString()}async function c(J){let Z=l(J.proxy.endpoint),$;try{$=await F(Z,{headers:{"User-Agent":_,Accept:"application/json"}})}catch(Q){return X.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!$.ok)return X.warn(`well-known returned ${$.status} — falling back to /v1/models`),null;let Y;try{Y=await $.json()}catch{return X.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return X.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let V=[],z=Y.builtinProviders??{};for(let[Q,q]of Object.entries(z)){if(!q||!Array.isArray(q.models))continue;let W=q.models.map((j)=>({id:String(j.id),name:typeof j.name==="string"?j.name:String(j.id),reasoning:Boolean(j.reasoning??H(String(j.id))),contextWindow:typeof j.contextWindow==="number"?j.contextWindow:200000,maxTokens:typeof j.maxTokens==="number"?j.maxTokens:16000,cost:j.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));V.push({name:Q,api:q.api??"openai-responses",models:W})}let M=(Array.isArray(Y.customModelPool)?Y.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??H(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:E(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",J.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Y?.upstream?.upstreamVersion==="string"?Y.upstream.upstreamVersion:null,builtinProviders:V,customPool:M,serverDiscoveryExcludes:Array.isArray(Y.discoveryExcludes)?Y.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Y?.counts?.upstreamTotal==="number"?Y.counts.upstreamTotal:0}}async function t(J,Z){let $=new URL("/v1/models",new URL(J.proxy.endpoint).origin).toString(),Y=await F($,{headers:{Authorization:`Bearer ${Z}`,Accept:"application/json","User-Agent":_}});if(!Y.ok)throw Error(`/v1/models returned ${Y.status}`);let V=await Y.json();if(!V?.data||!Array.isArray(V.data))return[];return V.data.map((z)=>({id:typeof z.id==="string"?z.id:"",owned_by:typeof z.owned_by==="string"?z.owned_by:""})).filter((z)=>z.id)}function i(J,Z){let $=Z.discoveryExcludes,Y=new Map,V=[],z=0;for(let M of J){if(z++,C(M.id,$))continue;if(M.owned_by==="openai"){let j=v(M.id);I(Y,"openai","openai-responses",N(j));continue}if(M.owned_by==="anthropic"){let j=v(M.id);I(Y,"anthropic","anthropic-messages",N(j));continue}let{slug:Q,api:q}=B(M.owned_by,Z.proxy.providerPrefix),W=v(M.id);V.push({id:M.id,name:W.name??M.id,reasoning:W.reasoning??!1,contextWindow:W.contextWindow??128000,maxTokens:W.maxTokens??16000,cost:W.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:q,suggestedProvider:Q,ownedBy:M.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:V,serverDiscoveryExcludes:[],upstreamTotal:z}}function I(J,Z,$,Y){let V=J.get(Z);if(!V)V={name:Z,api:$,models:[]},J.set(Z,V);V.models.push(Y)}function N(J){return{id:J.id,name:J.name??J.id,reasoning:J.reasoning??!1,contextWindow:J.contextWindow??128000,maxTokens:J.maxTokens??16000,cost:J.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function G0(J,Z){let $=G(J.proxy.endpoint,Z),Y=await c(J);if(Y)return X.info(`discovery via /.well-known/pi: ${Y.builtinProviders.length} builtin, ${Y.customPool.length} custom`),A(Y,$),Y;if(!Z)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let V=await t(J,Z),z=i(V,J);return X.info(`discovery via /v1/models: ${z.builtinProviders.length} builtin, ${z.customPool.length} custom`),A(z,$),z}function I0(J){let Z=new Set;for(let $ of J.builtinProviders)for(let Y of $.models)Z.add(Y.id);for(let $ of J.customPool)Z.add($.id);return Z}export{G0 as fetchDiscovery,I0 as discoveryToIdSet,_ as PLUGIN_USER_AGENT};
@@ -1 +1 @@
1
- import{dirname as U,join as Y}from"node:path";import{homedir as r}from"node:os";import{dirname as z,join as e}from"node:path";var v=!1;var s={info(...n){if(!v)console.log("[dm-cliproxy]",...n)},warn(...n){if(!v)console.warn("[dm-cliproxy]",...n)},error(...n){if(!v)console.error("[dm-cliproxy]",...n)},debug(...n){if(!v&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...n)}};var D=e(r(),".dm","agent","dm-cliproxy"),h=e(D,"config.json"),q=[e(r(),".pi","agent","pi-cliproxyapi","config.json"),e(r(),".config","pi-cliproxyapi","config.json")];var H=Y(D,"discovery-cache.json");var J="dm-cliproxy/0.3.5";var Z=15000,c=null;function N(){c=null}async function F(n,o,V={}){if(!V.force&&c&&Date.now()-c.fetchedAt<n.usageCacheTtlMs)return c.doc;if(!o)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let M=new URL("/api/usage",new URL(n.proxy.endpoint).origin).toString(),w=new AbortController,Q=setTimeout(()=>w.abort(Error("timeout")),Z),u;try{u=await fetch(M,{headers:{"X-Plugin-Key":o,Accept:"application/json","User-Agent":J},signal:w.signal})}finally{clearTimeout(Q)}if(!u.ok)throw Error(`/api/usage returned ${u.status}`);let t=await u.json();if(!t||t.schemaVersion!==1||!Array.isArray(t.accounts))throw Error("/api/usage returned unexpected payload shape");return c={fetchedAt:Date.now(),doc:t},s.debug("usage fetched, accounts:",t.accounts.length),t}export{F as fetchUsage,N as clearUsageCache};
1
+ import{dirname as O,join as z}from"node:path";import{homedir as A}from"node:os";import{dirname as U,join as $}from"node:path";var V=!1;var s={info(...n){if(!V)console.log("[dm-cliproxy]",...n)},warn(...n){if(!V)console.warn("[dm-cliproxy]",...n)},error(...n){if(!V)console.error("[dm-cliproxy]",...n)},debug(...n){if(!V&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...n)}};var M=$(A(),".dm","agent","dm-cliproxy"),H=$(M,"config.json"),C=[$(A(),".pi","agent","pi-cliproxyapi","config.json"),$(A(),".config","pi-cliproxyapi","config.json")];var I=z(M,"discovery-cache.json");var Z="dm-cliproxy/0.3.5";var R=15000,u=null;function l(){u=null}async function y(n,Q,j={}){if(!j.force&&u&&Date.now()-u.fetchedAt<n.usageCacheTtlMs)return u.doc;if(!Q)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let X=new URL("/api/usage",new URL(n.proxy.endpoint).origin).toString(),Y=new AbortController,w=setTimeout(()=>Y.abort(Error("timeout")),R),J;try{J=await fetch(X,{headers:{"X-Plugin-Key":Q,Accept:"application/json","User-Agent":Z},signal:Y.signal})}finally{clearTimeout(w)}if(!J.ok)throw Error(`/api/usage returned ${J.status}`);let t=await J.json();if(!t||t.schemaVersion!==1||!Array.isArray(t.accounts))throw Error("/api/usage returned unexpected payload shape");return u={fetchedAt:Date.now(),doc:t},s.debug("usage fetched, accounts:",t.accounts.length),t}export{y as fetchUsage,l as clearUsageCache};
@@ -1,2 +1,2 @@
1
- import{getKeybindings as R1,matchesKey as C}from"@duckmind/dm-tui";import{getModels as Sj}from"@duckmind/dm-ai/compat";var b$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function y$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function Z0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Qj=128000,Yj=16000,Zj={input:0,output:0,cacheRead:0,cacheWrite:0},Xj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function R$($){return Xj.some((j)=>j.test($))}var zj=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function E$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function X0($,j){let J=(j??"").trim(),Q=$.match(/^([a-z0-9]+-)(.*)$/);if(Q)return J?`${J}-${Q[1]}`:Q[1];return $}function z0($,j){for(let[J,Q,Y]of zj)if(J.has($))return{slug:E$(j,Q),api:Y};return{slug:E$(j,"misc"),api:"openai-completions"}}function Vj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function J$($){return{id:$,name:Vj($),contextWindow:Qj,maxTokens:Yj,reasoning:R$($),cost:{...Zj}}}import{execSync as qj}from"node:child_process";import{randomUUID as V0}from"node:crypto";import{chmodSync as _$,constants as Mj,copyFileSync as q0,existsSync as A$,linkSync as nj,mkdirSync as M0,readFileSync as Dj,rmSync as w$,writeFileSync as Uj}from"node:fs";import{homedir as C$}from"node:os";import{dirname as X$,join as z$}from"node:path";import{fileURLToPath as Ej}from"node:url";var G$=!1;var B={info(...$){if(!G$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!G$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!G$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!G$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var u$=z$(C$(),".dm","agent","dm-cliproxy"),w=z$(u$,"config.json"),Rj=[z$(C$(),".pi","agent","pi-cliproxyapi","config.json"),z$(C$(),".config","pi-cliproxyapi","config.json")];function Gj(){return A$(z$(X$(Ej(import.meta.url)),"..",".git"))}function _j($=Rj,j=w,J=Gj()){if(A$(j))return;let Y=(typeof $==="string"?[$]:[...$]).find((z)=>A$(z));if(!Y)return;let Z;try{M0(X$(j),{recursive:!0,mode:448}),_$(X$(j),448),Z=`${j}.${process.pid}.${V0()}.tmp`,q0(Y,Z,Mj.COPYFILE_EXCL),_$(Z,384),nj(Z,j),w$(Z),Z=void 0,B.info("legacy config copied to",j)}catch(z){if(Z)try{w$(Z,{force:!0})}catch(X){B.warn("failed to clean temporary config:",X)}B.warn("failed to migrate legacy config:",z)}}var O$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function H$(){if(_j(),!A$(w))return B.debug("config not found, using defaults at",w),structuredClone(O$);try{let $=JSON.parse(Dj(w,"utf8"));return Aj($)}catch($){return B.error("failed to read config:",$,"— using defaults"),structuredClone(O$)}}function W$($){M0(X$(w),{recursive:!0,mode:448}),_$(X$(w),448);let j=`${w}.${process.pid}.${V0()}.tmp`;try{Uj(j,JSON.stringify($,null,2)+`
2
- `,{encoding:"utf8",flag:"wx",mode:384}),q0(j,w),_$(w,384)}finally{w$(j,{force:!0})}B.info("config saved to",w)}function Aj($){if(!$||typeof $!=="object")return structuredClone(O$);let j=$,J=structuredClone(O$),Q=j.proxy??{};if(J.proxy.endpoint=typeof Q.endpoint==="string"?Q.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof Q.apiKey==="string"?Q.apiKey:"",typeof Q.usageKey==="string")J.proxy.usageKey=Q.usageKey;if(typeof Q.providerPrefix==="string"&&Q.providerPrefix.trim())J.proxy.providerPrefix=Q.providerPrefix.trim();if(j.builtinProviders&&typeof j.builtinProviders==="object")J.builtinProviders=j.builtinProviders;if(j.customProviders&&typeof j.customProviders==="object")J.customProviders=j.customProviders;if(Array.isArray(j.discoveryExcludes))J.discoveryExcludes=j.discoveryExcludes.filter((Y)=>typeof Y==="string");if(j.overrides&&typeof j.overrides==="object")J.overrides=j.overrides;if(typeof j.refreshIntervalMinutes==="number")J.refreshIntervalMinutes=j.refreshIntervalMinutes;if(typeof j.usageCacheTtlMs==="number")J.usageCacheTtlMs=j.usageCacheTtlMs;return J}function g($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return qj(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Q=J?.stderr?.toString?.()?.trim()??J.message;return B.warn(`failed to resolve "!" config value (${j}): ${Q}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{chmodSync as Oj,existsSync as K1,mkdirSync as Hj,readFileSync as S1,writeFileSync as Wj}from"node:fs";import{dirname as n0,join as kj}from"node:path";var v$=kj(u$,"discovery-cache.json");function f$($){try{Hj(n0(v$),{recursive:!0,mode:448}),Oj(n0(v$),448);let j={savedAt:Date.now(),discovery:$};Wj(v$,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){B.warn("failed to write discovery cache:",j.message)}}var Q$="dm-cliproxy/0.3.5",Nj=5000;async function E0($,j){let J=new AbortController,Q=setTimeout(()=>J.abort(Error("timeout")),Nj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Q)}}function Tj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function Bj($){let j=Tj($.proxy.endpoint),J;try{J=await E0(j,{headers:{"User-Agent":Q$,Accept:"application/json"}})}catch(X){return B.warn("well-known fetch failed:",X.message,"— falling back to /v1/models"),null}if(!J.ok)return B.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let Q;try{Q=await J.json()}catch{return B.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Q||Q.schemaVersion!==1)return B.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Y=[],Z=Q.builtinProviders??{};for(let[X,V]of Object.entries(Z)){if(!V||!Array.isArray(V.models))continue;let q=V.models.map((n)=>({id:String(n.id),name:typeof n.name==="string"?n.name:String(n.id),reasoning:Boolean(n.reasoning??R$(String(n.id))),contextWindow:typeof n.contextWindow==="number"?n.contextWindow:200000,maxTokens:typeof n.maxTokens==="number"?n.maxTokens:16000,cost:n.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));Y.push({name:X,api:V.api??"openai-responses",models:q})}let z=(Array.isArray(Q.customModelPool)?Q.customModelPool:[]).map((X)=>({id:String(X.id),name:typeof X.name==="string"?X.name:String(X.id),reasoning:Boolean(X.reasoning??R$(String(X.id))),contextWindow:typeof X.contextWindow==="number"?X.contextWindow:128000,maxTokens:typeof X.maxTokens==="number"?X.maxTokens:16000,cost:X.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:X.api??"openai-completions",suggestedProvider:X0(typeof X.suggestedProviderName==="string"?X.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof X.owned_by==="string"?X.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Q?.upstream?.upstreamVersion==="string"?Q.upstream.upstreamVersion:null,builtinProviders:Y,customPool:z,serverDiscoveryExcludes:Array.isArray(Q.discoveryExcludes)?Q.discoveryExcludes.filter((X)=>typeof X==="string"):[],upstreamTotal:typeof Q?.counts?.upstreamTotal==="number"?Q.counts.upstreamTotal:0}}async function Lj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Q=await E0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":Q$}});if(!Q.ok)throw Error(`/v1/models returned ${Q.status}`);let Y=await Q.json();if(!Y?.data||!Array.isArray(Y.data))return[];return Y.data.map((Z)=>({id:typeof Z.id==="string"?Z.id:"",owned_by:typeof Z.owned_by==="string"?Z.owned_by:""})).filter((Z)=>Z.id)}function Kj($,j){let J=j.discoveryExcludes,Q=new Map,Y=[],Z=0;for(let z of $){if(Z++,Z0(z.id,J))continue;if(z.owned_by==="openai"){let n=J$(z.id);D0(Q,"openai","openai-responses",U0(n));continue}if(z.owned_by==="anthropic"){let n=J$(z.id);D0(Q,"anthropic","anthropic-messages",U0(n));continue}let{slug:X,api:V}=z0(z.owned_by,j.proxy.providerPrefix),q=J$(z.id);Y.push({id:z.id,name:q.name??z.id,reasoning:q.reasoning??!1,contextWindow:q.contextWindow??128000,maxTokens:q.maxTokens??16000,cost:q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:V,suggestedProvider:X,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Q.values()),customPool:Y,serverDiscoveryExcludes:[],upstreamTotal:Z}}function D0($,j,J,Q){let Y=$.get(j);if(!Y)Y={name:j,api:J,models:[]},$.set(j,Y);Y.models.push(Q)}function U0($){return{id:$.id,name:$.name??$.id,reasoning:$.reasoning??!1,contextWindow:$.contextWindow??128000,maxTokens:$.maxTokens??16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function R0($,j){let J=await Bj($);if(J)return B.info(`discovery via /.well-known/pi: ${J.builtinProviders.length} builtin, ${J.customPool.length} custom`),f$(J),J;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Q=await Lj($,j),Y=Kj(Q,$);return B.info(`discovery via /v1/models: ${Y.builtinProviders.length} builtin, ${Y.customPool.length} custom`),f$(Y),Y}function G0($){let j=new Set;for(let J of $.builtinProviders)for(let Q of J.models)j.add(Q.id);for(let J of $.customPool)j.add(J.id);return j}async function g$($,j,J){let Q={registered:[],skipped:[]},Y=G0(J),Z=g(j.proxy.apiKey);if(!Z)return B.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),Q;let z=new Map;for(let V of J.builtinProviders)z.set(V.name,V.models.map((q)=>({id:q.id,name:q.name,reasoning:q.reasoning,contextWindow:q.contextWindow,maxTokens:q.maxTokens,cost:q.cost})));for(let[V,q]of Object.entries(j.builtinProviders)){if(!q?.enabled){Q.skipped.push({provider:V,reason:"disabled"});continue}if(!Array.isArray(q.models)||q.models.length===0){Q.skipped.push({provider:V,reason:"empty whitelist"});continue}let n=[];try{n=Sj(V)}catch{}let U=new Map(n.map((A)=>[A.id,A])),S=new Map((z.get(V)??[]).map((A)=>[A.id,A])),_=[];for(let A of q.models){if(!Y.has(A))continue;let W=U.get(A),P=S.get(A);if(W){_.push({id:W.id,name:W.name,reasoning:W.reasoning,contextWindow:W.contextWindow,maxTokens:W.maxTokens,cost:W.cost,input:W.input,api:W.api,thinkingLevelMap:W.thinkingLevelMap});continue}if(!P)continue;let p=V==="anthropic"?"anthropic-messages":q.apiOverride??"openai-responses";_.push({id:P.id,name:P.name,reasoning:P.reasoning,contextWindow:P.contextWindow,maxTokens:P.maxTokens,cost:P.cost,input:["text"],api:p})}if(_.length===0){Q.skipped.push({provider:V,reason:"no whitelisted models present on proxy"});continue}let G=q.apiOverride??_[0].api;if(!b$.has(G)){Q.skipped.push({provider:V,reason:`api "${G}" not in allowlist`});continue}let D=_.map((A)=>{let W=j.overrides[A.id]??{},P={id:A.id,name:typeof W.name==="string"?W.name:A.name,api:G,reasoning:typeof W.reasoning==="boolean"?W.reasoning:A.reasoning,input:A.input,cost:W.cost??A.cost,contextWindow:typeof W.contextWindow==="number"?W.contextWindow:A.contextWindow,maxTokens:typeof W.maxTokens==="number"?W.maxTokens:A.maxTokens};if(A.thinkingLevelMap)P.thinkingLevelMap=A.thinkingLevelMap;return P}),H={name:V,baseUrl:y$(G,j.proxy.endpoint),apiKey:Z,authHeader:!0,api:G,models:D};$.registerProvider(V,H),Q.registered.push({provider:V,modelCount:D.length,api:G})}let X=new Map(J.customPool.map((V)=>[V.id,V]));for(let[V,q]of Object.entries(j.customProviders)){if(!b$.has(q.api)){Q.skipped.push({provider:V,reason:`api "${q.api}" not in allowlist`});continue}let n=q.models.filter((_)=>Y.has(_.id));if(n.length===0){Q.skipped.push({provider:V,reason:"no configured models present on proxy"});continue}let U=n.map((_)=>{let G=X.get(_.id),D=J$(_.id),H=j.overrides[_.id]??{};return{id:_.id,name:_.name??G?.name??D.name??_.id,api:q.api,reasoning:Fj(_.reasoning,G?.reasoning,D.reasoning,H.reasoning)??!1,input:["text"],cost:_.cost??G?.cost??D.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:_0(_.contextWindow,G?.contextWindow,D.contextWindow,H.contextWindow)??128000,maxTokens:_0(_.maxTokens,G?.maxTokens,D.maxTokens,H.maxTokens)??16000}}),S={name:V,baseUrl:y$(q.api,j.proxy.endpoint),apiKey:Z,authHeader:!0,api:q.api,models:U};$.registerProvider(V,S),Q.registered.push({provider:V,modelCount:U.length,api:q.api})}return B.info(`applyAll: registered ${Q.registered.length} providers, skipped ${Q.skipped.length}`),Q}function _0(...$){for(let j of $)if(typeof j==="number")return j;return}function Fj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var Pj=15000,V$=null;function k$(){V$=null}async function A0($,j,J={}){if(!J.force&&V$&&Date.now()-V$.fetchedAt<$.usageCacheTtlMs)return V$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Q=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Y=new AbortController,Z=setTimeout(()=>Y.abort(Error("timeout")),Pj),z;try{z=await fetch(Q,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":Q$},signal:Y.signal})}finally{clearTimeout(Z)}if(!z.ok)throw Error(`/api/usage returned ${z.status}`);let X=await z.json();if(!X||X.schemaVersion!==1||!Array.isArray(X.accounts))throw Error("/api/usage returned unexpected payload shape");return V$={fetchedAt:Date.now(),doc:X},B.debug("usage fetched, accounts:",X.accounts.length),X}import{visibleWidth as p$}from"@duckmind/dm-tui";import{visibleWidth as O0}from"@duckmind/dm-tui";function L($,j){let J=O0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return h$($,j)}function h$($,j){if(j<=0)return"\x1B[0m";let J="",Q=0,Y=0;while(Y<$.length){let Z=$[Y];if(Z==="\x1B"&&$[Y+1]==="["){let X=$.indexOf("m",Y+2);if(X>=0){J+=$.slice(Y,X+1),Y=X+1;continue}}let z=O0(Z);if(Q+z>j)break;J+=Z,Q+=z,Y++}return`${J}\x1B[0m`}var Ij="│",xj="╭",bj="╮",yj="╰",wj="╯",q$="─";function o($,j){let J=Math.max(4,j.width);return[Cj($,j.title,j.titleColor??"accent",J),...j.lines.map((Q)=>uj($,Q,J)),vj($,j.footer,J)]}function Cj($,j,J,Q){let Y=j??"",Z=p$(Y),z=Math.max(0,Q-3-Z),X=Y?$.bold($.fg(J,Y)):"",V=`${xj}${q$}${X}${q$.repeat(z)}${bj}`;return $.fg("borderAccent",V)}function uj($,j,J){let Q=Math.max(0,J-2),Y=$.fg("borderAccent",Ij);return`${Y}${L(j,Q)}${Y}`}function vj($,j,J){let Q=`${yj}${q$}`,Y=`${wj}`,Z=3;if(!j||!j.hint&&!j.badge){let G=Math.max(0,J-3);return $.fg("borderAccent",`${Q}${q$.repeat(G)}${Y}`)}let z=j.hint??"",X=j.badge??"",V=p$(z),q=p$(X),n=Math.max(0,J-3-V-q),U=$.fg("dim",z),S=X?$.fg("muted",X):"",_=q$.repeat(n);return`${$.fg("borderAccent",Q)}${U}${$.fg("borderAccent",_)}${S}${$.fg("borderAccent",Y)}`}function N$($){return Math.max(0,$-2)}import{existsSync as H0}from"node:fs";import{homedir as fj}from"node:os";import{getKeybindings as gj,Input as hj,matchesKey as pj}from"@duckmind/dm-tui";var cj=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:($)=>{try{if(!new URL($).pathname.endsWith("/v1"))return"must end with /v1";return null}catch{return"not a valid URL"}}},{label:"apiKey",hint:"CliProxyAPI bearer key. Accepts literal, $ENV_VAR, !cmd, or ~/path",required:!0},{label:"providerPrefix",hint:"Prefix for your custom provider names. Suggested groups become <prefix>-glm, <prefix>-gemini, etc. Use any short slug (letters/digits/dashes).",required:!0,validate:($)=>/^[a-z0-9][a-z0-9-]*$/i.test($)?null:"letters/digits/dashes only"},{label:"usageKey",hint:"Optional X-Plugin-Key for /api/usage. Leave blank to skip the Usage tab",required:!1}];async function W0($,j=!1){let J=H$(),Q={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Y=!1;for(let z of cj){let X=j?Q[z.label]??z.initialValue??"":Q[z.label]??"";if(!j&&X)continue;let V=await mj($,z,X||z.initialValue||"");if(V===void 0){Y=!0;break}let q=V.trim();if(!q){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Y=!0;break}Q[z.label]="";continue}Q[z.label]=z.label==="providerPrefix"||z.label==="endpoint"?q:lj(q)}if(Y)return!1;let Z={...J};if(Z.proxy={...J.proxy,endpoint:Q.endpoint??"",apiKey:Q.apiKey??"",providerPrefix:Q.providerPrefix??""},Q.usageKey)Z.proxy.usageKey=Q.usageKey;else delete Z.proxy.usageKey;return W$(Z),$.ui.notify(`saved to ${w}`,"info"),!0}function lj($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,fj());return H0(j)?`!cat ${$}`:$}if($.startsWith("/"))return H0($)?`!cat ${$}`:$;return $}async function mj($,j,J){return $.ui.custom((Q,Y,Z,z)=>rj(Q,Y,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function rj($,j,J,Q,Y){let Z=new hj;Z.setValue(Q),Z.focused=!0;let z=null,X=(V)=>{if(!V&&!J.required){Y("");return}if(!V&&J.required){z="required field",$.requestRender();return}if(J.validate){let q=V.trim();if(q&&!q.startsWith("!")&&!q.startsWith("$")){let n=J.validate(q);if(n){z=n,$.requestRender();return}}}Y(V)};return Z.onSubmit=X,Z.onEscape=()=>Y(void 0),{render(V){let q=N$(V),n=Z.render(q-4),U=["",` ${j.fg("dim",J.hint)}`,"",...n.map((S)=>` ${j.fg("accent",`❯ ${S}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return o(j,{width:V,title:` setup: ${J.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(V){if(gj().matches(V,"tui.select.cancel")||pj(V,"escape")){Y(void 0);return}z=null,Z.handleInput(V),$.requestRender()}}}import{visibleWidth as T$}from"@duckmind/dm-tui";function k0($,j,J,Q){let Y=$.fg("borderAccent","│"),Z=j.map((z,X)=>{let V=`${X+1} ${z.label}`;return X===J?$.bold($.fg("accent",` ${V} `)):$.fg("dim",` ${V} `)});return L(` ${Z.join(Y)}`,Q)}function N0($,j,J){let Q=j.join($.fg("dim"," "));return L(` ${Q}`,J)}function T0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function i($,j,J){let Q=$.slice(j,j+J);while(Q.length<J)Q.push("");return Q}function B$($,j,J,Q,Y,Z){if(Y<=Q)return 0;let z=Math.max(0,Y-Q);if(j<Z)return 0;let X=Math.max(0,Math.min(J,z)),V=X+Z;if($<V)X=Math.max(0,$-Z);let q=X+Q-1;if(j>q)X=Math.min(z,j-(Q-1));return X}function L$($,j,J){let Q=Math.max(0,J-j);return Math.max(0,Math.min($,Q))}import{matchesKey as d}from"@duckmind/dm-tui";import{existsSync as sj,readFileSync as oj}from"node:fs";import{homedir as L0}from"node:os";import{join as K0}from"node:path";var ij=K0(L0(),".dm","models.json"),dj=K0(L0(),".dm","auth.json");function B0($){if(!sj($))return null;try{return JSON.parse(oj($,"utf8"))}catch{return null}}function S0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Q=B0(ij);if(Q&&typeof Q==="object"){for(let Z of Object.keys(Q))if(J.has(Z))j.push({kind:"models.json",provider:Z,detail:`provider "${Z}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Y=B0(dj);if(Y&&typeof Y==="object"){for(let Z of Object.keys(Y))if(J.has(Z))j.push({kind:"auth.json",provider:Z,detail:`provider "${Z}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function F0($){let{theme:j,cfg:J}=$,Q=0,Y=()=>{let X=$.getDiscovery(),V=(G)=>j.fg("success",G),q=(G)=>j.fg("error",G),n=(G)=>j.fg("dim",G),U=[];U.push(`${n("endpoint")} ${J.proxy.endpoint||q("(unset)")}`),U.push(`${n("apiKey")} ${g(J.proxy.apiKey)?V("resolves"):q("empty after resolution")}`),U.push(`${n("usageKey")} ${J.proxy.usageKey?g(J.proxy.usageKey)?V("resolves"):q("set but empty"):n("not configured")}`),U.push(`${n("user-agent")} ${Q$}`),U.push(""),U.push(`${n("discovery")} source=${X.source}`),U.push(`${n("upstream")} v=${X.upstreamVersion??"(unknown)"} · ${X.upstreamTotal} ids`);let S=X.builtinProviders.map((G)=>`${G.name}=${G.models.length}`).join(", ")||n("(none)");U.push(`${n("built-in")} ${S}`),U.push(`${n("custom pool")} ${X.customPool.length} models`);let _=S0(J);if(U.push(""),_.length===0)U.push(`${n("conflicts")} ${V("none")}`);else{U.push(`${n("conflicts")}`);for(let G of _)U.push(` ${j.fg("warning",`[${G.kind}]`)} ${G.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(X,V)=>{let q=Y();return Q=L$(Q,V,q.length),i(q,Q,V).map((n)=>L(` ${n}`,X))},handleInput:(X)=>{let V=Y().length;if(d(X,"up")||d(X,"k"))return Q=Math.max(0,Q-1),!0;if(d(X,"down")||d(X,"j"))return Q=Math.min(Math.max(0,V-1),Q+1),!0;if(d(X,"pageUp")||d(X,"b"))return Q=Math.max(0,Q-10),!0;if(d(X,"pageDown")||d(X,"f"))return Q=Math.min(Math.max(0,V-1),Q+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as N}from"@duckmind/dm-tui";function c$($){let j=new Map,J=new Map;for(let Y of $.builtinProviders){let Z=[];for(let z of Y.models)j.set(z.id,{id:z.id,name:z.name,suggestedApi:Y.api,subtitle:z.name&&z.name!==z.id?z.name:void 0,ownedBy:Y.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost}),Z.push(z.id);J.set(Y.name,Z)}let Q=[];for(let Y of $.customPool){if(!j.has(Y.id))j.set(Y.id,{id:Y.id,name:Y.name,suggestedApi:Y.api,subtitle:Y.name&&Y.name!==Y.id?Y.name:void 0,origin:Y.suggestedProvider,ownedBy:Y.ownedBy,reasoning:Y.reasoning,contextWindow:Y.contextWindow,maxTokens:Y.maxTokens,cost:Y.cost});Q.push(Y.id)}return{byId:j,builtinModelIds:J,customPoolIds:Q}}function tj($){let j=new Map;for(let[J,Q]of Object.entries($.customProviders))for(let Y of Q.models)j.set(Y.id,J);return j}function e($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function P0($,j,J){if(j.kind==="builtin"){let Z=J.builtinModelIds.get(j.name)??[],z=new Set(e($,j));return Z.filter((X)=>!z.has(X))}let Q=tj($),Y=new Set(e($,j));return J.customPoolIds.filter((Z)=>{if(Y.has(Z))return!1;let z=Q.get(Z);return z===void 0||z===j.name})}function aj($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function I0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name]??{enabled:!0,models:[]},Z=new Set(Y.models);Z.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Y.apiOverride??null,models:Array.from(Z).sort()};return}for(let[Y,Z]of Object.entries($.customProviders)){if(Y===j.name)continue;let z=Z.models.findIndex((X)=>X.id===J.id);if(z>=0)Z.models.splice(z,1)}let Q=$.customProviders[j.name]??{api:j.api,models:[]};if(!Q.models.some((Y)=>Y.id===J.id))Q.models.push(aj(J));$.customProviders[j.name]=Q}function x0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name];if(!Y)return;Y.models=Y.models.filter((Z)=>Z!==J),Y.enabled=Y.models.length>0;return}let Q=$.customProviders[j.name];if(!Q)return;Q.models=Q.models.filter((Y)=>Y.id!==J)}function l$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function b0($,j){let J=new Map;for(let Q of $){let Y=j.byId.get(Q),Z=Y?.ownedBy||Y?.origin||"misc",z=J.get(Z)??[];z.push(Q),J.set(Z,z)}return Array.from(J.entries()).sort((Q,Y)=>Q[0].localeCompare(Y[0])).map(([Q,Y])=>({label:Q,ids:Y}))}function y0($,j,J){let Q=J.trim().toLowerCase();if(!Q)return $;return $.filter((Y)=>{if(Y.toLowerCase().includes(Q))return!0;let Z=j.byId.get(Y)?.name;return Z?Z.toLowerCase().includes(Q):!1})}import{getModels as ej,getProviders as $1}from"@duckmind/dm-ai/compat";function m$($,j){let J=[],Q=new Set(j.builtinModelIds.keys()),Y=new Set($1()),Z=new Set([...Q,...Y]);for(let z of Array.from(Z).sort()){let X=j.builtinModelIds.get(z);if(!X||X.length===0)continue;let V;try{let n=ej(z).find((U)=>X.includes(U.id));if(n)V=n.api}catch{}if(!V){let q=X[0];V=j.byId.get(q)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:z,api:V,subtitle:`built-in · ${V}`}),!$.builtinProviders[z])$.builtinProviders[z]={enabled:!1,models:[]}}for(let z of Object.keys($.customProviders).sort()){let X=$.customProviders[z];J.push({kind:"custom",name:z,api:X.api,subtitle:`custom · ${X.api}`})}return J}import{getKeybindings as j1,matchesKey as Y$}from"@duckmind/dm-tui";async function w0($,j){return $.ui.custom((J,Q,Y,Z)=>J1(Q,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",Z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function J1($,j,J,Q){return{render(Y){return o($,{width:Y,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Y){if(j1().matches(Y,"tui.select.cancel")||Y$(Y,"escape")||Y$(Y,"n")||Y$(Y,"q")){Q(!1);return}if(Y$(Y,"y")||Y$(Y,"enter")||Y$(Y,"return")){Q(!0);return}}}}import{getKeybindings as Q1,Input as Y1,matchesKey as Z1}from"@duckmind/dm-tui";async function C0($,j){let J=E$(j,"group");return $.ui.custom((Q,Y,Z,z)=>X1(Q,Y,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function X1($,j,J,Q){let Y=new Y1;if(J)Y.setValue(J);Y.focused=!0;let Z=null;return Y.onSubmit=(z)=>{let X=z.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(X)){Z="letters / digits / dot / dash / underscore only",$.requestRender();return}Q(X)},Y.onEscape=()=>Q(null),{render(z){let X=N$(z),V=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",q=Y.render(X-4),n=["",` ${j.fg("dim",V)}`,"",...q.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",Z?` ${j.fg("error",`! ${Z}`)}`:""];return o(j,{width:z,title:" new custom group ",lines:n,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Y.invalidate()},handleInput(z){if(Q1().matches(z,"tui.select.cancel")||Z1(z,"escape")){Q(null);return}Z=null,Y.handleInput(z),$.requestRender()}}}import{visibleWidth as z1}from"@duckmind/dm-tui";function r$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function u0($,j){let J=z1($);if(J===j)return $;if(J>j)return h$($,j);return L($,j)}function v0($,j,J){let{theme:Q,width:Y,isCursor:Z,isFocused:z}=J,X=r$(Q,Z,z),V=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,q=$.kind==="builtin"?Q.fg("accent","B"):Q.fg("warning","C"),n=`${Q.fg("dim","[")}${q}${Q.fg("dim","]")}`,U=V>0?Q.fg("success","●"):Q.fg("dim","○"),S=V>0?Q.fg("success",String(V).padStart(2)):Q.fg("dim"," 0"),_=Z&&z?Q.bold(Q.fg("accent",$.name)):Z?Q.bold($.name):$.name,G=Q.fg("dim",$.api),D=`${X}${n} ${_} ${U}${S} ${G}`;return u0(D,Y)}function f0($,j,J,Q){let Y=r$($,j,J),Z=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return L(`${Y}${Z}`,Q)}function s$($,j,J,Q,Y){let{theme:Z,width:z,isCursor:X,isFocused:V}=Y,q=r$(Z,X,V),n=J==="assigned"?Z.fg("success","☑"):Z.fg("dim","☐"),U=Q?` ${Z.fg("warning","⚠")}`:"",S=X&&V?Z.fg("accent",$):$,_=j?.reasoning?` ${Z.fg("accent","✨")}`:"",G=j?Z.fg("muted",` · ${j.suggestedApi}`):Z.fg("error"," · not on proxy"),D=`${q}${n} ${S}${U}${_}${G}`;return u0(D,z)}function g0($,j,J){let Q=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return L(` ${Q}`,J)}function o$($,j,J){return L(` ${$.fg("dim",j)}`,J)}function h0($,j,J,Q){let Y=Q?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return L(`${Y}${j}`,J)}function p0($){let{tui:j,theme:J,ctx:Q,cfg:Y}=$,Z=$.onChange??(()=>{}),z=c$($.getDiscovery()),X=m$(Y,z),V="providers",q=0,n=0,U=0,S=0,_=0,G=0,D="",H=!1,A=()=>{if(X.length===0)return null;let M=Math.max(0,Math.min(q,X.length-1));return X[M]??null},W=(M)=>{let O=y0(P0(Y,M,z),z,D);return b0(O,z)},P=(M)=>W(M).flatMap((O)=>O.ids),p=()=>{X=m$(Y,z);let M=Math.max(0,X.length);if(q>M)q=M;let O=A();if(O){let F=e(Y,O).length,k=P(O).length;if(n>=F)n=Math.max(0,F-1);if(U>=k)U=Math.max(0,k-1)}},K$=()=>{z=c$($.getDiscovery()),p()},M$=(M)=>{let O=["providers","assigned","pool"],F=O.indexOf(V);V=M?O[(F-1+O.length)%O.length]:O[(F+1)%O.length]},R=(M)=>{if(V==="providers"){let k=X.length+1;q=Math.max(0,Math.min(q+M,k-1));return}let O=A();if(!O)return;if(V==="assigned"){let k=e(Y,O).length;if(k===0)return;n=Math.max(0,Math.min(n+M,k-1));return}let F=P(O).length;if(F===0)return;U=Math.max(0,Math.min(U+M,F-1))},I=async()=>{if(V==="providers"){if(q===X.length){let k=await C0(Q,Y.proxy.providerPrefix);if(k&&!Y.customProviders[k]){if(Y.customProviders[k]={api:"openai-completions",models:[]},Z(),p(),q=X.findIndex((K)=>K.kind==="custom"&&K.name===k),q<0)q=X.length-1;V="pool"}j.requestRender();return}V="pool";return}let M=A();if(!M)return;if(V==="assigned"){let k=e(Y,M)[n];if(!k)return;x0(Y,M,k),Z(),p();return}let O=P(M)[U];if(!O)return;let F=z.byId.get(O);if(!F)return;I0(Y,M,F),Z(),p()},l=async()=>{if(V!=="providers")return;let M=A();if(!M||M.kind!=="custom")return;if(!await w0(Q,M.name)){j.requestRender();return}if(delete Y.customProviders[M.name],Z(),p(),q>=X.length)q=Math.max(0,X.length-1);j.requestRender()},u=(M,O)=>h(M,O);function h(M,O){let F=Math.max(70,M),k=Math.min(56,Math.max(34,Math.floor(F*0.4))),K=F-k-1,m=Math.max(8,O),r=Math.max(5,Math.floor((m-1)/2)),i$=m-r,c=A(),Z$=0,S$=0,F$=0,d$=0,P$=0,t$=0,t=[];t.push($$(" providers ",k,V==="providers"));for(let T=0;T<X.length;T++){let v=X[T],y=V==="providers"&&T===q;if(y)Z$=t.length,S$=Z$;t.push(v0(v,Y,{theme:J,width:k,isCursor:y,isFocused:V==="providers"}))}{let T=V==="providers"&&q===X.length;if(T)Z$=t.length,S$=Z$;t.push(f0(J,T,V==="providers",k))}let a=[],a0=c?`assigned to ${J.bold(c.name)} ${J.fg("dim",`· ${c.api}`)}`:J.fg("dim","no provider selected");if(a.push($$(" assigned ",K,V==="assigned")),a.push(h0(J,a0,K,V==="assigned")),c){let T=e(Y,c);if(T.length===0)a.push(o$(J,"(nothing assigned yet)",K));for(let v=0;v<T.length;v++){let y=T[v],f=z.byId.get(y),U$=V==="assigned"&&v===n;if(U$)F$=a.length,d$=F$;let j$=f?!l$(c.api,f.suggestedApi):!1;a.push(s$(y,f,"assigned",j$,{theme:J,width:K,isCursor:U$,isFocused:V==="assigned"}))}}let s=[];if(s.push(x(K,V==="pool")),c){let T=W(c);if(T.reduce((y,f)=>y+f.ids.length,0)===0)s.push(o$(J,D?`(no matches for "${D}")`:"(no models available)",K));else{let y=0;for(let f of T){let U$=s.length;s.push(g0(J,f.label,K));for(let j$=0;j$<f.ids.length;j$++){let Q0=f.ids[j$],x$=z.byId.get(Q0),Y0=V==="pool"&&y===U;if(Y0)P$=s.length,t$=j$===0?U$:P$;let Jj=x$?!l$(c.api,x$.suggestedApi):!1;s.push(s$(Q0,x$,"pool",Jj,{theme:J,width:K,isCursor:Y0,isFocused:V==="pool"})),y++}}}}let e0=Math.max(1,i$-1),a$=B$(S$,Z$,S,m,t.length,1),e$=B$(V==="assigned"?d$:0,V==="assigned"?F$:0,_,r,a.length,2),$0=B$(V==="pool"?t$:0,V==="pool"?P$:0,G,e0,s.length,1);S=a$,_=e$,G=$0;let j0=i(t,a$,m),$j=i(a,e$,r),jj=i(s,$0,i$),J0=J.fg("borderAccent","│"),I$=[];for(let T=0;T<m;T++){let v=L(j0[T]??"",k),y=T<r?$j[T]:jj[T-r],f=L(y,K);I$.push(`${v}${J0}${f}`)}let D$=r;if(D$>0&&D$<m){let T=L(j0[D$]??"",k),v=J.fg("borderAccent","─".repeat(K));I$[D$]=`${T}${J0}${v}`}return I$}function $$(M,O,F){let k=F?J.bold(J.fg("accent",M)):J.fg("muted",M),K=J.fg("borderAccent","─".repeat(Math.max(0,O-T$(M)-1)));return L(`${k}${K}`,O)}function x(M,O){let k=O?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),K="";if(H)K=`${J.fg("dim"," /")}${J.fg("accent",D)}${J.fg("accent","█")} `;else if(D)K=`${J.fg("dim"," /")}${J.fg("warning",D)} `;let m=T$(" available pool ")+T$(K),r=J.fg("borderAccent","─".repeat(Math.max(0,M-m-1)));return L(`${k}${K}${r}`,M)}function n$(M){if(H){if(N(M,"escape"))return D="",H=!1,U=0,!0;if(N(M,"enter")||N(M,"return"))return H=!1,!0;if(N(M,"backspace")||N(M,"delete"))return D=D.slice(0,-1),U=0,!0;if(M.length===1&&M>=" "&&M!=="")return D+=M,U=0,!0;return!0}if(N(M,"tab"))return M$(!1),!0;if(N(M,"shift+tab"))return M$(!0),!0;if(N(M,"/"))return V="pool",H=!0,!0;if(N(M,"enter")||N(M,"return")||N(M,"space"))return I().then(()=>!0);if(V==="providers"&&(N(M,"d")||N(M,"delete")||N(M,"backspace")))return l().then(()=>!0);if(N(M,"up")||N(M,"k"))return R(-1),!0;if(N(M,"down")||N(M,"j"))return R(1),!0;if(N(M,"pageUp")||N(M,"b"))return R(-8),!0;if(N(M,"pageDown")||N(M,"f"))return R(8),!0;if(N(M,"left")||N(M,"h"))return V="providers",!0;if(N(M,"right")||N(M,"l")){if(V==="providers")V="assigned";else if(V==="assigned")V="pool";return!0}return!1}function t0(){if(H)return" type to filter · ↵ apply · esc clear ";return" tab ↔ panel · ↑↓ nav · ↵ move · / filter · d remove group "}return{id:"models",label:"Models",render:u,handleInput:n$,footerHint:t0,rebuild:K$}}import{matchesKey as b}from"@duckmind/dm-tui";var E={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function c0($,j={}){let J=[],Q=new Map,Y=0;for(let Z of $.accounts){if(!j.showDisabled&&Z.disabled){Y++;continue}let z=Q.get(Z.provider)??[];z.push(Z),Q.set(Z.provider,z)}if(J.push(`${E.dim}generated ${$.generatedAt}${E.reset}`),$.unsupportedProviders.length>0)J.push(`${E.dim}providers without quota lookup:${E.reset} ${$.unsupportedProviders.join(", ")}`);if(Y>0)J.push(`${E.dim}hidden disabled accounts:${E.reset} ${Y} ${E.dim2}(press d to show)${E.reset}`);for(let[Z,z]of Array.from(Q.entries()).sort()){J.push(""),J.push(`${E.bold}${E.accent}▌ ${Z}${E.reset}`);for(let X of z){if(J.push(q1(X)),!X.supported){J.push(` ${E.dim2}(provider not quota-aware)${E.reset}`);continue}if(X.error){if(j.verbose)for(let q of V1(X.error,88))J.push(` ${E.red}${q}${E.reset}`);continue}let V=X.groups??[];if(V.length===0){J.push(` ${E.dim2}(no active quota windows)${E.reset}`);continue}for(let q of V)J.push(n1(q))}}return J.push(""),J.push(`${E.dim}legend:${E.reset} ${l0} ok ${m0} error/unavailable ${r0} disabled ${E.green}✓N${E.reset}/${E.red}✗N${E.reset} request counters ${E.dim}v = verbose, d = show disabled${E.reset}`),J}function V1($,j){if($.length<=j)return[$];let J=[],Q=$;while(Q.length>j){let Y=Q.lastIndexOf(" ",j);if(Y<j*0.6)Y=j;J.push(Q.slice(0,Y)),Q=Q.slice(Y).replace(/^\s+/,"")}if(Q)J.push(Q);return J}function q1($){let j=M1($),J=`${E.green}✓${$.success}${E.reset} ${E.red}✗${$.failed}${E.reset}`,Q=i0($.label,36);return` ${j} ${E.bold}${Q}${E.reset} ${J}`}var l0=`${E.green}●${E.reset}`,m0=`${E.yellow}⚠${E.reset}`,r0=`${E.dim2}⊘${E.reset}`;function M1($){if($.disabled)return r0;if($.unavailable||$.error||$.status&&$.status!=="active")return m0;return l0}function n1($){let j=o0($.remainingFraction),J=Math.round(j*100),Q=D1(j),Y=$.resetTime?` ${E.dim}reset ${E1($.resetTime)}${E.reset}`:"",Z=i0($.label,28).padEnd(28," ");return` ${Q} ${U1(J,j)} ${Z}${Y}`}function D1($){let j=o0($),J=Math.round(j*18),Q=s0(j),Y=E.dim2,Z="█".repeat(J),z="░".repeat(18-J);return`${Y}[${Q}${Z}${Y}${z}]${E.reset}`}function U1($,j){return`${s0(j)}${String($).padStart(3)}%${E.reset}`}function s0($){if($>=0.4)return E.green;if($>=0.15)return E.yellow;return E.red}function E1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let Q=Math.round(J/60000);if(Q<60)return`${Q}m`;let Y=Math.round(Q/60);if(Y<48)return`${Y}h`;return`${Math.round(Y/24)}d`}function o0($){return Math.max(0,Math.min(1,$))}function i0($,j){if($.length<=j)return $;return`${$.slice(0,j-1)}…`}function d0($){let{tui:j,theme:J,cfg:Q}=$,Y="idle",Z=null,z="",X=0,V=!1,q=!1,n=(D)=>{Y="loading",j.requestRender();let H=g(Q.proxy.usageKey);A0(Q,H,{force:D}).then((A)=>{Z=A,Y="ready",X=0,j.requestRender()}).catch((A)=>{z=A.message,Y="error",j.requestRender()})},U=()=>{if(Y==="idle"||Y==="loading")return[J.fg("dim"," loading usage…")];if(Y==="error")return[J.fg("error",` usage failed: ${z}`)];if(!Z)return[J.fg("dim"," (no data)")];return c0(Z,{showDisabled:V,verbose:q})};return{id:"usage",label:"Usage",render:(D,H)=>{let A=U();return X=L$(X,H,A.length),i(A,X,H).map((W)=>L(` ${W}`,D))},handleInput:(D)=>{if(b(D,"d"))return V=!V,X=0,!0;if(b(D,"v"))return q=!q,X=0,!0;let H=U().length;if(b(D,"up")||b(D,"k"))return X=Math.max(0,X-1),!0;if(b(D,"down")||b(D,"j"))return X=Math.min(Math.max(0,H-1),X+1),!0;if(b(D,"pageUp")||b(D,"b"))return X=Math.max(0,X-10),!0;if(b(D,"pageDown")||b(D,"f"))return X=Math.min(Math.max(0,H-1),X+10),!0;if(b(D,"home")||b(D,"g"))return X=0,!0;if(b(D,"end")||b(D,"shift+g"))return X=Math.max(0,H-1),!0;return!1},footerHint:()=>{let D=V?J.fg("success","[d disabled]"):"d disabled",H=q?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${D} · ${H} `},onActivate:()=>{if(Y==="idle")n(!1)},reload:()=>{if(k$(),Y!=="idle")n(!0)}}}function XJ($){let{dm:j,ctx:J,tui:Q,theme:Y,cfg:Z,done:z}=$,X=$.discovery,V=!1,q="",n=p0({tui:Q,theme:Y,ctx:J,cfg:Z,getDiscovery:()=>X,onChange:()=>{V=!0,q=""}}),U=d0({tui:Q,theme:Y,cfg:Z}),S=F0({theme:Y,cfg:Z,getDiscovery:()=>X}),_=[n,U,S],G=0,D=()=>_[G],H=(R)=>{if(R<0||R>=_.length||R===G)return;G=R,D().onActivate?.(),Q.requestRender()},A=()=>{q=Y.fg("dim","saving…"),W$(Z),Q.requestRender(),g$(j,Z,X).then((R)=>{V=!1,q=Y.fg("success",`✓ settings saved · ${R.registered.length} registered, ${R.skipped.length} skipped`),Q.requestRender()}).catch((R)=>{q=Y.fg("error",`save failed: ${R.message}`),Q.requestRender()})},W=async()=>{q=Y.fg("dim","refreshing…"),Q.requestRender();try{let R=g(Z.proxy.apiKey);X=await R0(Z,R),k$(),n.rebuild(),U.reload();let I=await g$(j,Z,X);q=Y.fg("success",`✓ refreshed · ${I.registered.length} providers (${X.source})`)}catch(R){q=Y.fg("error",`refresh failed: ${R.message}`)}Q.requestRender()},P=async()=>{if(!await W0(J,!0)){Q.requestRender();return}let I=H$();Z.proxy={...Z.proxy,...I.proxy},await W()},p=()=>{let R=Z.proxy.endpoint||"(unset)",I=R.length>40?`…${R.slice(-39)}`:R,l=Boolean(g(Z.proxy.apiKey)),u=0,h=0;for(let x of Object.values(Z.builtinProviders)){if(x.enabled&&x.models.length>0)u++;h+=x.models.length}for(let x of Object.values(Z.customProviders)){if(x.models.length>0)u++;h+=x.models.length}let $$=q?q:V?Y.fg("warning","● unsaved — press s to save"):Y.fg("dim","✓ saved");return[`${Y.fg("dim","endpoint")} ${I}`,`${Y.fg("dim","key")} ${l?Y.fg("success","✓"):Y.fg("error","✗")}`,`${Y.fg("dim","providers")} ${u}`,`${Y.fg("dim","models")} ${h}`,$$]},K$=(R)=>{let I=Q.rows??40,u=Math.max(16,Math.min(I-6,38))-2,h=Math.max(72,R-2),$$=Math.max(6,u-3),x=[];return x.push(N0(Y,p(),h)),x.push(k0(Y,_.map((n$)=>({id:n$.id,label:n$.label})),G,h)),x.push(T0(Y,h)),x.push(...D().render(h,$$)),o(Y,{width:R,title:" /cliproxy ",lines:x,footer:{hint:D().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},M$=(R)=>{if(R1().matches(R,"tui.select.cancel")||C(R,"q")||C(R,"escape"))return z(),!0;if(C(R,"]")||C(R,"tab"))return H((G+1)%_.length),!0;if(C(R,"[")||C(R,"shift+tab"))return H((G-1+_.length)%_.length),!0;if(C(R,"1"))return H(0),!0;if(C(R,"2"))return H(1),!0;if(C(R,"3"))return H(2),!0;if(C(R,"r"))return W().then(()=>!0);if(C(R,"e"))return P().then(()=>!0);if(C(R,"s"))return A(),!0;return!1};return{render:K$,invalidate(){},handleInput(R){let I=D().handleInput(R);if(I instanceof Promise){q="",I.then((u)=>{if(u)Q.requestRender()});return}if(I){q="",Q.requestRender();return}let l=M$(R);if(l instanceof Promise)l.then((u)=>{if(u)Q.requestRender()});else if(l)Q.requestRender()}}}export{XJ as buildHub};
1
+ import{getKeybindings as x1,matchesKey as u}from"@duckmind/dm-tui";import{getModels as cj}from"@duckmind/dm-ai/compat";var w$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function u$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function V0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Uj=128000,Ej=16000,Dj={input:0,output:0,cacheRead:0,cacheWrite:0},Rj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function O$($){return Rj.some((j)=>j.test($))}var _j=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function H$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function U0($,j){let J=(j??"").trim(),Q=$.match(/^([a-z0-9]+-)(.*)$/);if(Q)return J?`${J}-${Q[1]}`:Q[1];return $}function E0($,j){for(let[J,Q,Y]of _j)if(J.has($))return{slug:H$(j,Q),api:Y};return{slug:H$(j,"misc"),api:"openai-completions"}}function Aj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function Y$($){return{id:$,name:Aj($),contextWindow:Uj,maxTokens:Ej,reasoning:O$($),cost:{...Dj}}}import{execSync as Hj}from"node:child_process";import{randomUUID as R0}from"node:crypto";import{chmodSync as g$,closeSync as D0,constants as Oj,copyFileSync as Gj,existsSync as M$,fsyncSync as Nj,linkSync as Wj,mkdirSync as kj,openSync as Tj,readFileSync as _0,renameSync as Bj,rmSync as v$,writeFileSync as Lj}from"node:fs";import{homedir as N$}from"node:os";import{dirname as k$,join as V$}from"node:path";import{fileURLToPath as Kj}from"node:url";var G$=!1;var K={info(...$){if(!G$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!G$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!G$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!G$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var f$=V$(N$(),".dm","agent","dm-cliproxy"),l=V$(f$,"config.json"),Fj=[V$(N$(),".pi","agent","pi-cliproxyapi","config.json"),V$(N$(),".config","pi-cliproxyapi","config.json")];function U$($){kj($,{recursive:!0,mode:448}),g$($,448)}function Z$($){if(M$($))g$($,384)}function Sj($){let j;try{j=JSON.parse(_0($,"utf8"))}catch{return}let J=j&&typeof j==="object"?j.proxy:void 0;for(let Q of[J?.apiKey,J?.usageKey]){if(typeof Q!=="string")continue;let Y=/^!cat\s+((?:~\/|\/)[^\s;&|`]+)$/.exec(Q.trim());if(!Y)continue;let Z=Y[1].replace(/^~/,N$());Z$(Z)}}function Ij(){return M$(V$(k$(Kj(import.meta.url)),"..",".git"))}function xj($=Fj,j=l,J=Ij()){if(M$(j))return;let Y=(typeof $==="string"?[$]:[...$]).find((z)=>M$(z));if(!Y)return;let Z;try{Z$(Y),Sj(Y),U$(k$(j)),Z=`${j}.${process.pid}.${R0()}.tmp`,Gj(Y,Z,Oj.COPYFILE_EXCL),g$(Z,384),Wj(Z,j),v$(Z),Z=void 0,K.info("legacy config copied to",j)}catch(z){if(Z)try{v$(Z,{force:!0})}catch(X){K.warn("failed to clean temporary config:",X)}K.warn("failed to migrate legacy config:",z)}}var W$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function T$(){if(xj(),!M$(l))return K.debug("config not found, using defaults at",l),structuredClone(W$);try{U$(k$(l)),Z$(l);let $=JSON.parse(_0(l,"utf8"));return nj($)}catch($){return K.error("failed to read config:",$,"— using defaults"),structuredClone(W$)}}function bj($,j=l){U$(k$(j));let J=`${j}.${process.pid}.${R0()}.tmp`,Q;try{Q=Tj(J,"wx",384),Lj(Q,JSON.stringify($,null,2)+`
2
+ `,{encoding:"utf8"}),Nj(Q),D0(Q),Q=void 0,Bj(J,j),Z$(j)}finally{if(Q!==void 0)D0(Q);v$(J,{force:!0})}}function B$($){bj($),K.info("config saved to",l)}function nj($){if(!$||typeof $!=="object")return structuredClone(W$);let j=$,J=structuredClone(W$),Q=j.proxy??{};if(J.proxy.endpoint=typeof Q.endpoint==="string"?Q.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof Q.apiKey==="string"?Q.apiKey:"",typeof Q.usageKey==="string")J.proxy.usageKey=Q.usageKey;if(typeof Q.providerPrefix==="string"&&Q.providerPrefix.trim())J.proxy.providerPrefix=Q.providerPrefix.trim();if(j.builtinProviders&&typeof j.builtinProviders==="object")J.builtinProviders=j.builtinProviders;if(j.customProviders&&typeof j.customProviders==="object")J.customProviders=j.customProviders;if(Array.isArray(j.discoveryExcludes))J.discoveryExcludes=j.discoveryExcludes.filter((Y)=>typeof Y==="string");if(j.overrides&&typeof j.overrides==="object")J.overrides=j.overrides;if(typeof j.refreshIntervalMinutes==="number")J.refreshIntervalMinutes=j.refreshIntervalMinutes;if(typeof j.usageCacheTtlMs==="number")J.usageCacheTtlMs=j.usageCacheTtlMs;return J}function h($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Hj(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Q=J?.status,Y=typeof Q==="number"?` (exit ${Q})`:"";return K.warn(`failed to resolve "!" config value${Y}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{createHash as Pj}from"node:crypto";import{existsSync as c1,readFileSync as l1,writeFileSync as yj}from"node:fs";import{dirname as Cj,join as wj}from"node:path";var uj=wj(f$,"discovery-cache.json");function A0($,j){return Pj("sha256").update($.trim().replace(/\/+$/,"")).update("\x00").update(j).digest("hex")}function h$($,j,J=uj){try{U$(Cj(J));let Q={savedAt:Date.now(),scope:j,discovery:$};yj(J,JSON.stringify(Q),{encoding:"utf8",mode:384}),Z$(J)}catch(Q){K.warn("failed to write discovery cache:",Q.message)}}var X$="dm-cliproxy/0.3.5",vj=5000;async function G0($,j){let J=new AbortController,Q=setTimeout(()=>J.abort(Error("timeout")),vj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Q)}}function gj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function fj($){let j=gj($.proxy.endpoint),J;try{J=await G0(j,{headers:{"User-Agent":X$,Accept:"application/json"}})}catch(X){return K.warn("well-known fetch failed:",X.message,"— falling back to /v1/models"),null}if(!J.ok)return K.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let Q;try{Q=await J.json()}catch{return K.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Q||Q.schemaVersion!==1)return K.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Y=[],Z=Q.builtinProviders??{};for(let[X,q]of Object.entries(Z)){if(!q||!Array.isArray(q.models))continue;let V=q.models.map((M)=>({id:String(M.id),name:typeof M.name==="string"?M.name:String(M.id),reasoning:Boolean(M.reasoning??O$(String(M.id))),contextWindow:typeof M.contextWindow==="number"?M.contextWindow:200000,maxTokens:typeof M.maxTokens==="number"?M.maxTokens:16000,cost:M.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));Y.push({name:X,api:q.api??"openai-responses",models:V})}let z=(Array.isArray(Q.customModelPool)?Q.customModelPool:[]).map((X)=>({id:String(X.id),name:typeof X.name==="string"?X.name:String(X.id),reasoning:Boolean(X.reasoning??O$(String(X.id))),contextWindow:typeof X.contextWindow==="number"?X.contextWindow:128000,maxTokens:typeof X.maxTokens==="number"?X.maxTokens:16000,cost:X.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:X.api??"openai-completions",suggestedProvider:U0(typeof X.suggestedProviderName==="string"?X.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof X.owned_by==="string"?X.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Q?.upstream?.upstreamVersion==="string"?Q.upstream.upstreamVersion:null,builtinProviders:Y,customPool:z,serverDiscoveryExcludes:Array.isArray(Q.discoveryExcludes)?Q.discoveryExcludes.filter((X)=>typeof X==="string"):[],upstreamTotal:typeof Q?.counts?.upstreamTotal==="number"?Q.counts.upstreamTotal:0}}async function hj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Q=await G0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":X$}});if(!Q.ok)throw Error(`/v1/models returned ${Q.status}`);let Y=await Q.json();if(!Y?.data||!Array.isArray(Y.data))return[];return Y.data.map((Z)=>({id:typeof Z.id==="string"?Z.id:"",owned_by:typeof Z.owned_by==="string"?Z.owned_by:""})).filter((Z)=>Z.id)}function pj($,j){let J=j.discoveryExcludes,Q=new Map,Y=[],Z=0;for(let z of $){if(Z++,V0(z.id,J))continue;if(z.owned_by==="openai"){let M=Y$(z.id);H0(Q,"openai","openai-responses",O0(M));continue}if(z.owned_by==="anthropic"){let M=Y$(z.id);H0(Q,"anthropic","anthropic-messages",O0(M));continue}let{slug:X,api:q}=E0(z.owned_by,j.proxy.providerPrefix),V=Y$(z.id);Y.push({id:z.id,name:V.name??z.id,reasoning:V.reasoning??!1,contextWindow:V.contextWindow??128000,maxTokens:V.maxTokens??16000,cost:V.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:q,suggestedProvider:X,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Q.values()),customPool:Y,serverDiscoveryExcludes:[],upstreamTotal:Z}}function H0($,j,J,Q){let Y=$.get(j);if(!Y)Y={name:j,api:J,models:[]},$.set(j,Y);Y.models.push(Q)}function O0($){return{id:$.id,name:$.name??$.id,reasoning:$.reasoning??!1,contextWindow:$.contextWindow??128000,maxTokens:$.maxTokens??16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function N0($,j){let J=A0($.proxy.endpoint,j),Q=await fj($);if(Q)return K.info(`discovery via /.well-known/pi: ${Q.builtinProviders.length} builtin, ${Q.customPool.length} custom`),h$(Q,J),Q;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await hj($,j),Z=pj(Y,$);return K.info(`discovery via /v1/models: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),h$(Z,J),Z}function W0($){let j=new Set;for(let J of $.builtinProviders)for(let Q of J.models)j.add(Q.id);for(let J of $.customPool)j.add(J.id);return j}var k0=new WeakMap,p$=new WeakMap;function c$($){let j=(p$.get($)??0)+1;return p$.set($,j),j}function L$($,j){return j===void 0||j===(p$.get($)??0)}function T0($,j,J){let Q=k0.get($)??new Set;for(let Y of Q){if(j.has(Y))continue;$.unregisterProvider(Y),J.unregistered.push(Y)}k0.set($,new Set(j))}async function l$($,j,J,Q){let Y={registered:[],skipped:[],unregistered:[]};if(!L$($,Q))return Y.skipped.push({provider:"*",reason:"stale refresh generation"}),Y;let Z=new Set,z=W0(J),X=h(j.proxy.apiKey);if(!X)return K.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),T0($,Z,Y),Y;let q=new Map;for(let M of J.builtinProviders)q.set(M.name,M.models.map((U)=>({id:U.id,name:U.name,reasoning:U.reasoning,contextWindow:U.contextWindow,maxTokens:U.maxTokens,cost:U.cost})));for(let[M,U]of Object.entries(j.builtinProviders)){if(!L$($,Q))return Y;if(!U?.enabled){Y.skipped.push({provider:M,reason:"disabled"});continue}if(!Array.isArray(U.models)||U.models.length===0){Y.skipped.push({provider:M,reason:"empty whitelist"});continue}let F=[];try{F=cj(M)}catch{}let T=new Map(F.map((N)=>[N.id,N])),H=new Map((q.get(M)??[]).map((N)=>[N.id,N])),D=[];for(let N of U.models){if(!z.has(N))continue;let G=T.get(N),n=H.get(N);if(G){D.push({id:G.id,name:G.name,reasoning:G.reasoning,contextWindow:G.contextWindow,maxTokens:G.maxTokens,cost:G.cost,input:G.input,api:G.api,thinkingLevelMap:G.thinkingLevelMap});continue}if(!n)continue;let j$=M==="anthropic"?"anthropic-messages":U.apiOverride??"openai-responses";D.push({id:n.id,name:n.name,reasoning:n.reasoning,contextWindow:n.contextWindow,maxTokens:n.maxTokens,cost:n.cost,input:["text"],api:j$})}if(D.length===0){Y.skipped.push({provider:M,reason:"no whitelisted models present on proxy"});continue}let A=U.apiOverride??D[0].api;if(!w$.has(A)){Y.skipped.push({provider:M,reason:`api "${A}" not in allowlist`});continue}let B=D.map((N)=>{let G=j.overrides[N.id]??{},n={id:N.id,name:typeof G.name==="string"?G.name:N.name,api:A,reasoning:typeof G.reasoning==="boolean"?G.reasoning:N.reasoning,input:N.input,cost:G.cost??N.cost,contextWindow:typeof G.contextWindow==="number"?G.contextWindow:N.contextWindow,maxTokens:typeof G.maxTokens==="number"?G.maxTokens:N.maxTokens};if(N.thinkingLevelMap)n.thinkingLevelMap=N.thinkingLevelMap;return n}),C={name:M,baseUrl:u$(A,j.proxy.endpoint),apiKey:X,authHeader:!0,api:A,models:B};$.registerProvider(M,C),Z.add(M),Y.registered.push({provider:M,modelCount:B.length,api:A})}let V=new Map(J.customPool.map((M)=>[M.id,M]));for(let[M,U]of Object.entries(j.customProviders)){if(!L$($,Q))return Y;if(!w$.has(U.api)){Y.skipped.push({provider:M,reason:`api "${U.api}" not in allowlist`});continue}let F=U.models.filter((D)=>z.has(D.id));if(F.length===0){Y.skipped.push({provider:M,reason:"no configured models present on proxy"});continue}let T=F.map((D)=>{let A=V.get(D.id),B=Y$(D.id),C=j.overrides[D.id]??{};return{id:D.id,name:D.name??A?.name??B.name??D.id,api:U.api,reasoning:lj(D.reasoning,A?.reasoning,B.reasoning,C.reasoning)??!1,input:["text"],cost:D.cost??A?.cost??B.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:B0(D.contextWindow,A?.contextWindow,B.contextWindow,C.contextWindow)??128000,maxTokens:B0(D.maxTokens,A?.maxTokens,B.maxTokens,C.maxTokens)??16000}}),H={name:M,baseUrl:u$(U.api,j.proxy.endpoint),apiKey:X,authHeader:!0,api:U.api,models:T};$.registerProvider(M,H),Z.add(M),Y.registered.push({provider:M,modelCount:T.length,api:U.api})}if(L$($,Q))T0($,Z,Y);return K.info(`applyAll: registered ${Y.registered.length} providers, skipped ${Y.skipped.length}, unregistered ${Y.unregistered.length}`),Y}function B0(...$){for(let j of $)if(typeof j==="number")return j;return}function lj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var mj=15000,E$=null;function K$(){E$=null}async function L0($,j,J={}){if(!J.force&&E$&&Date.now()-E$.fetchedAt<$.usageCacheTtlMs)return E$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Q=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Y=new AbortController,Z=setTimeout(()=>Y.abort(Error("timeout")),mj),z;try{z=await fetch(Q,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":X$},signal:Y.signal})}finally{clearTimeout(Z)}if(!z.ok)throw Error(`/api/usage returned ${z.status}`);let X=await z.json();if(!X||X.schemaVersion!==1||!Array.isArray(X.accounts))throw Error("/api/usage returned unexpected payload shape");return E$={fetchedAt:Date.now(),doc:X},K.debug("usage fetched, accounts:",X.accounts.length),X}import{visibleWidth as s$}from"@duckmind/dm-tui";import{visibleWidth as K0}from"@duckmind/dm-tui";function S($,j){let J=K0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return m$($,j)}function m$($,j){if(j<=0)return"\x1B[0m";let J="",Q=0,Y=0;while(Y<$.length){let Z=$[Y];if(Z==="\x1B"&&$[Y+1]==="["){let X=$.indexOf("m",Y+2);if(X>=0){J+=$.slice(Y,X+1),Y=X+1;continue}}let z=K0(Z);if(Q+z>j)break;J+=Z,Q+=z,Y++}return`${J}\x1B[0m`}var sj="│",oj="╭",ij="╮",rj="╰",dj="╯",D$="─";function r($,j){let J=Math.max(4,j.width);return[tj($,j.title,j.titleColor??"accent",J),...j.lines.map((Q)=>aj($,Q,J)),ej($,j.footer,J)]}function tj($,j,J,Q){let Y=j??"",Z=s$(Y),z=Math.max(0,Q-3-Z),X=Y?$.bold($.fg(J,Y)):"",q=`${oj}${D$}${X}${D$.repeat(z)}${ij}`;return $.fg("borderAccent",q)}function aj($,j,J){let Q=Math.max(0,J-2),Y=$.fg("borderAccent",sj);return`${Y}${S(j,Q)}${Y}`}function ej($,j,J){let Q=`${rj}${D$}`,Y=`${dj}`,Z=3;if(!j||!j.hint&&!j.badge){let H=Math.max(0,J-3);return $.fg("borderAccent",`${Q}${D$.repeat(H)}${Y}`)}let z=j.hint??"",X=j.badge??"",q=s$(z),V=s$(X),M=Math.max(0,J-3-q-V),U=$.fg("dim",z),F=X?$.fg("muted",X):"",T=D$.repeat(M);return`${$.fg("borderAccent",Q)}${U}${$.fg("borderAccent",T)}${F}${$.fg("borderAccent",Y)}`}function F$($){return Math.max(0,$-2)}import{existsSync as F0}from"node:fs";import{homedir as $1}from"node:os";import{getKeybindings as j1,Input as o$,matchesKey as J1}from"@duckmind/dm-tui";var Q1=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:($)=>{try{if(!new URL($).pathname.endsWith("/v1"))return"must end with /v1";return null}catch{return"not a valid URL"}}},{label:"apiKey",hint:"CliProxyAPI bearer key. Input is masked; blank keeps an existing key",required:!0,secret:!0},{label:"providerPrefix",hint:"Prefix for your custom provider names. Suggested groups become <prefix>-glm, <prefix>-gemini, etc. Use any short slug (letters/digits/dashes).",required:!0,validate:($)=>/^[a-z0-9][a-z0-9-]*$/i.test($)?null:"letters/digits/dashes only"},{label:"usageKey",hint:"Optional X-Plugin-Key for /api/usage. Input is masked; blank keeps it, '-' clears it",required:!1,secret:!0}];async function S0($,j=!1){let J=T$(),Q={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Y=!1;for(let z of Q1){let X=Q[z.label]??"",q=z.secret?"":j?Q[z.label]??z.initialValue??"":Q[z.label]??"";if(!j&&q)continue;let V=z.secret&&X?{...z,required:!1}:z,M=await X1($,V,q||z.initialValue||"");if(M===void 0){Y=!0;break}let U=Z1(z,X,M);if(U===null){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Y=!0;break}}Q[z.label]=U??""}if(Y)return!1;let Z={...J};if(Z.proxy={...J.proxy,endpoint:Q.endpoint??"",apiKey:Q.apiKey??"",providerPrefix:Q.providerPrefix??""},Q.usageKey)Z.proxy.usageKey=Q.usageKey;else delete Z.proxy.usageKey;return B$(Z),$.ui.notify(`saved to ${l}`,"info"),!0}function Y1($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,$1());return F0(j)?`!cat ${$}`:$}if($.startsWith("/"))return F0($)?`!cat ${$}`:$;return $}function Z1($,j,J){let Q=J.trim();if(!Q){if($.secret&&j)return j;return $.required?null:""}if($.secret&&!$.required&&Q==="-")return"";return $.label==="providerPrefix"||$.label==="endpoint"?Q:Y1(Q)}async function X1($,j,J){return $.ui.custom((Q,Y,Z,z)=>z1(Q,Y,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}class I0{rawInput=new o$;displayInput=new o$;pasteActive=!1;get focused(){return this.rawInput.focused}set focused($){this.rawInput.focused=$,this.displayInput.focused=$}set onSubmit($){this.rawInput.onSubmit=$}set onEscape($){this.rawInput.onEscape=$}getValue(){return this.rawInput.getValue()}setValue($){this.rawInput.setValue($),this.displayInput.setValue("•".repeat($.length))}handleInput($){this.rawInput.handleInput($),this.displayInput.handleInput(this.maskInput($)),this.displayInput.setValue("•".repeat(this.rawInput.getValue().length))}render($){return this.displayInput.render($)}invalidate(){this.rawInput.invalidate(),this.displayInput.invalidate()}maskInput($){let j="";for(let J=0;J<$.length;){if($.startsWith("\x1B[200~",J)){this.pasteActive=!0,j+="\x1B[200~",J+=6;continue}if($.startsWith("\x1B[201~",J)){this.pasteActive=!1,j+="\x1B[201~",J+=6;continue}if(!this.pasteActive&&$.charCodeAt(J)===27)return $;let Q=$.codePointAt(J),Y=String.fromCodePoint(Q);j+=Q<32||Q===127?Y:"•",J+=Y.length}return j}}function z1($,j,J,Q,Y){let Z=J.secret?new I0:new o$;Z.setValue(Q),Z.focused=!0;let z=null,X=(q)=>{if(!q&&!J.required){Y("");return}if(!q&&J.required){z="required field",$.requestRender();return}if(J.validate){let V=q.trim();if(V&&!V.startsWith("!")&&!V.startsWith("$")){let M=J.validate(V);if(M){z=M,$.requestRender();return}}}Y(q)};return Z.onSubmit=X,Z.onEscape=()=>Y(void 0),{render(q){let V=F$(q),M=Z.render(V-4),U=["",` ${j.fg("dim",J.hint)}`,"",...M.map((F)=>` ${j.fg("accent",`❯ ${F}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return r(j,{width:q,title:` setup: ${J.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(q){if(j1().matches(q,"tui.select.cancel")||J1(q,"escape")){Y(void 0);return}z=null,Z.handleInput(q),$.requestRender()}}}import{visibleWidth as S$}from"@duckmind/dm-tui";function x0($,j,J,Q){let Y=$.fg("borderAccent","│"),Z=j.map((z,X)=>{let q=`${X+1} ${z.label}`;return X===J?$.bold($.fg("accent",` ${q} `)):$.fg("dim",` ${q} `)});return S(` ${Z.join(Y)}`,Q)}function b0($,j,J){let Q=j.join($.fg("dim"," "));return S(` ${Q}`,J)}function n0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function d($,j,J){let Q=$.slice(j,j+J);while(Q.length<J)Q.push("");return Q}function I$($,j,J,Q,Y,Z){if(Y<=Q)return 0;let z=Math.max(0,Y-Q);if(j<Z)return 0;let X=Math.max(0,Math.min(J,z)),q=X+Z;if($<q)X=Math.max(0,$-Z);let V=X+Q-1;if(j>V)X=Math.min(z,j-(Q-1));return X}function x$($,j,J){let Q=Math.max(0,J-j);return Math.max(0,Math.min($,Q))}import{matchesKey as t}from"@duckmind/dm-tui";import{existsSync as q1,readFileSync as M1}from"node:fs";import{homedir as y0}from"node:os";import{join as C0}from"node:path";var V1=C0(y0(),".dm","models.json"),U1=C0(y0(),".dm","auth.json");function P0($){if(!q1($))return null;try{return JSON.parse(M1($,"utf8"))}catch{return null}}function w0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Q=P0(V1);if(Q&&typeof Q==="object"){for(let Z of Object.keys(Q))if(J.has(Z))j.push({kind:"models.json",provider:Z,detail:`provider "${Z}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Y=P0(U1);if(Y&&typeof Y==="object"){for(let Z of Object.keys(Y))if(J.has(Z))j.push({kind:"auth.json",provider:Z,detail:`provider "${Z}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function u0($){let{theme:j,cfg:J}=$,Q=0,Y=()=>{let X=$.getDiscovery(),q=(H)=>j.fg("success",H),V=(H)=>j.fg("error",H),M=(H)=>j.fg("dim",H),U=[];U.push(`${M("endpoint")} ${J.proxy.endpoint||V("(unset)")}`),U.push(`${M("apiKey")} ${h(J.proxy.apiKey)?q("resolves"):V("empty after resolution")}`),U.push(`${M("usageKey")} ${J.proxy.usageKey?h(J.proxy.usageKey)?q("resolves"):V("set but empty"):M("not configured")}`),U.push(`${M("user-agent")} ${X$}`),U.push(""),U.push(`${M("discovery")} source=${X.source}`),U.push(`${M("upstream")} v=${X.upstreamVersion??"(unknown)"} · ${X.upstreamTotal} ids`);let F=X.builtinProviders.map((H)=>`${H.name}=${H.models.length}`).join(", ")||M("(none)");U.push(`${M("built-in")} ${F}`),U.push(`${M("custom pool")} ${X.customPool.length} models`);let T=w0(J);if(U.push(""),T.length===0)U.push(`${M("conflicts")} ${q("none")}`);else{U.push(`${M("conflicts")}`);for(let H of T)U.push(` ${j.fg("warning",`[${H.kind}]`)} ${H.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(X,q)=>{let V=Y();return Q=x$(Q,q,V.length),d(V,Q,q).map((M)=>S(` ${M}`,X))},handleInput:(X)=>{let q=Y().length;if(t(X,"up")||t(X,"k"))return Q=Math.max(0,Q-1),!0;if(t(X,"down")||t(X,"j"))return Q=Math.min(Math.max(0,q-1),Q+1),!0;if(t(X,"pageUp")||t(X,"b"))return Q=Math.max(0,Q-10),!0;if(t(X,"pageDown")||t(X,"f"))return Q=Math.min(Math.max(0,q-1),Q+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as k}from"@duckmind/dm-tui";function i$($){let j=new Map,J=new Map;for(let Y of $.builtinProviders){let Z=[];for(let z of Y.models)j.set(z.id,{id:z.id,name:z.name,suggestedApi:Y.api,subtitle:z.name&&z.name!==z.id?z.name:void 0,ownedBy:Y.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost}),Z.push(z.id);J.set(Y.name,Z)}let Q=[];for(let Y of $.customPool){if(!j.has(Y.id))j.set(Y.id,{id:Y.id,name:Y.name,suggestedApi:Y.api,subtitle:Y.name&&Y.name!==Y.id?Y.name:void 0,origin:Y.suggestedProvider,ownedBy:Y.ownedBy,reasoning:Y.reasoning,contextWindow:Y.contextWindow,maxTokens:Y.maxTokens,cost:Y.cost});Q.push(Y.id)}return{byId:j,builtinModelIds:J,customPoolIds:Q}}function E1($){let j=new Map;for(let[J,Q]of Object.entries($.customProviders))for(let Y of Q.models)j.set(Y.id,J);return j}function $$($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function v0($,j,J){if(j.kind==="builtin"){let Z=J.builtinModelIds.get(j.name)??[],z=new Set($$($,j));return Z.filter((X)=>!z.has(X))}let Q=E1($),Y=new Set($$($,j));return J.customPoolIds.filter((Z)=>{if(Y.has(Z))return!1;let z=Q.get(Z);return z===void 0||z===j.name})}function D1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function g0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name]??{enabled:!0,models:[]},Z=new Set(Y.models);Z.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Y.apiOverride??null,models:Array.from(Z).sort()};return}for(let[Y,Z]of Object.entries($.customProviders)){if(Y===j.name)continue;let z=Z.models.findIndex((X)=>X.id===J.id);if(z>=0)Z.models.splice(z,1)}let Q=$.customProviders[j.name]??{api:j.api,models:[]};if(!Q.models.some((Y)=>Y.id===J.id))Q.models.push(D1(J));$.customProviders[j.name]=Q}function f0($,j,J){if(j.kind==="builtin"){let Y=$.builtinProviders[j.name];if(!Y)return;Y.models=Y.models.filter((Z)=>Z!==J),Y.enabled=Y.models.length>0;return}let Q=$.customProviders[j.name];if(!Q)return;Q.models=Q.models.filter((Y)=>Y.id!==J)}function r$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function h0($,j){let J=new Map;for(let Q of $){let Y=j.byId.get(Q),Z=Y?.ownedBy||Y?.origin||"misc",z=J.get(Z)??[];z.push(Q),J.set(Z,z)}return Array.from(J.entries()).sort((Q,Y)=>Q[0].localeCompare(Y[0])).map(([Q,Y])=>({label:Q,ids:Y}))}function p0($,j,J){let Q=J.trim().toLowerCase();if(!Q)return $;return $.filter((Y)=>{if(Y.toLowerCase().includes(Q))return!0;let Z=j.byId.get(Y)?.name;return Z?Z.toLowerCase().includes(Q):!1})}import{getModels as R1,getProviders as _1}from"@duckmind/dm-ai/compat";function d$($,j){let J=[],Q=new Set(j.builtinModelIds.keys()),Y=new Set(_1()),Z=new Set([...Q,...Y]);for(let z of Array.from(Z).sort()){let X=j.builtinModelIds.get(z);if(!X||X.length===0)continue;let q;try{let M=R1(z).find((U)=>X.includes(U.id));if(M)q=M.api}catch{}if(!q){let V=X[0];q=j.byId.get(V)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:z,api:q,subtitle:`built-in · ${q}`}),!$.builtinProviders[z])$.builtinProviders[z]={enabled:!1,models:[]}}for(let z of Object.keys($.customProviders).sort()){let X=$.customProviders[z];J.push({kind:"custom",name:z,api:X.api,subtitle:`custom · ${X.api}`})}return J}import{getKeybindings as A1,matchesKey as z$}from"@duckmind/dm-tui";async function c0($,j){return $.ui.custom((J,Q,Y,Z)=>H1(Q,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",Z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function H1($,j,J,Q){return{render(Y){return r($,{width:Y,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Y){if(A1().matches(Y,"tui.select.cancel")||z$(Y,"escape")||z$(Y,"n")||z$(Y,"q")){Q(!1);return}if(z$(Y,"y")||z$(Y,"enter")||z$(Y,"return")){Q(!0);return}}}}import{getKeybindings as O1,Input as G1,matchesKey as N1}from"@duckmind/dm-tui";async function l0($,j){let J=H$(j,"group");return $.ui.custom((Q,Y,Z,z)=>W1(Q,Y,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function W1($,j,J,Q){let Y=new G1;if(J)Y.setValue(J);Y.focused=!0;let Z=null;return Y.onSubmit=(z)=>{let X=z.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(X)){Z="letters / digits / dot / dash / underscore only",$.requestRender();return}Q(X)},Y.onEscape=()=>Q(null),{render(z){let X=F$(z),q=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",V=Y.render(X-4),M=["",` ${j.fg("dim",q)}`,"",...V.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",Z?` ${j.fg("error",`! ${Z}`)}`:""];return r(j,{width:z,title:" new custom group ",lines:M,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Y.invalidate()},handleInput(z){if(O1().matches(z,"tui.select.cancel")||N1(z,"escape")){Q(null);return}Z=null,Y.handleInput(z),$.requestRender()}}}import{visibleWidth as k1}from"@duckmind/dm-tui";function t$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function m0($,j){let J=k1($);if(J===j)return $;if(J>j)return m$($,j);return S($,j)}function s0($,j,J){let{theme:Q,width:Y,isCursor:Z,isFocused:z}=J,X=t$(Q,Z,z),q=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,V=$.kind==="builtin"?Q.fg("accent","B"):Q.fg("warning","C"),M=`${Q.fg("dim","[")}${V}${Q.fg("dim","]")}`,U=q>0?Q.fg("success","●"):Q.fg("dim","○"),F=q>0?Q.fg("success",String(q).padStart(2)):Q.fg("dim"," 0"),T=Z&&z?Q.bold(Q.fg("accent",$.name)):Z?Q.bold($.name):$.name,H=Q.fg("dim",$.api),D=`${X}${M} ${T} ${U}${F} ${H}`;return m0(D,Y)}function o0($,j,J,Q){let Y=t$($,j,J),Z=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return S(`${Y}${Z}`,Q)}function a$($,j,J,Q,Y){let{theme:Z,width:z,isCursor:X,isFocused:q}=Y,V=t$(Z,X,q),M=J==="assigned"?Z.fg("success","☑"):Z.fg("dim","☐"),U=Q?` ${Z.fg("warning","⚠")}`:"",F=X&&q?Z.fg("accent",$):$,T=j?.reasoning?` ${Z.fg("accent","✨")}`:"",H=j?Z.fg("muted",` · ${j.suggestedApi}`):Z.fg("error"," · not on proxy"),D=`${V}${M} ${F}${U}${T}${H}`;return m0(D,z)}function i0($,j,J){let Q=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return S(` ${Q}`,J)}function e$($,j,J){return S(` ${$.fg("dim",j)}`,J)}function r0($,j,J,Q){let Y=Q?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return S(`${Y}${j}`,J)}function d0($){let{tui:j,theme:J,ctx:Q,cfg:Y}=$,Z=$.onChange??(()=>{}),z=i$($.getDiscovery()),X=d$(Y,z),q="providers",V=0,M=0,U=0,F=0,T=0,H=0,D="",A=!1,B=()=>{if(X.length===0)return null;let E=Math.max(0,Math.min(V,X.length-1));return X[E]??null},C=(E)=>{let O=p0(v0(Y,E,z),z,D);return h0(O,z)},N=(E)=>C(E).flatMap((O)=>O.ids),G=()=>{X=d$(Y,z);let E=Math.max(0,X.length);if(V>E)V=E;let O=B();if(O){let b=$$(Y,O).length,W=N(O).length;if(M>=b)M=Math.max(0,b-1);if(U>=W)U=Math.max(0,W-1)}},n=()=>{z=i$($.getDiscovery()),G()},j$=(E)=>{let O=["providers","assigned","pool"],b=O.indexOf(q);q=E?O[(b-1+O.length)%O.length]:O[(b+1)%O.length]},_=(E)=>{if(q==="providers"){let W=X.length+1;V=Math.max(0,Math.min(V+E,W-1));return}let O=B();if(!O)return;if(q==="assigned"){let W=$$(Y,O).length;if(W===0)return;M=Math.max(0,Math.min(M+E,W-1));return}let b=N(O).length;if(b===0)return;U=Math.max(0,Math.min(U+E,b-1))},x=async()=>{if(q==="providers"){if(V===X.length){let W=await l0(Q,Y.proxy.providerPrefix);if(W&&!Y.customProviders[W]){if(Y.customProviders[W]={api:"openai-completions",models:[]},Z(),G(),V=X.findIndex((I)=>I.kind==="custom"&&I.name===W),V<0)V=X.length-1;q="pool"}j.requestRender();return}q="pool";return}let E=B();if(!E)return;if(q==="assigned"){let W=$$(Y,E)[M];if(!W)return;f0(Y,E,W),Z(),G();return}let O=N(E)[U];if(!O)return;let b=z.byId.get(O);if(!b)return;g0(Y,E,b),Z(),G()},p=async()=>{if(q!=="providers")return;let E=B();if(!E||E.kind!=="custom")return;if(!await c0(Q,E.name)){j.requestRender();return}if(delete Y.customProviders[E.name],Z(),G(),V>=X.length)V=Math.max(0,X.length-1);j.requestRender()},v=(E,O)=>c(E,O);function c(E,O){let b=Math.max(70,E),W=Math.min(56,Math.max(34,Math.floor(b*0.4))),I=b-W-1,s=Math.max(8,O),o=Math.max(5,Math.floor((s-1)/2)),$0=s-o,m=B(),q$=0,b$=0,n$=0,j0=0,P$=0,J0=0,a=[];a.push(J$(" providers ",W,q==="providers"));for(let L=0;L<X.length;L++){let g=X[L],w=q==="providers"&&L===V;if(w)q$=a.length,b$=q$;a.push(s0(g,Y,{theme:J,width:W,isCursor:w,isFocused:q==="providers"}))}{let L=q==="providers"&&V===X.length;if(L)q$=a.length,b$=q$;a.push(o0(J,L,q==="providers",W))}let e=[],Xj=m?`assigned to ${J.bold(m.name)} ${J.fg("dim",`· ${m.api}`)}`:J.fg("dim","no provider selected");if(e.push(J$(" assigned ",I,q==="assigned")),e.push(r0(J,Xj,I,q==="assigned")),m){let L=$$(Y,m);if(L.length===0)e.push(e$(J,"(nothing assigned yet)",I));for(let g=0;g<L.length;g++){let w=L[g],f=z.byId.get(w),A$=q==="assigned"&&g===M;if(A$)n$=e.length,j0=n$;let Q$=f?!r$(m.api,f.suggestedApi):!1;e.push(a$(w,f,"assigned",Q$,{theme:J,width:I,isCursor:A$,isFocused:q==="assigned"}))}}let i=[];if(i.push(P(I,q==="pool")),m){let L=C(m);if(L.reduce((w,f)=>w+f.ids.length,0)===0)i.push(e$(J,D?`(no matches for "${D}")`:"(no models available)",I));else{let w=0;for(let f of L){let A$=i.length;i.push(i0(J,f.label,I));for(let Q$=0;Q$<f.ids.length;Q$++){let q0=f.ids[Q$],C$=z.byId.get(q0),M0=q==="pool"&&w===U;if(M0)P$=i.length,J0=Q$===0?A$:P$;let Vj=C$?!r$(m.api,C$.suggestedApi):!1;i.push(a$(q0,C$,"pool",Vj,{theme:J,width:I,isCursor:M0,isFocused:q==="pool"})),w++}}}}let zj=Math.max(1,$0-1),Q0=I$(b$,q$,F,s,a.length,1),Y0=I$(q==="assigned"?j0:0,q==="assigned"?n$:0,T,o,e.length,2),Z0=I$(q==="pool"?J0:0,q==="pool"?P$:0,H,zj,i.length,1);F=Q0,T=Y0,H=Z0;let X0=d(a,Q0,s),qj=d(e,Y0,o),Mj=d(i,Z0,$0),z0=J.fg("borderAccent","│"),y$=[];for(let L=0;L<s;L++){let g=S(X0[L]??"",W),w=L<o?qj[L]:Mj[L-o],f=S(w,I);y$.push(`${g}${z0}${f}`)}let _$=o;if(_$>0&&_$<s){let L=S(X0[_$]??"",W),g=J.fg("borderAccent","─".repeat(I));y$[_$]=`${L}${z0}${g}`}return y$}function J$(E,O,b){let W=b?J.bold(J.fg("accent",E)):J.fg("muted",E),I=J.fg("borderAccent","─".repeat(Math.max(0,O-S$(E)-1)));return S(`${W}${I}`,O)}function P(E,O){let W=O?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),I="";if(A)I=`${J.fg("dim"," /")}${J.fg("accent",D)}${J.fg("accent","█")} `;else if(D)I=`${J.fg("dim"," /")}${J.fg("warning",D)} `;let s=S$(" available pool ")+S$(I),o=J.fg("borderAccent","─".repeat(Math.max(0,E-s-1)));return S(`${W}${I}${o}`,E)}function R$(E){if(A){if(k(E,"escape"))return D="",A=!1,U=0,!0;if(k(E,"enter")||k(E,"return"))return A=!1,!0;if(k(E,"backspace")||k(E,"delete"))return D=D.slice(0,-1),U=0,!0;if(E.length===1&&E>=" "&&E!=="")return D+=E,U=0,!0;return!0}if(k(E,"tab"))return j$(!1),!0;if(k(E,"shift+tab"))return j$(!0),!0;if(k(E,"/"))return q="pool",A=!0,!0;if(k(E,"enter")||k(E,"return")||k(E,"space"))return x().then(()=>!0);if(q==="providers"&&(k(E,"d")||k(E,"delete")||k(E,"backspace")))return p().then(()=>!0);if(k(E,"up")||k(E,"k"))return _(-1),!0;if(k(E,"down")||k(E,"j"))return _(1),!0;if(k(E,"pageUp")||k(E,"b"))return _(-8),!0;if(k(E,"pageDown")||k(E,"f"))return _(8),!0;if(k(E,"left")||k(E,"h"))return q="providers",!0;if(k(E,"right")||k(E,"l")){if(q==="providers")q="assigned";else if(q==="assigned")q="pool";return!0}return!1}function Zj(){if(A)return" type to filter · ↵ apply · esc clear ";return" tab ↔ panel · ↑↓ nav · ↵ move · / filter · d remove group "}return{id:"models",label:"Models",render:v,handleInput:R$,footerHint:Zj,rebuild:n}}import{matchesKey as y}from"@duckmind/dm-tui";var R={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function t0($,j={}){let J=[],Q=new Map,Y=0;for(let Z of $.accounts){if(!j.showDisabled&&Z.disabled){Y++;continue}let z=Q.get(Z.provider)??[];z.push(Z),Q.set(Z.provider,z)}if(J.push(`${R.dim}generated ${$.generatedAt}${R.reset}`),$.unsupportedProviders.length>0)J.push(`${R.dim}providers without quota lookup:${R.reset} ${$.unsupportedProviders.join(", ")}`);if(Y>0)J.push(`${R.dim}hidden disabled accounts:${R.reset} ${Y} ${R.dim2}(press d to show)${R.reset}`);for(let[Z,z]of Array.from(Q.entries()).sort()){J.push(""),J.push(`${R.bold}${R.accent}▌ ${Z}${R.reset}`);for(let X of z){if(J.push(B1(X)),!X.supported){J.push(` ${R.dim2}(provider not quota-aware)${R.reset}`);continue}if(X.error){if(j.verbose)for(let V of T1(X.error,88))J.push(` ${R.red}${V}${R.reset}`);continue}let q=X.groups??[];if(q.length===0){J.push(` ${R.dim2}(no active quota windows)${R.reset}`);continue}for(let V of q)J.push(K1(V))}}return J.push(""),J.push(`${R.dim}legend:${R.reset} ${a0} ok ${e0} error/unavailable ${$j} disabled ${R.green}✓N${R.reset}/${R.red}✗N${R.reset} request counters ${R.dim}v = verbose, d = show disabled${R.reset}`),J}function T1($,j){if($.length<=j)return[$];let J=[],Q=$;while(Q.length>j){let Y=Q.lastIndexOf(" ",j);if(Y<j*0.6)Y=j;J.push(Q.slice(0,Y)),Q=Q.slice(Y).replace(/^\s+/,"")}if(Q)J.push(Q);return J}function B1($){let j=L1($),J=`${R.green}✓${$.success}${R.reset} ${R.red}✗${$.failed}${R.reset}`,Q=Qj($.label,36);return` ${j} ${R.bold}${Q}${R.reset} ${J}`}var a0=`${R.green}●${R.reset}`,e0=`${R.yellow}⚠${R.reset}`,$j=`${R.dim2}⊘${R.reset}`;function L1($){if($.disabled)return $j;if($.unavailable||$.error||$.status&&$.status!=="active")return e0;return a0}function K1($){let j=Jj($.remainingFraction),J=Math.round(j*100),Q=F1(j),Y=$.resetTime?` ${R.dim}reset ${I1($.resetTime)}${R.reset}`:"",Z=Qj($.label,28).padEnd(28," ");return` ${Q} ${S1(J,j)} ${Z}${Y}`}function F1($){let j=Jj($),J=Math.round(j*18),Q=jj(j),Y=R.dim2,Z="█".repeat(J),z="░".repeat(18-J);return`${Y}[${Q}${Z}${Y}${z}]${R.reset}`}function S1($,j){return`${jj(j)}${String($).padStart(3)}%${R.reset}`}function jj($){if($>=0.4)return R.green;if($>=0.15)return R.yellow;return R.red}function I1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let Q=Math.round(J/60000);if(Q<60)return`${Q}m`;let Y=Math.round(Q/60);if(Y<48)return`${Y}h`;return`${Math.round(Y/24)}d`}function Jj($){return Math.max(0,Math.min(1,$))}function Qj($,j){if($.length<=j)return $;return`${$.slice(0,j-1)}…`}function Yj($){let{tui:j,theme:J,cfg:Q}=$,Y="idle",Z=null,z="",X=0,q=!1,V=!1,M=(D)=>{Y="loading",j.requestRender();let A=h(Q.proxy.usageKey);L0(Q,A,{force:D}).then((B)=>{Z=B,Y="ready",X=0,j.requestRender()}).catch((B)=>{z=B.message,Y="error",j.requestRender()})},U=()=>{if(Y==="idle"||Y==="loading")return[J.fg("dim"," loading usage…")];if(Y==="error")return[J.fg("error",` usage failed: ${z}`)];if(!Z)return[J.fg("dim"," (no data)")];return t0(Z,{showDisabled:q,verbose:V})};return{id:"usage",label:"Usage",render:(D,A)=>{let B=U();return X=x$(X,A,B.length),d(B,X,A).map((C)=>S(` ${C}`,D))},handleInput:(D)=>{if(y(D,"d"))return q=!q,X=0,!0;if(y(D,"v"))return V=!V,X=0,!0;let A=U().length;if(y(D,"up")||y(D,"k"))return X=Math.max(0,X-1),!0;if(y(D,"down")||y(D,"j"))return X=Math.min(Math.max(0,A-1),X+1),!0;if(y(D,"pageUp")||y(D,"b"))return X=Math.max(0,X-10),!0;if(y(D,"pageDown")||y(D,"f"))return X=Math.min(Math.max(0,A-1),X+10),!0;if(y(D,"home")||y(D,"g"))return X=0,!0;if(y(D,"end")||y(D,"shift+g"))return X=Math.max(0,A-1),!0;return!1},footerHint:()=>{let D=q?J.fg("success","[d disabled]"):"d disabled",A=V?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${D} · ${A} `},onActivate:()=>{if(Y==="idle")M(!1)},reload:()=>{if(K$(),Y!=="idle")M(!0)}}}function kJ($){let{dm:j,ctx:J,tui:Q,theme:Y,cfg:Z,done:z}=$,X=$.discovery,q=!1,V="",M=d0({tui:Q,theme:Y,ctx:J,cfg:Z,getDiscovery:()=>X,onChange:()=>{q=!0,V=""}}),U=Yj({tui:Q,theme:Y,cfg:Z}),F=u0({theme:Y,cfg:Z,getDiscovery:()=>X}),T=[M,U,F],H=0,D=()=>T[H],A=(_)=>{if(_<0||_>=T.length||_===H)return;H=_,D().onActivate?.(),Q.requestRender()},B=()=>{V=Y.fg("dim","saving…"),B$(Z),Q.requestRender();let _=c$(j);l$(j,Z,X,_).then((x)=>{q=!1,V=Y.fg("success",`✓ settings saved · ${x.registered.length} registered, ${x.skipped.length} skipped`),Q.requestRender()}).catch((x)=>{V=Y.fg("error",`save failed: ${x.message}`),Q.requestRender()})},C=async()=>{V=Y.fg("dim","refreshing…"),Q.requestRender();try{let _=c$(j),x=h(Z.proxy.apiKey);X=await N0(Z,x),K$(),M.rebuild(),U.reload();let p=await l$(j,Z,X,_);V=Y.fg("success",`✓ refreshed · ${p.registered.length} providers (${X.source})`)}catch(_){V=Y.fg("error",`refresh failed: ${_.message}`)}Q.requestRender()},N=async()=>{if(!await S0(J,!0)){Q.requestRender();return}let x=T$();Z.proxy={...Z.proxy,...x.proxy},await C()},G=()=>{let _=Z.proxy.endpoint||"(unset)",x=_.length>40?`…${_.slice(-39)}`:_,p=Boolean(h(Z.proxy.apiKey)),v=0,c=0;for(let P of Object.values(Z.builtinProviders)){if(P.enabled&&P.models.length>0)v++;c+=P.models.length}for(let P of Object.values(Z.customProviders)){if(P.models.length>0)v++;c+=P.models.length}let J$=V?V:q?Y.fg("warning","● unsaved — press s to save"):Y.fg("dim","✓ saved");return[`${Y.fg("dim","endpoint")} ${x}`,`${Y.fg("dim","key")} ${p?Y.fg("success","✓"):Y.fg("error","✗")}`,`${Y.fg("dim","providers")} ${v}`,`${Y.fg("dim","models")} ${c}`,J$]},n=(_)=>{let x=Q.rows??40,v=Math.max(16,Math.min(x-6,38))-2,c=Math.max(72,_-2),J$=Math.max(6,v-3),P=[];return P.push(b0(Y,G(),c)),P.push(x0(Y,T.map((R$)=>({id:R$.id,label:R$.label})),H,c)),P.push(n0(Y,c)),P.push(...D().render(c,J$)),r(Y,{width:_,title:" /cliproxy ",lines:P,footer:{hint:D().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},j$=(_)=>{if(x1().matches(_,"tui.select.cancel")||u(_,"q")||u(_,"escape"))return z(),!0;if(u(_,"]")||u(_,"tab"))return A((H+1)%T.length),!0;if(u(_,"[")||u(_,"shift+tab"))return A((H-1+T.length)%T.length),!0;if(u(_,"1"))return A(0),!0;if(u(_,"2"))return A(1),!0;if(u(_,"3"))return A(2),!0;if(u(_,"r"))return C().then(()=>!0);if(u(_,"e"))return N().then(()=>!0);if(u(_,"s"))return B(),!0;return!1};return{render:n,invalidate(){},handleInput(_){let x=D().handleInput(_);if(x instanceof Promise){V="",x.then((v)=>{if(v)Q.requestRender()});return}if(x){V="",Q.requestRender();return}let p=j$(_);if(p instanceof Promise)p.then((v)=>{if(v)Q.requestRender()});else if(p)Q.requestRender()}}}export{kJ as buildHub};