@duckmind/dm-darwin-x64 0.49.9 → 0.50.9

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.
Files changed (38) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +4 -185
  3. package/extensions/dm-cliproxy/index.js +2 -2
  4. package/extensions/dm-cliproxy/scripts/check-config-migration.js +8 -10
  5. package/extensions/dm-cliproxy/src/apply.js +1 -1
  6. package/extensions/dm-cliproxy/src/cache.js +1 -1
  7. package/extensions/dm-cliproxy/src/commands.js +2 -2
  8. package/extensions/dm-cliproxy/src/config.js +2 -2
  9. package/extensions/dm-cliproxy/src/fetch-models.js +1 -1
  10. package/extensions/dm-cliproxy/src/fetch-usage.js +1 -1
  11. package/extensions/dm-cliproxy/src/ui-hub/hub.js +2 -2
  12. package/extensions/dm-cliproxy/src/ui-hub/index.js +2 -2
  13. package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +1 -1
  14. package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +1 -1
  15. package/extensions/dm-cliproxy/src/ui-setup.js +2 -2
  16. package/extensions/dm-cliproxy/src/usage-shared-cache.js +1 -1
  17. package/extensions/dm-image2/index.js +7 -7
  18. package/extensions/dm-image2/src/image-lib.mjs +1 -1
  19. package/package.json +1 -1
  20. package/CHANGELOG.md +0 -4796
  21. package/extensions/dm-ask-user/index.js +0 -10
  22. package/extensions/dm-ask-user/package.json +0 -18
  23. package/extensions/dm-cli-anything/index.js +0 -5
  24. package/extensions/dm-cli-anything/package.json +0 -22
  25. package/extensions/dm-cli-anything/skills/cli-anything/SKILL.md +0 -21
  26. package/extensions/dm-cli-anything/vendor/public_registry.json +0 -367
  27. package/extensions/dm-cli-anything/vendor/registry.json +0 -1232
  28. package/extensions/dm-grill-me/index.js +0 -174
  29. package/extensions/dm-grill-me/package.json +0 -23
  30. package/extensions/dm-tasks/package.json +0 -20
  31. package/extensions/dm-tasks/src/auto-clear.js +0 -1
  32. package/extensions/dm-tasks/src/index.js +0 -212
  33. package/extensions/dm-tasks/src/process-tracker.js +0 -1
  34. package/extensions/dm-tasks/src/task-store.js +0 -1
  35. package/extensions/dm-tasks/src/tasks-config.js +0 -1
  36. package/extensions/dm-tasks/src/types.js +0 -0
  37. package/extensions/dm-tasks/src/ui/settings-menu.js +0 -1
  38. package/extensions/dm-tasks/src/ui/task-widget.js +0 -1
@@ -1,2 +1,2 @@
1
- var Q$=!1;function b$($){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]",...$)}};import{getKeybindings as _1,matchesKey as C}from"@duckmind/dm-tui";import{getModels as Pj}from"@duckmind/dm-ai/compat";var y$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function w$($,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 Xj=128000,Qj=16000,zj={input:0,output:0,cacheRead:0,cacheWrite:0},Vj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function G$($){return Vj.some((j)=>j.test($))}var qj=[[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 R$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function z0($,j){let J=(j??"").trim(),Y=$.match(/^([a-z0-9]+-)(.*)$/);if(Y)return J?`${J}-${Y[1]}`:Y[1];return $}function V0($,j){for(let[J,Y,Z]of qj)if(J.has($))return{slug:R$(j,Y),api:Z};return{slug:R$(j,"misc"),api:"openai-completions"}}function Mj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function J$($){return{id:$,name:Mj($),contextWindow:Xj,maxTokens:Qj,reasoning:G$($),cost:{...zj}}}import{execSync as Dj}from"node:child_process";import{randomUUID as q0}from"node:crypto";import{chmodSync as _$,constants as Uj,copyFileSync as M0,existsSync as A$,linkSync as nj,mkdirSync as D0,readFileSync as Ej,rmSync as C$,writeFileSync as Rj}from"node:fs";import{homedir as u$}from"node:os";import{dirname as z$,join as V$}from"node:path";import{fileURLToPath as Gj}from"node:url";var v$=V$(u$(),".dm","agent","dm-cliproxy"),w=V$(v$,"config.json"),_j=[V$(u$(),".pi","agent","pi-cliproxyapi","config.json"),V$(u$(),".config","pi-cliproxyapi","config.json")];function Aj(){return A$(V$(z$(Gj(import.meta.url)),"..",".git"))}function Oj($=_j,j=w,J=Aj()){if(A$(j))return;let Z=(typeof $==="string"?[$]:[...$]).find((z)=>A$(z));if(!Z)return;let X;try{D0(z$(j),{recursive:!0,mode:448}),_$(z$(j),448),X=`${j}.${process.pid}.${q0()}.tmp`,M0(Z,X,Uj.COPYFILE_EXCL),_$(X,384),nj(X,j),C$(X),X=void 0,B.info("legacy config copied to",j)}catch(z){if(X)try{C$(X,{force:!0})}catch(Q){B.warn("failed to clean temporary config:",Q)}B.warn("failed to migrate legacy config:",z)}}var O$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function W$(){if(Oj(),!A$(w))return B.debug("config not found, using defaults at",w),structuredClone(O$);try{let $=JSON.parse(Ej(w,"utf8"));return Wj($)}catch($){return B.error("failed to read config:",$,"— using defaults"),structuredClone(O$)}}function H$($){D0(z$(w),{recursive:!0,mode:448}),_$(z$(w),448);let j=`${w}.${process.pid}.${q0()}.tmp`;try{Rj(j,JSON.stringify($,null,2)+`
2
- `,{encoding:"utf8",flag:"wx",mode:384}),M0(j,w),_$(w,384)}finally{C$(j,{force:!0})}B.info("config saved to",w)}function Wj($){if(!$||typeof $!=="object")return structuredClone(O$);let j=$,J=structuredClone(O$),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 g($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Dj(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 Hj,existsSync as L1,mkdirSync as kj,readFileSync as P1,writeFileSync as Nj}from"node:fs";import{dirname as U0,join as Tj}from"node:path";var f$=Tj(v$,"discovery-cache.json");function g$($){try{kj(U0(f$),{recursive:!0,mode:448}),Hj(U0(f$),448);let j={savedAt:Date.now(),discovery:$};Nj(f$,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){B.warn("failed to write discovery cache:",j.message)}}var Y$="dm-cliproxy/0.3.5",Bj=5000;async function R0($,j){let J=new AbortController,Y=setTimeout(()=>J.abort(Error("timeout")),Bj);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 Sj($){let j=Kj($.proxy.endpoint),J;try{J=await R0(j,{headers:{"User-Agent":Y$,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,V]of Object.entries(X)){if(!V||!Array.isArray(V.models))continue;let q=V.models.map((D)=>({id:String(D.id),name:typeof D.name==="string"?D.name:String(D.id),reasoning:Boolean(D.reasoning??G$(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:V.api??"openai-responses",models:q})}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??G$(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:z0(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 Fj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Y=await R0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":Y$}});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 Lj($,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=J$(z.id);n0(Y,"openai","openai-responses",E0(D));continue}if(z.owned_by==="anthropic"){let D=J$(z.id);n0(Y,"anthropic","anthropic-messages",E0(D));continue}let{slug:Q,api:V}=V0(z.owned_by,j.proxy.providerPrefix),q=J$(z.id);Z.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:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:Z,serverDiscoveryExcludes:[],upstreamTotal:X}}function n0($,j,J,Y){let Z=$.get(j);if(!Z)Z={name:j,api:J,models:[]},$.set(j,Z);Z.models.push(Y)}function E0($){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 G0($,j){let J=await Sj($);if(J)return B.info(`discovery via /.well-known/pi: ${J.builtinProviders.length} builtin, ${J.customPool.length} custom`),g$(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 Fj($,j),Z=Lj(Y,$);return B.info(`discovery via /v1/models: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),g$(Z),Z}function _0($){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 h$($,j,J){let Y={registered:[],skipped:[]},Z=_0(J),X=g(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 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){Y.skipped.push({provider:V,reason:"disabled"});continue}if(!Array.isArray(q.models)||q.models.length===0){Y.skipped.push({provider:V,reason:"empty whitelist"});continue}let D=[];try{D=Pj(V)}catch{}let n=new Map(D.map((A)=>[A.id,A])),F=new Map((z.get(V)??[]).map((A)=>[A.id,A])),_=[];for(let A of q.models){if(!Z.has(A))continue;let H=n.get(A),P=F.get(A);if(H){_.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=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){Y.skipped.push({provider:V,reason:"no whitelisted models present on proxy"});continue}let G=q.apiOverride??_[0].api;if(!y$.has(G)){Y.skipped.push({provider:V,reason:`api "${G}" not in allowlist`});continue}let U=_.map((A)=>{let H=j.overrides[A.id]??{},P={id:A.id,name:typeof H.name==="string"?H.name:A.name,api:G,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:V,baseUrl:w$(G,j.proxy.endpoint),apiKey:X,authHeader:!0,api:G,models:U};$.registerProvider(V,W),Y.registered.push({provider:V,modelCount:U.length,api:G})}let Q=new Map(J.customPool.map((V)=>[V.id,V]));for(let[V,q]of Object.entries(j.customProviders)){if(!y$.has(q.api)){Y.skipped.push({provider:V,reason:`api "${q.api}" not in allowlist`});continue}let D=q.models.filter((_)=>Z.has(_.id));if(D.length===0){Y.skipped.push({provider:V,reason:"no configured models present on proxy"});continue}let n=D.map((_)=>{let G=Q.get(_.id),U=J$(_.id),W=j.overrides[_.id]??{};return{id:_.id,name:_.name??G?.name??U.name??_.id,api:q.api,reasoning:Ij(_.reasoning,G?.reasoning,U.reasoning,W.reasoning)??!1,input:["text"],cost:_.cost??G?.cost??U.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:A0(_.contextWindow,G?.contextWindow,U.contextWindow,W.contextWindow)??128000,maxTokens:A0(_.maxTokens,G?.maxTokens,U.maxTokens,W.maxTokens)??16000}}),F={name:V,baseUrl:w$(q.api,j.proxy.endpoint),apiKey:X,authHeader:!0,api:q.api,models:n};$.registerProvider(V,F),Y.registered.push({provider:V,modelCount:n.length,api:q.api})}return B.info(`applyAll: registered ${Y.registered.length} providers, skipped ${Y.skipped.length}`),Y}function A0(...$){for(let j of $)if(typeof j==="number")return j;return}function Ij(...$){for(let j of $)if(typeof j==="boolean")return j;return}var xj=15000,q$=null;function k$(){q$=null}async function O0($,j,J={}){if(!J.force&&q$&&Date.now()-q$.fetchedAt<$.usageCacheTtlMs)return q$.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":Y$},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 q$={fetchedAt:Date.now(),doc:Q},B.debug("usage fetched, accounts:",Q.accounts.length),Q}import{visibleWidth as c$}from"@duckmind/dm-tui";import{visibleWidth as W0}from"@duckmind/dm-tui";function K($,j){let J=W0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return p$($,j)}function p$($,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=W0(X);if(Y+z>j)break;J+=X,Y+=z,Z++}return`${J}\x1B[0m`}var bj="│",yj="╭",wj="╮",Cj="╰",uj="╯",M$="─";function o($,j){let J=Math.max(4,j.width);return[vj($,j.title,j.titleColor??"accent",J),...j.lines.map((Y)=>fj($,Y,J)),gj($,j.footer,J)]}function vj($,j,J,Y){let Z=j??"",X=c$(Z),z=Math.max(0,Y-3-X),Q=Z?$.bold($.fg(J,Z)):"",V=`${yj}${M$}${Q}${M$.repeat(z)}${wj}`;return $.fg("borderAccent",V)}function fj($,j,J){let Y=Math.max(0,J-2),Z=$.fg("borderAccent",bj);return`${Z}${K(j,Y)}${Z}`}function gj($,j,J){let Y=`${Cj}${M$}`,Z=`${uj}`,X=3;if(!j||!j.hint&&!j.badge){let G=Math.max(0,J-3);return $.fg("borderAccent",`${Y}${M$.repeat(G)}${Z}`)}let z=j.hint??"",Q=j.badge??"",V=c$(z),q=c$(Q),D=Math.max(0,J-3-V-q),n=$.fg("dim",z),F=Q?$.fg("muted",Q):"",_=M$.repeat(D);return`${$.fg("borderAccent",Y)}${n}${$.fg("borderAccent",_)}${F}${$.fg("borderAccent",Z)}`}function N$($){return Math.max(0,$-2)}import{existsSync as H0}from"node:fs";import{homedir as hj}from"node:os";import{getKeybindings as pj,Input as cj,matchesKey as lj}from"@duckmind/dm-tui";var mj=[{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 k0($,j=!1){let J=W$(),Y={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Z=!1;for(let z of mj){let Q=j?Y[z.label]??z.initialValue??"":Y[z.label]??"";if(!j&&Q)continue;let V=await sj($,z,Q||z.initialValue||"");if(V===void 0){Z=!0;break}let q=V.trim();if(!q){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"?q:rj(q)}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 H$(X),$.ui.notify(`saved to ${w}`,"info"),!0}function rj($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,hj());return H0(j)?`!cat ${$}`:$}if($.startsWith("/"))return H0($)?`!cat ${$}`:$;return $}async function sj($,j,J){return $.ui.custom((Y,Z,X,z)=>oj(Y,Z,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function oj($,j,J,Y,Z){let X=new cj;X.setValue(Y),X.focused=!0;let z=null,Q=(V)=>{if(!V&&!J.required){Z("");return}if(!V&&J.required){z="required field",$.requestRender();return}if(J.validate){let q=V.trim();if(q&&!q.startsWith("!")&&!q.startsWith("$")){let D=J.validate(q);if(D){z=D,$.requestRender();return}}}Z(V)};return X.onSubmit=Q,X.onEscape=()=>Z(void 0),{render(V){let q=N$(V),D=X.render(q-4),n=["",` ${j.fg("dim",J.hint)}`,"",...D.map((F)=>` ${j.fg("accent",`❯ ${F}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return o(j,{width:V,title:` setup: ${J.label} `,lines:n,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){X.invalidate()},handleInput(V){if(pj().matches(V,"tui.select.cancel")||lj(V,"escape")){Z(void 0);return}z=null,X.handleInput(V),$.requestRender()}}}import{visibleWidth as T$}from"@duckmind/dm-tui";function N0($,j,J,Y){let Z=$.fg("borderAccent","│"),X=j.map((z,Q)=>{let V=`${Q+1} ${z.label}`;return Q===J?$.bold($.fg("accent",` ${V} `)):$.fg("dim",` ${V} `)});return K(` ${X.join(Z)}`,Y)}function T0($,j,J){let Y=j.join($.fg("dim"," "));return K(` ${Y}`,J)}function B0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function i($,j,J){let Y=$.slice(j,j+J);while(Y.length<J)Y.push("");return Y}function B$($,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)),V=Q+X;if($<V)Q=Math.max(0,$-X);let q=Q+Y-1;if(j>q)Q=Math.min(z,j-(Y-1));return Q}function K$($,j,J){let Y=Math.max(0,J-j);return Math.max(0,Math.min($,Y))}import{matchesKey as d}from"@duckmind/dm-tui";import{existsSync as ij,readFileSync as dj}from"node:fs";import{homedir as S0}from"node:os";import{join as F0}from"node:path";var tj=F0(S0(),".dm","models.json"),aj=F0(S0(),".dm","auth.json");function K0($){if(!ij($))return null;try{return JSON.parse(dj($,"utf8"))}catch{return null}}function L0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Y=K0(tj);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=K0(aj);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(),V=(G)=>j.fg("success",G),q=(G)=>j.fg("error",G),D=(G)=>j.fg("dim",G),n=[];n.push(`${D("endpoint")} ${J.proxy.endpoint||q("(unset)")}`),n.push(`${D("apiKey")} ${g(J.proxy.apiKey)?V("resolves"):q("empty after resolution")}`),n.push(`${D("usageKey")} ${J.proxy.usageKey?g(J.proxy.usageKey)?V("resolves"):q("set but empty"):D("not configured")}`),n.push(`${D("user-agent")} ${Y$}`),n.push(""),n.push(`${D("discovery")} source=${Q.source}`),n.push(`${D("upstream")} v=${Q.upstreamVersion??"(unknown)"} · ${Q.upstreamTotal} ids`);let F=Q.builtinProviders.map((G)=>`${G.name}=${G.models.length}`).join(", ")||D("(none)");n.push(`${D("built-in")} ${F}`),n.push(`${D("custom pool")} ${Q.customPool.length} models`);let _=L0(J);if(n.push(""),_.length===0)n.push(`${D("conflicts")} ${V("none")}`);else{n.push(`${D("conflicts")}`);for(let G of _)n.push(` ${j.fg("warning",`[${G.kind}]`)} ${G.detail}`)}return n};return{id:"diagnostics",label:"Diagnostics",render:(Q,V)=>{let q=Z();return Y=K$(Y,V,q.length),i(q,Y,V).map((D)=>K(` ${D}`,Q))},handleInput:(Q)=>{let V=Z().length;if(d(Q,"up")||d(Q,"k"))return Y=Math.max(0,Y-1),!0;if(d(Q,"down")||d(Q,"j"))return Y=Math.min(Math.max(0,V-1),Y+1),!0;if(d(Q,"pageUp")||d(Q,"b"))return Y=Math.max(0,Y-10),!0;if(d(Q,"pageDown")||d(Q,"f"))return Y=Math.min(Math.max(0,V-1),Y+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as N}from"@duckmind/dm-tui";function l$($){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 ej($){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 e($,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(e($,j));return X.filter((Q)=>!z.has(Q))}let Y=ej($),Z=new Set(e($,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 $1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function x0($,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($1(J));$.customProviders[j.name]=Y}function b0($,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 m$($,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 J1}from"@duckmind/dm-ai/compat";function r$($,j){let J=[],Y=new Set(j.builtinModelIds.keys()),Z=new Set(J1()),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 V;try{let D=j1(z).find((n)=>Q.includes(n.id));if(D)V=D.api}catch{}if(!V){let q=Q[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 Q=$.customProviders[z];J.push({kind:"custom",name:z,api:Q.api,subtitle:`custom · ${Q.api}`})}return J}import{getKeybindings as Y1,matchesKey as Z$}from"@duckmind/dm-tui";async function C0($,j){return $.ui.custom((J,Y,Z,X)=>Z1(Y,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",X),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function Z1($,j,J,Y){return{render(Z){return o($,{width:Z,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Z){if(Y1().matches(Z,"tui.select.cancel")||Z$(Z,"escape")||Z$(Z,"n")||Z$(Z,"q")){Y(!1);return}if(Z$(Z,"y")||Z$(Z,"enter")||Z$(Z,"return")){Y(!0);return}}}}import{getKeybindings as X1,Input as Q1,matchesKey as z1}from"@duckmind/dm-tui";async function u0($,j){let J=R$(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 Q1;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=N$(z),V=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",q=Z.render(Q-4),D=["",` ${j.fg("dim",V)}`,"",...q.map((n)=>` ${j.fg("accent",`❯ ${n}`)}`),"",X?` ${j.fg("error",`! ${X}`)}`:""];return o(j,{width:z,title:" new custom group ",lines:D,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(z){if(X1().matches(z,"tui.select.cancel")||z1(z,"escape")){Y(null);return}X=null,Z.handleInput(z),$.requestRender()}}}import{visibleWidth as q1}from"@duckmind/dm-tui";function s$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function v0($,j){let J=q1($);if(J===j)return $;if(J>j)return p$($,j);return K($,j)}function f0($,j,J){let{theme:Y,width:Z,isCursor:X,isFocused:z}=J,Q=s$(Y,X,z),V=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,q=$.kind==="builtin"?Y.fg("accent","B"):Y.fg("warning","C"),D=`${Y.fg("dim","[")}${q}${Y.fg("dim","]")}`,n=V>0?Y.fg("success","●"):Y.fg("dim","○"),F=V>0?Y.fg("success",String(V).padStart(2)):Y.fg("dim"," 0"),_=X&&z?Y.bold(Y.fg("accent",$.name)):X?Y.bold($.name):$.name,G=Y.fg("dim",$.api),U=`${Q}${D} ${_} ${n}${F} ${G}`;return v0(U,Z)}function g0($,j,J,Y){let Z=s$($,j,J),X=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return K(`${Z}${X}`,Y)}function o$($,j,J,Y,Z){let{theme:X,width:z,isCursor:Q,isFocused:V}=Z,q=s$(X,Q,V),D=J==="assigned"?X.fg("success","☑"):X.fg("dim","☐"),n=Y?` ${X.fg("warning","⚠")}`:"",F=Q&&V?X.fg("accent",$):$,_=j?.reasoning?` ${X.fg("accent","✨")}`:"",G=j?X.fg("muted",` · ${j.suggestedApi}`):X.fg("error"," · not on proxy"),U=`${q}${D} ${F}${n}${_}${G}`;return v0(U,z)}function h0($,j,J){let Y=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return K(` ${Y}`,J)}function i$($,j,J){return K(` ${$.fg("dim",j)}`,J)}function p0($,j,J,Y){let Z=Y?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return K(`${Z}${j}`,J)}function c0($){let{tui:j,theme:J,ctx:Y,cfg:Z}=$,X=$.onChange??(()=>{}),z=l$($.getDiscovery()),Q=r$(Z,z),V="providers",q=0,D=0,n=0,F=0,_=0,G=0,U="",W=!1,A=()=>{if(Q.length===0)return null;let M=Math.max(0,Math.min(q,Q.length-1));return Q[M]??null},H=(M)=>{let O=w0(I0(Z,M,z),z,U);return y0(O,z)},P=(M)=>H(M).flatMap((O)=>O.ids),p=()=>{Q=r$(Z,z);let M=Math.max(0,Q.length);if(q>M)q=M;let O=A();if(O){let L=e(Z,O).length,k=P(O).length;if(D>=L)D=Math.max(0,L-1);if(n>=k)n=Math.max(0,k-1)}},S$=()=>{z=l$($.getDiscovery()),p()},D$=(M)=>{let O=["providers","assigned","pool"],L=O.indexOf(V);V=M?O[(L-1+O.length)%O.length]:O[(L+1)%O.length]},R=(M)=>{if(V==="providers"){let k=Q.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(Z,O).length;if(k===0)return;D=Math.max(0,Math.min(D+M,k-1));return}let L=P(O).length;if(L===0)return;n=Math.max(0,Math.min(n+M,L-1))},I=async()=>{if(V==="providers"){if(q===Q.length){let k=await u0(Y,Z.proxy.providerPrefix);if(k&&!Z.customProviders[k]){if(Z.customProviders[k]={api:"openai-completions",models:[]},X(),p(),q=Q.findIndex((S)=>S.kind==="custom"&&S.name===k),q<0)q=Q.length-1;V="pool"}j.requestRender();return}V="pool";return}let M=A();if(!M)return;if(V==="assigned"){let k=e(Z,M)[D];if(!k)return;b0(Z,M,k),X(),p();return}let O=P(M)[n];if(!O)return;let L=z.byId.get(O);if(!L)return;x0(Z,M,L),X(),p()},l=async()=>{if(V!=="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(),q>=Q.length)q=Math.max(0,Q.length-1);j.requestRender()},u=(M,O)=>h(M,O);function h(M,O){let L=Math.max(70,M),k=Math.min(56,Math.max(34,Math.floor(L*0.4))),S=L-k-1,m=Math.max(8,O),r=Math.max(5,Math.floor((m-1)/2)),d$=m-r,c=A(),X$=0,F$=0,L$=0,t$=0,P$=0,a$=0,t=[];t.push($$(" providers ",k,V==="providers"));for(let T=0;T<Q.length;T++){let v=Q[T],y=V==="providers"&&T===q;if(y)X$=t.length,F$=X$;t.push(f0(v,Z,{theme:J,width:k,isCursor:y,isFocused:V==="providers"}))}{let T=V==="providers"&&q===Q.length;if(T)X$=t.length,F$=X$;t.push(g0(J,T,V==="providers",k))}let a=[],$j=c?`assigned to ${J.bold(c.name)} ${J.fg("dim",`· ${c.api}`)}`:J.fg("dim","no provider selected");if(a.push($$(" assigned ",S,V==="assigned")),a.push(p0(J,$j,S,V==="assigned")),c){let T=e(Z,c);if(T.length===0)a.push(i$(J,"(nothing assigned yet)",S));for(let v=0;v<T.length;v++){let y=T[v],f=z.byId.get(y),E$=V==="assigned"&&v===D;if(E$)L$=a.length,t$=L$;let j$=f?!m$(c.api,f.suggestedApi):!1;a.push(o$(y,f,"assigned",j$,{theme:J,width:S,isCursor:E$,isFocused:V==="assigned"}))}}let s=[];if(s.push(x(S,V==="pool")),c){let T=H(c);if(T.reduce((y,f)=>y+f.ids.length,0)===0)s.push(i$(J,U?`(no matches for "${U}")`:"(no models available)",S));else{let y=0;for(let f of T){let E$=s.length;s.push(h0(J,f.label,S));for(let j$=0;j$<f.ids.length;j$++){let Z0=f.ids[j$],x$=z.byId.get(Z0),X0=V==="pool"&&y===n;if(X0)P$=s.length,a$=j$===0?E$:P$;let Zj=x$?!m$(c.api,x$.suggestedApi):!1;s.push(o$(Z0,x$,"pool",Zj,{theme:J,width:S,isCursor:X0,isFocused:V==="pool"})),y++}}}}let jj=Math.max(1,d$-1),e$=B$(F$,X$,F,m,t.length,1),$0=B$(V==="assigned"?t$:0,V==="assigned"?L$:0,_,r,a.length,2),j0=B$(V==="pool"?a$:0,V==="pool"?P$:0,G,jj,s.length,1);F=e$,_=$0,G=j0;let J0=i(t,e$,m),Jj=i(a,$0,r),Yj=i(s,j0,d$),Y0=J.fg("borderAccent","│"),I$=[];for(let T=0;T<m;T++){let v=K(J0[T]??"",k),y=T<r?Jj[T]:Yj[T-r],f=K(y,S);I$.push(`${v}${Y0}${f}`)}let n$=r;if(n$>0&&n$<m){let T=K(J0[n$]??"",k),v=J.fg("borderAccent","─".repeat(S));I$[n$]=`${T}${Y0}${v}`}return I$}function $$(M,O,L){let k=L?J.bold(J.fg("accent",M)):J.fg("muted",M),S=J.fg("borderAccent","─".repeat(Math.max(0,O-T$(M)-1)));return K(`${k}${S}`,O)}function x(M,O){let k=O?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),S="";if(W)S=`${J.fg("dim"," /")}${J.fg("accent",U)}${J.fg("accent","█")} `;else if(U)S=`${J.fg("dim"," /")}${J.fg("warning",U)} `;let m=T$(" available pool ")+T$(S),r=J.fg("borderAccent","─".repeat(Math.max(0,M-m-1)));return K(`${k}${S}${r}`,M)}function U$(M){if(W){if(N(M,"escape"))return U="",W=!1,n=0,!0;if(N(M,"enter")||N(M,"return"))return W=!1,!0;if(N(M,"backspace")||N(M,"delete"))return U=U.slice(0,-1),n=0,!0;if(M.length===1&&M>=" "&&M!=="")return U+=M,n=0,!0;return!0}if(N(M,"tab"))return D$(!1),!0;if(N(M,"shift+tab"))return D$(!0),!0;if(N(M,"/"))return V="pool",W=!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 e0(){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:U$,footerHint:e0,rebuild:S$}}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 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(`${E.dim}generated ${$.generatedAt}${E.reset}`),$.unsupportedProviders.length>0)J.push(`${E.dim}providers without quota lookup:${E.reset} ${$.unsupportedProviders.join(", ")}`);if(Z>0)J.push(`${E.dim}hidden disabled accounts:${E.reset} ${Z} ${E.dim2}(press d to show)${E.reset}`);for(let[X,z]of Array.from(Y.entries()).sort()){J.push(""),J.push(`${E.bold}${E.accent}▌ ${X}${E.reset}`);for(let Q of z){if(J.push(D1(Q)),!Q.supported){J.push(` ${E.dim2}(provider not quota-aware)${E.reset}`);continue}if(Q.error){if(j.verbose)for(let q of M1(Q.error,88))J.push(` ${E.red}${q}${E.reset}`);continue}let V=Q.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} ${m0} ok ${r0} error/unavailable ${s0} disabled ${E.green}✓N${E.reset}/${E.red}✗N${E.reset} request counters ${E.dim}v = verbose, d = show disabled${E.reset}`),J}function M1($,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 D1($){let j=U1($),J=`${E.green}✓${$.success}${E.reset} ${E.red}✗${$.failed}${E.reset}`,Y=d0($.label,36);return` ${j} ${E.bold}${Y}${E.reset} ${J}`}var m0=`${E.green}●${E.reset}`,r0=`${E.yellow}⚠${E.reset}`,s0=`${E.dim2}⊘${E.reset}`;function U1($){if($.disabled)return s0;if($.unavailable||$.error||$.status&&$.status!=="active")return r0;return m0}function n1($){let j=i0($.remainingFraction),J=Math.round(j*100),Y=E1(j),Z=$.resetTime?` ${E.dim}reset ${G1($.resetTime)}${E.reset}`:"",X=d0($.label,28).padEnd(28," ");return` ${Y} ${R1(J,j)} ${X}${Z}`}function E1($){let j=i0($),J=Math.round(j*18),Y=o0(j),Z=E.dim2,X="█".repeat(J),z="░".repeat(18-J);return`${Z}[${Y}${X}${Z}${z}]${E.reset}`}function R1($,j){return`${o0(j)}${String($).padStart(3)}%${E.reset}`}function o0($){if($>=0.4)return E.green;if($>=0.15)return E.yellow;return E.red}function G1($){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,V=!1,q=!1,D=(U)=>{Z="loading",j.requestRender();let W=g(Y.proxy.usageKey);O0(Y,W,{force:U}).then((A)=>{X=A,Z="ready",Q=0,j.requestRender()}).catch((A)=>{z=A.message,Z="error",j.requestRender()})},n=()=>{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:V,verbose:q})};return{id:"usage",label:"Usage",render:(U,W)=>{let A=n();return Q=K$(Q,W,A.length),i(A,Q,W).map((H)=>K(` ${H}`,U))},handleInput:(U)=>{if(b(U,"d"))return V=!V,Q=0,!0;if(b(U,"v"))return q=!q,Q=0,!0;let W=n().length;if(b(U,"up")||b(U,"k"))return Q=Math.max(0,Q-1),!0;if(b(U,"down")||b(U,"j"))return Q=Math.min(Math.max(0,W-1),Q+1),!0;if(b(U,"pageUp")||b(U,"b"))return Q=Math.max(0,Q-10),!0;if(b(U,"pageDown")||b(U,"f"))return Q=Math.min(Math.max(0,W-1),Q+10),!0;if(b(U,"home")||b(U,"g"))return Q=0,!0;if(b(U,"end")||b(U,"shift+g"))return Q=Math.max(0,W-1),!0;return!1},footerHint:()=>{let U=V?J.fg("success","[d disabled]"):"d disabled",W=q?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${U} · ${W} `},onActivate:()=>{if(Z==="idle")D(!1)},reload:()=>{if(k$(),Z!=="idle")D(!0)}}}function a0($){let{dm:j,ctx:J,tui:Y,theme:Z,cfg:X,done:z}=$,Q=$.discovery,V=!1,q="",D=c0({tui:Y,theme:Z,ctx:J,cfg:X,getDiscovery:()=>Q,onChange:()=>{V=!0,q=""}}),n=t0({tui:Y,theme:Z,cfg:X}),F=P0({theme:Z,cfg:X,getDiscovery:()=>Q}),_=[D,n,F],G=0,U=()=>_[G],W=(R)=>{if(R<0||R>=_.length||R===G)return;G=R,U().onActivate?.(),Y.requestRender()},A=()=>{q=Z.fg("dim","saving…"),H$(X),Y.requestRender(),h$(j,X,Q).then((R)=>{V=!1,q=Z.fg("success",`✓ settings saved · ${R.registered.length} registered, ${R.skipped.length} skipped`),Y.requestRender()}).catch((R)=>{q=Z.fg("error",`save failed: ${R.message}`),Y.requestRender()})},H=async()=>{q=Z.fg("dim","refreshing…"),Y.requestRender();try{let R=g(X.proxy.apiKey);Q=await G0(X,R),k$(),D.rebuild(),n.reload();let I=await h$(j,X,Q);q=Z.fg("success",`✓ refreshed · ${I.registered.length} providers (${Q.source})`)}catch(R){q=Z.fg("error",`refresh failed: ${R.message}`)}Y.requestRender()},P=async()=>{if(!await k0(J,!0)){Y.requestRender();return}let I=W$();X.proxy={...X.proxy,...I.proxy},await H()},p=()=>{let R=X.proxy.endpoint||"(unset)",I=R.length>40?`…${R.slice(-39)}`:R,l=Boolean(g(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 $$=q?q:V?Z.fg("warning","● unsaved — press s to save"):Z.fg("dim","✓ saved");return[`${Z.fg("dim","endpoint")} ${I}`,`${Z.fg("dim","key")} ${l?Z.fg("success","✓"):Z.fg("error","✗")}`,`${Z.fg("dim","providers")} ${u}`,`${Z.fg("dim","models")} ${h}`,$$]},S$=(R)=>{let I=Y.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(T0(Z,p(),h)),x.push(N0(Z,_.map((U$)=>({id:U$.id,label:U$.label})),G,h)),x.push(B0(Z,h)),x.push(...U().render(h,$$)),o(Z,{width:R,title:" /cliproxy ",lines:x,footer:{hint:U().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},D$=(R)=>{if(_1().matches(R,"tui.select.cancel")||C(R,"q")||C(R,"escape"))return z(),!0;if(C(R,"]")||C(R,"tab"))return W((G+1)%_.length),!0;if(C(R,"[")||C(R,"shift+tab"))return W((G-1+_.length)%_.length),!0;if(C(R,"1"))return W(0),!0;if(C(R,"2"))return W(1),!0;if(C(R,"3"))return W(2),!0;if(C(R,"r"))return H().then(()=>!0);if(C(R,"e"))return P().then(()=>!0);if(C(R,"s"))return A(),!0;return!1};return{render:S$,invalidate(){},handleInput(R){let I=U().handleInput(R);if(I instanceof Promise){q="",I.then((u)=>{if(u)Y.requestRender()});return}if(I){q="",Y.requestRender();return}let l=D$(R);if(l instanceof Promise)l.then((u)=>{if(u)Y.requestRender()});else if(l)Y.requestRender()}}}async function DJ($,j,J,Y){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Z=structuredClone(J);b$(!0);try{await j.ui.custom((X,z,Q,V)=>a0({dm:$,ctx:j,tui:X,theme:z,cfg:Z,discovery:Y,done:V}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{b$(!1)}}export{DJ as runHub};
1
+ var M$=!1;function w$($){M$=$}var K={info(...$){if(!M$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!M$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!M$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!M$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};import{getKeybindings as n1,matchesKey as u}from"@duckmind/dm-tui";import{getModels as mj}from"@duckmind/dm-ai/compat";var u$=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 U0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Dj=128000,Rj=16000,_j={input:0,output:0,cacheRead:0,cacheWrite:0},Aj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function G$($){return Aj.some((j)=>j.test($))}var Oj=[[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 E0($,j){let J=(j??"").trim(),Y=$.match(/^([a-z0-9]+-)(.*)$/);if(Y)return J?`${J}-${Y[1]}`:Y[1];return $}function D0($,j){for(let[J,Y,Z]of Oj)if(J.has($))return{slug:H$(j,Y),api:Z};return{slug:H$(j,"misc"),api:"openai-completions"}}function Hj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function Z$($){return{id:$,name:Hj($),contextWindow:Dj,maxTokens:Rj,reasoning:G$($),cost:{..._j}}}import{execSync as Gj}from"node:child_process";import{randomUUID as _0}from"node:crypto";import{chmodSync as f$,closeSync as R0,constants as Nj,copyFileSync as Wj,existsSync as V$,fsyncSync as kj,linkSync as Tj,mkdirSync as Bj,openSync as Lj,readFileSync as A0,renameSync as Kj,rmSync as g$,writeFileSync as Fj}from"node:fs";import{homedir as N$}from"node:os";import{dirname as k$,join as U$}from"node:path";import{fileURLToPath as Sj}from"node:url";var h$=U$(N$(),".dm","agent","dm-cliproxy"),l=U$(h$,"config.json"),Ij=[U$(N$(),".pi","agent","pi-cliproxyapi","config.json"),U$(N$(),".config","pi-cliproxyapi","config.json")];function E$($){Bj($,{recursive:!0,mode:448}),f$($,448)}function X$($){if(V$($))f$($,384)}function bj($){let j;try{j=JSON.parse(A0($,"utf8"))}catch{return}let J=j&&typeof j==="object"?j.proxy:void 0;for(let Y of[J?.apiKey,J?.usageKey]){if(typeof Y!=="string")continue;let Z=/^!cat\s+((?:~\/|\/)[^\s;&|`]+)$/.exec(Y.trim());if(!Z)continue;let X=Z[1].replace(/^~/,N$());X$(X)}}function xj(){return V$(U$(k$(Sj(import.meta.url)),"..",".git"))}function nj($=Ij,j=l,J=xj()){if(V$(j))return;let Z=(typeof $==="string"?[$]:[...$]).find((z)=>V$(z));if(!Z)return;let X;try{X$(Z),bj(Z),E$(k$(j)),X=`${j}.${process.pid}.${_0()}.tmp`,Wj(Z,X,Nj.COPYFILE_EXCL),f$(X,384),Tj(X,j),g$(X),X=void 0,K.info("legacy config copied to",j)}catch(z){if(X)try{g$(X,{force:!0})}catch(Q){K.warn("failed to clean temporary config:",Q)}K.warn("failed to migrate legacy config:",z)}}var W$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function T$(){if(nj(),!V$(l))return K.debug("config not found, using defaults at",l),structuredClone(W$);try{E$(k$(l)),X$(l);let $=JSON.parse(A0(l,"utf8"));return yj($)}catch($){return K.error("failed to read config:",$,"— using defaults"),structuredClone(W$)}}function Pj($,j=l){E$(k$(j));let J=`${j}.${process.pid}.${_0()}.tmp`,Y;try{Y=Lj(J,"wx",384),Fj(Y,JSON.stringify($,null,2)+`
2
+ `,{encoding:"utf8"}),kj(Y),R0(Y),Y=void 0,Kj(J,j),X$(j)}finally{if(Y!==void 0)R0(Y);g$(J,{force:!0})}}function B$($){Pj($),K.info("config saved to",l)}function yj($){if(!$||typeof $!=="object")return structuredClone(W$);let j=$,J=structuredClone(W$),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 h($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Gj(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Y=J?.status,Z=typeof Y==="number"?` (exit ${Y})`:"";return K.warn(`failed to resolve "!" config value${Z}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{createHash as Cj}from"node:crypto";import{existsSync as m1,readFileSync as s1,writeFileSync as wj}from"node:fs";import{dirname as uj,join as vj}from"node:path";var gj=vj(h$,"discovery-cache.json");function O0($,j){return Cj("sha256").update($.trim().replace(/\/+$/,"")).update("\x00").update(j).digest("hex")}function p$($,j,J=gj){try{E$(uj(J));let Y={savedAt:Date.now(),scope:j,discovery:$};wj(J,JSON.stringify(Y),{encoding:"utf8",mode:384}),X$(J)}catch(Y){K.warn("failed to write discovery cache:",Y.message)}}var Q$="dm-cliproxy/0.3.5",fj=5000;async function N0($,j){let J=new AbortController,Y=setTimeout(()=>J.abort(Error("timeout")),fj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Y)}}function hj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function pj($){let j=hj($.proxy.endpoint),J;try{J=await N0(j,{headers:{"User-Agent":Q$,Accept:"application/json"}})}catch(Q){return K.warn("well-known fetch failed:",Q.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 Y;try{Y=await J.json()}catch{return K.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return K.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((M)=>({id:String(M.id),name:typeof M.name==="string"?M.name:String(M.id),reasoning:Boolean(M.reasoning??G$(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}}));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??G$(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:E0(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 cj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Y=await N0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":Q$}});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 lj($,j){let J=j.discoveryExcludes,Y=new Map,Z=[],X=0;for(let z of $){if(X++,U0(z.id,J))continue;if(z.owned_by==="openai"){let M=Z$(z.id);H0(Y,"openai","openai-responses",G0(M));continue}if(z.owned_by==="anthropic"){let M=Z$(z.id);H0(Y,"anthropic","anthropic-messages",G0(M));continue}let{slug:Q,api:q}=D0(z.owned_by,j.proxy.providerPrefix),V=Z$(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 H0($,j,J,Y){let Z=$.get(j);if(!Z)Z={name:j,api:J,models:[]},$.set(j,Z);Z.models.push(Y)}function G0($){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 W0($,j){let J=O0($.proxy.endpoint,j),Y=await pj($);if(Y)return K.info(`discovery via /.well-known/pi: ${Y.builtinProviders.length} builtin, ${Y.customPool.length} custom`),p$(Y,J),Y;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Z=await cj($,j),X=lj(Z,$);return K.info(`discovery via /v1/models: ${X.builtinProviders.length} builtin, ${X.customPool.length} custom`),p$(X,J),X}function k0($){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}var T0=new WeakMap,c$=new WeakMap;function l$($){let j=(c$.get($)??0)+1;return c$.set($,j),j}function L$($,j){return j===void 0||j===(c$.get($)??0)}function B0($,j,J){let Y=T0.get($)??new Set;for(let Z of Y){if(j.has(Z))continue;$.unregisterProvider(Z),J.unregistered.push(Z)}T0.set($,new Set(j))}async function m$($,j,J,Y){let Z={registered:[],skipped:[],unregistered:[]};if(!L$($,Y))return Z.skipped.push({provider:"*",reason:"stale refresh generation"}),Z;let X=new Set,z=k0(J),Q=h(j.proxy.apiKey);if(!Q)return K.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),B0($,X,Z),Z;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$($,Y))return Z;if(!U?.enabled){Z.skipped.push({provider:M,reason:"disabled"});continue}if(!Array.isArray(U.models)||U.models.length===0){Z.skipped.push({provider:M,reason:"empty whitelist"});continue}let F=[];try{F=mj(M)}catch{}let T=new Map(F.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=T.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){Z.skipped.push({provider:M,reason:"no whitelisted models present on proxy"});continue}let A=U.apiOverride??D[0].api;if(!u$.has(A)){Z.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:v$(A,j.proxy.endpoint),apiKey:Q,authHeader:!0,api:A,models:B};$.registerProvider(M,C),X.add(M),Z.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$($,Y))return Z;if(!u$.has(U.api)){Z.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){Z.skipped.push({provider:M,reason:"no configured models present on proxy"});continue}let T=F.map((D)=>{let A=V.get(D.id),B=Z$(D.id),C=j.overrides[D.id]??{};return{id:D.id,name:D.name??A?.name??B.name??D.id,api:U.api,reasoning:sj(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:L0(D.contextWindow,A?.contextWindow,B.contextWindow,C.contextWindow)??128000,maxTokens:L0(D.maxTokens,A?.maxTokens,B.maxTokens,C.maxTokens)??16000}}),O={name:M,baseUrl:v$(U.api,j.proxy.endpoint),apiKey:Q,authHeader:!0,api:U.api,models:T};$.registerProvider(M,O),X.add(M),Z.registered.push({provider:M,modelCount:T.length,api:U.api})}if(L$($,Y))B0($,X,Z);return K.info(`applyAll: registered ${Z.registered.length} providers, skipped ${Z.skipped.length}, unregistered ${Z.unregistered.length}`),Z}function L0(...$){for(let j of $)if(typeof j==="number")return j;return}function sj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var oj=15000,D$=null;function K$(){D$=null}async function K0($,j,J={}){if(!J.force&&D$&&Date.now()-D$.fetchedAt<$.usageCacheTtlMs)return D$.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")),oj),z;try{z=await fetch(Y,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":Q$},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 D$={fetchedAt:Date.now(),doc:Q},K.debug("usage fetched, accounts:",Q.accounts.length),Q}import{visibleWidth as o$}from"@duckmind/dm-tui";import{visibleWidth as F0}from"@duckmind/dm-tui";function S($,j){let J=F0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return s$($,j)}function s$($,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=F0(X);if(Y+z>j)break;J+=X,Y+=z,Z++}return`${J}\x1B[0m`}var ij="│",rj="╭",dj="╮",tj="╰",aj="╯",R$="─";function r($,j){let J=Math.max(4,j.width);return[ej($,j.title,j.titleColor??"accent",J),...j.lines.map((Y)=>$1($,Y,J)),j1($,j.footer,J)]}function ej($,j,J,Y){let Z=j??"",X=o$(Z),z=Math.max(0,Y-3-X),Q=Z?$.bold($.fg(J,Z)):"",q=`${rj}${R$}${Q}${R$.repeat(z)}${dj}`;return $.fg("borderAccent",q)}function $1($,j,J){let Y=Math.max(0,J-2),Z=$.fg("borderAccent",ij);return`${Z}${S(j,Y)}${Z}`}function j1($,j,J){let Y=`${tj}${R$}`,Z=`${aj}`,X=3;if(!j||!j.hint&&!j.badge){let O=Math.max(0,J-3);return $.fg("borderAccent",`${Y}${R$.repeat(O)}${Z}`)}let z=j.hint??"",Q=j.badge??"",q=o$(z),V=o$(Q),M=Math.max(0,J-3-q-V),U=$.fg("dim",z),F=Q?$.fg("muted",Q):"",T=R$.repeat(M);return`${$.fg("borderAccent",Y)}${U}${$.fg("borderAccent",T)}${F}${$.fg("borderAccent",Z)}`}function F$($){return Math.max(0,$-2)}import{existsSync as S0}from"node:fs";import{homedir as J1}from"node:os";import{getKeybindings as Y1,Input as i$,matchesKey as Z1}from"@duckmind/dm-tui";var X1=[{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 I0($,j=!1){let J=T$(),Y={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Z=!1;for(let z of X1){let Q=Y[z.label]??"",q=z.secret?"":j?Y[z.label]??z.initialValue??"":Y[z.label]??"";if(!j&&q)continue;let V=z.secret&&Q?{...z,required:!1}:z,M=await q1($,V,q||z.initialValue||"");if(M===void 0){Z=!0;break}let U=z1(z,Q,M);if(U===null){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Z=!0;break}}Y[z.label]=U??""}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 ${l}`,"info"),!0}function Q1($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,J1());return S0(j)?`!cat ${$}`:$}if($.startsWith("/"))return S0($)?`!cat ${$}`:$;return $}function z1($,j,J){let Y=J.trim();if(!Y){if($.secret&&j)return j;return $.required?null:""}if($.secret&&!$.required&&Y==="-")return"";return $.label==="providerPrefix"||$.label==="endpoint"?Y:Q1(Y)}async function q1($,j,J){return $.ui.custom((Y,Z,X,z)=>M1(Y,Z,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}class b0{rawInput=new i$;displayInput=new i$;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 Y=$.codePointAt(J),Z=String.fromCodePoint(Y);j+=Y<32||Y===127?Z:"•",J+=Z.length}return j}}function M1($,j,J,Y,Z){let X=J.secret?new b0:new i$;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 M=J.validate(V);if(M){z=M,$.requestRender();return}}}Z(q)};return X.onSubmit=Q,X.onEscape=()=>Z(void 0),{render(q){let V=F$(q),M=X.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(){X.invalidate()},handleInput(q){if(Y1().matches(q,"tui.select.cancel")||Z1(q,"escape")){Z(void 0);return}z=null,X.handleInput(q),$.requestRender()}}}import{visibleWidth as S$}from"@duckmind/dm-tui";function x0($,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 S(` ${X.join(Z)}`,Y)}function n0($,j,J){let Y=j.join($.fg("dim"," "));return S(` ${Y}`,J)}function P0($,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 I$($,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 b$($,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 V1,readFileSync as U1}from"node:fs";import{homedir as C0}from"node:os";import{join as w0}from"node:path";var E1=w0(C0(),".dm","models.json"),D1=w0(C0(),".dm","auth.json");function y0($){if(!V1($))return null;try{return JSON.parse(U1($,"utf8"))}catch{return null}}function u0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Y=y0(E1);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=y0(D1);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 v0($){let{theme:j,cfg:J}=$,Y=0,Z=()=>{let Q=$.getDiscovery(),q=(O)=>j.fg("success",O),V=(O)=>j.fg("error",O),M=(O)=>j.fg("dim",O),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")} ${Q$}`),U.push(""),U.push(`${M("discovery")} source=${Q.source}`),U.push(`${M("upstream")} v=${Q.upstreamVersion??"(unknown)"} · ${Q.upstreamTotal} ids`);let F=Q.builtinProviders.map((O)=>`${O.name}=${O.models.length}`).join(", ")||M("(none)");U.push(`${M("built-in")} ${F}`),U.push(`${M("custom pool")} ${Q.customPool.length} models`);let T=u0(J);if(U.push(""),T.length===0)U.push(`${M("conflicts")} ${q("none")}`);else{U.push(`${M("conflicts")}`);for(let O of T)U.push(` ${j.fg("warning",`[${O.kind}]`)} ${O.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(Q,q)=>{let V=Z();return Y=b$(Y,q,V.length),d(V,Y,q).map((M)=>S(` ${M}`,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 R1($){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 g0($,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=R1($),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 _1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function f0($,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(_1(J));$.customProviders[j.name]=Y}function h0($,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 d$($,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 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 c0($,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 A1,getProviders as O1}from"@duckmind/dm-ai/compat";function t$($,j){let J=[],Y=new Set(j.builtinModelIds.keys()),Z=new Set(O1()),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 M=A1(z).find((U)=>Q.includes(U.id));if(M)q=M.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 H1,matchesKey as z$}from"@duckmind/dm-tui";async function l0($,j){return $.ui.custom((J,Y,Z,X)=>G1(Y,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",X),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function G1($,j,J,Y){return{render(Z){return r($,{width:Z,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Z){if(H1().matches(Z,"tui.select.cancel")||z$(Z,"escape")||z$(Z,"n")||z$(Z,"q")){Y(!1);return}if(z$(Z,"y")||z$(Z,"enter")||z$(Z,"return")){Y(!0);return}}}}import{getKeybindings as N1,Input as W1,matchesKey as k1}from"@duckmind/dm-tui";async function m0($,j){let J=H$(j,"group");return $.ui.custom((Y,Z,X,z)=>T1(Y,Z,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function T1($,j,J,Y){let Z=new W1;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),M=["",` ${j.fg("dim",q)}`,"",...V.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",X?` ${j.fg("error",`! ${X}`)}`:""];return r(j,{width:z,title:" new custom group ",lines:M,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(z){if(N1().matches(z,"tui.select.cancel")||k1(z,"escape")){Y(null);return}X=null,Z.handleInput(z),$.requestRender()}}}import{visibleWidth as B1}from"@duckmind/dm-tui";function a$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function s0($,j){let J=B1($);if(J===j)return $;if(J>j)return s$($,j);return S($,j)}function o0($,j,J){let{theme:Y,width:Z,isCursor:X,isFocused:z}=J,Q=a$(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"),M=`${Y.fg("dim","[")}${V}${Y.fg("dim","]")}`,U=q>0?Y.fg("success","●"):Y.fg("dim","○"),F=q>0?Y.fg("success",String(q).padStart(2)):Y.fg("dim"," 0"),T=X&&z?Y.bold(Y.fg("accent",$.name)):X?Y.bold($.name):$.name,O=Y.fg("dim",$.api),D=`${Q}${M} ${T} ${U}${F} ${O}`;return s0(D,Z)}function i0($,j,J,Y){let Z=a$($,j,J),X=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return S(`${Z}${X}`,Y)}function e$($,j,J,Y,Z){let{theme:X,width:z,isCursor:Q,isFocused:q}=Z,V=a$(X,Q,q),M=J==="assigned"?X.fg("success","☑"):X.fg("dim","☐"),U=Y?` ${X.fg("warning","⚠")}`:"",F=Q&&q?X.fg("accent",$):$,T=j?.reasoning?` ${X.fg("accent","✨")}`:"",O=j?X.fg("muted",` · ${j.suggestedApi}`):X.fg("error"," · not on proxy"),D=`${V}${M} ${F}${U}${T}${O}`;return s0(D,z)}function r0($,j,J){let Y=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return S(` ${Y}`,J)}function $0($,j,J){return S(` ${$.fg("dim",j)}`,J)}function d0($,j,J,Y){let Z=Y?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return S(`${Z}${j}`,J)}function t0($){let{tui:j,theme:J,ctx:Y,cfg:Z}=$,X=$.onChange??(()=>{}),z=r$($.getDiscovery()),Q=t$(Z,z),q="providers",V=0,M=0,U=0,F=0,T=0,O=0,D="",A=!1,B=()=>{if(Q.length===0)return null;let E=Math.max(0,Math.min(V,Q.length-1));return Q[E]??null},C=(E)=>{let H=c0(g0(Z,E,z),z,D);return p0(H,z)},N=(E)=>C(E).flatMap((H)=>H.ids),G=()=>{Q=t$(Z,z);let E=Math.max(0,Q.length);if(V>E)V=E;let H=B();if(H){let x=$$(Z,H).length,W=N(H).length;if(M>=x)M=Math.max(0,x-1);if(U>=W)U=Math.max(0,W-1)}},n=()=>{z=r$($.getDiscovery()),G()},j$=(E)=>{let H=["providers","assigned","pool"],x=H.indexOf(q);q=E?H[(x-1+H.length)%H.length]:H[(x+1)%H.length]},_=(E)=>{if(q==="providers"){let W=Q.length+1;V=Math.max(0,Math.min(V+E,W-1));return}let H=B();if(!H)return;if(q==="assigned"){let W=$$(Z,H).length;if(W===0)return;M=Math.max(0,Math.min(M+E,W-1));return}let x=N(H).length;if(x===0)return;U=Math.max(0,Math.min(U+E,x-1))},b=async()=>{if(q==="providers"){if(V===Q.length){let W=await m0(Y,Z.proxy.providerPrefix);if(W&&!Z.customProviders[W]){if(Z.customProviders[W]={api:"openai-completions",models:[]},X(),G(),V=Q.findIndex((I)=>I.kind==="custom"&&I.name===W),V<0)V=Q.length-1;q="pool"}j.requestRender();return}q="pool";return}let E=B();if(!E)return;if(q==="assigned"){let W=$$(Z,E)[M];if(!W)return;h0(Z,E,W),X(),G();return}let H=N(E)[U];if(!H)return;let x=z.byId.get(H);if(!x)return;f0(Z,E,x),X(),G()},p=async()=>{if(q!=="providers")return;let E=B();if(!E||E.kind!=="custom")return;if(!await l0(Y,E.name)){j.requestRender();return}if(delete Z.customProviders[E.name],X(),G(),V>=Q.length)V=Math.max(0,Q.length-1);j.requestRender()},v=(E,H)=>c(E,H);function c(E,H){let x=Math.max(70,E),W=Math.min(56,Math.max(34,Math.floor(x*0.4))),I=x-W-1,s=Math.max(8,H),o=Math.max(5,Math.floor((s-1)/2)),j0=s-o,m=B(),q$=0,x$=0,n$=0,J0=0,P$=0,Y0=0,a=[];a.push(J$(" providers ",W,q==="providers"));for(let L=0;L<Q.length;L++){let g=Q[L],w=q==="providers"&&L===V;if(w)q$=a.length,x$=q$;a.push(o0(g,Z,{theme:J,width:W,isCursor:w,isFocused:q==="providers"}))}{let L=q==="providers"&&V===Q.length;if(L)q$=a.length,x$=q$;a.push(i0(J,L,q==="providers",W))}let e=[],qj=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(d0(J,qj,I,q==="assigned")),m){let L=$$(Z,m);if(L.length===0)e.push($0(J,"(nothing assigned yet)",I));for(let g=0;g<L.length;g++){let w=L[g],f=z.byId.get(w),O$=q==="assigned"&&g===M;if(O$)n$=e.length,J0=n$;let Y$=f?!d$(m.api,f.suggestedApi):!1;e.push(e$(w,f,"assigned",Y$,{theme:J,width:I,isCursor:O$,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($0(J,D?`(no matches for "${D}")`:"(no models available)",I));else{let w=0;for(let f of L){let O$=i.length;i.push(r0(J,f.label,I));for(let Y$=0;Y$<f.ids.length;Y$++){let M0=f.ids[Y$],C$=z.byId.get(M0),V0=q==="pool"&&w===U;if(V0)P$=i.length,Y0=Y$===0?O$:P$;let Ej=C$?!d$(m.api,C$.suggestedApi):!1;i.push(e$(M0,C$,"pool",Ej,{theme:J,width:I,isCursor:V0,isFocused:q==="pool"})),w++}}}}let Mj=Math.max(1,j0-1),Z0=I$(x$,q$,F,s,a.length,1),X0=I$(q==="assigned"?J0:0,q==="assigned"?n$:0,T,o,e.length,2),Q0=I$(q==="pool"?Y0:0,q==="pool"?P$:0,O,Mj,i.length,1);F=Z0,T=X0,O=Q0;let z0=d(a,Z0,s),Vj=d(e,X0,o),Uj=d(i,Q0,j0),q0=J.fg("borderAccent","│"),y$=[];for(let L=0;L<s;L++){let g=S(z0[L]??"",W),w=L<o?Vj[L]:Uj[L-o],f=S(w,I);y$.push(`${g}${q0}${f}`)}let A$=o;if(A$>0&&A$<s){let L=S(z0[A$]??"",W),g=J.fg("borderAccent","─".repeat(I));y$[A$]=`${L}${q0}${g}`}return y$}function J$(E,H,x){let W=x?J.bold(J.fg("accent",E)):J.fg("muted",E),I=J.fg("borderAccent","─".repeat(Math.max(0,H-S$(E)-1)));return S(`${W}${I}`,H)}function P(E,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=S$(" available pool ")+S$(I),o=J.fg("borderAccent","─".repeat(Math.max(0,E-s-1)));return S(`${W}${I}${o}`,E)}function _$(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 b().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:_$,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 a0($,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(K1(Q)),!Q.supported){J.push(` ${R.dim2}(provider not quota-aware)${R.reset}`);continue}if(Q.error){if(j.verbose)for(let V of L1(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(S1(V))}}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 L1($,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 K1($){let j=F1($),J=`${R.green}✓${$.success}${R.reset} ${R.red}✗${$.failed}${R.reset}`,Y=Zj($.label,36);return` ${j} ${R.bold}${Y}${R.reset} ${J}`}var e0=`${R.green}●${R.reset}`,$j=`${R.yellow}⚠${R.reset}`,jj=`${R.dim2}⊘${R.reset}`;function F1($){if($.disabled)return jj;if($.unavailable||$.error||$.status&&$.status!=="active")return $j;return e0}function S1($){let j=Yj($.remainingFraction),J=Math.round(j*100),Y=I1(j),Z=$.resetTime?` ${R.dim}reset ${x1($.resetTime)}${R.reset}`:"",X=Zj($.label,28).padEnd(28," ");return` ${Y} ${b1(J,j)} ${X}${Z}`}function I1($){let j=Yj($),J=Math.round(j*18),Y=Jj(j),Z=R.dim2,X="█".repeat(J),z="░".repeat(18-J);return`${Z}[${Y}${X}${Z}${z}]${R.reset}`}function b1($,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 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 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:Y}=$,Z="idle",X=null,z="",Q=0,q=!1,V=!1,M=(D)=>{Z="loading",j.requestRender();let A=h(Y.proxy.usageKey);K0(Y,A,{force:D}).then((B)=>{X=B,Z="ready",Q=0,j.requestRender()}).catch((B)=>{z=B.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 a0(X,{showDisabled:q,verbose:V})};return{id:"usage",label:"Usage",render:(D,A)=>{let B=U();return Q=b$(Q,A,B.length),d(B,Q,A).map((C)=>S(` ${C}`,D))},handleInput:(D)=>{if(y(D,"d"))return q=!q,Q=0,!0;if(y(D,"v"))return V=!V,Q=0,!0;let A=U().length;if(y(D,"up")||y(D,"k"))return Q=Math.max(0,Q-1),!0;if(y(D,"down")||y(D,"j"))return Q=Math.min(Math.max(0,A-1),Q+1),!0;if(y(D,"pageUp")||y(D,"b"))return Q=Math.max(0,Q-10),!0;if(y(D,"pageDown")||y(D,"f"))return Q=Math.min(Math.max(0,A-1),Q+10),!0;if(y(D,"home")||y(D,"g"))return Q=0,!0;if(y(D,"end")||y(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=V?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${D} · ${A} `},onActivate:()=>{if(Z==="idle")M(!1)},reload:()=>{if(K$(),Z!=="idle")M(!0)}}}function Qj($){let{dm:j,ctx:J,tui:Y,theme:Z,cfg:X,done:z}=$,Q=$.discovery,q=!1,V="",M=t0({tui:Y,theme:Z,ctx:J,cfg:X,getDiscovery:()=>Q,onChange:()=>{q=!0,V=""}}),U=Xj({tui:Y,theme:Z,cfg:X}),F=v0({theme:Z,cfg:X,getDiscovery:()=>Q}),T=[M,U,F],O=0,D=()=>T[O],A=(_)=>{if(_<0||_>=T.length||_===O)return;O=_,D().onActivate?.(),Y.requestRender()},B=()=>{V=Z.fg("dim","saving…"),B$(X),Y.requestRender();let _=l$(j);m$(j,X,Q,_).then((b)=>{q=!1,V=Z.fg("success",`✓ settings saved · ${b.registered.length} registered, ${b.skipped.length} skipped`),Y.requestRender()}).catch((b)=>{V=Z.fg("error",`save failed: ${b.message}`),Y.requestRender()})},C=async()=>{V=Z.fg("dim","refreshing…"),Y.requestRender();try{let _=l$(j),b=h(X.proxy.apiKey);Q=await W0(X,b),K$(),M.rebuild(),U.reload();let p=await m$(j,X,Q,_);V=Z.fg("success",`✓ refreshed · ${p.registered.length} providers (${Q.source})`)}catch(_){V=Z.fg("error",`refresh failed: ${_.message}`)}Y.requestRender()},N=async()=>{if(!await I0(J,!0)){Y.requestRender();return}let b=T$();X.proxy={...X.proxy,...b.proxy},await C()},G=()=>{let _=X.proxy.endpoint||"(unset)",b=_.length>40?`…${_.slice(-39)}`:_,p=Boolean(h(X.proxy.apiKey)),v=0,c=0;for(let P of Object.values(X.builtinProviders)){if(P.enabled&&P.models.length>0)v++;c+=P.models.length}for(let P of Object.values(X.customProviders)){if(P.models.length>0)v++;c+=P.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")} ${p?Z.fg("success","✓"):Z.fg("error","✗")}`,`${Z.fg("dim","providers")} ${v}`,`${Z.fg("dim","models")} ${c}`,J$]},n=(_)=>{let b=Y.rows??40,v=Math.max(16,Math.min(b-6,38))-2,c=Math.max(72,_-2),J$=Math.max(6,v-3),P=[];return P.push(n0(Z,G(),c)),P.push(x0(Z,T.map((_$)=>({id:_$.id,label:_$.label})),O,c)),P.push(P0(Z,c)),P.push(...D().render(c,J$)),r(Z,{width:_,title:" /cliproxy ",lines:P,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)%T.length),!0;if(u(_,"[")||u(_,"shift+tab"))return A((O-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 b=D().handleInput(_);if(b instanceof Promise){V="",b.then((v)=>{if(v)Y.requestRender()});return}if(b){V="",Y.requestRender();return}let p=j$(_);if(p instanceof Promise)p.then((v)=>{if(v)Y.requestRender()});else if(p)Y.requestRender()}}}async function FJ($,j,J,Y){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Z=structuredClone(J);w$(!0);try{await j.ui.custom((X,z,Q,q)=>Qj({dm:$,ctx:j,tui:X,theme:z,cfg:Z,discovery:Y,done:q}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{w$(!1)}}export{FJ as runHub};
@@ -1 +1 @@
1
- import{matchesKey as v}from"@duckmind/dm-tui";import{execSync as L}from"node:child_process";import{homedir as c}from"node:os";import{dirname as I,join as Y}from"node:path";var V=!1;var J={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 K=Y(c(),".dm","agent","dm-cliproxy"),_=Y(K,"config.json"),F=[Y(c(),".pi","agent","pi-cliproxyapi","config.json"),Y(c(),".config","pi-cliproxyapi","config.json")];function Q(n){if(!n)return"";let o=n.trim();if(o.startsWith("!"))try{return L(o.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(r){let s=r?.stderr?.toString?.()?.trim()??r.message;return J.warn(`failed to resolve "!" config value (${o}): ${s}`),""}if(o.startsWith("$"))return process.env[o.slice(1)]??"";return o}import{existsSync as C,readFileSync as E}from"node:fs";import{homedir as X}from"node:os";import{join as k}from"node:path";var A=k(X(),".dm","models.json"),i=k(X(),".dm","auth.json");function W(n){if(!C(n))return null;try{return JSON.parse(E(n,"utf8"))}catch{return null}}function q(n){let o=[],r=new Set([...Object.keys(n.builtinProviders),...Object.keys(n.customProviders)]),s=W(A);if(s&&typeof s==="object"){for(let u of Object.keys(s))if(r.has(u))o.push({kind:"models.json",provider:u,detail:`provider "${u}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let f=W(i);if(f&&typeof f==="object"){for(let u of Object.keys(f))if(r.has(u))o.push({kind:"auth.json",provider:u,detail:`provider "${u}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return o}import{dirname as m,join as U}from"node:path";var sn=U(K,"discovery-cache.json");var H="dm-cliproxy/0.3.5";import{visibleWidth as h}from"@duckmind/dm-tui";function p(n,o){let r=h(n);if(r===o)return n;if(r<o)return n+" ".repeat(o-r);return S(n,o)}function S(n,o){if(o<=0)return"\x1B[0m";let r="",s=0,f=0;while(f<n.length){let u=n[f];if(u==="\x1B"&&n[f+1]==="["){let $=n.indexOf("m",f+2);if($>=0){r+=n.slice(f,$+1),f=$+1;continue}}let Z=h(u);if(s+Z>o)break;r+=u,s+=Z,f++}return`${r}\x1B[0m`}import{visibleWidth as cn}from"@duckmind/dm-tui";function R(n,o,r){let s=n.slice(o,o+r);while(s.length<r)s.push("");return s}function y(n,o,r){let s=Math.max(0,r-o);return Math.max(0,Math.min(n,s))}function Hn(n){let{theme:o,cfg:r}=n,s=0,f=()=>{let $=n.getDiscovery(),e=(D)=>o.fg("success",D),M=(D)=>o.fg("error",D),t=(D)=>o.fg("dim",D),j=[];j.push(`${t("endpoint")} ${r.proxy.endpoint||M("(unset)")}`),j.push(`${t("apiKey")} ${Q(r.proxy.apiKey)?e("resolves"):M("empty after resolution")}`),j.push(`${t("usageKey")} ${r.proxy.usageKey?Q(r.proxy.usageKey)?e("resolves"):M("set but empty"):t("not configured")}`),j.push(`${t("user-agent")} ${H}`),j.push(""),j.push(`${t("discovery")} source=${$.source}`),j.push(`${t("upstream")} v=${$.upstreamVersion??"(unknown)"} · ${$.upstreamTotal} ids`);let O=$.builtinProviders.map((D)=>`${D.name}=${D.models.length}`).join(", ")||t("(none)");j.push(`${t("built-in")} ${O}`),j.push(`${t("custom pool")} ${$.customPool.length} models`);let z=q(r);if(j.push(""),z.length===0)j.push(`${t("conflicts")} ${e("none")}`);else{j.push(`${t("conflicts")}`);for(let D of z)j.push(` ${o.fg("warning",`[${D.kind}]`)} ${D.detail}`)}return j};return{id:"diagnostics",label:"Diagnostics",render:($,e)=>{let M=f();return s=y(s,e,M.length),R(M,s,e).map((t)=>p(` ${t}`,$))},handleInput:($)=>{let e=f().length;if(v($,"up")||v($,"k"))return s=Math.max(0,s-1),!0;if(v($,"down")||v($,"j"))return s=Math.min(Math.max(0,e-1),s+1),!0;if(v($,"pageUp")||v($,"b"))return s=Math.max(0,s-10),!0;if(v($,"pageDown")||v($,"f"))return s=Math.min(Math.max(0,e-1),s+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}export{Hn as buildDiagnosticsView};
1
+ import{matchesKey as Y}from"@duckmind/dm-tui";import{execSync as U}from"node:child_process";import{homedir as H}from"node:os";import{dirname as T,join as Q}from"node:path";var r=!1;var v={info(...n){if(!r)console.log("[dm-cliproxy]",...n)},warn(...n){if(!r)console.warn("[dm-cliproxy]",...n)},error(...n){if(!r)console.error("[dm-cliproxy]",...n)},debug(...n){if(!r&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...n)}};var K=Q(H(),".dm","agent","dm-cliproxy"),g=Q(K,"config.json"),h=[Q(H(),".pi","agent","pi-cliproxyapi","config.json"),Q(H(),".config","pi-cliproxyapi","config.json")];function W(n){if(!n)return"";let $=n.trim();if($.startsWith("!"))try{return U($.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(s){let o=s?.status,M=typeof o==="number"?` (exit ${o})`:"";return v.warn(`failed to resolve "!" config value${M}`),""}if($.startsWith("$"))return process.env[$.slice(1)]??"";return $}import{existsSync as x,readFileSync as B}from"node:fs";import{homedir as O}from"node:os";import{join as R}from"node:path";var G=R(O(),".dm","models.json"),I=R(O(),".dm","auth.json");function q(n){if(!x(n))return null;try{return JSON.parse(B(n,"utf8"))}catch{return null}}function C(n){let $=[],s=new Set([...Object.keys(n.builtinProviders),...Object.keys(n.customProviders)]),o=q(G);if(o&&typeof o==="object"){for(let J of Object.keys(o))if(s.has(J))$.push({kind:"models.json",provider:J,detail:`provider "${J}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let M=q(I);if(M&&typeof M==="object"){for(let J of Object.keys(M))if(s.has(J))$.push({kind:"auth.json",provider:J,detail:`provider "${J}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return $}import{dirname as $n,join as N}from"node:path";var jn=N(K,"discovery-cache.json");var L="dm-cliproxy/0.3.5";import{visibleWidth as t}from"@duckmind/dm-tui";function X(n,$){let s=t(n);if(s===$)return n;if(s<$)return n+" ".repeat($-s);return w(n,$)}function w(n,$){if($<=0)return"\x1B[0m";let s="",o=0,M=0;while(M<n.length){let J=n[M];if(J==="\x1B"&&n[M+1]==="["){let j=n.indexOf("m",M+2);if(j>=0){s+=n.slice(M,j+1),M=j+1;continue}}let z=t(J);if(o+z>$)break;s+=J,o+=z,M++}return`${s}\x1B[0m`}import{visibleWidth as Xn}from"@duckmind/dm-tui";function p(n,$,s){let o=n.slice($,$+s);while(o.length<s)o.push("");return o}function A(n,$,s){let o=Math.max(0,s-$);return Math.max(0,Math.min(n,o))}function An(n){let{theme:$,cfg:s}=n,o=0,M=()=>{let j=n.getDiscovery(),f=(D)=>$.fg("success",D),Z=(D)=>$.fg("error",D),u=(D)=>$.fg("dim",D),V=[];V.push(`${u("endpoint")} ${s.proxy.endpoint||Z("(unset)")}`),V.push(`${u("apiKey")} ${W(s.proxy.apiKey)?f("resolves"):Z("empty after resolution")}`),V.push(`${u("usageKey")} ${s.proxy.usageKey?W(s.proxy.usageKey)?f("resolves"):Z("set but empty"):u("not configured")}`),V.push(`${u("user-agent")} ${L}`),V.push(""),V.push(`${u("discovery")} source=${j.source}`),V.push(`${u("upstream")} v=${j.upstreamVersion??"(unknown)"} · ${j.upstreamTotal} ids`);let E=j.builtinProviders.map((D)=>`${D.name}=${D.models.length}`).join(", ")||u("(none)");V.push(`${u("built-in")} ${E}`),V.push(`${u("custom pool")} ${j.customPool.length} models`);let k=C(s);if(V.push(""),k.length===0)V.push(`${u("conflicts")} ${f("none")}`);else{V.push(`${u("conflicts")}`);for(let D of k)V.push(` ${$.fg("warning",`[${D.kind}]`)} ${D.detail}`)}return V};return{id:"diagnostics",label:"Diagnostics",render:(j,f)=>{let Z=M();return o=A(o,f,Z.length),p(Z,o,f).map((u)=>X(` ${u}`,j))},handleInput:(j)=>{let f=M().length;if(Y(j,"up")||Y(j,"k"))return o=Math.max(0,o-1),!0;if(Y(j,"down")||Y(j,"j"))return o=Math.min(Math.max(0,f-1),o+1),!0;if(Y(j,"pageUp")||Y(j,"b"))return o=Math.max(0,o-10),!0;if(Y(j,"pageDown")||Y(j,"f"))return o=Math.min(Math.max(0,f-1),o+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}export{An as buildDiagnosticsView};
@@ -1 +1 @@
1
- import{matchesKey as q}from"@duckmind/dm-tui";import{execSync as p}from"node:child_process";import{homedir as G}from"node:os";import{dirname as Y0,join as L}from"node:path";var D=!1;var W={info(...J){if(!D)console.log("[dm-cliproxy]",...J)},warn(...J){if(!D)console.warn("[dm-cliproxy]",...J)},error(...J){if(!D)console.error("[dm-cliproxy]",...J)},debug(...J){if(!D&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var k=L(G(),".dm","agent","dm-cliproxy"),$0=L(k,"config.json"),X0=[L(G(),".pi","agent","pi-cliproxyapi","config.json"),L(G(),".config","pi-cliproxyapi","config.json")];function S(J){if(!J)return"";let Q=J.trim();if(Q.startsWith("!"))try{return p(Q.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(V){let Z=V?.stderr?.toString?.()?.trim()??V.message;return W.warn(`failed to resolve "!" config value (${Q}): ${Z}`),""}if(Q.startsWith("$"))return process.env[Q.slice(1)]??"";return Q}import{dirname as q0,join as C}from"node:path";var R0=C(k,"discovery-cache.json");var n="dm-cliproxy/0.3.5";var h=15000,H=null;function O(){H=null}async function T(J,Q,V={}){if(!V.force&&H&&Date.now()-H.fetchedAt<J.usageCacheTtlMs)return H.doc;if(!Q)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Z=new URL("/api/usage",new URL(J.proxy.endpoint).origin).toString(),$=new AbortController,j=setTimeout(()=>$.abort(Error("timeout")),h),z;try{z=await fetch(Z,{headers:{"X-Plugin-Key":Q,Accept:"application/json","User-Agent":n},signal:$.signal})}finally{clearTimeout(j)}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 H={fetchedAt:Date.now(),doc:X},W.debug("usage fetched, accounts:",X.accounts.length),X}import{visibleWidth as F}from"@duckmind/dm-tui";function K(J,Q){let V=F(J);if(V===Q)return J;if(V<Q)return J+" ".repeat(Q-V);return f(J,Q)}function f(J,Q){if(Q<=0)return"\x1B[0m";let V="",Z=0,$=0;while($<J.length){let j=J[$];if(j==="\x1B"&&J[$+1]==="["){let X=J.indexOf("m",$+2);if(X>=0){V+=J.slice($,X+1),$=X+1;continue}}let z=F(j);if(Z+z>Q)break;V+=j,Z+=z,$++}return`${V}\x1B[0m`}var Y={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 w(J,Q={}){let V=[],Z=new Map,$=0;for(let j of J.accounts){if(!Q.showDisabled&&j.disabled){$++;continue}let z=Z.get(j.provider)??[];z.push(j),Z.set(j.provider,z)}if(V.push(`${Y.dim}generated ${J.generatedAt}${Y.reset}`),J.unsupportedProviders.length>0)V.push(`${Y.dim}providers without quota lookup:${Y.reset} ${J.unsupportedProviders.join(", ")}`);if($>0)V.push(`${Y.dim}hidden disabled accounts:${Y.reset} ${$} ${Y.dim2}(press d to show)${Y.reset}`);for(let[j,z]of Array.from(Z.entries()).sort()){V.push(""),V.push(`${Y.bold}${Y.accent}▌ ${j}${Y.reset}`);for(let X of z){if(V.push(r(X)),!X.supported){V.push(` ${Y.dim2}(provider not quota-aware)${Y.reset}`);continue}if(X.error){if(Q.verbose)for(let A of c(X.error,88))V.push(` ${Y.red}${A}${Y.reset}`);continue}let R=X.groups??[];if(R.length===0){V.push(` ${Y.dim2}(no active quota windows)${Y.reset}`);continue}for(let A of R)V.push(o(A))}}return V.push(""),V.push(`${Y.dim}legend:${Y.reset} ${I} ok ${_} error/unavailable ${N} disabled ${Y.green}✓N${Y.reset}/${Y.red}✗N${Y.reset} request counters ${Y.dim}v = verbose, d = show disabled${Y.reset}`),V}function c(J,Q){if(J.length<=Q)return[J];let V=[],Z=J;while(Z.length>Q){let $=Z.lastIndexOf(" ",Q);if($<Q*0.6)$=Q;V.push(Z.slice(0,$)),Z=Z.slice($).replace(/^\s+/,"")}if(Z)V.push(Z);return V}function r(J){let Q=l(J),V=`${Y.green}✓${J.success}${Y.reset} ${Y.red}✗${J.failed}${Y.reset}`,Z=b(J.label,36);return` ${Q} ${Y.bold}${Z}${Y.reset} ${V}`}var I=`${Y.green}●${Y.reset}`,_=`${Y.yellow}⚠${Y.reset}`,N=`${Y.dim2}⊘${Y.reset}`;function l(J){if(J.disabled)return N;if(J.unavailable||J.error||J.status&&J.status!=="active")return _;return I}function o(J){let Q=P(J.remainingFraction),V=Math.round(Q*100),Z=i(Q),$=J.resetTime?` ${Y.dim}reset ${m(J.resetTime)}${Y.reset}`:"",j=b(J.label,28).padEnd(28," ");return` ${Z} ${d(V,Q)} ${j}${$}`}function i(J){let Q=P(J),V=Math.round(Q*18),Z=x(Q),$=Y.dim2,j="█".repeat(V),z="░".repeat(18-V);return`${$}[${Z}${j}${$}${z}]${Y.reset}`}function d(J,Q){return`${x(Q)}${String(J).padStart(3)}%${Y.reset}`}function x(J){if(J>=0.4)return Y.green;if(J>=0.15)return Y.yellow;return Y.red}function m(J){let Q=Date.parse(J);if(!Number.isFinite(Q))return J;let V=Q-Date.now();if(V<=0)return"now";let Z=Math.round(V/60000);if(Z<60)return`${Z}m`;let $=Math.round(Z/60);if($<48)return`${$}h`;return`${Math.round($/24)}d`}function P(J){return Math.max(0,Math.min(1,J))}function b(J,Q){if(J.length<=Q)return J;return`${J.slice(0,Q-1)}…`}import{visibleWidth as N0}from"@duckmind/dm-tui";function u(J,Q,V){let Z=J.slice(Q,Q+V);while(Z.length<V)Z.push("");return Z}function y(J,Q,V){let Z=Math.max(0,V-Q);return Math.max(0,Math.min(J,Z))}function h0(J){let{tui:Q,theme:V,cfg:Z}=J,$="idle",j=null,z="",X=0,R=!1,A=!1,B=(M)=>{$="loading",Q.requestRender();let E=S(Z.proxy.usageKey);T(Z,E,{force:M}).then((U)=>{j=U,$="ready",X=0,Q.requestRender()}).catch((U)=>{z=U.message,$="error",Q.requestRender()})},v=()=>{if($==="idle"||$==="loading")return[V.fg("dim"," loading usage…")];if($==="error")return[V.fg("error",` usage failed: ${z}`)];if(!j)return[V.fg("dim"," (no data)")];return w(j,{showDisabled:R,verbose:A})};return{id:"usage",label:"Usage",render:(M,E)=>{let U=v();return X=y(X,E,U.length),u(U,X,E).map((g)=>K(` ${g}`,M))},handleInput:(M)=>{if(q(M,"d"))return R=!R,X=0,!0;if(q(M,"v"))return A=!A,X=0,!0;let E=v().length;if(q(M,"up")||q(M,"k"))return X=Math.max(0,X-1),!0;if(q(M,"down")||q(M,"j"))return X=Math.min(Math.max(0,E-1),X+1),!0;if(q(M,"pageUp")||q(M,"b"))return X=Math.max(0,X-10),!0;if(q(M,"pageDown")||q(M,"f"))return X=Math.min(Math.max(0,E-1),X+10),!0;if(q(M,"home")||q(M,"g"))return X=0,!0;if(q(M,"end")||q(M,"shift+g"))return X=Math.max(0,E-1),!0;return!1},footerHint:()=>{let M=R?V.fg("success","[d disabled]"):"d disabled",E=A?V.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${M} · ${E} `},onActivate:()=>{if($==="idle")B(!1)},reload:()=>{if(O(),$!=="idle")B(!0)}}}export{h0 as buildUsageView};
1
+ import{matchesKey as q}from"@duckmind/dm-tui";import{execSync as p}from"node:child_process";import{homedir as D}from"node:os";import{dirname as V0,join as G}from"node:path";var L=!1;var R={info(...J){if(!L)console.log("[dm-cliproxy]",...J)},warn(...J){if(!L)console.warn("[dm-cliproxy]",...J)},error(...J){if(!L)console.error("[dm-cliproxy]",...J)},debug(...J){if(!L&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var k=G(D(),".dm","agent","dm-cliproxy"),Z0=G(k,"config.json"),X0=[G(D(),".pi","agent","pi-cliproxyapi","config.json"),G(D(),".config","pi-cliproxyapi","config.json")];function T(J){if(!J)return"";let $=J.trim();if($.startsWith("!"))try{return p($.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(Q){let Z=Q?.status,Y=typeof Z==="number"?` (exit ${Z})`:"";return R.warn(`failed to resolve "!" config value${Y}`),""}if($.startsWith("$"))return process.env[$.slice(1)]??"";return $}import{dirname as A0,join as y}from"node:path";var R0=y(k,"discovery-cache.json");var I="dm-cliproxy/0.3.5";var f=15000,W=null;function _(){W=null}async function F(J,$,Q={}){if(!Q.force&&W&&Date.now()-W.fetchedAt<J.usageCacheTtlMs)return W.doc;if(!$)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Z=new URL("/api/usage",new URL(J.proxy.endpoint).origin).toString(),Y=new AbortController,j=setTimeout(()=>Y.abort(Error("timeout")),f),z;try{z=await fetch(Z,{headers:{"X-Plugin-Key":$,Accept:"application/json","User-Agent":I},signal:Y.signal})}finally{clearTimeout(j)}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 W={fetchedAt:Date.now(),doc:X},R.debug("usage fetched, accounts:",X.accounts.length),X}import{visibleWidth as N}from"@duckmind/dm-tui";function K(J,$){let Q=N(J);if(Q===$)return J;if(Q<$)return J+" ".repeat($-Q);return h(J,$)}function h(J,$){if($<=0)return"\x1B[0m";let Q="",Z=0,Y=0;while(Y<J.length){let j=J[Y];if(j==="\x1B"&&J[Y+1]==="["){let X=J.indexOf("m",Y+2);if(X>=0){Q+=J.slice(Y,X+1),Y=X+1;continue}}let z=N(j);if(Z+z>$)break;Q+=j,Z+=z,Y++}return`${Q}\x1B[0m`}var V={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 w(J,$={}){let Q=[],Z=new Map,Y=0;for(let j of J.accounts){if(!$.showDisabled&&j.disabled){Y++;continue}let z=Z.get(j.provider)??[];z.push(j),Z.set(j.provider,z)}if(Q.push(`${V.dim}generated ${J.generatedAt}${V.reset}`),J.unsupportedProviders.length>0)Q.push(`${V.dim}providers without quota lookup:${V.reset} ${J.unsupportedProviders.join(", ")}`);if(Y>0)Q.push(`${V.dim}hidden disabled accounts:${V.reset} ${Y} ${V.dim2}(press d to show)${V.reset}`);for(let[j,z]of Array.from(Z.entries()).sort()){Q.push(""),Q.push(`${V.bold}${V.accent}▌ ${j}${V.reset}`);for(let X of z){if(Q.push(c(X)),!X.supported){Q.push(` ${V.dim2}(provider not quota-aware)${V.reset}`);continue}if(X.error){if($.verbose)for(let A of r(X.error,88))Q.push(` ${V.red}${A}${V.reset}`);continue}let H=X.groups??[];if(H.length===0){Q.push(` ${V.dim2}(no active quota windows)${V.reset}`);continue}for(let A of H)Q.push(d(A))}}return Q.push(""),Q.push(`${V.dim}legend:${V.reset} ${S} ok ${v} error/unavailable ${n} disabled ${V.green}✓N${V.reset}/${V.red}✗N${V.reset} request counters ${V.dim}v = verbose, d = show disabled${V.reset}`),Q}function r(J,$){if(J.length<=$)return[J];let Q=[],Z=J;while(Z.length>$){let Y=Z.lastIndexOf(" ",$);if(Y<$*0.6)Y=$;Q.push(Z.slice(0,Y)),Z=Z.slice(Y).replace(/^\s+/,"")}if(Z)Q.push(Z);return Q}function c(J){let $=l(J),Q=`${V.green}✓${J.success}${V.reset} ${V.red}✗${J.failed}${V.reset}`,Z=u(J.label,36);return` ${$} ${V.bold}${Z}${V.reset} ${Q}`}var S=`${V.green}●${V.reset}`,v=`${V.yellow}⚠${V.reset}`,n=`${V.dim2}⊘${V.reset}`;function l(J){if(J.disabled)return n;if(J.unavailable||J.error||J.status&&J.status!=="active")return v;return S}function d(J){let $=b(J.remainingFraction),Q=Math.round($*100),Z=o($),Y=J.resetTime?` ${V.dim}reset ${i(J.resetTime)}${V.reset}`:"",j=u(J.label,28).padEnd(28," ");return` ${Z} ${m(Q,$)} ${j}${Y}`}function o(J){let $=b(J),Q=Math.round($*18),Z=x($),Y=V.dim2,j="█".repeat(Q),z="░".repeat(18-Q);return`${Y}[${Z}${j}${Y}${z}]${V.reset}`}function m(J,$){return`${x($)}${String(J).padStart(3)}%${V.reset}`}function x(J){if(J>=0.4)return V.green;if(J>=0.15)return V.yellow;return V.red}function i(J){let $=Date.parse(J);if(!Number.isFinite($))return J;let Q=$-Date.now();if(Q<=0)return"now";let Z=Math.round(Q/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 b(J){return Math.max(0,Math.min(1,J))}function u(J,$){if(J.length<=$)return J;return`${J.slice(0,$-1)}…`}import{visibleWidth as u0}from"@duckmind/dm-tui";function C(J,$,Q){let Z=J.slice($,$+Q);while(Z.length<Q)Z.push("");return Z}function P(J,$,Q){let Z=Math.max(0,Q-$);return Math.max(0,Math.min(J,Z))}function c0(J){let{tui:$,theme:Q,cfg:Z}=J,Y="idle",j=null,z="",X=0,H=!1,A=!1,B=(M)=>{Y="loading",$.requestRender();let E=T(Z.proxy.usageKey);F(Z,E,{force:M}).then((U)=>{j=U,Y="ready",X=0,$.requestRender()}).catch((U)=>{z=U.message,Y="error",$.requestRender()})},O=()=>{if(Y==="idle"||Y==="loading")return[Q.fg("dim"," loading usage…")];if(Y==="error")return[Q.fg("error",` usage failed: ${z}`)];if(!j)return[Q.fg("dim"," (no data)")];return w(j,{showDisabled:H,verbose:A})};return{id:"usage",label:"Usage",render:(M,E)=>{let U=O();return X=P(X,E,U.length),C(U,X,E).map((g)=>K(` ${g}`,M))},handleInput:(M)=>{if(q(M,"d"))return H=!H,X=0,!0;if(q(M,"v"))return A=!A,X=0,!0;let E=O().length;if(q(M,"up")||q(M,"k"))return X=Math.max(0,X-1),!0;if(q(M,"down")||q(M,"j"))return X=Math.min(Math.max(0,E-1),X+1),!0;if(q(M,"pageUp")||q(M,"b"))return X=Math.max(0,X-10),!0;if(q(M,"pageDown")||q(M,"f"))return X=Math.min(Math.max(0,E-1),X+10),!0;if(q(M,"home")||q(M,"g"))return X=0,!0;if(q(M,"end")||q(M,"shift+g"))return X=Math.max(0,E-1),!0;return!1},footerHint:()=>{let M=H?Q.fg("success","[d disabled]"):"d disabled",E=A?Q.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${M} · ${E} `},onActivate:()=>{if(Y==="idle")B(!1)},reload:()=>{if(_(),Y!=="idle")B(!0)}}}export{c0 as buildUsageView};
@@ -1,2 +1,2 @@
1
- import{existsSync as f}from"node:fs";import{homedir as YJ}from"node:os";import{getKeybindings as $J,Input as zJ,matchesKey as MJ}from"@duckmind/dm-tui";import{execSync as g}from"node:child_process";import{randomUUID as T}from"node:crypto";import{chmodSync as B,constants as w,copyFileSync as A,existsSync as R,linkSync as p,mkdirSync as I,readFileSync as c,rmSync as G,writeFileSync as m}from"node:fs";import{homedir as N}from"node:os";import{dirname as D,join as E}from"node:path";import{fileURLToPath as h}from"node:url";var L=!1;var W={info(...J){if(!L)console.log("[dm-cliproxy]",...J)},warn(...J){if(!L)console.warn("[dm-cliproxy]",...J)},error(...J){if(!L)console.error("[dm-cliproxy]",...J)},debug(...J){if(!L&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var l=E(N(),".dm","agent","dm-cliproxy"),q=E(l,"config.json"),d=[E(N(),".pi","agent","pi-cliproxyapi","config.json"),E(N(),".config","pi-cliproxyapi","config.json")];function s(){return R(E(D(h(import.meta.url)),"..",".git"))}function n(J=d,Q=q,X=s()){if(R(Q))return;let Y=(typeof J==="string"?[J]:[...J]).find(($)=>R($));if(!Y)return;let z;try{I(D(Q),{recursive:!0,mode:448}),B(D(Q),448),z=`${Q}.${process.pid}.${T()}.tmp`,A(Y,z,w.COPYFILE_EXCL),B(z,384),p(z,Q),G(z),z=void 0,W.info("legacy config copied to",Q)}catch($){if(z)try{G(z,{force:!0})}catch(K){W.warn("failed to clean temporary config:",K)}W.warn("failed to migrate legacy config:",$)}}var H={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function _(){if(n(),!R(q))return W.debug("config not found, using defaults at",q),structuredClone(H);try{let J=JSON.parse(c(q,"utf8"));return o(J)}catch(J){return W.error("failed to read config:",J,"— using defaults"),structuredClone(H)}}function F(J){I(D(q),{recursive:!0,mode:448}),B(D(q),448);let Q=`${q}.${process.pid}.${T()}.tmp`;try{m(Q,JSON.stringify(J,null,2)+`
2
- `,{encoding:"utf8",flag:"wx",mode:384}),A(Q,q),B(q,384)}finally{G(Q,{force:!0})}W.info("config saved to",q)}function o(J){if(!J||typeof J!=="object")return structuredClone(H);let Q=J,X=structuredClone(H),Z=Q.proxy??{};if(X.proxy.endpoint=typeof Z.endpoint==="string"?Z.endpoint:X.proxy.endpoint,X.proxy.apiKey=typeof Z.apiKey==="string"?Z.apiKey:"",typeof Z.usageKey==="string")X.proxy.usageKey=Z.usageKey;if(typeof Z.providerPrefix==="string"&&Z.providerPrefix.trim())X.proxy.providerPrefix=Z.providerPrefix.trim();if(Q.builtinProviders&&typeof Q.builtinProviders==="object")X.builtinProviders=Q.builtinProviders;if(Q.customProviders&&typeof Q.customProviders==="object")X.customProviders=Q.customProviders;if(Array.isArray(Q.discoveryExcludes))X.discoveryExcludes=Q.discoveryExcludes.filter((Y)=>typeof Y==="string");if(Q.overrides&&typeof Q.overrides==="object")X.overrides=Q.overrides;if(typeof Q.refreshIntervalMinutes==="number")X.refreshIntervalMinutes=Q.refreshIntervalMinutes;if(typeof Q.usageCacheTtlMs==="number")X.usageCacheTtlMs=Q.usageCacheTtlMs;return X}function C(J){if(!J)return"";let Q=J.trim();if(Q.startsWith("!"))try{return g(Q.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(X){let Z=X?.stderr?.toString?.()?.trim()??X.message;return W.warn(`failed to resolve "!" config value (${Q}): ${Z}`),""}if(Q.startsWith("$"))return process.env[Q.slice(1)]??"";return Q}import{visibleWidth as b}from"@duckmind/dm-tui";import{visibleWidth as S}from"@duckmind/dm-tui";function v(J,Q){let X=S(J);if(X===Q)return J;if(X<Q)return J+" ".repeat(Q-X);return a(J,Q)}function a(J,Q){if(Q<=0)return"\x1B[0m";let X="",Z=0,Y=0;while(Y<J.length){let z=J[Y];if(z==="\x1B"&&J[Y+1]==="["){let K=J.indexOf("m",Y+2);if(K>=0){X+=J.slice(Y,K+1),Y=K+1;continue}}let $=S(z);if(Z+$>Q)break;X+=z,Z+=$,Y++}return`${X}\x1B[0m`}var i="│",r="╭",t="╮",e="╰",JJ="╯",U="─";function x(J,Q){let X=Math.max(4,Q.width);return[QJ(J,Q.title,Q.titleColor??"accent",X),...Q.lines.map((Z)=>XJ(J,Z,X)),ZJ(J,Q.footer,X)]}function QJ(J,Q,X,Z){let Y=Q??"",z=b(Y),$=Math.max(0,Z-3-z),K=Y?J.bold(J.fg(X,Y)):"",M=`${r}${U}${K}${U.repeat($)}${t}`;return J.fg("borderAccent",M)}function XJ(J,Q,X){let Z=Math.max(0,X-2),Y=J.fg("borderAccent",i);return`${Y}${v(Q,Z)}${Y}`}function ZJ(J,Q,X){let Z=`${e}${U}`,Y=`${JJ}`,z=3;if(!Q||!Q.hint&&!Q.badge){let u=Math.max(0,X-3);return J.fg("borderAccent",`${Z}${U.repeat(u)}${Y}`)}let $=Q.hint??"",K=Q.badge??"",M=b($),j=b(K),V=Math.max(0,X-3-M-j),O=J.fg("dim",$),k=K?J.fg("muted",K):"",y=U.repeat(V);return`${J.fg("borderAccent",Z)}${O}${J.fg("borderAccent",y)}${k}${J.fg("borderAccent",Y)}`}function P(J){return Math.max(0,J-2)}var KJ=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:(J)=>{try{if(!new URL(J).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:(J)=>/^[a-z0-9][a-z0-9-]*$/i.test(J)?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 vJ(J){let Q=_(),X=Boolean(Q.proxy.endpoint),Z=Boolean(C(Q.proxy.apiKey));if(X&&Z)return!1;if(!J.hasUI)return!1;return jJ(J,!0)}async function jJ(J,Q=!1){let X=_(),Z={endpoint:X.proxy.endpoint??"",apiKey:X.proxy.apiKey??"",providerPrefix:X.proxy.providerPrefix??"",usageKey:X.proxy.usageKey??""},Y=!1;for(let $ of KJ){let K=Q?Z[$.label]??$.initialValue??"":Z[$.label]??"";if(!Q&&K)continue;let M=await WJ(J,$,K||$.initialValue||"");if(M===void 0){Y=!0;break}let j=M.trim();if(!j){if($.required){J.ui.notify(`${$.label} is required — aborted`,"warning"),Y=!0;break}Z[$.label]="";continue}Z[$.label]=$.label==="providerPrefix"||$.label==="endpoint"?j:qJ(j)}if(Y)return!1;let z={...X};if(z.proxy={...X.proxy,endpoint:Z.endpoint??"",apiKey:Z.apiKey??"",providerPrefix:Z.providerPrefix??""},Z.usageKey)z.proxy.usageKey=Z.usageKey;else delete z.proxy.usageKey;return F(z),J.ui.notify(`saved to ${q}`,"info"),!0}function qJ(J){if(J.startsWith("!")||J.startsWith("$"))return J;if(J.startsWith("~/")){let Q=J.replace(/^~/,YJ());return f(Q)?`!cat ${J}`:J}if(J.startsWith("/"))return f(J)?`!cat ${J}`:J;return J}async function WJ(J,Q,X){return J.ui.custom((Z,Y,z,$)=>VJ(Z,Y,Q,X,$),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function VJ(J,Q,X,Z,Y){let z=new zJ;z.setValue(Z),z.focused=!0;let $=null,K=(M)=>{if(!M&&!X.required){Y("");return}if(!M&&X.required){$="required field",J.requestRender();return}if(X.validate){let j=M.trim();if(j&&!j.startsWith("!")&&!j.startsWith("$")){let V=X.validate(j);if(V){$=V,J.requestRender();return}}}Y(M)};return z.onSubmit=K,z.onEscape=()=>Y(void 0),{render(M){let j=P(M),V=z.render(j-4),O=["",` ${Q.fg("dim",X.hint)}`,"",...V.map((k)=>` ${Q.fg("accent",`❯ ${k}`)}`),"",$?` ${Q.fg("error",`! ${$}`)}`:` ${Q.fg("dim","enter = save · esc = cancel")}`];return x(Q,{width:M,title:` setup: ${X.label} `,lines:O,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){z.invalidate()},handleInput(M){if($J().matches(M,"tui.select.cancel")||MJ(M,"escape")){Y(void 0);return}$=null,z.handleInput(M),J.requestRender()}}}export{vJ as runSetupIfNeeded,jJ as runSetup};
1
+ import{existsSync as w}from"node:fs";import{homedir as LJ}from"node:os";import{getKeybindings as BJ,Input as I,matchesKey as RJ}from"@duckmind/dm-tui";import{execSync as c}from"node:child_process";import{randomUUID as F}from"node:crypto";import{chmodSync as T,closeSync as C,constants as h,copyFileSync as l,existsSync as L,fsyncSync as d,linkSync as n,mkdirSync as s,openSync as o,readFileSync as S,renameSync as i,rmSync as D,writeFileSync as a}from"node:fs";import{homedir as H}from"node:os";import{dirname as G,join as B}from"node:path";import{fileURLToPath as r}from"node:url";var V=!1;var E={info(...J){if(!V)console.log("[dm-cliproxy]",...J)},warn(...J){if(!V)console.warn("[dm-cliproxy]",...J)},error(...J){if(!V)console.error("[dm-cliproxy]",...J)},debug(...J){if(!V&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var t=B(H(),".dm","agent","dm-cliproxy"),q=B(t,"config.json"),e=[B(H(),".pi","agent","pi-cliproxyapi","config.json"),B(H(),".config","pi-cliproxyapi","config.json")];function k(J){s(J,{recursive:!0,mode:448}),T(J,448)}function N(J){if(L(J))T(J,384)}function JJ(J){let Q;try{Q=JSON.parse(S(J,"utf8"))}catch{return}let X=Q&&typeof Q==="object"?Q.proxy:void 0;for(let Z of[X?.apiKey,X?.usageKey]){if(typeof Z!=="string")continue;let Y=/^!cat\s+((?:~\/|\/)[^\s;&|`]+)$/.exec(Z.trim());if(!Y)continue;let z=Y[1].replace(/^~/,H());N(z)}}function QJ(){return L(B(G(r(import.meta.url)),"..",".git"))}function XJ(J=e,Q=q,X=QJ()){if(L(Q))return;let Y=(typeof J==="string"?[J]:[...J]).find(($)=>L($));if(!Y)return;let z;try{N(Y),JJ(Y),k(G(Q)),z=`${Q}.${process.pid}.${F()}.tmp`,l(Y,z,h.COPYFILE_EXCL),T(z,384),n(z,Q),D(z),z=void 0,E.info("legacy config copied to",Q)}catch($){if(z)try{D(z,{force:!0})}catch(M){E.warn("failed to clean temporary config:",M)}E.warn("failed to migrate legacy config:",$)}}var O={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function b(){if(XJ(),!L(q))return E.debug("config not found, using defaults at",q),structuredClone(O);try{k(G(q)),N(q);let J=JSON.parse(S(q,"utf8"));return YJ(J)}catch(J){return E.error("failed to read config:",J,"— using defaults"),structuredClone(O)}}function ZJ(J,Q=q){k(G(Q));let X=`${Q}.${process.pid}.${F()}.tmp`,Z;try{Z=o(X,"wx",384),a(Z,JSON.stringify(J,null,2)+`
2
+ `,{encoding:"utf8"}),d(Z),C(Z),Z=void 0,i(X,Q),N(Q)}finally{if(Z!==void 0)C(Z);D(X,{force:!0})}}function x(J){ZJ(J),E.info("config saved to",q)}function YJ(J){if(!J||typeof J!=="object")return structuredClone(O);let Q=J,X=structuredClone(O),Z=Q.proxy??{};if(X.proxy.endpoint=typeof Z.endpoint==="string"?Z.endpoint:X.proxy.endpoint,X.proxy.apiKey=typeof Z.apiKey==="string"?Z.apiKey:"",typeof Z.usageKey==="string")X.proxy.usageKey=Z.usageKey;if(typeof Z.providerPrefix==="string"&&Z.providerPrefix.trim())X.proxy.providerPrefix=Z.providerPrefix.trim();if(Q.builtinProviders&&typeof Q.builtinProviders==="object")X.builtinProviders=Q.builtinProviders;if(Q.customProviders&&typeof Q.customProviders==="object")X.customProviders=Q.customProviders;if(Array.isArray(Q.discoveryExcludes))X.discoveryExcludes=Q.discoveryExcludes.filter((Y)=>typeof Y==="string");if(Q.overrides&&typeof Q.overrides==="object")X.overrides=Q.overrides;if(typeof Q.refreshIntervalMinutes==="number")X.refreshIntervalMinutes=Q.refreshIntervalMinutes;if(typeof Q.usageCacheTtlMs==="number")X.usageCacheTtlMs=Q.usageCacheTtlMs;return X}function v(J){if(!J)return"";let Q=J.trim();if(Q.startsWith("!"))try{return c(Q.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(X){let Z=X?.status,Y=typeof Z==="number"?` (exit ${Z})`:"";return E.warn(`failed to resolve "!" config value${Y}`),""}if(Q.startsWith("$"))return process.env[Q.slice(1)]??"";return Q}import{visibleWidth as A}from"@duckmind/dm-tui";import{visibleWidth as P}from"@duckmind/dm-tui";function y(J,Q){let X=P(J);if(X===Q)return J;if(X<Q)return J+" ".repeat(Q-X);return $J(J,Q)}function $J(J,Q){if(Q<=0)return"\x1B[0m";let X="",Z=0,Y=0;while(Y<J.length){let z=J[Y];if(z==="\x1B"&&J[Y+1]==="["){let M=J.indexOf("m",Y+2);if(M>=0){X+=J.slice(Y,M+1),Y=M+1;continue}}let $=P(z);if(Z+$>Q)break;X+=z,Z+=$,Y++}return`${X}\x1B[0m`}var zJ="│",KJ="╭",MJ="╮",jJ="╰",qJ="╯",R="─";function f(J,Q){let X=Math.max(4,Q.width);return[WJ(J,Q.title,Q.titleColor??"accent",X),...Q.lines.map((Z)=>EJ(J,Z,X)),UJ(J,Q.footer,X)]}function WJ(J,Q,X,Z){let Y=Q??"",z=A(Y),$=Math.max(0,Z-3-z),M=Y?J.bold(J.fg(X,Y)):"",K=`${KJ}${R}${M}${R.repeat($)}${MJ}`;return J.fg("borderAccent",K)}function EJ(J,Q,X){let Z=Math.max(0,X-2),Y=J.fg("borderAccent",zJ);return`${Y}${y(Q,Z)}${Y}`}function UJ(J,Q,X){let Z=`${jJ}${R}`,Y=`${qJ}`,z=3;if(!Q||!Q.hint&&!Q.badge){let p=Math.max(0,X-3);return J.fg("borderAccent",`${Z}${R.repeat(p)}${Y}`)}let $=Q.hint??"",M=Q.badge??"",K=A($),j=A(M),W=Math.max(0,X-3-K-j),U=J.fg("dim",$),_=M?J.fg("muted",M):"",u=R.repeat(W);return`${J.fg("borderAccent",Z)}${U}${J.fg("borderAccent",u)}${_}${J.fg("borderAccent",Y)}`}function g(J){return Math.max(0,J-2)}var VJ=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:(J)=>{try{if(!new URL(J).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:(J)=>/^[a-z0-9][a-z0-9-]*$/i.test(J)?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 cJ(J){let Q=b(),X=Boolean(Q.proxy.endpoint),Z=Boolean(v(Q.proxy.apiKey));if(X&&Z)return!1;if(!J.hasUI)return!1;return HJ(J,!0)}async function HJ(J,Q=!1){let X=b(),Z={endpoint:X.proxy.endpoint??"",apiKey:X.proxy.apiKey??"",providerPrefix:X.proxy.providerPrefix??"",usageKey:X.proxy.usageKey??""},Y=!1;for(let $ of VJ){let M=Z[$.label]??"",K=$.secret?"":Q?Z[$.label]??$.initialValue??"":Z[$.label]??"";if(!Q&&K)continue;let j=$.secret&&M?{...$,required:!1}:$,W=await NJ(J,j,K||$.initialValue||"");if(W===void 0){Y=!0;break}let U=GJ($,M,W);if(U===null){if($.required){J.ui.notify(`${$.label} is required — aborted`,"warning"),Y=!0;break}}Z[$.label]=U??""}if(Y)return!1;let z={...X};if(z.proxy={...X.proxy,endpoint:Z.endpoint??"",apiKey:Z.apiKey??"",providerPrefix:Z.providerPrefix??""},Z.usageKey)z.proxy.usageKey=Z.usageKey;else delete z.proxy.usageKey;return x(z),J.ui.notify(`saved to ${q}`,"info"),!0}function OJ(J){if(J.startsWith("!")||J.startsWith("$"))return J;if(J.startsWith("~/")){let Q=J.replace(/^~/,LJ());return w(Q)?`!cat ${J}`:J}if(J.startsWith("/"))return w(J)?`!cat ${J}`:J;return J}function GJ(J,Q,X){let Z=X.trim();if(!Z){if(J.secret&&Q)return Q;return J.required?null:""}if(J.secret&&!J.required&&Z==="-")return"";return J.label==="providerPrefix"||J.label==="endpoint"?Z:OJ(Z)}async function NJ(J,Q,X){return J.ui.custom((Z,Y,z,$)=>_J(Z,Y,Q,X,$),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}class m{rawInput=new I;displayInput=new I;pasteActive=!1;get focused(){return this.rawInput.focused}set focused(J){this.rawInput.focused=J,this.displayInput.focused=J}set onSubmit(J){this.rawInput.onSubmit=J}set onEscape(J){this.rawInput.onEscape=J}getValue(){return this.rawInput.getValue()}setValue(J){this.rawInput.setValue(J),this.displayInput.setValue("•".repeat(J.length))}handleInput(J){this.rawInput.handleInput(J),this.displayInput.handleInput(this.maskInput(J)),this.displayInput.setValue("•".repeat(this.rawInput.getValue().length))}render(J){return this.displayInput.render(J)}invalidate(){this.rawInput.invalidate(),this.displayInput.invalidate()}maskInput(J){let Q="";for(let X=0;X<J.length;){if(J.startsWith("\x1B[200~",X)){this.pasteActive=!0,Q+="\x1B[200~",X+=6;continue}if(J.startsWith("\x1B[201~",X)){this.pasteActive=!1,Q+="\x1B[201~",X+=6;continue}if(!this.pasteActive&&J.charCodeAt(X)===27)return J;let Z=J.codePointAt(X),Y=String.fromCodePoint(Z);Q+=Z<32||Z===127?Y:"•",X+=Y.length}return Q}}function _J(J,Q,X,Z,Y){let z=X.secret?new m:new I;z.setValue(Z),z.focused=!0;let $=null,M=(K)=>{if(!K&&!X.required){Y("");return}if(!K&&X.required){$="required field",J.requestRender();return}if(X.validate){let j=K.trim();if(j&&!j.startsWith("!")&&!j.startsWith("$")){let W=X.validate(j);if(W){$=W,J.requestRender();return}}}Y(K)};return z.onSubmit=M,z.onEscape=()=>Y(void 0),{render(K){let j=g(K),W=z.render(j-4),U=["",` ${Q.fg("dim",X.hint)}`,"",...W.map((_)=>` ${Q.fg("accent",`❯ ${_}`)}`),"",$?` ${Q.fg("error",`! ${$}`)}`:` ${Q.fg("dim","enter = save · esc = cancel")}`];return f(Q,{width:K,title:` setup: ${X.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){z.invalidate()},handleInput(K){if(BJ().matches(K,"tui.select.cancel")||RJ(K,"escape")){Y(void 0);return}$=null,z.handleInput(K),J.requestRender()}}}export{cJ as runSetupIfNeeded,HJ as runSetup,GJ as resolveWizardValue,_J as buildStepOverlay};
@@ -1 +1 @@
1
- import{chmodSync as R,existsSync as V,mkdirSync as B,readFileSync as q,statSync as D,unlinkSync as M,writeFileSync as j}from"node:fs";import{join as K}from"node:path";import{homedir as Y}from"node:os";import{dirname as N,join as z}from"node:path";var b=!1;var Z={info(...J){if(!b)console.log("[dm-cliproxy]",...J)},warn(...J){if(!b)console.warn("[dm-cliproxy]",...J)},error(...J){if(!b)console.error("[dm-cliproxy]",...J)},debug(...J){if(!b&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var W=z(Y(),".dm","agent","dm-cliproxy"),f=z(W,"config.json"),v=[z(Y(),".pi","agent","pi-cliproxyapi","config.json"),z(Y(),".config","pi-cliproxyapi","config.json")];var $=K(W,"usage-cache.json"),X=K(W,"usage-cache.lock"),w=120000,L=30000;function G(){if(!V($))return null;try{let J=JSON.parse(q($,"utf8"));if(!J||typeof J.fetchedAt!=="number"||!J.doc||!Array.isArray(J.doc.accounts))return null;return{doc:J.doc,ageMs:Date.now()-J.fetchedAt}}catch(J){return Z.warn("failed to read usage cache:",J.message),null}}function F(J){return J<w}function u(J){try{B(W,{recursive:!0,mode:448}),R(W,448);let Q={fetchedAt:Date.now(),doc:J};j($,JSON.stringify(Q),{encoding:"utf8",mode:384})}catch(Q){Z.warn("failed to write usage cache:",Q.message)}}function C(){let J=`${process.pid}@${Date.now()}`;if(V(X))try{let Q=D(X);if(Date.now()-Q.mtimeMs>L)Z.debug("removing stale usage lock"),M(X);else return null}catch{return null}try{return j(X,J,{flag:"wx",mode:384}),J}catch{return null}}function A(J){try{if(q(X,"utf8").trim()===J)return M(X),!0;return!1}catch{return!1}}export{u as writeUsageCache,C as tryAcquireUsageLock,A as releaseUsageLock,G as readUsageCache,F as isUsageFresh,X as USAGE_LOCK_PATH,w as USAGE_CACHE_TTL_MS,$ as USAGE_CACHE_PATH};
1
+ import{createHash as O}from"node:crypto";import{existsSync as j,readFileSync as B,statSync as x,unlinkSync as L,writeFileSync as E}from"node:fs";import{dirname as V,join as K}from"node:path";import{chmodSync as R,closeSync as D,constants as C,copyFileSync as _,existsSync as w,fsyncSync as F,linkSync as k,mkdirSync as N,openSync as S,readFileSync as v,renameSync as f,rmSync as p,writeFileSync as u}from"node:fs";import{homedir as q}from"node:os";import{dirname as g,join as $}from"node:path";var Y=!1;var Z={info(...J){if(!Y)console.log("[dm-cliproxy]",...J)},warn(...J){if(!Y)console.warn("[dm-cliproxy]",...J)},error(...J){if(!Y)console.error("[dm-cliproxy]",...J)},debug(...J){if(!Y&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...J)}};var b=$(q(),".dm","agent","dm-cliproxy"),s=$(b,"config.json"),P=[$(q(),".pi","agent","pi-cliproxyapi","config.json"),$(q(),".config","pi-cliproxyapi","config.json")];function z(J){N(J,{recursive:!0,mode:448}),R(J,448)}function X(J){if(w(J))R(J,384)}var U=K(b,"usage-cache.json"),H=K(b,"usage-cache.lock"),G=120000,I=30000;function t(J,Q,W=b){let M=O("sha256").update(J.trim().replace(/\/+$/,"")).update("\x00").update(Q).digest("hex").slice(0,24);return{cachePath:K(W,`usage-cache-${M}.json`),lockPath:K(W,`usage-cache-${M}.lock`)}}function r(J=U){if(!j(J))return null;try{z(V(J)),X(J);let Q=JSON.parse(B(J,"utf8"));if(!Q||typeof Q.fetchedAt!=="number"||!Q.doc||!Array.isArray(Q.doc.accounts))return null;return{doc:Q.doc,ageMs:Date.now()-Q.fetchedAt}}catch(Q){return Z.warn("failed to read usage cache:",Q.message),null}}function a(J){return J<G}function e(J,Q=U){try{z(V(Q));let W={fetchedAt:Date.now(),doc:J};E(Q,JSON.stringify(W),{encoding:"utf8",mode:384}),X(Q)}catch(W){Z.warn("failed to write usage cache:",W.message)}}function JJ(J=H){let Q=`${process.pid}@${Date.now()}`;if(j(J))try{z(V(J)),X(J);let W=x(J);if(Date.now()-W.mtimeMs>I)Z.debug("removing stale usage lock"),L(J);else return null}catch{return null}try{return z(V(J)),E(J,Q,{flag:"wx",mode:384}),X(J),Q}catch{return null}}function QJ(J,Q=H){try{if(X(Q),B(Q,"utf8").trim()===J)return L(Q),!0;return!1}catch{return!1}}export{e as writeUsageCache,t as usageCachePaths,JJ as tryAcquireUsageLock,QJ as releaseUsageLock,r as readUsageCache,a as isUsageFresh,H as USAGE_LOCK_PATH,G as USAGE_CACHE_TTL_MS,U as USAGE_CACHE_PATH};
@@ -1,9 +1,9 @@
1
- import{existsSync as X$}from"node:fs";import{join as f$}from"node:path";import{Type as D}from"@sinclair/typebox";import{getAgentDir as H1}from"@duckmind/dm-coding-agent";import{randomUUID as i}from"node:crypto";import{existsSync as w,mkdirSync as x,readFileSync as k,unlinkSync as J$,writeFileSync as o}from"node:fs";import{dirname as A,join as N,resolve as S}from"node:path";import{spawn as Q$,spawnSync as z$}from"node:child_process";import{homedir as u}from"node:os";import{getAgentDir as r}from"@duckmind/dm-coding-agent";var O$="https://chatgpt.com/backend-api/codex/responses",V$="https://openrouter.ai/api/v1/chat/completions",P="1:1",U$="png",v=900000,B$="DM_IMAGE_TEST_DELAY_MS",s="DM_IMAGE_ALLOW_LEGACY_FALLBACK",I="@preset/image2",_$=I,R="gpt-5.5",q$=new Set(["image2",I,"duckmind/image2","duckmind/@preset/image2","openrouter/image2","openrouter/@preset/image2"]),N$=new Set([R,`openai-codex/${R}`,`codex/${R}`]),F={"1:1":{width:1024,height:1024},"4:5":{width:1024,height:1280},"16:9":{width:1600,height:900}},a=S(A(new URL(import.meta.url).pathname),"..","vendor","imagen"),y=N(a,"imagen.py");function D$($){return String($??"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)||"image"}function g($){return typeof $==="string"&&$ in F?$:P}function h($){return $==="svg"?"svg":U$}function t($){let j=String($??"").trim();if(N$.has(j))return R;return q$.has(j)?I:_$}function M$($){return t($)===I}function L$($=process.env[s]){return typeof $==="string"&&/^(1|true|yes|on)$/i.test($.trim())}function C($="Request was aborted"){let j=Error($);return j.name="AbortError",j}function b($){if(!$)return!1;if($ instanceof Error&&$.name==="AbortError")return!0;let j=$ instanceof Error?$.message:String($);return j==="Request was aborted"||j==="This operation was aborted"}function E($){if(!$?.aborted)return;if($.reason instanceof Error)throw $.reason;throw C()}function S$($,j=v){let Y=new AbortController,Z=setTimeout(()=>Y.abort(C(`Image request timed out after ${Math.round(j/1000)}s`)),j),G=()=>{Y.abort($?.reason instanceof Error?$.reason:C())};if($?.aborted)G();else if($)$.addEventListener("abort",G,{once:!0});return{signal:Y.signal,cleanup(){clearTimeout(Z),$?.removeEventListener("abort",G)}}}function T$($,j){if(!Number.isFinite($)||$<=0)return Promise.resolve();return E(j),new Promise((Y,Z)=>{let G=setTimeout(()=>{j?.removeEventListener("abort",H),Y()},$),H=()=>{clearTimeout(G),j?.removeEventListener("abort",H),Z(C())};j?.addEventListener("abort",H,{once:!0})})}function b$(){let $=String(process.env[B$]??"").trim();if(!$)return 0;let j=Number.parseInt($,10);if(!Number.isFinite(j)||j<=0)return 0;return Math.min(j,300000)}function e($){return N(r(),$)}function p($){try{return JSON.parse(k($,"utf-8"))}catch{return}}function w$($){if(!$||typeof $!=="object")return;let j=Object.keys($).filter((H)=>H==="openai-codex"||/^openai-codex-account-\d+$/.test(H)).sort((H,W)=>{if(H==="openai-codex")return-1;if(W==="openai-codex")return 1;return H.localeCompare(W,void 0,{numeric:!0})}).find((H)=>{let W=$[H];return W&&typeof W==="object"&&!Array.isArray(W)}),Y=j?$[j]:void 0;if(!Y||typeof Y!=="object"||Array.isArray(Y))return;let Z=typeof Y.access==="string"?Y.access:void 0,G=typeof Y.accountId==="string"?Y.accountId:typeof Y.account_id==="string"?Y.account_id:void 0;if(!Z||!G)return;return{accessToken:Z,accountId:G,email:typeof Y.email==="string"?Y.email:void 0}}function k$($){try{let j=String($??"").split(".");if(j.length!==3)return;let Z=JSON.parse(Buffer.from(j[1],"base64url").toString("utf8"))?.["https://api.openai.com/auth"]?.chatgpt_account_id;return typeof Z==="string"&&Z.trim()?Z.trim():void 0}catch{return}}function d($,j){if(!$||typeof $!=="object")return;let Y=j.toLowerCase();for(let[Z,G]of Object.entries($)){if(String(Z).toLowerCase()!==Y)continue;if(typeof G==="string"&&G.trim())return G.trim()}return}function F$($){let j=$?.modelRegistry,Y=[],Z=new Set,G=(H)=>{if(!H||typeof H!=="object")return;if(H.provider!=="openai-codex")return;let W=`${H.provider}/${H.id}`;if(Z.has(W))return;Z.add(W),Y.push(H)};if(G($?.model),j&&typeof j.find==="function")G(j.find("openai-codex",R));if(j&&typeof j.getAvailable==="function")for(let H of j.getAvailable())G(H);return Y}async function C$($){let j=$?.modelRegistry;if(!j||typeof j.getApiKeyAndHeaders!=="function")return;for(let Y of F$($)){let Z=await j.getApiKeyAndHeaders(Y);if(!Z?.ok||!Z.apiKey)continue;let G=k$(Z.apiKey)||d(Z.headers,"ChatGPT-Account-Id")||d(Z.headers,"chatgpt-account-id");if(!G)continue;return{accessToken:Z.apiKey,accountId:G,email:void 0,source:`model-registry:${Y.provider}/${Y.id}`}}return}function $$(){let $=p(e("auth.json")),j=w$($);if(j)return{...j,source:"auth.json"};throw Error("Missing active Codex credentials. Ensure ~/.dm/agent/auth.json contains an openai-codex or openai-codex-account-N account.")}function E$(){return["You are a focused image-generation assistant.","Finish by calling image_generation for the final answer.","Do not stop at plain text when the user asked for an image.","Follow the requested visual direction, aspect ratio, and subject details closely."].join(" ")}function R$(){return["You are a vector illustrator.","Return exactly one standalone SVG image and no prose.","Do not wrap the SVG in markdown fences.","Do not return a data URI unless absolutely necessary.","Do not mention limitations, policies, or explanations in the answer."].join(" ")}function I$($,j){let Y=F[j]??F[P];return[`Create one polished self-contained SVG illustration for this brief: ${$}`,`Use a ${j} aspect ratio with a ${Y.width}x${Y.height} canvas and a matching viewBox.`,"Return only raw <svg>...</svg> markup.","Use simple shapes, gradients, paths, and fills; avoid external fonts, scripts, or remote URLs.","If the request is a portrait, make it respectful, stylized, and presentation-ready."].join(`
1
+ import{existsSync as X$}from"node:fs";import{join as f$}from"node:path";import{Type as D}from"@sinclair/typebox";import{getAgentDir as H1}from"@duckmind/dm-coding-agent";import{randomUUID as i}from"node:crypto";import{existsSync as w,mkdirSync as x,readFileSync as k,unlinkSync as J$,writeFileSync as o}from"node:fs";import{dirname as A,join as N,resolve as S}from"node:path";import{spawn as Q$,spawnSync as z$}from"node:child_process";import{homedir as u}from"node:os";import{getAgentDir as r}from"@duckmind/dm-coding-agent";var V$="https://chatgpt.com/backend-api/codex/responses",O$="https://openrouter.ai/api/v1/chat/completions",P="1:1",U$="png",v=900000,B$="DM_IMAGE_TEST_DELAY_MS",s="DM_IMAGE_ALLOW_LEGACY_FALLBACK",I="@preset/image2",_$=I,R="gpt-5.5",q$=new Set(["image2",I,"duckmind/image2","duckmind/@preset/image2","openrouter/image2","openrouter/@preset/image2"]),N$=new Set([R,`openai-codex/${R}`,`codex/${R}`]),F={"1:1":{width:1024,height:1024},"4:5":{width:1024,height:1280},"16:9":{width:1600,height:900}},a=S(A(new URL(import.meta.url).pathname),"..","vendor","imagen"),y=N(a,"imagen.py");function D$($){return String($??"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,48)||"image"}function g($){return typeof $==="string"&&$ in F?$:P}function h($){return $==="svg"?"svg":U$}function t($){let j=String($??"").trim();if(N$.has(j))return R;return q$.has(j)?I:_$}function M$($){return t($)===I}function L$($=process.env[s]){return typeof $==="string"&&/^(1|true|yes|on)$/i.test($.trim())}function C($="Request was aborted"){let j=Error($);return j.name="AbortError",j}function b($){if(!$)return!1;if($ instanceof Error&&$.name==="AbortError")return!0;let j=$ instanceof Error?$.message:String($);return j==="Request was aborted"||j==="This operation was aborted"}function E($){if(!$?.aborted)return;if($.reason instanceof Error)throw $.reason;throw C()}function S$($,j=v){let Y=new AbortController,Z=setTimeout(()=>Y.abort(C(`Image request timed out after ${Math.round(j/1000)}s`)),j),G=()=>{Y.abort($?.reason instanceof Error?$.reason:C())};if($?.aborted)G();else if($)$.addEventListener("abort",G,{once:!0});return{signal:Y.signal,cleanup(){clearTimeout(Z),$?.removeEventListener("abort",G)}}}function T$($,j){if(!Number.isFinite($)||$<=0)return Promise.resolve();return E(j),new Promise((Y,Z)=>{let G=setTimeout(()=>{j?.removeEventListener("abort",H),Y()},$),H=()=>{clearTimeout(G),j?.removeEventListener("abort",H),Z(C())};j?.addEventListener("abort",H,{once:!0})})}function b$(){let $=String(process.env[B$]??"").trim();if(!$)return 0;let j=Number.parseInt($,10);if(!Number.isFinite(j)||j<=0)return 0;return Math.min(j,300000)}function e($){return N(r(),$)}function p($){try{return JSON.parse(k($,"utf-8"))}catch{return}}function w$($){if(!$||typeof $!=="object")return;let j=Object.keys($).filter((H)=>H==="openai-codex"||/^openai-codex-account-\d+$/.test(H)).sort((H,W)=>{if(H==="openai-codex")return-1;if(W==="openai-codex")return 1;return H.localeCompare(W,void 0,{numeric:!0})}).find((H)=>{let W=$[H];return W&&typeof W==="object"&&!Array.isArray(W)}),Y=j?$[j]:void 0;if(!Y||typeof Y!=="object"||Array.isArray(Y))return;let Z=typeof Y.access==="string"?Y.access:void 0,G=typeof Y.accountId==="string"?Y.accountId:typeof Y.account_id==="string"?Y.account_id:void 0;if(!Z||!G)return;return{accessToken:Z,accountId:G,email:typeof Y.email==="string"?Y.email:void 0}}function k$($){try{let j=String($??"").split(".");if(j.length!==3)return;let Z=JSON.parse(Buffer.from(j[1],"base64url").toString("utf8"))?.["https://api.openai.com/auth"]?.chatgpt_account_id;return typeof Z==="string"&&Z.trim()?Z.trim():void 0}catch{return}}function d($,j){if(!$||typeof $!=="object")return;let Y=j.toLowerCase();for(let[Z,G]of Object.entries($)){if(String(Z).toLowerCase()!==Y)continue;if(typeof G==="string"&&G.trim())return G.trim()}return}function F$($){let j=$?.modelRegistry,Y=[],Z=new Set,G=(H)=>{if(!H||typeof H!=="object")return;if(H.provider!=="openai-codex")return;let W=`${H.provider}/${H.id}`;if(Z.has(W))return;Z.add(W),Y.push(H)};if(G($?.model),j&&typeof j.find==="function")G(j.find("openai-codex",R));if(j&&typeof j.getAvailable==="function")for(let H of j.getAvailable())G(H);return Y}async function C$($){let j=$?.modelRegistry;if(!j||typeof j.getApiKeyAndHeaders!=="function")return;for(let Y of F$($)){let Z=await j.getApiKeyAndHeaders(Y);if(!Z?.ok||!Z.apiKey)continue;let G=k$(Z.apiKey)||d(Z.headers,"ChatGPT-Account-Id")||d(Z.headers,"chatgpt-account-id");if(!G)continue;return{accessToken:Z.apiKey,accountId:G,email:void 0,source:`model-registry:${Y.provider}/${Y.id}`}}return}function $$(){let $=p(e("auth.json")),j=w$($);if(j)return{...j,source:"auth.json"};throw Error("Missing active Codex credentials. Ensure ~/.dm/agent/auth.json contains an openai-codex or openai-codex-account-N account.")}function E$(){return["You are a focused image-generation assistant.","Finish by calling image_generation for the final answer.","Do not stop at plain text when the user asked for an image.","Follow the requested visual direction, aspect ratio, and subject details closely."].join(" ")}function R$(){return["You are a vector illustrator.","Return exactly one standalone SVG image and no prose.","Do not wrap the SVG in markdown fences.","Do not return a data URI unless absolutely necessary.","Do not mention limitations, policies, or explanations in the answer."].join(" ")}function I$($,j){let Y=F[j]??F[P];return[`Create one polished self-contained SVG illustration for this brief: ${$}`,`Use a ${j} aspect ratio with a ${Y.width}x${Y.height} canvas and a matching viewBox.`,"Return only raw <svg>...</svg> markup.","Use simple shapes, gradients, paths, and fills; avoid external fonts, scripts, or remote URLs.","If the request is a portrait, make it respectful, stylized, and presentation-ready."].join(`
2
2
  `)}function x$($,j){let Y=F[j]??F[P];return[$,`Output in exactly ${Y.width}px x ${Y.height}px (${j}).`,"Prefer production-ready composition, grounded local detail when relevant, and the strongest final image_generation call."].join(`
3
3
  `)}function j$($,j){let Y=F[j]??F[P];return[$,`Target aspect ratio: ${j}.`,`Compose for roughly ${Y.width}x${Y.height} output.`,"Generate the final answer by calling the image_generation tool.","If the prompt is a portrait or public person, keep it respectful and presentation-ready."].join(`
4
- `)}function A$($){let j=String($??"").trim();if(!j)throw Error("Codex returned an empty image response.");let Y=j.match(/!\[[^\]]*]\((data:image\/svg\+xml[^)]+)\)/i);if(Y?.[1]){let X=Y[1],f=X.indexOf(",");if(f!==-1)return decodeURIComponent(X.slice(f+1)).trim()}let Z=j.match(/data:image\/svg\+xml[^,]*,(.+)$/is);if(Z?.[1])return decodeURIComponent(Z[1]).trim();let H=j.match(/```(?:svg)?\s*([\s\S]*?)```/i)?.[1]?.trim();if(H?.startsWith("<svg"))return H;let W=j.match(/<svg[\s\S]*<\/svg>/i);if(W?.[0])return W[0].trim();throw Error(`Expected SVG markup from Codex, received: ${j.slice(0,240)}`)}async function l($,j,Y){let Z=S$(Y,v),G;try{G=await fetch(O$,{method:"POST",signal:Z.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${j.accessToken}`,Accept:"text/event-stream","Cache-Control":"no-cache",originator:"Codex Desktop","User-Agent":"Codex Desktop/26.212.1823 (darwin; arm64)","ChatGPT-Account-Id":j.accountId},body:JSON.stringify($)})}catch(K){if(Z.cleanup(),b(K)||Z.signal.aborted)throw C();throw K}if(!G.ok){Z.cleanup();let K=await G.text().catch(()=>"");throw Error(`Codex image request failed: HTTP ${G.status} ${K.slice(0,240)}`)}if(!G.body)throw Z.cleanup(),Error("Codex image request returned no response body.");let H=new TextDecoder,W=G.body.getReader(),X="",f=null,O=[],V="",z,B=[],U=()=>{if(!f||O.length===0)return f=null,O=[],!1;let K=JSON.parse(O.join(`
5
- `));if(f==="response.output_text.delta"&&typeof K.delta==="string")V+=K.delta;if(f==="response.output_item.done"&&K.item&&typeof K.item==="object")B.push(K.item);if(f==="response.completed"||f==="response.done")return z=K.response?.id??z,f=null,O=[],!0;if(f==="response.failed"||f==="response.incomplete"){let Q=K.response?.error?.message||K.response?.incomplete_details?.reason||"Codex image request did not complete.";throw Error(String(Q))}return f=null,O=[],!1};try{while(!0){E(Z.signal);let{value:K,done:Q}=await W.read();X+=H.decode(K??new Uint8Array,{stream:!Q});while(!0){let _=X.indexOf(`
6
- `);if(_===-1)break;let J=X.slice(0,_);if(X=X.slice(_+1),J.endsWith("\r"))J=J.slice(0,-1);if(!J){if(U())return{assistantText:V.trim(),outputItems:B,responseId:z};continue}if(J.startsWith("event: "))f=J.slice(7).trim();else if(J.startsWith("data: "))O.push(J.slice(6))}if(Q)break}if(O.length>0)U();return{assistantText:V.trim(),outputItems:B,responseId:z}}catch(K){if(await W.cancel().catch(()=>{}),b(K)||Z.signal.aborted)throw C();throw K}finally{Z.cleanup(),W.releaseLock()}}function P$($,j,Y){switch(j){case"global":return S(N(r(),"generated-images"));case"custom":if(!Y||!String(Y).trim())throw Error("save=custom requires saveDir.");return S(String(Y).trim());case"project":default:return S($,".dm","generated-images")}}function y$($,j,Y,Z){let G=Z||`run-${i().slice(0,8)}`;return S("/tmp","dm-imagen-runs",G)}function m($,j){x(A($),{recursive:!0}),o($,j,"utf-8")}function c($,j){x(A($),{recursive:!0}),o($,j)}function v$($,j){let Y=z$("sips",["-s","format","png",$,"--out",j],{encoding:"utf-8"});if(Y.status===0&&w(j))return;let Z=(Y.stderr||Y.stdout||`exit ${Y.status??"unknown"}`).trim();throw Error(`Failed to convert SVG to PNG via sips: ${Z}`)}function Y$($,j="png"){let Y=String($??"").trim();if(!Y)throw Error("image_generation.result is empty");let Z=Y,G="";if(Y.startsWith("data:")){let X=Y.indexOf(",");if(X===-1)throw Error("image_generation.result data URL is malformed");let f=Y.slice(5,X);G=String(f.split(";",1)[0]??"").trim(),Z=Y.slice(X+1)}let H=Buffer.from(Z,"base64");if(!H.length)throw Error("image_generation.result decoded to empty bytes");let W=String(j||"png").trim().toLowerCase().replace(/^\./,"")||"png";if(G==="image/jpeg")W="jpg";else if(G==="image/webp")W="webp";else if(G==="image/gif")W="gif";else if(G==="image/png")W="png";return{bytes:H,mimeType:G||(W==="jpg"?"image/jpeg":`image/${W}`),extension:W}}function g$($){return String($??"").trim().replace(/^['"]|['"]$/g,"")}function h$($){if(!$||!w($))return;try{for(let j of k($,"utf-8").split(/\r?\n/)){let Y=j.trim();if(!Y||Y.startsWith("#")||!Y.includes("="))continue;if(Y.startsWith("export "))Y=Y.slice(7).trim();let[Z,...G]=Y.split("="),H=Z.trim(),W=g$(G.join("="));if((H==="OPENROUTER_API_KEY"||H==="OPENROUTER_KEY")&&W)return{apiKey:W,source:`config:${$}`}}}catch{return}return}function n($){let j=[],Y=S($||process.cwd());while(!0){j.push(N(Y,"config","openrouter.cnf"));let Z=A(Y);if(Z===Y)break;Y=Z}return j}function p$($){let j=process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_KEY;if(j)return{apiKey:j,source:"env:OPENROUTER_API_KEY"};let Y=[...n($),...n(process.cwd()),N(u(),".dm","openrouter.cnf"),N(u(),".config","dm","openrouter.cnf")],Z=new Set;for(let G of Y){if(Z.has(G))continue;Z.add(G);let H=h$(G);if(H)return H}return}async function m$($){let j=$?.modelRegistry;if(!j||typeof j!=="object")return;if(typeof j.getApiKeyForProvider==="function")for(let H of["openrouter","duckmind"]){let W=await j.getApiKeyForProvider(H);if(typeof W==="string"&&W.trim())return{apiKey:W.trim(),source:`model-registry:${H}`}}if(typeof j.getApiKeyAndHeaders!=="function")return;let Y=[],Z=new Set,G=(H)=>{if(!H||typeof H!=="object")return;let W=String(H.provider??"").toLowerCase();if(W!=="openrouter"&&W!=="duckmind")return;let X=String(H.id??H.modelId??""),f=`${W}/${X}`;if(Z.has(f))return;Z.add(f),Y.push(H)};if(G($?.model),typeof j.find==="function")G(j.find("openrouter",I)),G(j.find("openrouter","@preset/free"));if(typeof j.getAvailable==="function")for(let H of j.getAvailable())G(H);for(let H of Y){let W=await j.getApiKeyAndHeaders(H);if(W?.ok&&typeof W.apiKey==="string"&&W.apiKey.trim())return{apiKey:W.apiKey.trim(),source:`model-registry:${H.provider}/${H.id??H.modelId??""}`}}return}async function c$($,j){return await m$(j)??p$($)}function u$($){let j=$?.content;if(typeof j==="string")return j.trim();if(!Array.isArray(j))return"";return j.map((Y)=>{if(!Y||typeof Y!=="object")return"";return typeof Y.text==="string"?Y.text:""}).join("").trim()}function d$($){for(let j of Array.isArray($?.choices)?$.choices:[]){let Y=j?.message;for(let Z of Array.isArray(Y?.images)?Y.images:[]){let G=Z?.image_url,H=typeof G==="string"?G:G?.url??Z?.url;if(typeof H==="string"&&H.trim())return H.trim()}for(let Z of Array.isArray(Y?.content)?Y.content:[]){let G=Z?.image_url,H=typeof G==="string"?G:G?.url??Z?.url;if(typeof H==="string"&&H.trim())return H.trim()}}return""}async function l$({prompt:$,aspectRatio:j,outputFormat:Y,model:Z,outputRoot:G,baseName:H,cwd:W,signal:X,runtimeAuthContext:f}){if(Y!=="png")throw Error("DuckMind image2 currently supports PNG output only.");if(typeof fetch!=="function")throw Error("DuckMind image2 requires a runtime with global fetch support.");let O=await c$(W,f);if(!O?.apiKey)throw Error("Missing DuckMind API key for image2. Set OPENROUTER_API_KEY, paste a DuckMind API key via /login, or provide a local DuckMind/OpenRouter config.");let V={model:Z,modalities:["image","text"],messages:[{role:"user",content:[{type:"text",text:j$($,j)}]}]},z=await fetch(V$,{method:"POST",headers:{Authorization:`Bearer ${O.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(V),signal:X}),B=await z.text(),U;try{U=B?JSON.parse(B):{}}catch{U={}}if(!z.ok){let q=U?.error?.message||U?.message||B.slice(0,400)||z.statusText;throw Error(`OpenRouter image_generation failed (${z.status}): ${q}`)}let K=d$(U);if(!K)throw Error("OpenRouter image_generation returned no image data.");let Q=Y$(K,Y),_=N(G,`${H}.${Q.extension}`);c(_,Q.bytes);let J=U?.choices?.[0]?.message;return{status:"ok",imagePath:_,svgPath:"",imageBase64:Q.bytes.toString("base64"),mimeType:Q.mimeType,prompt:$,aspectRatio:j,model:Z,source:O.source,responseId:typeof U?.id==="string"?U.id:"",revisedPrompt:"",backendMode:"openrouter-image-generation",requestedBackend:"openrouter:image2",authSource:O.source,assistantText:u$(J),openRouterModel:typeof U?.model==="string"?U.model:""}}function n$($){return Array.isArray($)?$.filter((j)=>j&&typeof j==="object"&&j.type==="image_generation_call"):[]}function i$(){let $=$$();return{tokens:{access_token:$.accessToken,account_id:$.accountId}}}function o$($){let j=N($,"auth.json");return m(j,JSON.stringify(i$(),null,2)+`
7
- `),j}function Z$(){let $=[],j=new Set;for(let[Y,Z]of[["env:auth_file",process.env.auth_file],["env:M_AUTH_FILE",process.env.M_AUTH_FILE]]){if(typeof Z!=="string"||!Z.trim())continue;let G=S(Z);if(!w(G)||j.has(G))continue;j.add(G),$.push({kind:"file",authSource:Y,authFile:G})}return $}function G$(){let $=p(e("auth.json"));if(!$||typeof $!=="object")return[];return Object.keys($).filter((j)=>j==="openai-codex"||/^openai-codex-account-\d+$/.test(j)).sort((j,Y)=>{if(j==="openai-codex")return-1;if(Y==="openai-codex")return 1;return j.localeCompare(Y,void 0,{numeric:!0})}).map((j)=>{let Y=$[j],Z=typeof Y?.access==="string"?Y.access:"",G=typeof Y?.accountId==="string"?Y.accountId:typeof Y?.account_id==="string"?Y.account_id:"";if(!Z||!G)return;return{kind:"managed",authSource:`auth.json:${j}`,email:typeof Y?.email==="string"?Y.email:j,authData:{tokens:{access_token:Z,account_id:G}}}}).filter(Boolean)}function r$($,j){let Y=[],Z=new Set,G=(X,f)=>{let O=f?.tokens?.access_token,V=f?.tokens?.account_id;if(typeof O!=="string"||!O.trim())return;if(typeof V!=="string"||!V.trim())return;let z=`inline:${X}:${V}`;if(Z.has(z))return;Z.add(z),Y.push({kind:"managed",authSource:X,email:X,authData:f})},H=(X,f)=>{if(!f)return;let O=S(f);if(!w(O))return;let V=`file:${O}`;if(Z.has(V))return;Z.add(V),Y.push({kind:"file",authSource:X,authFile:O})},W=j?.liveCodexCredentials;if(W?.accessToken&&W?.accountId)G(W.source||"model-registry",{tokens:{access_token:W.accessToken,account_id:W.accountId}});for(let X of Z$())H(X.authSource,X.authFile);for(let X of G$()){let f=`managed:${X.email}`;if(Z.has(f))continue;Z.add(f),Y.push(X)}if(Y.length===0)Y.push({kind:"file",authSource:"dm-auth-shim",authFile:o$($)});return Y}function s$($){let Y=p($)?.tokens,Z=typeof Y?.access_token==="string"?Y.access_token.trim():"",G=typeof Y?.account_id==="string"?Y.account_id.trim():"";if(!Z||!G)return;return{accessToken:Z,accountId:G,email:void 0,source:$}}function a$($){let j=$?.tokens,Y=typeof j?.access_token==="string"?j.access_token.trim():"",Z=typeof j?.account_id==="string"?j.account_id.trim():"";if(!Y||!Z)return;return{accessToken:Y,accountId:Z,email:void 0,source:"managed-inline"}}function t$(){for(let $ of Z$()){let j=s$($.authFile);if(j)return{...j,source:$.authSource}}for(let $ of G$()){let j=a$($.authData);if(j)return{...j,source:$.authSource}}return $$()}function H$($){return String($??"").split(/\r?\n/).map((j)=>j.trim()).filter(Boolean).map((j)=>S(j))}function e$($){if(!w($))return[];return k($,"utf-8").split(/\r?\n/).map((j)=>j.trim()).filter(Boolean).map((j)=>{try{return JSON.parse(j)}catch{return null}}).filter(Boolean)}function $1($){let j=e$($),Y="",Z="";for(let G of j)if(G?.type==="image_generation_call"&&typeof G.saved_path==="string"&&G.saved_path){if(Y=G.saved_path,typeof G.revised_prompt==="string"&&G.revised_prompt)Z=G.revised_prompt}return{savedPath:Y,revisedPrompt:Z}}async function j1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,signal:H,sessionRoot:W,candidate:X,index:f}){let O=N(W,`session-${f}.jsonl`),V=X.authFile;if(X.kind==="managed")V=N(W,`auth-${f}.json`),m(V,JSON.stringify(X.authData,null,2)+`
8
- `);let z={...process.env,PYTHONPATH:a+(process.env.PYTHONPATH?`:${process.env.PYTHONPATH}`:""),auth_file:V,model:Y,quiet:"1",no_session_lock:"1",session:`new:${O}`},B=v;return await new Promise((U,K)=>{let Q=!1,_="",J="",q=Q$("python3",[y,x$($,j)],{cwd:G,env:z,stdio:["ignore","pipe","pipe"]}),T=setTimeout(()=>{q.kill("SIGTERM")},B),M=()=>{q.kill("SIGTERM")};H?.addEventListener("abort",M,{once:!0}),q.stdout.on("data",(L)=>{_+=L.toString("utf-8")}),q.stderr.on("data",(L)=>{J+=L.toString("utf-8")}),q.on("error",(L)=>{if(Q)return;Q=!0,clearTimeout(T),H?.removeEventListener("abort",M),K(L)}),q.on("close",(L,K$)=>{if(Q)return;if(Q=!0,clearTimeout(T),H?.removeEventListener("abort",M),H?.aborted){K(C());return}if(K$==="SIGTERM"){K(Error(`imagen.py timed out after ${Math.round(B/1000)}s`));return}if(L!==0){K(Error(J.trim()||_.trim()||`imagen.py exited ${L}`));return}U({stdout:_,stderr:J,sessionFile:O,sessionRoot:W,authSource:X.authSource})})})}async function Y1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,save:H,saveDir:W,signal:X,runId:f,runtimeAuthContext:O}){if(Z!=="png")throw Error("The bundled imagen.py lane only supports PNG output.");if(!w(y))throw Error(`Bundled imagen.py is missing: ${y}`);let V=y$(G,H,W,f);x(V,{recursive:!0});let z=r$(V,O),B=[];for(let[U,K]of z.entries())try{let Q=await j1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,signal:X,sessionRoot:V,candidate:K,index:U});if(H$(Q.stdout).length>0)return Q;B.push(`${K.authSource}: no saved image path`)}catch(Q){if(b(Q))throw Q;B.push(`${K.authSource}: ${Q instanceof Error?Q.message:String(Q)}`)}throw Error(`imagen.py candidates exhausted: ${B.slice(-5).join(" | ")}`)}function Z1($,j,Y){let Z=S($);if(!w(Z))throw Error(`imagen.py reported a missing artifact: ${Z}`);let G=Z.split(".").pop()||"png",H=N(j,`${Y}.${G}`);return c(H,k(Z)),H}async function G1({prompt:$,aspectRatio:j,outputFormat:Y,model:Z,outputRoot:G,baseName:H,credentials:W,signal:X,imagenError:f,requestedBackend:O}){let V="",z="",B="",U="image/png";try{if(Y==="png"){let J=await l({model:Z,instructions:E$(),input:[{type:"message",role:"user",content:[{type:"input_text",text:j$($,j)}]}],reasoning:{effort:"medium",summary:"detailed"},tools:[{type:"image_generation",output_format:"png"}],tool_choice:"auto",parallel_tool_calls:!1,store:!1,stream:!0,include:["reasoning.encrypted_content"]},W,X),q=n$(J.outputItems);if(q.length>0){let T=q[0],M=Y$(T.result,"png");return z=N(G,`${H}.${M.extension}`),c(z,M.bytes),B=k(z).toString("base64"),{status:"ok",imagePath:z,svgPath:"",imageBase64:B,mimeType:M.mimeType,prompt:$,aspectRatio:j,model:Z,source:W.source,responseId:J.responseId,revisedPrompt:typeof T.revised_prompt==="string"?T.revised_prompt:"",backendMode:"native-image-generation",requestedBackend:O,imagenError:f,assistantText:J.assistantText}}}let{assistantText:K,responseId:Q}=await l({model:Z,instructions:R$(),input:[{type:"message",role:"user",content:[{type:"input_text",text:I$($,j)}]}],reasoning:{effort:"medium",summary:"detailed"},tool_choice:"auto",parallel_tool_calls:!1,store:!1,stream:!0,include:["reasoning.encrypted_content"]},W,X);E(X);let _=A$(K);if(V=N(G,`${H}.svg`),m(V,_),z=V,U="image/svg+xml",Y==="png"){let J=N(G,`${H}.png`);E(X),v$(V,J),E(X),z=J,B=k(J).toString("base64"),U="image/png"}return{status:"ok",imagePath:z,svgPath:V,imageBase64:B,mimeType:U,prompt:$,aspectRatio:j,model:Z,source:W.source,responseId:Q,backendMode:"svg-fallback",requestedBackend:O,imagenError:f,assistantText:K}}catch(K){if(b(K))for(let Q of[z,V]){if(!Q||!w(Q))continue;try{J$(Q)}catch{}}throw K}}async function W$($,j,Y,Z=void 0){let G=String($.prompt??"").trim();if(!G)throw Error("image_generation.prompt is required.");E(Y);let H=g($.aspectRatio),W=h($.outputFormat),X=t($.model),f=P$(j,$.save??"project",$.saveDir);x(f,{recursive:!0});let O=new Date().toISOString().replace(/[:.]/g,"-"),V=D$(G),z=`image-${O}-${V}-${i().slice(0,8)}`;if(M$(X))return await l$({prompt:G,aspectRatio:H,outputFormat:W,model:X,outputRoot:f,baseName:z,cwd:j,signal:Y,runtimeAuthContext:Z});let B=await C$(Z),U=B??t$();try{let K=b$();if(K>0)await T$(K,Y);let Q="",_=L$();if(W==="png"){try{let J=await Y1({prompt:G,aspectRatio:H,model:X,outputFormat:W,cwd:j,save:$.save??"project",saveDir:$.saveDir,signal:Y,runId:z,runtimeAuthContext:B?{liveCodexCredentials:B}:Z}),q=H$(J.stdout);if(q.length>0){let T=$1(J.sessionFile),M=Z1(T.savedPath||q[0],f,z),L=k(M).toString("base64");return{status:"ok",imagePath:M,svgPath:"",imageBase64:L,mimeType:"image/png",prompt:G,aspectRatio:H,model:X,source:U.source,responseId:"",revisedPrompt:T.revisedPrompt||"",backendMode:"imagen-py",requestedBackend:"imagen-py",authSource:J.authSource,assistantText:String(J.stderr??"").trim(),sessionFile:J.sessionFile,imagenSavedPaths:q}}Q=`imagen.py produced no saved image path. stderr=${J.stderr.trim().slice(0,400)}`}catch(J){if(b(J))throw J;Q=J instanceof Error?J.message:String(J)}if(!_)throw Error(`Bundled imagen.py is required for PNG image_generation, but it failed: ${Q}. Provide a healthy DM Codex credential source or set ${s}=1 only for emergency legacy fallback debugging.`)}return await G1({prompt:G,aspectRatio:H,outputFormat:W,model:X,outputRoot:f,baseName:z,credentials:U,signal:Y,imagenError:Q,requestedBackend:"legacy-fallback"})}catch(K){if(b(K))throw K;throw K}}var W1=["project","global","custom"],X1=D.Object({prompt:D.String({description:"Detailed art direction for the image. Include subject, pose, mood, style, background, and any research findings you want preserved."}),aspectRatio:D.Optional(D.String({description:"Target aspect ratio. Supported: 1:1, 4:5, 16:9. Default: 1:1."})),model:D.Optional(D.String({description:"Optional model override. Defaults to DuckMind image2/@preset/image2 on OpenRouter. Use gpt-5.5/openai-codex/gpt-5.5 only for the legacy Codex lane."})),outputFormat:D.Optional(D.String({description:"Artifact format. Supported: png, svg. Default: png."})),save:D.Optional(D.String({description:"Artifact destination: project, global, or custom. Default: project."})),saveDir:D.Optional(D.String({description:"Custom artifact directory when save=custom."}))},{additionalProperties:!1});function f1($){let j=[`Saved image: ${$.imagePath}`];if($.svgPath&&$.svgPath!==$.imagePath)j.push(`SVG source: ${$.svgPath}`);if(j.push(`Model: ${$.model}`),j.push(`Aspect: ${$.aspectRatio}`),$.backendMode)j.push(`Backend: ${$.backendMode}`);if($.source)j.push(`Auth source: ${$.source}`);return j.join(`
9
- `)}function K1($){$.on("session_start",async(j,Y)=>{let Z=H1(),G=typeof Y.modelRegistry?.getProviderAuthStatus==="function"?Y.modelRegistry.getProviderAuthStatus("openrouter"):void 0;if(!(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_KEY||X$(f$(process.cwd(),"config","openrouter.cnf"))||G?.configured)&&!X$(f$(Z,"auth.json")))Y.ui.notify("dm-image2: no DuckMind API key or Codex auth.json account found. image2 can use OPENROUTER_API_KEY, /login, or local config; the legacy Codex lane needs ~/.dm/agent/auth.json.","warning")}),$.registerTool({name:"image_generation",label:"Image Generation",description:"Generate a polished PNG image artifact using DuckMind image2 on OpenRouter by default, or the bundled imagen.py lane from M only when model=gpt-5.5/openai-codex/gpt-5.5. Use this after research for logos, diagrams, posters, portraits, and other image tasks instead of asking the model to dump raw image data inline.",promptSnippet:"Dedicated image-generation lane. Use it for logos, portraits, diagrams, product shots, posters, UI mockups, character sheets, and artifacts you want saved to disk.",promptGuidelines:["Prefer image_generation over raw SVG or markdown image data in the final answer.","Use the bundled image-generation skill's pattern families: product hero, ad storyboard, editorial portrait, poster, character sheet, UI mockup, and comparison exploration.","Do research first when the image must reflect real people, products, or public facts.","Do not call third-party image APIs; route generation through this tool.","Answer with the saved artifact path after the tool succeeds."],parameters:X1,async execute(j,Y,Z,G,H){try{let W=await W$({prompt:Y.prompt,aspectRatio:g(Y.aspectRatio),model:Y.model,outputFormat:h(Y.outputFormat),save:typeof Y.save==="string"&&W1.includes(Y.save)?Y.save:"project",saveDir:typeof Y.saveDir==="string"?Y.saveDir:void 0},H.cwd,Z,{modelRegistry:H.modelRegistry,model:H.model}),X=[{type:"text",text:f1(W)}];if(W.imageBase64&&W.mimeType==="image/png")X.push({type:"image",data:W.imageBase64,mimeType:W.mimeType});return{content:X,details:W}}catch(W){if(Z?.aborted||b(W))throw W;let X=W instanceof Error?W.message:String(W);return{content:[{type:"text",text:`image_generation failed: ${X}`}],details:{status:"error",message:X},isError:!0}}}})}export{K1 as default};
4
+ `)}function A$($){let j=String($??"").trim();if(!j)throw Error("Codex returned an empty image response.");let Y=j.match(/!\[[^\]]*]\((data:image\/svg\+xml[^)]+)\)/i);if(Y?.[1]){let X=Y[1],f=X.indexOf(",");if(f!==-1)return decodeURIComponent(X.slice(f+1)).trim()}let Z=j.match(/data:image\/svg\+xml[^,]*,(.+)$/is);if(Z?.[1])return decodeURIComponent(Z[1]).trim();let H=j.match(/```(?:svg)?\s*([\s\S]*?)```/i)?.[1]?.trim();if(H?.startsWith("<svg"))return H;let W=j.match(/<svg[\s\S]*<\/svg>/i);if(W?.[0])return W[0].trim();throw Error(`Expected SVG markup from Codex, received: ${j.slice(0,240)}`)}async function l($,j,Y){let Z=S$(Y,v),G;try{G=await fetch(V$,{method:"POST",signal:Z.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${j.accessToken}`,Accept:"text/event-stream","Cache-Control":"no-cache",originator:"Codex Desktop","User-Agent":"Codex Desktop/26.212.1823 (darwin; arm64)","ChatGPT-Account-Id":j.accountId},body:JSON.stringify($)})}catch(K){if(Z.cleanup(),b(K)||Z.signal.aborted)throw C();throw K}if(!G.ok){Z.cleanup();let K=await G.text().catch(()=>"");throw Error(`Codex image request failed: HTTP ${G.status} ${K.slice(0,240)}`)}if(!G.body)throw Z.cleanup(),Error("Codex image request returned no response body.");let H=new TextDecoder,W=G.body.getReader(),X="",f=null,V=[],O="",z,B=[],U=()=>{if(!f||V.length===0)return f=null,V=[],!1;let K=JSON.parse(V.join(`
5
+ `));if(f==="response.output_text.delta"&&typeof K.delta==="string")O+=K.delta;if(f==="response.output_item.done"&&K.item&&typeof K.item==="object")B.push(K.item);if(f==="response.completed"||f==="response.done")return z=K.response?.id??z,f=null,V=[],!0;if(f==="response.failed"||f==="response.incomplete"){let Q=K.response?.error?.message||K.response?.incomplete_details?.reason||"Codex image request did not complete.";throw Error(String(Q))}return f=null,V=[],!1};try{while(!0){E(Z.signal);let{value:K,done:Q}=await W.read();X+=H.decode(K??new Uint8Array,{stream:!Q});while(!0){let _=X.indexOf(`
6
+ `);if(_===-1)break;let J=X.slice(0,_);if(X=X.slice(_+1),J.endsWith("\r"))J=J.slice(0,-1);if(!J){if(U())return{assistantText:O.trim(),outputItems:B,responseId:z};continue}if(J.startsWith("event: "))f=J.slice(7).trim();else if(J.startsWith("data: "))V.push(J.slice(6))}if(Q)break}if(V.length>0)U();return{assistantText:O.trim(),outputItems:B,responseId:z}}catch(K){if(await W.cancel().catch(()=>{}),b(K)||Z.signal.aborted)throw C();throw K}finally{Z.cleanup(),W.releaseLock()}}function P$($,j,Y){switch(j){case"global":return S(N(r(),"generated-images"));case"custom":if(!Y||!String(Y).trim())throw Error("save=custom requires saveDir.");return S(String(Y).trim());case"project":default:return S($,".dm","generated-images")}}function y$($,j,Y,Z){let G=Z||`run-${i().slice(0,8)}`;return S("/tmp","dm-imagen-runs",G)}function m($,j){x(A($),{recursive:!0}),o($,j,"utf-8")}function c($,j){x(A($),{recursive:!0}),o($,j)}function v$($,j){let Y=z$("sips",["-s","format","png",$,"--out",j],{encoding:"utf-8"});if(Y.status===0&&w(j))return;let Z=(Y.stderr||Y.stdout||`exit ${Y.status??"unknown"}`).trim();throw Error(`Failed to convert SVG to PNG via sips: ${Z}`)}function Y$($,j="png"){let Y=String($??"").trim();if(!Y)throw Error("image_generation.result is empty");let Z=Y,G="";if(Y.startsWith("data:")){let X=Y.indexOf(",");if(X===-1)throw Error("image_generation.result data URL is malformed");let f=Y.slice(5,X);G=String(f.split(";",1)[0]??"").trim(),Z=Y.slice(X+1)}let H=Buffer.from(Z,"base64");if(!H.length)throw Error("image_generation.result decoded to empty bytes");let W=String(j||"png").trim().toLowerCase().replace(/^\./,"")||"png";if(G==="image/jpeg")W="jpg";else if(G==="image/webp")W="webp";else if(G==="image/gif")W="gif";else if(G==="image/png")W="png";return{bytes:H,mimeType:G||(W==="jpg"?"image/jpeg":`image/${W}`),extension:W}}function g$($){return String($??"").trim().replace(/^['"]|['"]$/g,"")}function h$($){if(!$||!w($))return;try{for(let j of k($,"utf-8").split(/\r?\n/)){let Y=j.trim();if(!Y||Y.startsWith("#")||!Y.includes("="))continue;if(Y.startsWith("export "))Y=Y.slice(7).trim();let[Z,...G]=Y.split("="),H=Z.trim(),W=g$(G.join("="));if((H==="OPENROUTER_API_KEY"||H==="OPENROUTER_KEY")&&W)return{apiKey:W,source:`config:${$}`}}}catch{return}return}function n($){let j=[],Y=S($||process.cwd());while(!0){j.push(N(Y,"config","openrouter.cnf"));let Z=A(Y);if(Z===Y)break;Y=Z}return j}function p$($){let j=process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_KEY;if(j)return{apiKey:j,source:"env:OPENROUTER_API_KEY"};let Y=[...n($),...n(process.cwd()),N(u(),".dm","openrouter.cnf"),N(u(),".config","dm","openrouter.cnf")],Z=new Set;for(let G of Y){if(Z.has(G))continue;Z.add(G);let H=h$(G);if(H)return H}return}async function m$($){let j=$?.modelRegistry;if(!j||typeof j!=="object")return;if(typeof j.getApiKeyForProvider==="function")for(let H of["openrouter","duckmind"]){let W=await j.getApiKeyForProvider(H);if(typeof W==="string"&&W.trim())return{apiKey:W.trim(),source:`model-registry:${H}`}}if(typeof j.getApiKeyAndHeaders!=="function")return;let Y=[],Z=new Set,G=(H)=>{if(!H||typeof H!=="object")return;let W=String(H.provider??"").toLowerCase();if(W!=="openrouter"&&W!=="duckmind")return;let X=String(H.id??H.modelId??""),f=`${W}/${X}`;if(Z.has(f))return;Z.add(f),Y.push(H)};if(G($?.model),typeof j.find==="function")G(j.find("openrouter",I)),G(j.find("openrouter","@preset/free"));if(typeof j.getAvailable==="function")for(let H of j.getAvailable())G(H);for(let H of Y){let W=await j.getApiKeyAndHeaders(H);if(W?.ok&&typeof W.apiKey==="string"&&W.apiKey.trim())return{apiKey:W.apiKey.trim(),source:`model-registry:${H.provider}/${H.id??H.modelId??""}`}}return}async function c$($,j){return await m$(j)??p$($)}function u$($){let j=$?.content;if(typeof j==="string")return j.trim();if(!Array.isArray(j))return"";return j.map((Y)=>{if(!Y||typeof Y!=="object")return"";return typeof Y.text==="string"?Y.text:""}).join("").trim()}function d$($){for(let j of Array.isArray($?.choices)?$.choices:[]){let Y=j?.message;for(let Z of Array.isArray(Y?.images)?Y.images:[]){let G=Z?.image_url,H=typeof G==="string"?G:G?.url??Z?.url;if(typeof H==="string"&&H.trim())return H.trim()}for(let Z of Array.isArray(Y?.content)?Y.content:[]){let G=Z?.image_url,H=typeof G==="string"?G:G?.url??Z?.url;if(typeof H==="string"&&H.trim())return H.trim()}}return""}async function l$({prompt:$,aspectRatio:j,outputFormat:Y,model:Z,outputRoot:G,baseName:H,cwd:W,signal:X,runtimeAuthContext:f}){if(Y!=="png")throw Error("DuckMind image2 currently supports PNG output only.");if(typeof fetch!=="function")throw Error("DuckMind image2 requires a runtime with global fetch support.");let V=await c$(W,f);if(!V?.apiKey)throw Error("Missing DuckMind API key for image2. Set OPENROUTER_API_KEY, paste a DuckMind API key via /login, or provide a local DuckMind image service config.");let O={model:Z,modalities:["image","text"],messages:[{role:"user",content:[{type:"text",text:j$($,j)}]}]},z=await fetch(O$,{method:"POST",headers:{Authorization:`Bearer ${V.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(O),signal:X}),B=await z.text(),U;try{U=B?JSON.parse(B):{}}catch{U={}}if(!z.ok){let q=U?.error?.message||U?.message||B.slice(0,400)||z.statusText;throw Error(`DuckMind image_generation failed (${z.status}): ${q}`)}let K=d$(U);if(!K)throw Error("DuckMind image_generation returned no image data.");let Q=Y$(K,Y),_=N(G,`${H}.${Q.extension}`);c(_,Q.bytes);let J=U?.choices?.[0]?.message;return{status:"ok",imagePath:_,svgPath:"",imageBase64:Q.bytes.toString("base64"),mimeType:Q.mimeType,prompt:$,aspectRatio:j,model:Z,source:V.source,responseId:typeof U?.id==="string"?U.id:"",revisedPrompt:"",backendMode:"openrouter-image-generation",requestedBackend:"openrouter:image2",authSource:V.source,assistantText:u$(J),openRouterModel:typeof U?.model==="string"?U.model:""}}function n$($){return Array.isArray($)?$.filter((j)=>j&&typeof j==="object"&&j.type==="image_generation_call"):[]}function i$(){let $=$$();return{tokens:{access_token:$.accessToken,account_id:$.accountId}}}function o$($){let j=N($,"auth.json");return m(j,JSON.stringify(i$(),null,2)+`
7
+ `),j}function Z$(){let $=[],j=new Set;for(let[Y,Z]of[["env:auth_file",process.env.auth_file],["env:M_AUTH_FILE",process.env.M_AUTH_FILE]]){if(typeof Z!=="string"||!Z.trim())continue;let G=S(Z);if(!w(G)||j.has(G))continue;j.add(G),$.push({kind:"file",authSource:Y,authFile:G})}return $}function G$(){let $=p(e("auth.json"));if(!$||typeof $!=="object")return[];return Object.keys($).filter((j)=>j==="openai-codex"||/^openai-codex-account-\d+$/.test(j)).sort((j,Y)=>{if(j==="openai-codex")return-1;if(Y==="openai-codex")return 1;return j.localeCompare(Y,void 0,{numeric:!0})}).map((j)=>{let Y=$[j],Z=typeof Y?.access==="string"?Y.access:"",G=typeof Y?.accountId==="string"?Y.accountId:typeof Y?.account_id==="string"?Y.account_id:"";if(!Z||!G)return;return{kind:"managed",authSource:`auth.json:${j}`,email:typeof Y?.email==="string"?Y.email:j,authData:{tokens:{access_token:Z,account_id:G}}}}).filter(Boolean)}function r$($,j){let Y=[],Z=new Set,G=(X,f)=>{let V=f?.tokens?.access_token,O=f?.tokens?.account_id;if(typeof V!=="string"||!V.trim())return;if(typeof O!=="string"||!O.trim())return;let z=`inline:${X}:${O}`;if(Z.has(z))return;Z.add(z),Y.push({kind:"managed",authSource:X,email:X,authData:f})},H=(X,f)=>{if(!f)return;let V=S(f);if(!w(V))return;let O=`file:${V}`;if(Z.has(O))return;Z.add(O),Y.push({kind:"file",authSource:X,authFile:V})},W=j?.liveCodexCredentials;if(W?.accessToken&&W?.accountId)G(W.source||"model-registry",{tokens:{access_token:W.accessToken,account_id:W.accountId}});for(let X of Z$())H(X.authSource,X.authFile);for(let X of G$()){let f=`managed:${X.email}`;if(Z.has(f))continue;Z.add(f),Y.push(X)}if(Y.length===0)Y.push({kind:"file",authSource:"dm-auth-shim",authFile:o$($)});return Y}function s$($){let Y=p($)?.tokens,Z=typeof Y?.access_token==="string"?Y.access_token.trim():"",G=typeof Y?.account_id==="string"?Y.account_id.trim():"";if(!Z||!G)return;return{accessToken:Z,accountId:G,email:void 0,source:$}}function a$($){let j=$?.tokens,Y=typeof j?.access_token==="string"?j.access_token.trim():"",Z=typeof j?.account_id==="string"?j.account_id.trim():"";if(!Y||!Z)return;return{accessToken:Y,accountId:Z,email:void 0,source:"managed-inline"}}function t$(){for(let $ of Z$()){let j=s$($.authFile);if(j)return{...j,source:$.authSource}}for(let $ of G$()){let j=a$($.authData);if(j)return{...j,source:$.authSource}}return $$()}function H$($){return String($??"").split(/\r?\n/).map((j)=>j.trim()).filter(Boolean).map((j)=>S(j))}function e$($){if(!w($))return[];return k($,"utf-8").split(/\r?\n/).map((j)=>j.trim()).filter(Boolean).map((j)=>{try{return JSON.parse(j)}catch{return null}}).filter(Boolean)}function $1($){let j=e$($),Y="",Z="";for(let G of j)if(G?.type==="image_generation_call"&&typeof G.saved_path==="string"&&G.saved_path){if(Y=G.saved_path,typeof G.revised_prompt==="string"&&G.revised_prompt)Z=G.revised_prompt}return{savedPath:Y,revisedPrompt:Z}}async function j1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,signal:H,sessionRoot:W,candidate:X,index:f}){let V=N(W,`session-${f}.jsonl`),O=X.authFile;if(X.kind==="managed")O=N(W,`auth-${f}.json`),m(O,JSON.stringify(X.authData,null,2)+`
8
+ `);let z={...process.env,PYTHONPATH:a+(process.env.PYTHONPATH?`:${process.env.PYTHONPATH}`:""),auth_file:O,model:Y,quiet:"1",no_session_lock:"1",session:`new:${V}`},B=v;return await new Promise((U,K)=>{let Q=!1,_="",J="",q=Q$("python3",[y,x$($,j)],{cwd:G,env:z,stdio:["ignore","pipe","pipe"]}),T=setTimeout(()=>{q.kill("SIGTERM")},B),M=()=>{q.kill("SIGTERM")};H?.addEventListener("abort",M,{once:!0}),q.stdout.on("data",(L)=>{_+=L.toString("utf-8")}),q.stderr.on("data",(L)=>{J+=L.toString("utf-8")}),q.on("error",(L)=>{if(Q)return;Q=!0,clearTimeout(T),H?.removeEventListener("abort",M),K(L)}),q.on("close",(L,K$)=>{if(Q)return;if(Q=!0,clearTimeout(T),H?.removeEventListener("abort",M),H?.aborted){K(C());return}if(K$==="SIGTERM"){K(Error(`imagen.py timed out after ${Math.round(B/1000)}s`));return}if(L!==0){K(Error(J.trim()||_.trim()||`imagen.py exited ${L}`));return}U({stdout:_,stderr:J,sessionFile:V,sessionRoot:W,authSource:X.authSource})})})}async function Y1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,save:H,saveDir:W,signal:X,runId:f,runtimeAuthContext:V}){if(Z!=="png")throw Error("The bundled imagen.py lane only supports PNG output.");if(!w(y))throw Error(`Bundled imagen.py is missing: ${y}`);let O=y$(G,H,W,f);x(O,{recursive:!0});let z=r$(O,V),B=[];for(let[U,K]of z.entries())try{let Q=await j1({prompt:$,aspectRatio:j,model:Y,outputFormat:Z,cwd:G,signal:X,sessionRoot:O,candidate:K,index:U});if(H$(Q.stdout).length>0)return Q;B.push(`${K.authSource}: no saved image path`)}catch(Q){if(b(Q))throw Q;B.push(`${K.authSource}: ${Q instanceof Error?Q.message:String(Q)}`)}throw Error(`imagen.py candidates exhausted: ${B.slice(-5).join(" | ")}`)}function Z1($,j,Y){let Z=S($);if(!w(Z))throw Error(`imagen.py reported a missing artifact: ${Z}`);let G=Z.split(".").pop()||"png",H=N(j,`${Y}.${G}`);return c(H,k(Z)),H}async function G1({prompt:$,aspectRatio:j,outputFormat:Y,model:Z,outputRoot:G,baseName:H,credentials:W,signal:X,imagenError:f,requestedBackend:V}){let O="",z="",B="",U="image/png";try{if(Y==="png"){let J=await l({model:Z,instructions:E$(),input:[{type:"message",role:"user",content:[{type:"input_text",text:j$($,j)}]}],reasoning:{effort:"medium",summary:"detailed"},tools:[{type:"image_generation",output_format:"png"}],tool_choice:"auto",parallel_tool_calls:!1,store:!1,stream:!0,include:["reasoning.encrypted_content"]},W,X),q=n$(J.outputItems);if(q.length>0){let T=q[0],M=Y$(T.result,"png");return z=N(G,`${H}.${M.extension}`),c(z,M.bytes),B=k(z).toString("base64"),{status:"ok",imagePath:z,svgPath:"",imageBase64:B,mimeType:M.mimeType,prompt:$,aspectRatio:j,model:Z,source:W.source,responseId:J.responseId,revisedPrompt:typeof T.revised_prompt==="string"?T.revised_prompt:"",backendMode:"native-image-generation",requestedBackend:V,imagenError:f,assistantText:J.assistantText}}}let{assistantText:K,responseId:Q}=await l({model:Z,instructions:R$(),input:[{type:"message",role:"user",content:[{type:"input_text",text:I$($,j)}]}],reasoning:{effort:"medium",summary:"detailed"},tool_choice:"auto",parallel_tool_calls:!1,store:!1,stream:!0,include:["reasoning.encrypted_content"]},W,X);E(X);let _=A$(K);if(O=N(G,`${H}.svg`),m(O,_),z=O,U="image/svg+xml",Y==="png"){let J=N(G,`${H}.png`);E(X),v$(O,J),E(X),z=J,B=k(J).toString("base64"),U="image/png"}return{status:"ok",imagePath:z,svgPath:O,imageBase64:B,mimeType:U,prompt:$,aspectRatio:j,model:Z,source:W.source,responseId:Q,backendMode:"svg-fallback",requestedBackend:V,imagenError:f,assistantText:K}}catch(K){if(b(K))for(let Q of[z,O]){if(!Q||!w(Q))continue;try{J$(Q)}catch{}}throw K}}async function W$($,j,Y,Z=void 0){let G=String($.prompt??"").trim();if(!G)throw Error("image_generation.prompt is required.");E(Y);let H=g($.aspectRatio),W=h($.outputFormat),X=t($.model),f=P$(j,$.save??"project",$.saveDir);x(f,{recursive:!0});let V=new Date().toISOString().replace(/[:.]/g,"-"),O=D$(G),z=`image-${V}-${O}-${i().slice(0,8)}`;if(M$(X))return await l$({prompt:G,aspectRatio:H,outputFormat:W,model:X,outputRoot:f,baseName:z,cwd:j,signal:Y,runtimeAuthContext:Z});let B=await C$(Z),U=B??t$();try{let K=b$();if(K>0)await T$(K,Y);let Q="",_=L$();if(W==="png"){try{let J=await Y1({prompt:G,aspectRatio:H,model:X,outputFormat:W,cwd:j,save:$.save??"project",saveDir:$.saveDir,signal:Y,runId:z,runtimeAuthContext:B?{liveCodexCredentials:B}:Z}),q=H$(J.stdout);if(q.length>0){let T=$1(J.sessionFile),M=Z1(T.savedPath||q[0],f,z),L=k(M).toString("base64");return{status:"ok",imagePath:M,svgPath:"",imageBase64:L,mimeType:"image/png",prompt:G,aspectRatio:H,model:X,source:U.source,responseId:"",revisedPrompt:T.revisedPrompt||"",backendMode:"imagen-py",requestedBackend:"imagen-py",authSource:J.authSource,assistantText:String(J.stderr??"").trim(),sessionFile:J.sessionFile,imagenSavedPaths:q}}Q=`imagen.py produced no saved image path. stderr=${J.stderr.trim().slice(0,400)}`}catch(J){if(b(J))throw J;Q=J instanceof Error?J.message:String(J)}if(!_)throw Error(`Bundled imagen.py is required for PNG image_generation, but it failed: ${Q}. Provide a healthy DM Codex credential source or set ${s}=1 only for emergency legacy fallback debugging.`)}return await G1({prompt:G,aspectRatio:H,outputFormat:W,model:X,outputRoot:f,baseName:z,credentials:U,signal:Y,imagenError:Q,requestedBackend:"legacy-fallback"})}catch(K){if(b(K))throw K;throw K}}var W1=["project","global","custom"],X1=D.Object({prompt:D.String({description:"Detailed art direction for the image. Include subject, pose, mood, style, background, and any research findings you want preserved."}),aspectRatio:D.Optional(D.String({description:"Target aspect ratio. Supported: 1:1, 4:5, 16:9. Default: 1:1."})),model:D.Optional(D.String({description:"Optional model override. Defaults to DuckMind image2/@preset/image2. Use gpt-5.5/openai-codex/gpt-5.5 only for the legacy Codex lane."})),outputFormat:D.Optional(D.String({description:"Artifact format. Supported: png, svg. Default: png."})),save:D.Optional(D.String({description:"Artifact destination: project, global, or custom. Default: project."})),saveDir:D.Optional(D.String({description:"Custom artifact directory when save=custom."}))},{additionalProperties:!1});function f1($){let j=[`Saved image: ${$.imagePath}`];if($.svgPath&&$.svgPath!==$.imagePath)j.push(`SVG source: ${$.svgPath}`);if(j.push(`Model: ${$.model}`),j.push(`Aspect: ${$.aspectRatio}`),$.backendMode)j.push(`Backend: ${$.backendMode}`);if($.source)j.push(`Auth source: ${$.source}`);return j.join(`
9
+ `)}function K1($){$.on("session_start",async(j,Y)=>{let Z=H1(),G=typeof Y.modelRegistry?.getProviderAuthStatus==="function"?Y.modelRegistry.getProviderAuthStatus("openrouter"):void 0;if(!(process.env.OPENROUTER_API_KEY||process.env.OPENROUTER_KEY||X$(f$(process.cwd(),"config","openrouter.cnf"))||G?.configured)&&!X$(f$(Z,"auth.json")))Y.ui.notify("dm-image2: no DuckMind API key or Codex auth.json account found. image2 can use OPENROUTER_API_KEY, /login, or local config; the legacy Codex lane needs ~/.dm/agent/auth.json.","warning")}),$.registerTool({name:"image_generation",label:"Image Generation",description:"Generate a polished PNG image artifact using DuckMind image2 by default, or the bundled imagen.py lane from M only when model=gpt-5.5/openai-codex/gpt-5.5. Use this after research for logos, diagrams, posters, portraits, and other image tasks instead of asking the model to dump raw image data inline.",promptSnippet:"Dedicated image-generation lane. Use it for logos, portraits, diagrams, product shots, posters, UI mockups, character sheets, and artifacts you want saved to disk.",promptGuidelines:["Prefer image_generation over raw SVG or markdown image data in the final answer.","Use the bundled image-generation skill's pattern families: product hero, ad storyboard, editorial portrait, poster, character sheet, UI mockup, and comparison exploration.","Do research first when the image must reflect real people, products, or public facts.","Do not call third-party image APIs; route generation through this tool.","Answer with the saved artifact path after the tool succeeds."],parameters:X1,async execute(j,Y,Z,G,H){try{let W=await W$({prompt:Y.prompt,aspectRatio:g(Y.aspectRatio),model:Y.model,outputFormat:h(Y.outputFormat),save:typeof Y.save==="string"&&W1.includes(Y.save)?Y.save:"project",saveDir:typeof Y.saveDir==="string"?Y.saveDir:void 0},H.cwd,Z,{modelRegistry:H.modelRegistry,model:H.model}),X=[{type:"text",text:f1(W)}];if(W.imageBase64&&W.mimeType==="image/png")X.push({type:"image",data:W.imageBase64,mimeType:W.mimeType});return{content:X,details:W}}catch(W){if(Z?.aborted||b(W))throw W;let X=W instanceof Error?W.message:String(W);return{content:[{type:"text",text:`image_generation failed: ${X}`}],details:{status:"error",message:X},isError:!0}}}})}export{K1 as default};