@duckmind/dm-darwin-x64 0.49.8 → 0.49.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.
- package/dm +0 -0
- package/extensions/.dm-extensions.json +44 -15
- package/extensions/dm-cliproxy/NOTICE.md +12 -0
- package/extensions/dm-cliproxy/index.js +2 -0
- package/extensions/dm-cliproxy/package.json +20 -0
- package/extensions/dm-cliproxy/scripts/check-config-migration.js +10 -0
- package/extensions/dm-cliproxy/src/apply.js +1 -0
- package/extensions/dm-cliproxy/src/cache.js +1 -0
- package/extensions/dm-cliproxy/src/commands.js +2 -0
- package/extensions/dm-cliproxy/src/compat.js +1 -0
- package/extensions/dm-cliproxy/src/config.js +2 -0
- package/extensions/dm-cliproxy/src/conflicts.js +1 -0
- package/extensions/dm-cliproxy/src/fetch-models.js +1 -0
- package/extensions/dm-cliproxy/src/fetch-usage.js +1 -0
- package/extensions/dm-cliproxy/src/log.js +1 -0
- package/extensions/dm-cliproxy/src/status-quota.js +1 -0
- package/extensions/dm-cliproxy/src/ui-frame.js +1 -0
- package/extensions/dm-cliproxy/src/ui-hub/hub.js +2 -0
- package/extensions/dm-cliproxy/src/ui-hub/index.js +2 -0
- package/extensions/dm-cliproxy/src/ui-hub/shell.js +1 -0
- package/extensions/dm-cliproxy/src/ui-hub/types.js +0 -0
- package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +1 -0
- package/extensions/dm-cliproxy/src/ui-hub/view-models.js +1 -0
- package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/catalog.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/mutate.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/providers.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/render-text.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/rows.js +1 -0
- package/extensions/dm-cliproxy/src/ui-picker/types.js +0 -0
- package/extensions/dm-cliproxy/src/ui-setup.js +2 -0
- package/extensions/dm-cliproxy/src/ui-usage.js +1 -0
- package/extensions/dm-cliproxy/src/usage-shared-cache.js +1 -0
- package/extensions/dm-subagents/src/extension/doctor.js +10 -10
- package/extensions/dm-subagents/src/extension/fanout-child.js +129 -129
- package/extensions/dm-subagents/src/extension/index.js +179 -179
- package/extensions/dm-subagents/src/extension/rpc.js +5 -5
- package/extensions/dm-subagents/src/extension/schemas.js +1 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +2 -2
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -5
- package/extensions/dm-subagents/src/runs/background/async-execution.js +19 -19
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +10 -10
- package/extensions/dm-subagents/src/runs/background/async-resume.js +5 -5
- package/extensions/dm-subagents/src/runs/background/async-status.js +8 -8
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +14 -14
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +5 -5
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +3 -3
- package/extensions/dm-subagents/src/runs/background/run-status.js +20 -20
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +7 -7
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +38 -38
- package/extensions/dm-subagents/src/runs/background/wait.js +7 -7
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +58 -58
- package/extensions/dm-subagents/src/runs/foreground/execution.js +36 -36
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +129 -129
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +6 -6
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -13
- package/package.json +1 -1
- package/extensions/dm-9router-ext/package.json +0 -23
- package/extensions/dm-9router-ext/src/index.js +0 -5
package/dm
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"status": "ok",
|
|
3
|
-
"prepared_at": "2026-07-
|
|
3
|
+
"prepared_at": "2026-07-12T11:45:43.264428+00:00",
|
|
4
4
|
"managed_entries": [
|
|
5
5
|
{
|
|
6
6
|
"id": "dm-context",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"bundle_mode": "source-package"
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
|
-
"id": "dm-
|
|
47
|
-
"target_dir": "extensions/dm-
|
|
46
|
+
"id": "dm-cliproxy",
|
|
47
|
+
"target_dir": "extensions/dm-cliproxy",
|
|
48
48
|
"bundle_mode": "source-package-with-runtime-deps"
|
|
49
49
|
},
|
|
50
50
|
{
|
|
@@ -237,8 +237,8 @@
|
|
|
237
237
|
"src/tui/render.js"
|
|
238
238
|
],
|
|
239
239
|
"file_count": 93,
|
|
240
|
-
"before_bytes":
|
|
241
|
-
"after_bytes":
|
|
240
|
+
"before_bytes": 1544913,
|
|
241
|
+
"after_bytes": 3104479,
|
|
242
242
|
"externals": [
|
|
243
243
|
"@duckmind/dm-agent-core",
|
|
244
244
|
"@duckmind/dm-ai",
|
|
@@ -563,20 +563,21 @@
|
|
|
563
563
|
}
|
|
564
564
|
},
|
|
565
565
|
{
|
|
566
|
-
"id": "dm-
|
|
567
|
-
"staged_dir": "extensions/dm-
|
|
566
|
+
"id": "dm-cliproxy",
|
|
567
|
+
"staged_dir": "extensions/dm-cliproxy",
|
|
568
568
|
"bundle_mode": "source-package-with-runtime-deps",
|
|
569
569
|
"dependencies_installed": false,
|
|
570
570
|
"dependency_mode": "platform-package-dependency",
|
|
571
571
|
"dependencies_declared": [
|
|
572
|
+
"@duckmind/dm-ai",
|
|
572
573
|
"@duckmind/dm-coding-agent",
|
|
573
|
-
"
|
|
574
|
+
"@duckmind/dm-tui"
|
|
574
575
|
],
|
|
575
576
|
"dependency_patches": [
|
|
576
577
|
"dm.extensions ts->js",
|
|
577
|
-
"main ts->js",
|
|
578
578
|
"drop-devDependencies",
|
|
579
579
|
"drop-peerDependencies",
|
|
580
|
+
"drop-repository",
|
|
580
581
|
"drop-scripts",
|
|
581
582
|
"drop-files"
|
|
582
583
|
],
|
|
@@ -586,18 +587,46 @@
|
|
|
586
587
|
"javascript_bundle_minify": {
|
|
587
588
|
"tool": "bun build --minify",
|
|
588
589
|
"files": [
|
|
589
|
-
"
|
|
590
|
+
"index.js",
|
|
591
|
+
"scripts/check-config-migration.js",
|
|
592
|
+
"src/apply.js",
|
|
593
|
+
"src/cache.js",
|
|
594
|
+
"src/commands.js",
|
|
595
|
+
"src/compat.js",
|
|
596
|
+
"src/config.js",
|
|
597
|
+
"src/conflicts.js",
|
|
598
|
+
"src/fetch-models.js",
|
|
599
|
+
"src/fetch-usage.js",
|
|
600
|
+
"src/log.js",
|
|
601
|
+
"src/status-quota.js",
|
|
602
|
+
"src/ui-frame.js",
|
|
603
|
+
"src/ui-hub/hub.js",
|
|
604
|
+
"src/ui-hub/index.js",
|
|
605
|
+
"src/ui-hub/shell.js",
|
|
606
|
+
"src/ui-hub/types.js",
|
|
607
|
+
"src/ui-hub/view-diagnostics.js",
|
|
608
|
+
"src/ui-hub/view-models.js",
|
|
609
|
+
"src/ui-hub/view-usage.js",
|
|
610
|
+
"src/ui-picker/catalog.js",
|
|
611
|
+
"src/ui-picker/mutate.js",
|
|
612
|
+
"src/ui-picker/prompt-confirm.js",
|
|
613
|
+
"src/ui-picker/prompt-name.js",
|
|
614
|
+
"src/ui-picker/providers.js",
|
|
615
|
+
"src/ui-picker/render-text.js",
|
|
616
|
+
"src/ui-picker/rows.js",
|
|
617
|
+
"src/ui-picker/types.js",
|
|
618
|
+
"src/ui-setup.js",
|
|
619
|
+
"src/ui-usage.js",
|
|
620
|
+
"src/usage-shared-cache.js"
|
|
590
621
|
],
|
|
591
|
-
"file_count":
|
|
592
|
-
"before_bytes":
|
|
593
|
-
"after_bytes":
|
|
622
|
+
"file_count": 31,
|
|
623
|
+
"before_bytes": 127821,
|
|
624
|
+
"after_bytes": 239481,
|
|
594
625
|
"externals": [
|
|
595
626
|
"@duckmind/dm-agent-core",
|
|
596
627
|
"@duckmind/dm-ai",
|
|
597
628
|
"@duckmind/dm-coding-agent",
|
|
598
629
|
"@duckmind/dm-tui",
|
|
599
|
-
"@types/node",
|
|
600
|
-
"typebox",
|
|
601
630
|
"typescript"
|
|
602
631
|
]
|
|
603
632
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# dm-cliproxy provenance notice
|
|
2
|
+
|
|
3
|
+
- Upstream technical source: `https://github.com/abix5/pi-cliproxyapi.git`
|
|
4
|
+
- Pinned revision: `b0ce7712f95eab9035b85dfa05aee0352b40c546`
|
|
5
|
+
- Upstream tag at review time: `v0.3.5`
|
|
6
|
+
- Upstream package metadata declares the MIT license. The pinned tree does not
|
|
7
|
+
contain a standalone license file, so this notice preserves that limitation
|
|
8
|
+
instead of inventing license text.
|
|
9
|
+
|
|
10
|
+
Allowed technical compatibility strings in the DM adaptation are limited to
|
|
11
|
+
the upstream URL/name, the `/.well-known/pi` discovery route, and legacy config
|
|
12
|
+
paths used by copy-only migration.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{getModels as j1}from"@duckmind/dm-ai/compat";var l$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function c$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function N0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Kj=128000,Pj=16000,Sj={input:0,output:0,cacheRead:0,cacheWrite:0},bj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function A$($){return bj.some((j)=>j.test($))}var nj=[[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 T$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function O0($,j){let J=(j??"").trim(),X=$.match(/^([a-z0-9]+-)(.*)$/);if(X)return J?`${J}-${X[1]}`:X[1];return $}function H0($,j){for(let[J,X,Z]of nj)if(J.has($))return{slug:T$(j,X),api:Z};return{slug:T$(j,"misc"),api:"openai-completions"}}function xj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function Y$($){return{id:$,name:xj($),contextWindow:Kj,maxTokens:Pj,reasoning:A$($),cost:{...Sj}}}import{execSync as wj}from"node:child_process";import{randomUUID as k0}from"node:crypto";import{chmodSync as L$,constants as yj,copyFileSync as U0,existsSync as F$,linkSync as Cj,mkdirSync as B0,readFileSync as vj,rmSync as r$,writeFileSync as uj}from"node:fs";import{homedir as s$}from"node:os";import{dirname as E$,join as G$}from"node:path";import{fileURLToPath as fj}from"node:url";var R$=!1;function i$($){R$=$}var O={info(...$){if(!R$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!R$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!R$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!R$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var t=G$(s$(),".dm","agent","dm-cliproxy"),C=G$(t,"config.json"),gj=[G$(s$(),".pi","agent","pi-cliproxyapi","config.json"),G$(s$(),".config","pi-cliproxyapi","config.json")];function hj(){return F$(G$(E$(fj(import.meta.url)),"..",".git"))}function pj($=gj,j=C,J=hj()){if(F$(j))return;let Z=(typeof $==="string"?[$]:[...$]).find((q)=>F$(q));if(!Z)return;let z;try{B0(E$(j),{recursive:!0,mode:448}),L$(E$(j),448),z=`${j}.${process.pid}.${k0()}.tmp`,U0(Z,z,yj.COPYFILE_EXCL),L$(z,384),Cj(z,j),r$(z),z=void 0,O.info("legacy config copied to",j)}catch(q){if(z)try{r$(z,{force:!0})}catch(Y){O.warn("failed to clean temporary config:",Y)}O.warn("failed to migrate legacy config:",q)}}var I$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function h(){if(pj(),!F$(C))return O.debug("config not found, using defaults at",C),structuredClone(I$);try{let $=JSON.parse(vj(C,"utf8"));return mj($)}catch($){return O.error("failed to read config:",$,"— using defaults"),structuredClone(I$)}}function K$($){B0(E$(C),{recursive:!0,mode:448}),L$(E$(C),448);let j=`${C}.${process.pid}.${k0()}.tmp`;try{uj(j,JSON.stringify($,null,2)+`
|
|
2
|
+
`,{encoding:"utf8",flag:"wx",mode:384}),U0(j,C),L$(C,384)}finally{r$(j,{force:!0})}O.info("config saved to",C)}function mj($){if(!$||typeof $!=="object")return structuredClone(I$);let j=$,J=structuredClone(I$),X=j.proxy??{};if(J.proxy.endpoint=typeof X.endpoint==="string"?X.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof X.apiKey==="string"?X.apiKey:"",typeof X.usageKey==="string")J.proxy.usageKey=X.usageKey;if(typeof X.providerPrefix==="string"&&X.providerPrefix.trim())J.proxy.providerPrefix=X.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 P($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return wj(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let X=J?.stderr?.toString?.()?.trim()??J.message;return O.warn(`failed to resolve "!" config value (${j}): ${X}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{chmodSync as lj,existsSync as cj,mkdirSync as ij,readFileSync as rj,writeFileSync as sj}from"node:fs";import{dirname as _0,join as oj}from"node:path";var W$=oj(t,"discovery-cache.json");function T0(){if(!cj(W$))return null;try{let $=JSON.parse(rj(W$,"utf8"));if(!$||typeof $.savedAt!=="number"||!$.discovery||!Array.isArray($.discovery.builtinProviders)||!Array.isArray($.discovery.customPool))return null;return{discovery:$.discovery,ageMs:Date.now()-$.savedAt}}catch($){return O.warn("failed to read discovery cache:",$.message),null}}function o$($){try{ij(_0(W$),{recursive:!0,mode:448}),lj(_0(W$),448);let j={savedAt:Date.now(),discovery:$};sj(W$,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){O.warn("failed to write discovery cache:",j.message)}}var q$="dm-cliproxy/0.3.5",dj=5000;async function F0($,j){let J=new AbortController,X=setTimeout(()=>J.abort(Error("timeout")),dj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(X)}}function tj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function aj($){let j=tj($.proxy.endpoint),J;try{J=await F0(j,{headers:{"User-Agent":q$,Accept:"application/json"}})}catch(Y){return O.warn("well-known fetch failed:",Y.message,"— falling back to /v1/models"),null}if(!J.ok)return O.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let X;try{X=await J.json()}catch{return O.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!X||X.schemaVersion!==1)return O.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Z=[],z=X.builtinProviders??{};for(let[Y,V]of Object.entries(z)){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??A$(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:Y,api:V.api??"openai-responses",models:Q})}let q=(Array.isArray(X.customModelPool)?X.customModelPool:[]).map((Y)=>({id:String(Y.id),name:typeof Y.name==="string"?Y.name:String(Y.id),reasoning:Boolean(Y.reasoning??A$(String(Y.id))),contextWindow:typeof Y.contextWindow==="number"?Y.contextWindow:128000,maxTokens:typeof Y.maxTokens==="number"?Y.maxTokens:16000,cost:Y.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Y.api??"openai-completions",suggestedProvider:O0(typeof Y.suggestedProviderName==="string"?Y.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof Y.owned_by==="string"?Y.owned_by:""}));return{source:"well-known",upstreamVersion:typeof X?.upstream?.upstreamVersion==="string"?X.upstream.upstreamVersion:null,builtinProviders:Z,customPool:q,serverDiscoveryExcludes:Array.isArray(X.discoveryExcludes)?X.discoveryExcludes.filter((Y)=>typeof Y==="string"):[],upstreamTotal:typeof X?.counts?.upstreamTotal==="number"?X.counts.upstreamTotal:0}}async function ej($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),X=await F0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":q$}});if(!X.ok)throw Error(`/v1/models returned ${X.status}`);let Z=await X.json();if(!Z?.data||!Array.isArray(Z.data))return[];return Z.data.map((z)=>({id:typeof z.id==="string"?z.id:"",owned_by:typeof z.owned_by==="string"?z.owned_by:""})).filter((z)=>z.id)}function $1($,j){let J=j.discoveryExcludes,X=new Map,Z=[],z=0;for(let q of $){if(z++,N0(q.id,J))continue;if(q.owned_by==="openai"){let D=Y$(q.id);A0(X,"openai","openai-responses",L0(D));continue}if(q.owned_by==="anthropic"){let D=Y$(q.id);A0(X,"anthropic","anthropic-messages",L0(D));continue}let{slug:Y,api:V}=H0(q.owned_by,j.proxy.providerPrefix),Q=Y$(q.id);Z.push({id:q.id,name:Q.name??q.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:Y,ownedBy:q.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(X.values()),customPool:Z,serverDiscoveryExcludes:[],upstreamTotal:z}}function A0($,j,J,X){let Z=$.get(j);if(!Z)Z={name:j,api:J,models:[]},$.set(j,Z);Z.models.push(X)}function L0($){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 i($,j){let J=await aj($);if(J)return O.info(`discovery via /.well-known/pi: ${J.builtinProviders.length} builtin, ${J.customPool.length} custom`),o$(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 X=await ej($,j),Z=$1(X,$);return O.info(`discovery via /v1/models: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),o$(Z),Z}function I0($){let j=new Set;for(let J of $.builtinProviders)for(let X of J.models)j.add(X.id);for(let J of $.customPool)j.add(J.id);return j}async function m($,j,J){let X={registered:[],skipped:[]},Z=I0(J),z=P(j.proxy.apiKey);if(!z)return O.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),X;let q=new Map;for(let V of J.builtinProviders)q.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){X.skipped.push({provider:V,reason:"disabled"});continue}if(!Array.isArray(Q.models)||Q.models.length===0){X.skipped.push({provider:V,reason:"empty whitelist"});continue}let D=[];try{D=j1(V)}catch{}let E=new Map(D.map((k)=>[k.id,k])),K=new Map((q.get(V)??[]).map((k)=>[k.id,k])),H=[];for(let k of Q.models){if(!Z.has(k))continue;let _=E.get(k),b=K.get(k);if(_){H.push({id:_.id,name:_.name,reasoning:_.reasoning,contextWindow:_.contextWindow,maxTokens:_.maxTokens,cost:_.cost,input:_.input,api:_.api,thinkingLevelMap:_.thinkingLevelMap});continue}if(!b)continue;let l=V==="anthropic"?"anthropic-messages":Q.apiOverride??"openai-responses";H.push({id:b.id,name:b.name,reasoning:b.reasoning,contextWindow:b.contextWindow,maxTokens:b.maxTokens,cost:b.cost,input:["text"],api:l})}if(H.length===0){X.skipped.push({provider:V,reason:"no whitelisted models present on proxy"});continue}let N=Q.apiOverride??H[0].api;if(!l$.has(N)){X.skipped.push({provider:V,reason:`api "${N}" not in allowlist`});continue}let R=H.map((k)=>{let _=j.overrides[k.id]??{},b={id:k.id,name:typeof _.name==="string"?_.name:k.name,api:N,reasoning:typeof _.reasoning==="boolean"?_.reasoning:k.reasoning,input:k.input,cost:_.cost??k.cost,contextWindow:typeof _.contextWindow==="number"?_.contextWindow:k.contextWindow,maxTokens:typeof _.maxTokens==="number"?_.maxTokens:k.maxTokens};if(k.thinkingLevelMap)b.thinkingLevelMap=k.thinkingLevelMap;return b}),B={name:V,baseUrl:c$(N,j.proxy.endpoint),apiKey:z,authHeader:!0,api:N,models:R};$.registerProvider(V,B),X.registered.push({provider:V,modelCount:R.length,api:N})}let Y=new Map(J.customPool.map((V)=>[V.id,V]));for(let[V,Q]of Object.entries(j.customProviders)){if(!l$.has(Q.api)){X.skipped.push({provider:V,reason:`api "${Q.api}" not in allowlist`});continue}let D=Q.models.filter((H)=>Z.has(H.id));if(D.length===0){X.skipped.push({provider:V,reason:"no configured models present on proxy"});continue}let E=D.map((H)=>{let N=Y.get(H.id),R=Y$(H.id),B=j.overrides[H.id]??{};return{id:H.id,name:H.name??N?.name??R.name??H.id,api:Q.api,reasoning:J1(H.reasoning,N?.reasoning,R.reasoning,B.reasoning)??!1,input:["text"],cost:H.cost??N?.cost??R.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:K0(H.contextWindow,N?.contextWindow,R.contextWindow,B.contextWindow)??128000,maxTokens:K0(H.maxTokens,N?.maxTokens,R.maxTokens,B.maxTokens)??16000}}),K={name:V,baseUrl:c$(Q.api,j.proxy.endpoint),apiKey:z,authHeader:!0,api:Q.api,models:E};$.registerProvider(V,K),X.registered.push({provider:V,modelCount:E.length,api:Q.api})}return O.info(`applyAll: registered ${X.registered.length} providers, skipped ${X.skipped.length}`),X}function K0(...$){for(let j of $)if(typeof j==="number")return j;return}function J1(...$){for(let j of $)if(typeof j==="boolean")return j;return}var Z1=15000,N$=null;function V$(){N$=null}async function P$($,j,J={}){if(!J.force&&N$&&Date.now()-N$.fetchedAt<$.usageCacheTtlMs)return N$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let X=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Z=new AbortController,z=setTimeout(()=>Z.abort(Error("timeout")),Z1),q;try{q=await fetch(X,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":q$},signal:Z.signal})}finally{clearTimeout(z)}if(!q.ok)throw Error(`/api/usage returned ${q.status}`);let Y=await q.json();if(!Y||Y.schemaVersion!==1||!Array.isArray(Y.accounts))throw Error("/api/usage returned unexpected payload shape");return N$={fetchedAt:Date.now(),doc:Y},O.debug("usage fetched, accounts:",Y.accounts.length),Y}import{getKeybindings as p1,matchesKey as v}from"@duckmind/dm-tui";import{visibleWidth as t$}from"@duckmind/dm-tui";import{visibleWidth as P0}from"@duckmind/dm-tui";function F($,j){let J=P0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return d$($,j)}function d$($,j){if(j<=0)return"\x1B[0m";let J="",X=0,Z=0;while(Z<$.length){let z=$[Z];if(z==="\x1B"&&$[Z+1]==="["){let Y=$.indexOf("m",Z+2);if(Y>=0){J+=$.slice(Z,Y+1),Z=Y+1;continue}}let q=P0(z);if(X+q>j)break;J+=z,X+=q,Z++}return`${J}\x1B[0m`}var X1="│",z1="╭",Y1="╮",q1="╰",V1="╯",O$="─";function a($,j){let J=Math.max(4,j.width);return[Q1($,j.title,j.titleColor??"accent",J),...j.lines.map((X)=>M1($,X,J)),D1($,j.footer,J)]}function Q1($,j,J,X){let Z=j??"",z=t$(Z),q=Math.max(0,X-3-z),Y=Z?$.bold($.fg(J,Z)):"",V=`${z1}${O$}${Y}${O$.repeat(q)}${Y1}`;return $.fg("borderAccent",V)}function M1($,j,J){let X=Math.max(0,J-2),Z=$.fg("borderAccent",X1);return`${Z}${F(j,X)}${Z}`}function D1($,j,J){let X=`${q1}${O$}`,Z=`${V1}`,z=3;if(!j||!j.hint&&!j.badge){let N=Math.max(0,J-3);return $.fg("borderAccent",`${X}${O$.repeat(N)}${Z}`)}let q=j.hint??"",Y=j.badge??"",V=t$(q),Q=t$(Y),D=Math.max(0,J-3-V-Q),E=$.fg("dim",q),K=Y?$.fg("muted",Y):"",H=O$.repeat(D);return`${$.fg("borderAccent",X)}${E}${$.fg("borderAccent",H)}${K}${$.fg("borderAccent",Z)}`}function S$($){return Math.max(0,$-2)}import{existsSync as S0}from"node:fs";import{homedir as R1}from"node:os";import{getKeybindings as E1,Input as G1,matchesKey as W1}from"@duckmind/dm-tui";var N1=[{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 H$($,j=!1){let J=h(),X={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Z=!1;for(let q of N1){let Y=j?X[q.label]??q.initialValue??"":X[q.label]??"";if(!j&&Y)continue;let V=await H1($,q,Y||q.initialValue||"");if(V===void 0){Z=!0;break}let Q=V.trim();if(!Q){if(q.required){$.ui.notify(`${q.label} is required — aborted`,"warning"),Z=!0;break}X[q.label]="";continue}X[q.label]=q.label==="providerPrefix"||q.label==="endpoint"?Q:O1(Q)}if(Z)return!1;let z={...J};if(z.proxy={...J.proxy,endpoint:X.endpoint??"",apiKey:X.apiKey??"",providerPrefix:X.providerPrefix??""},X.usageKey)z.proxy.usageKey=X.usageKey;else delete z.proxy.usageKey;return K$(z),$.ui.notify(`saved to ${C}`,"info"),!0}function O1($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,R1());return S0(j)?`!cat ${$}`:$}if($.startsWith("/"))return S0($)?`!cat ${$}`:$;return $}async function H1($,j,J){return $.ui.custom((X,Z,z,q)=>k1(X,Z,j,J,q),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function k1($,j,J,X,Z){let z=new G1;z.setValue(X),z.focused=!0;let q=null,Y=(V)=>{if(!V&&!J.required){Z("");return}if(!V&&J.required){q="required field",$.requestRender();return}if(J.validate){let Q=V.trim();if(Q&&!Q.startsWith("!")&&!Q.startsWith("$")){let D=J.validate(Q);if(D){q=D,$.requestRender();return}}}Z(V)};return z.onSubmit=Y,z.onEscape=()=>Z(void 0),{render(V){let Q=S$(V),D=z.render(Q-4),E=["",` ${j.fg("dim",J.hint)}`,"",...D.map((K)=>` ${j.fg("accent",`❯ ${K}`)}`),"",q?` ${j.fg("error",`! ${q}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return a(j,{width:V,title:` setup: ${J.label} `,lines:E,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){z.invalidate()},handleInput(V){if(E1().matches(V,"tui.select.cancel")||W1(V,"escape")){Z(void 0);return}q=null,z.handleInput(V),$.requestRender()}}}import{visibleWidth as b$}from"@duckmind/dm-tui";function b0($,j,J,X){let Z=$.fg("borderAccent","│"),z=j.map((q,Y)=>{let V=`${Y+1} ${q.label}`;return Y===J?$.bold($.fg("accent",` ${V} `)):$.fg("dim",` ${V} `)});return F(` ${z.join(Z)}`,X)}function n0($,j,J){let X=j.join($.fg("dim"," "));return F(` ${X}`,J)}function x0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function e($,j,J){let X=$.slice(j,j+J);while(X.length<J)X.push("");return X}function n$($,j,J,X,Z,z){if(Z<=X)return 0;let q=Math.max(0,Z-X);if(j<z)return 0;let Y=Math.max(0,Math.min(J,q)),V=Y+z;if($<V)Y=Math.max(0,$-z);let Q=Y+X-1;if(j>Q)Y=Math.min(q,j-(X-1));return Y}function x$($,j,J){let X=Math.max(0,J-j);return Math.max(0,Math.min($,X))}import{matchesKey as $$}from"@duckmind/dm-tui";import{existsSync as U1,readFileSync as B1}from"node:fs";import{homedir as y0}from"node:os";import{join as C0}from"node:path";var _1=C0(y0(),".dm","models.json"),T1=C0(y0(),".dm","auth.json");function w0($){if(!U1($))return null;try{return JSON.parse(B1($,"utf8"))}catch{return null}}function w$($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),X=w0(_1);if(X&&typeof X==="object"){for(let z of Object.keys(X))if(J.has(z))j.push({kind:"models.json",provider:z,detail:`provider "${z}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Z=w0(T1);if(Z&&typeof Z==="object"){for(let z of Object.keys(Z))if(J.has(z))j.push({kind:"auth.json",provider:z,detail:`provider "${z}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function v0($){let{theme:j,cfg:J}=$,X=0,Z=()=>{let Y=$.getDiscovery(),V=(N)=>j.fg("success",N),Q=(N)=>j.fg("error",N),D=(N)=>j.fg("dim",N),E=[];E.push(`${D("endpoint")} ${J.proxy.endpoint||Q("(unset)")}`),E.push(`${D("apiKey")} ${P(J.proxy.apiKey)?V("resolves"):Q("empty after resolution")}`),E.push(`${D("usageKey")} ${J.proxy.usageKey?P(J.proxy.usageKey)?V("resolves"):Q("set but empty"):D("not configured")}`),E.push(`${D("user-agent")} ${q$}`),E.push(""),E.push(`${D("discovery")} source=${Y.source}`),E.push(`${D("upstream")} v=${Y.upstreamVersion??"(unknown)"} · ${Y.upstreamTotal} ids`);let K=Y.builtinProviders.map((N)=>`${N.name}=${N.models.length}`).join(", ")||D("(none)");E.push(`${D("built-in")} ${K}`),E.push(`${D("custom pool")} ${Y.customPool.length} models`);let H=w$(J);if(E.push(""),H.length===0)E.push(`${D("conflicts")} ${V("none")}`);else{E.push(`${D("conflicts")}`);for(let N of H)E.push(` ${j.fg("warning",`[${N.kind}]`)} ${N.detail}`)}return E};return{id:"diagnostics",label:"Diagnostics",render:(Y,V)=>{let Q=Z();return X=x$(X,V,Q.length),e(Q,X,V).map((D)=>F(` ${D}`,Y))},handleInput:(Y)=>{let V=Z().length;if($$(Y,"up")||$$(Y,"k"))return X=Math.max(0,X-1),!0;if($$(Y,"down")||$$(Y,"j"))return X=Math.min(Math.max(0,V-1),X+1),!0;if($$(Y,"pageUp")||$$(Y,"b"))return X=Math.max(0,X-10),!0;if($$(Y,"pageDown")||$$(Y,"f"))return X=Math.min(Math.max(0,V-1),X+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as A}from"@duckmind/dm-tui";function a$($){let j=new Map,J=new Map;for(let Z of $.builtinProviders){let z=[];for(let q of Z.models)j.set(q.id,{id:q.id,name:q.name,suggestedApi:Z.api,subtitle:q.name&&q.name!==q.id?q.name:void 0,ownedBy:Z.name,reasoning:q.reasoning,contextWindow:q.contextWindow,maxTokens:q.maxTokens,cost:q.cost}),z.push(q.id);J.set(Z.name,z)}let X=[];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});X.push(Z.id)}return{byId:j,builtinModelIds:J,customPoolIds:X}}function A1($){let j=new Map;for(let[J,X]of Object.entries($.customProviders))for(let Z of X.models)j.set(Z.id,J);return j}function Z$($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function u0($,j,J){if(j.kind==="builtin"){let z=J.builtinModelIds.get(j.name)??[],q=new Set(Z$($,j));return z.filter((Y)=>!q.has(Y))}let X=A1($),Z=new Set(Z$($,j));return J.customPoolIds.filter((z)=>{if(Z.has(z))return!1;let q=X.get(z);return q===void 0||q===j.name})}function L1($){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:[]},z=new Set(Z.models);z.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Z.apiOverride??null,models:Array.from(z).sort()};return}for(let[Z,z]of Object.entries($.customProviders)){if(Z===j.name)continue;let q=z.models.findIndex((Y)=>Y.id===J.id);if(q>=0)z.models.splice(q,1)}let X=$.customProviders[j.name]??{api:j.api,models:[]};if(!X.models.some((Z)=>Z.id===J.id))X.models.push(L1(J));$.customProviders[j.name]=X}function g0($,j,J){if(j.kind==="builtin"){let Z=$.builtinProviders[j.name];if(!Z)return;Z.models=Z.models.filter((z)=>z!==J),Z.enabled=Z.models.length>0;return}let X=$.customProviders[j.name];if(!X)return;X.models=X.models.filter((Z)=>Z.id!==J)}function e$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function h0($,j){let J=new Map;for(let X of $){let Z=j.byId.get(X),z=Z?.ownedBy||Z?.origin||"misc",q=J.get(z)??[];q.push(X),J.set(z,q)}return Array.from(J.entries()).sort((X,Z)=>X[0].localeCompare(Z[0])).map(([X,Z])=>({label:X,ids:Z}))}function p0($,j,J){let X=J.trim().toLowerCase();if(!X)return $;return $.filter((Z)=>{if(Z.toLowerCase().includes(X))return!0;let z=j.byId.get(Z)?.name;return z?z.toLowerCase().includes(X):!1})}import{getModels as F1,getProviders as I1}from"@duckmind/dm-ai/compat";function $0($,j){let J=[],X=new Set(j.builtinModelIds.keys()),Z=new Set(I1()),z=new Set([...X,...Z]);for(let q of Array.from(z).sort()){let Y=j.builtinModelIds.get(q);if(!Y||Y.length===0)continue;let V;try{let D=F1(q).find((E)=>Y.includes(E.id));if(D)V=D.api}catch{}if(!V){let Q=Y[0];V=j.byId.get(Q)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:q,api:V,subtitle:`built-in · ${V}`}),!$.builtinProviders[q])$.builtinProviders[q]={enabled:!1,models:[]}}for(let q of Object.keys($.customProviders).sort()){let Y=$.customProviders[q];J.push({kind:"custom",name:q,api:Y.api,subtitle:`custom · ${Y.api}`})}return J}import{getKeybindings as K1,matchesKey as Q$}from"@duckmind/dm-tui";async function m0($,j){return $.ui.custom((J,X,Z,z)=>P1(X,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function P1($,j,J,X){return{render(Z){return a($,{width:Z,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Z){if(K1().matches(Z,"tui.select.cancel")||Q$(Z,"escape")||Q$(Z,"n")||Q$(Z,"q")){X(!1);return}if(Q$(Z,"y")||Q$(Z,"enter")||Q$(Z,"return")){X(!0);return}}}}import{getKeybindings as S1,Input as b1,matchesKey as n1}from"@duckmind/dm-tui";async function l0($,j){let J=T$(j,"group");return $.ui.custom((X,Z,z,q)=>x1(X,Z,J,q),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function x1($,j,J,X){let Z=new b1;if(J)Z.setValue(J);Z.focused=!0;let z=null;return Z.onSubmit=(q)=>{let Y=q.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(Y)){z="letters / digits / dot / dash / underscore only",$.requestRender();return}X(Y)},Z.onEscape=()=>X(null),{render(q){let Y=S$(q),V=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",Q=Z.render(Y-4),D=["",` ${j.fg("dim",V)}`,"",...Q.map((E)=>` ${j.fg("accent",`❯ ${E}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:""];return a(j,{width:q,title:" new custom group ",lines:D,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(q){if(S1().matches(q,"tui.select.cancel")||n1(q,"escape")){X(null);return}z=null,Z.handleInput(q),$.requestRender()}}}import{visibleWidth as w1}from"@duckmind/dm-tui";function j0($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function c0($,j){let J=w1($);if(J===j)return $;if(J>j)return d$($,j);return F($,j)}function i0($,j,J){let{theme:X,width:Z,isCursor:z,isFocused:q}=J,Y=j0(X,z,q),V=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,Q=$.kind==="builtin"?X.fg("accent","B"):X.fg("warning","C"),D=`${X.fg("dim","[")}${Q}${X.fg("dim","]")}`,E=V>0?X.fg("success","●"):X.fg("dim","○"),K=V>0?X.fg("success",String(V).padStart(2)):X.fg("dim"," 0"),H=z&&q?X.bold(X.fg("accent",$.name)):z?X.bold($.name):$.name,N=X.fg("dim",$.api),R=`${Y}${D} ${H} ${E}${K} ${N}`;return c0(R,Z)}function r0($,j,J,X){let Z=j0($,j,J),z=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return F(`${Z}${z}`,X)}function J0($,j,J,X,Z){let{theme:z,width:q,isCursor:Y,isFocused:V}=Z,Q=j0(z,Y,V),D=J==="assigned"?z.fg("success","☑"):z.fg("dim","☐"),E=X?` ${z.fg("warning","⚠")}`:"",K=Y&&V?z.fg("accent",$):$,H=j?.reasoning?` ${z.fg("accent","✨")}`:"",N=j?z.fg("muted",` · ${j.suggestedApi}`):z.fg("error"," · not on proxy"),R=`${Q}${D} ${K}${E}${H}${N}`;return c0(R,q)}function s0($,j,J){let X=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return F(` ${X}`,J)}function Z0($,j,J){return F(` ${$.fg("dim",j)}`,J)}function o0($,j,J,X){let Z=X?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return F(`${Z}${j}`,J)}function d0($){let{tui:j,theme:J,ctx:X,cfg:Z}=$,z=$.onChange??(()=>{}),q=a$($.getDiscovery()),Y=$0(Z,q),V="providers",Q=0,D=0,E=0,K=0,H=0,N=0,R="",B=!1,k=()=>{if(Y.length===0)return null;let M=Math.max(0,Math.min(Q,Y.length-1));return Y[M]??null},_=(M)=>{let U=p0(u0(Z,M,q),q,R);return h0(U,q)},b=(M)=>_(M).flatMap((U)=>U.ids),l=()=>{Y=$0(Z,q);let M=Math.max(0,Y.length);if(Q>M)Q=M;let U=k();if(U){let S=Z$(Z,U).length,T=b(U).length;if(D>=S)D=Math.max(0,S-1);if(E>=T)E=Math.max(0,T-1)}},u$=()=>{q=a$($.getDiscovery()),l()},k$=(M)=>{let U=["providers","assigned","pool"],S=U.indexOf(V);V=M?U[(S-1+U.length)%U.length]:U[(S+1)%U.length]},W=(M)=>{if(V==="providers"){let T=Y.length+1;Q=Math.max(0,Math.min(Q+M,T-1));return}let U=k();if(!U)return;if(V==="assigned"){let T=Z$(Z,U).length;if(T===0)return;D=Math.max(0,Math.min(D+M,T-1));return}let S=b(U).length;if(S===0)return;E=Math.max(0,Math.min(E+M,S-1))},n=async()=>{if(V==="providers"){if(Q===Y.length){let T=await l0(X,Z.proxy.providerPrefix);if(T&&!Z.customProviders[T]){if(Z.customProviders[T]={api:"openai-completions",models:[]},z(),l(),Q=Y.findIndex((I)=>I.kind==="custom"&&I.name===T),Q<0)Q=Y.length-1;V="pool"}j.requestRender();return}V="pool";return}let M=k();if(!M)return;if(V==="assigned"){let T=Z$(Z,M)[D];if(!T)return;g0(Z,M,T),z(),l();return}let U=b(M)[E];if(!U)return;let S=q.byId.get(U);if(!S)return;f0(Z,M,S),z(),l()},r=async()=>{if(V!=="providers")return;let M=k();if(!M||M.kind!=="custom")return;if(!await m0(X,M.name)){j.requestRender();return}if(delete Z.customProviders[M.name],z(),l(),Q>=Y.length)Q=Math.max(0,Y.length-1);j.requestRender()},u=(M,U)=>p(M,U);function p(M,U){let S=Math.max(70,M),T=Math.min(56,Math.max(34,Math.floor(S*0.4))),I=S-T-1,s=Math.max(8,U),o=Math.max(5,Math.floor((s-1)/2)),Y0=s-o,c=k(),D$=0,f$=0,g$=0,q0=0,h$=0,V0=0,j$=[];j$.push(X$(" providers ",T,V==="providers"));for(let L=0;L<Y.length;L++){let f=Y[L],y=V==="providers"&&L===Q;if(y)D$=j$.length,f$=D$;j$.push(i0(f,Z,{theme:J,width:T,isCursor:y,isFocused:V==="providers"}))}{let L=V==="providers"&&Q===Y.length;if(L)D$=j$.length,f$=D$;j$.push(r0(J,L,V==="providers",T))}let J$=[],Tj=c?`assigned to ${J.bold(c.name)} ${J.fg("dim",`· ${c.api}`)}`:J.fg("dim","no provider selected");if(J$.push(X$(" assigned ",I,V==="assigned")),J$.push(o0(J,Tj,I,V==="assigned")),c){let L=Z$(Z,c);if(L.length===0)J$.push(Z0(J,"(nothing assigned yet)",I));for(let f=0;f<L.length;f++){let y=L[f],g=q.byId.get(y),_$=V==="assigned"&&f===D;if(_$)g$=J$.length,q0=g$;let z$=g?!e$(c.api,g.suggestedApi):!1;J$.push(J0(y,g,"assigned",z$,{theme:J,width:I,isCursor:_$,isFocused:V==="assigned"}))}}let d=[];if(d.push(x(I,V==="pool")),c){let L=_(c);if(L.reduce((y,g)=>y+g.ids.length,0)===0)d.push(Z0(J,R?`(no matches for "${R}")`:"(no models available)",I));else{let y=0;for(let g of L){let _$=d.length;d.push(s0(J,g.label,I));for(let z$=0;z$<g.ids.length;z$++){let G0=g.ids[z$],m$=q.byId.get(G0),W0=V==="pool"&&y===E;if(W0)h$=d.length,V0=z$===0?_$:h$;let Ij=m$?!e$(c.api,m$.suggestedApi):!1;d.push(J0(G0,m$,"pool",Ij,{theme:J,width:I,isCursor:W0,isFocused:V==="pool"})),y++}}}}let Aj=Math.max(1,Y0-1),Q0=n$(f$,D$,K,s,j$.length,1),M0=n$(V==="assigned"?q0:0,V==="assigned"?g$:0,H,o,J$.length,2),D0=n$(V==="pool"?V0:0,V==="pool"?h$:0,N,Aj,d.length,1);K=Q0,H=M0,N=D0;let R0=e(j$,Q0,s),Lj=e(J$,M0,o),Fj=e(d,D0,Y0),E0=J.fg("borderAccent","│"),p$=[];for(let L=0;L<s;L++){let f=F(R0[L]??"",T),y=L<o?Lj[L]:Fj[L-o],g=F(y,I);p$.push(`${f}${E0}${g}`)}let B$=o;if(B$>0&&B$<s){let L=F(R0[B$]??"",T),f=J.fg("borderAccent","─".repeat(I));p$[B$]=`${L}${E0}${f}`}return p$}function X$(M,U,S){let T=S?J.bold(J.fg("accent",M)):J.fg("muted",M),I=J.fg("borderAccent","─".repeat(Math.max(0,U-b$(M)-1)));return F(`${T}${I}`,U)}function x(M,U){let T=U?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),I="";if(B)I=`${J.fg("dim"," /")}${J.fg("accent",R)}${J.fg("accent","█")} `;else if(R)I=`${J.fg("dim"," /")}${J.fg("warning",R)} `;let s=b$(" available pool ")+b$(I),o=J.fg("borderAccent","─".repeat(Math.max(0,M-s-1)));return F(`${T}${I}${o}`,M)}function U$(M){if(B){if(A(M,"escape"))return R="",B=!1,E=0,!0;if(A(M,"enter")||A(M,"return"))return B=!1,!0;if(A(M,"backspace")||A(M,"delete"))return R=R.slice(0,-1),E=0,!0;if(M.length===1&&M>=" "&&M!=="")return R+=M,E=0,!0;return!0}if(A(M,"tab"))return k$(!1),!0;if(A(M,"shift+tab"))return k$(!0),!0;if(A(M,"/"))return V="pool",B=!0,!0;if(A(M,"enter")||A(M,"return")||A(M,"space"))return n().then(()=>!0);if(V==="providers"&&(A(M,"d")||A(M,"delete")||A(M,"backspace")))return r().then(()=>!0);if(A(M,"up")||A(M,"k"))return W(-1),!0;if(A(M,"down")||A(M,"j"))return W(1),!0;if(A(M,"pageUp")||A(M,"b"))return W(-8),!0;if(A(M,"pageDown")||A(M,"f"))return W(8),!0;if(A(M,"left")||A(M,"h"))return V="providers",!0;if(A(M,"right")||A(M,"l")){if(V==="providers")V="assigned";else if(V==="assigned")V="pool";return!0}return!1}function _j(){if(B)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:_j,rebuild:u$}}import{matchesKey as w}from"@duckmind/dm-tui";var G={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function t0($,j={}){let J=[],X=new Map,Z=0;for(let z of $.accounts){if(!j.showDisabled&&z.disabled){Z++;continue}let q=X.get(z.provider)??[];q.push(z),X.set(z.provider,q)}if(J.push(`${G.dim}generated ${$.generatedAt}${G.reset}`),$.unsupportedProviders.length>0)J.push(`${G.dim}providers without quota lookup:${G.reset} ${$.unsupportedProviders.join(", ")}`);if(Z>0)J.push(`${G.dim}hidden disabled accounts:${G.reset} ${Z} ${G.dim2}(press d to show)${G.reset}`);for(let[z,q]of Array.from(X.entries()).sort()){J.push(""),J.push(`${G.bold}${G.accent}▌ ${z}${G.reset}`);for(let Y of q){if(J.push(C1(Y)),!Y.supported){J.push(` ${G.dim2}(provider not quota-aware)${G.reset}`);continue}if(Y.error){if(j.verbose)for(let Q of y1(Y.error,88))J.push(` ${G.red}${Q}${G.reset}`);continue}let V=Y.groups??[];if(V.length===0){J.push(` ${G.dim2}(no active quota windows)${G.reset}`);continue}for(let Q of V)J.push(u1(Q))}}return J.push(""),J.push(`${G.dim}legend:${G.reset} ${a0} ok ${e0} error/unavailable ${$j} disabled ${G.green}✓N${G.reset}/${G.red}✗N${G.reset} request counters ${G.dim}v = verbose, d = show disabled${G.reset}`),J}function y1($,j){if($.length<=j)return[$];let J=[],X=$;while(X.length>j){let Z=X.lastIndexOf(" ",j);if(Z<j*0.6)Z=j;J.push(X.slice(0,Z)),X=X.slice(Z).replace(/^\s+/,"")}if(X)J.push(X);return J}function C1($){let j=v1($),J=`${G.green}✓${$.success}${G.reset} ${G.red}✗${$.failed}${G.reset}`,X=Zj($.label,36);return` ${j} ${G.bold}${X}${G.reset} ${J}`}var a0=`${G.green}●${G.reset}`,e0=`${G.yellow}⚠${G.reset}`,$j=`${G.dim2}⊘${G.reset}`;function v1($){if($.disabled)return $j;if($.unavailable||$.error||$.status&&$.status!=="active")return e0;return a0}function u1($){let j=Jj($.remainingFraction),J=Math.round(j*100),X=f1(j),Z=$.resetTime?` ${G.dim}reset ${h1($.resetTime)}${G.reset}`:"",z=Zj($.label,28).padEnd(28," ");return` ${X} ${g1(J,j)} ${z}${Z}`}function f1($){let j=Jj($),J=Math.round(j*18),X=jj(j),Z=G.dim2,z="█".repeat(J),q="░".repeat(18-J);return`${Z}[${X}${z}${Z}${q}]${G.reset}`}function g1($,j){return`${jj(j)}${String($).padStart(3)}%${G.reset}`}function jj($){if($>=0.4)return G.green;if($>=0.15)return G.yellow;return G.red}function h1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let X=Math.round(J/60000);if(X<60)return`${X}m`;let Z=Math.round(X/60);if(Z<48)return`${Z}h`;return`${Math.round(Z/24)}d`}function Jj($){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:X}=$,Z="idle",z=null,q="",Y=0,V=!1,Q=!1,D=(R)=>{Z="loading",j.requestRender();let B=P(X.proxy.usageKey);P$(X,B,{force:R}).then((k)=>{z=k,Z="ready",Y=0,j.requestRender()}).catch((k)=>{q=k.message,Z="error",j.requestRender()})},E=()=>{if(Z==="idle"||Z==="loading")return[J.fg("dim"," loading usage…")];if(Z==="error")return[J.fg("error",` usage failed: ${q}`)];if(!z)return[J.fg("dim"," (no data)")];return t0(z,{showDisabled:V,verbose:Q})};return{id:"usage",label:"Usage",render:(R,B)=>{let k=E();return Y=x$(Y,B,k.length),e(k,Y,B).map((_)=>F(` ${_}`,R))},handleInput:(R)=>{if(w(R,"d"))return V=!V,Y=0,!0;if(w(R,"v"))return Q=!Q,Y=0,!0;let B=E().length;if(w(R,"up")||w(R,"k"))return Y=Math.max(0,Y-1),!0;if(w(R,"down")||w(R,"j"))return Y=Math.min(Math.max(0,B-1),Y+1),!0;if(w(R,"pageUp")||w(R,"b"))return Y=Math.max(0,Y-10),!0;if(w(R,"pageDown")||w(R,"f"))return Y=Math.min(Math.max(0,B-1),Y+10),!0;if(w(R,"home")||w(R,"g"))return Y=0,!0;if(w(R,"end")||w(R,"shift+g"))return Y=Math.max(0,B-1),!0;return!1},footerHint:()=>{let R=V?J.fg("success","[d disabled]"):"d disabled",B=Q?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${R} · ${B} `},onActivate:()=>{if(Z==="idle")D(!1)},reload:()=>{if(V$(),Z!=="idle")D(!0)}}}function zj($){let{dm:j,ctx:J,tui:X,theme:Z,cfg:z,done:q}=$,Y=$.discovery,V=!1,Q="",D=d0({tui:X,theme:Z,ctx:J,cfg:z,getDiscovery:()=>Y,onChange:()=>{V=!0,Q=""}}),E=Xj({tui:X,theme:Z,cfg:z}),K=v0({theme:Z,cfg:z,getDiscovery:()=>Y}),H=[D,E,K],N=0,R=()=>H[N],B=(W)=>{if(W<0||W>=H.length||W===N)return;N=W,R().onActivate?.(),X.requestRender()},k=()=>{Q=Z.fg("dim","saving…"),K$(z),X.requestRender(),m(j,z,Y).then((W)=>{V=!1,Q=Z.fg("success",`✓ settings saved · ${W.registered.length} registered, ${W.skipped.length} skipped`),X.requestRender()}).catch((W)=>{Q=Z.fg("error",`save failed: ${W.message}`),X.requestRender()})},_=async()=>{Q=Z.fg("dim","refreshing…"),X.requestRender();try{let W=P(z.proxy.apiKey);Y=await i(z,W),V$(),D.rebuild(),E.reload();let n=await m(j,z,Y);Q=Z.fg("success",`✓ refreshed · ${n.registered.length} providers (${Y.source})`)}catch(W){Q=Z.fg("error",`refresh failed: ${W.message}`)}X.requestRender()},b=async()=>{if(!await H$(J,!0)){X.requestRender();return}let n=h();z.proxy={...z.proxy,...n.proxy},await _()},l=()=>{let W=z.proxy.endpoint||"(unset)",n=W.length>40?`…${W.slice(-39)}`:W,r=Boolean(P(z.proxy.apiKey)),u=0,p=0;for(let x of Object.values(z.builtinProviders)){if(x.enabled&&x.models.length>0)u++;p+=x.models.length}for(let x of Object.values(z.customProviders)){if(x.models.length>0)u++;p+=x.models.length}let X$=Q?Q:V?Z.fg("warning","● unsaved — press s to save"):Z.fg("dim","✓ saved");return[`${Z.fg("dim","endpoint")} ${n}`,`${Z.fg("dim","key")} ${r?Z.fg("success","✓"):Z.fg("error","✗")}`,`${Z.fg("dim","providers")} ${u}`,`${Z.fg("dim","models")} ${p}`,X$]},u$=(W)=>{let n=X.rows??40,u=Math.max(16,Math.min(n-6,38))-2,p=Math.max(72,W-2),X$=Math.max(6,u-3),x=[];return x.push(n0(Z,l(),p)),x.push(b0(Z,H.map((U$)=>({id:U$.id,label:U$.label})),N,p)),x.push(x0(Z,p)),x.push(...R().render(p,X$)),a(Z,{width:W,title:" /cliproxy ",lines:x,footer:{hint:R().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},k$=(W)=>{if(p1().matches(W,"tui.select.cancel")||v(W,"q")||v(W,"escape"))return q(),!0;if(v(W,"]")||v(W,"tab"))return B((N+1)%H.length),!0;if(v(W,"[")||v(W,"shift+tab"))return B((N-1+H.length)%H.length),!0;if(v(W,"1"))return B(0),!0;if(v(W,"2"))return B(1),!0;if(v(W,"3"))return B(2),!0;if(v(W,"r"))return _().then(()=>!0);if(v(W,"e"))return b().then(()=>!0);if(v(W,"s"))return k(),!0;return!1};return{render:u$,invalidate(){},handleInput(W){let n=R().handleInput(W);if(n instanceof Promise){Q="",n.then((u)=>{if(u)X.requestRender()});return}if(n){Q="",X.requestRender();return}let r=k$(W);if(r instanceof Promise)r.then((u)=>{if(u)X.requestRender()});else if(r)X.requestRender()}}}async function Yj($,j,J,X){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Z=structuredClone(J);i$(!0);try{await j.ui.custom((z,q,Y,V)=>zj({dm:$,ctx:j,tui:z,theme:q,cfg:Z,discovery:X,done:V}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{i$(!1)}}function qj($){$.registerCommand("cliproxy",{description:"Manage proxy models, usage, and diagnostics in one hub overlay",handler:m1.bind(null,$)}),$.registerCommand("cliproxy-setup",{description:"Set endpoint, API key, and (optional) usage key for the proxy",handler:l1.bind(null,$)})}async function m1($,j,J){let X=h();if(!X.proxy.endpoint||!P(X.proxy.apiKey)){if(J.ui.notify("endpoint or API key not set — launching setup first","info"),!await H$(J,!0))return}let Z=h(),z=P(Z.proxy.apiKey),q;try{q=await i(Z,z)}catch(Y){J.ui.notify(`discovery failed: ${Y.message}`,"error");return}await Yj($,J,Z,q)}async function l1($,j,J){if(!await H$(J,!0))return;let Z=h();try{let z=await i(Z,P(Z.proxy.apiKey)),q=await m($,Z,z);V$(),J.ui.notify(`setup ok · ${q.registered.length} providers registered (source=${z.source})`,"info")}catch(z){J.ui.notify(`setup saved, but apply failed: ${z.message}`,"warning")}}import{chmodSync as c1,existsSync as Vj,mkdirSync as i1,readFileSync as Qj,statSync as r1,unlinkSync as Mj,writeFileSync as Dj}from"node:fs";import{join as Rj}from"node:path";var X0=Rj(t,"usage-cache.json"),M$=Rj(t,"usage-cache.lock"),s1=120000,o1=30000;function Ej(){if(!Vj(X0))return null;try{let $=JSON.parse(Qj(X0,"utf8"));if(!$||typeof $.fetchedAt!=="number"||!$.doc||!Array.isArray($.doc.accounts))return null;return{doc:$.doc,ageMs:Date.now()-$.fetchedAt}}catch($){return O.warn("failed to read usage cache:",$.message),null}}function Gj($){return $<s1}function Wj($){try{i1(t,{recursive:!0,mode:448}),c1(t,448);let j={fetchedAt:Date.now(),doc:$};Dj(X0,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){O.warn("failed to write usage cache:",j.message)}}function Nj(){let $=`${process.pid}@${Date.now()}`;if(Vj(M$))try{let j=r1(M$);if(Date.now()-j.mtimeMs>o1)O.debug("removing stale usage lock"),Mj(M$);else return null}catch{return null}try{return Dj(M$,$,{flag:"wx",mode:384}),$}catch{return null}}function Oj($){try{if(Qj(M$,"utf8").trim()===$)return Mj(M$),!0;return!1}catch{return!1}}var z0=["⡀","⠂","⣀","⣄","⣤","⣶","⣷","⣾"];function d1($){if($==="anthropic")return"claude";if($==="openai")return"codex";return null}function t1($){return!$.disabled&&!$.unavailable&&$.supported&&Array.isArray($.groups)&&$.groups.length>0}function a1($){let j=`${$.id} ${$.label??""}`.toLowerCase();return j.includes("5h")||j.includes("five-hour")||j.includes("five hour")}function e1($){let j=`${$.id} ${$.label??""}`.toLowerCase();return j.includes("7d")||j.includes("seven-day")||j.includes("seven day")}function Hj($,j){let J=-1;for(let X of $){if(!t1(X))continue;let Z=1/0;for(let z of X.groups??[])if(j(z)){if(z.remainingFraction<Z)Z=z.remainingFraction}if(Z!==1/0&&Z>J)J=Z}if(J<0)return null;return{fraction:$7(J)}}function $7($){return Math.max(0,Math.min(1,$))}function kj($){let j=Math.min(z0.length-1,Math.floor($*z0.length));return z0[j]}function y$($){if($>=0.7)return"success";if($>=0.3)return"warning";return"error"}function Uj($){return Math.round($*100)}function Bj($,j,J){let X=d1(j);if(!X)return null;let Z=$.accounts.filter((V)=>V.provider===X);if(Z.length===0)return null;let z=Hj(Z,a1),q=Hj(Z,e1);if(!z&&!q)return null;let Y=[J.fg("dim","\uDB81\uDE27")];if(z)Y.push(`${J.fg("dim","5h")} ${J.fg(y$(z.fraction),kj(z.fraction))} ${J.fg(y$(z.fraction),String(Uj(z.fraction)))}`);if(q)Y.push(`${J.fg("dim","7d")} ${J.fg(y$(q.fraction),kj(q.fraction))} ${J.fg(y$(q.fraction),String(Uj(q.fraction)))}`);return Y.join(" ")}var C$="0quota",j7=5000;async function J7($,j,J={}){let X=Ej();if(X&&Gj(X.ageMs))return X.doc;if(J.readOnly)return X?.doc??null;let Z=Nj();if(!Z)return X?.doc??null;try{let z=await P$($,j,{force:!0});return Wj(z),z}catch(z){return O.debug("usage fetch failed in shared cache:",z.message),X?.doc??null}finally{Oj(Z)}}async function v$($,j,J,X,Z={}){if(!X){J.setStatus(C$,void 0);return}if(!j){J.setStatus(C$,void 0);return}let z=await J7($,j,Z);if(!z){J.setStatus(C$,void 0);return}let q=Bj(z,X.provider,J.theme);J.setStatus(C$,q??void 0)}async function Z7($){qj($);let j=h(),J=P(j.proxy.apiKey);if(!J){O.debug("apiKey is empty after resolution — skipping initial apply. Run /cliproxy-setup to configure.");return}let X=w$(j);for(let z of X)O.warn(`conflict (${z.kind}): ${z.detail}`);try{let z=T0();if(z)O.info(`discovery from cache (age ${Math.round(z.ageMs/1000)}s): ${z.discovery.builtinProviders.length} builtin, ${z.discovery.customPool.length} custom`),await m($,j,z.discovery),(async()=>{try{let q=await i(j,J);await m($,j,q),O.debug("discovery revalidated from network")}catch(q){O.warn("background discovery revalidate failed:",q.message)}})();else{let q=await i(j,J);await m($,j,q)}}catch(z){O.error("initial apply failed:",z.message)}if(j.refreshIntervalMinutes>0){let z=j.refreshIntervalMinutes*60000;setInterval(()=>{(async()=>{try{let q=h(),Y=P(q.proxy.apiKey);if(!Y)return;let V=await i(q,Y);await m($,q,V),O.debug("background refresh ok")}catch(q){O.warn("background refresh failed:",q.message)}})()},z),O.info(`background refresh every ${j.refreshIntervalMinutes}m`)}let Z=P(j.proxy.usageKey);if(Z){let z=0;$.on("session_start",async(q,Y)=>{if(!Y.hasUI)return;await v$(j,Z,Y.ui,Y.model)}),$.on("model_select",async(q,Y)=>{if(!Y.hasUI)return;await v$(j,Z,Y.ui,Y.model)}),$.on("turn_end",async(q,Y)=>{if(!Y.hasUI)return;let V=Date.now();if(V-z<j7){await v$(j,Z,Y.ui,Y.model,{readOnly:!0});return}z=V,await v$(j,Z,Y.ui,Y.model)})}else O.debug("usageKey not configured — quota status segment disabled")}export{Z7 as default};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dm-cliproxy",
|
|
3
|
+
"version": "0.3.5",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "DM extension for managing model providers through a single CliProxyAPI endpoint",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"dm": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"./index.js"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"duckmind",
|
|
14
|
+
"dm",
|
|
15
|
+
"dm-extension",
|
|
16
|
+
"cliproxy",
|
|
17
|
+
"cliproxyapi",
|
|
18
|
+
"proxy"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import $ from"node:assert/strict";import{chmodSync as G,existsSync as v,mkdtempSync as N,mkdirSync as L,readFileSync as V,rmSync as C,statSync as w,writeFileSync as k}from"node:fs";import{tmpdir as I}from"node:os";import{dirname as J,join as K}from"node:path";import{randomUUID as S}from"node:crypto";import{chmodSync as D,constants as U,copyFileSync as x,existsSync as i,linkSync as n,mkdirSync as H,readFileSync as F,rmSync as p,writeFileSync as l}from"node:fs";import{homedir as R}from"node:os";import{dirname as s,join as z}from"node:path";import{fileURLToPath as c}from"node:url";var b=!1;function B(f){b=f}var M={info(...f){if(!b)console.log("[dm-cliproxy]",...f)},warn(...f){if(!b)console.warn("[dm-cliproxy]",...f)},error(...f){if(!b)console.error("[dm-cliproxy]",...f)},debug(...f){if(!b&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...f)}};var t=z(R(),".dm","agent","dm-cliproxy"),O=z(t,"config.json"),T=[z(R(),".pi","agent","pi-cliproxyapi","config.json"),z(R(),".config","pi-cliproxyapi","config.json")];function A(){return i(z(s(c(import.meta.url)),"..",".git"))}function E(f=T,q=O,Z=A()){if(i(q))return;let Y=(typeof f==="string"?[f]:[...f]).find((W)=>i(W));if(!Y)return;let u;try{H(s(q),{recursive:!0,mode:448}),D(s(q),448),u=`${q}.${process.pid}.${S()}.tmp`,x(Y,u,U.COPYFILE_EXCL),D(u,384),n(u,q),p(u),u=void 0,M.info("legacy config copied to",q)}catch(W){if(u)try{p(u,{force:!0})}catch(Q){M.warn("failed to clean temporary config:",Q)}M.warn("failed to migrate legacy config:",W)}}B(!0);var X=N(K(I(),"dm-cliproxy-migration-"));try{for(let Z of[!0,!1]){let j=K(X,String(Z),"legacy","config.json"),Y=K(X,String(Z),"missing","config.json"),u=K(X,String(Z),"current","config.json"),W=Buffer.from(`{\r
|
|
2
|
+
"proxy": {"apiKey": "!cat ~/.pi/agent/pi-cliproxyapi/key", "usageKey": "!cat ~/.config/pi-cliproxyapi/usage-key"}\r
|
|
3
|
+
}\r
|
|
4
|
+
`);L(J(j),{recursive:!0}),k(j,W),G(j,416);for(let Q of["key","usage-key"])k(K(J(j),Q),`${Q}
|
|
5
|
+
`);E([Y,j],u,Z),$.deepEqual(V(u),W),$.equal(w(u).mode&511,384),$.equal(w(J(u)).mode&511,448),$.equal(v(j),!0);for(let Q of["key","usage-key"])$.equal(V(K(J(j),Q),"utf8"),`${Q}
|
|
6
|
+
`),$.equal(v(K(J(u),Q)),!1)}let f=K(X,"no-overwrite","legacy","config.json"),q=K(X,"no-overwrite","current","config.json");L(J(f),{recursive:!0}),L(J(q),{recursive:!0}),k(f,`legacy
|
|
7
|
+
`),k(q,`current
|
|
8
|
+
`),E(f,q,!1),$.equal(V(q,"utf8"),`current
|
|
9
|
+
`),$.equal(V(f,"utf8"),`legacy
|
|
10
|
+
`),console.log("dm-cliproxy config migration check: ok")}finally{C(X,{recursive:!0,force:!0})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getModels as n}from"@duckmind/dm-ai/compat";var A=new Set(["openai-completions","openai-responses","anthropic-messages"]);function O(Y,J){let X=J.replace(/\/+$/,"");if(Y==="anthropic-messages")return X.replace(/\/v1$/,"");return X}var T=128000,x=16000,b={input:0,output:0,cacheRead:0,cacheWrite:0},u=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function F(Y){return u.some((J)=>J.test(Y))}function P(Y){return Y.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((J)=>J[0].toUpperCase()+J.slice(1)).join(" ")}function C(Y){return{id:Y,name:P(Y),contextWindow:T,maxTokens:x,reasoning:F(Y),cost:{...b}}}import{execSync as y}from"node:child_process";import{homedir as B}from"node:os";import{dirname as i,join as E}from"node:path";var w=!1;var H={info(...Y){if(!w)console.log("[dm-cliproxy]",...Y)},warn(...Y){if(!w)console.warn("[dm-cliproxy]",...Y)},error(...Y){if(!w)console.error("[dm-cliproxy]",...Y)},debug(...Y){if(!w&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...Y)}};var U=E(B(),".dm","agent","dm-cliproxy"),r=E(U,"config.json"),o=[E(B(),".pi","agent","pi-cliproxyapi","config.json"),E(B(),".config","pi-cliproxyapi","config.json")];function N(Y){if(!Y)return"";let J=Y.trim();if(J.startsWith("!"))try{return y(J.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(X){let j=X?.stderr?.toString?.()?.trim()??X.message;return H.warn(`failed to resolve "!" config value (${J}): ${j}`),""}if(J.startsWith("$"))return process.env[J.slice(1)]??"";return J}import{dirname as m,join as f}from"node:path";var Z0=f(U,"discovery-cache.json");function _(Y){let J=new Set;for(let X of Y.builtinProviders)for(let j of X.models)J.add(j.id);for(let X of Y.customPool)J.add(X.id);return J}async function E0(Y,J,X){let j={registered:[],skipped:[]},G=_(X),L=N(J.proxy.apiKey);if(!L)return H.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),j;let S=new Map;for(let Z of X.builtinProviders)S.set(Z.name,Z.models.map((Q)=>({id:Q.id,name:Q.name,reasoning:Q.reasoning,contextWindow:Q.contextWindow,maxTokens:Q.maxTokens,cost:Q.cost})));for(let[Z,Q]of Object.entries(J.builtinProviders)){if(!Q?.enabled){j.skipped.push({provider:Z,reason:"disabled"});continue}if(!Array.isArray(Q.models)||Q.models.length===0){j.skipped.push({provider:Z,reason:"empty whitelist"});continue}let R=[];try{R=n(Z)}catch{}let K=new Map(R.map(($)=>[$.id,$])),k=new Map((S.get(Z)??[]).map(($)=>[$.id,$])),V=[];for(let $ of Q.models){if(!G.has($))continue;let z=K.get($),q=k.get($);if(z){V.push({id:z.id,name:z.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost,input:z.input,api:z.api,thinkingLevelMap:z.thinkingLevelMap});continue}if(!q)continue;let I=Z==="anthropic"?"anthropic-messages":Q.apiOverride??"openai-responses";V.push({id:q.id,name:q.name,reasoning:q.reasoning,contextWindow:q.contextWindow,maxTokens:q.maxTokens,cost:q.cost,input:["text"],api:I})}if(V.length===0){j.skipped.push({provider:Z,reason:"no whitelisted models present on proxy"});continue}let M=Q.apiOverride??V[0].api;if(!A.has(M)){j.skipped.push({provider:Z,reason:`api "${M}" not in allowlist`});continue}let W=V.map(($)=>{let z=J.overrides[$.id]??{},q={id:$.id,name:typeof z.name==="string"?z.name:$.name,api:M,reasoning:typeof z.reasoning==="boolean"?z.reasoning:$.reasoning,input:$.input,cost:z.cost??$.cost,contextWindow:typeof z.contextWindow==="number"?z.contextWindow:$.contextWindow,maxTokens:typeof z.maxTokens==="number"?z.maxTokens:$.maxTokens};if($.thinkingLevelMap)q.thinkingLevelMap=$.thinkingLevelMap;return q}),D={name:Z,baseUrl:O(M,J.proxy.endpoint),apiKey:L,authHeader:!0,api:M,models:W};Y.registerProvider(Z,D),j.registered.push({provider:Z,modelCount:W.length,api:M})}let v=new Map(X.customPool.map((Z)=>[Z.id,Z]));for(let[Z,Q]of Object.entries(J.customProviders)){if(!A.has(Q.api)){j.skipped.push({provider:Z,reason:`api "${Q.api}" not in allowlist`});continue}let R=Q.models.filter((V)=>G.has(V.id));if(R.length===0){j.skipped.push({provider:Z,reason:"no configured models present on proxy"});continue}let K=R.map((V)=>{let M=v.get(V.id),W=C(V.id),D=J.overrides[V.id]??{};return{id:V.id,name:V.name??M?.name??W.name??V.id,api:Q.api,reasoning:c(V.reasoning,M?.reasoning,W.reasoning,D.reasoning)??!1,input:["text"],cost:V.cost??M?.cost??W.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:h(V.contextWindow,M?.contextWindow,W.contextWindow,D.contextWindow)??128000,maxTokens:h(V.maxTokens,M?.maxTokens,W.maxTokens,D.maxTokens)??16000}}),k={name:Z,baseUrl:O(Q.api,J.proxy.endpoint),apiKey:L,authHeader:!0,api:Q.api,models:K};Y.registerProvider(Z,k),j.registered.push({provider:Z,modelCount:K.length,api:Q.api})}return H.info(`applyAll: registered ${j.registered.length} providers, skipped ${j.skipped.length}`),j}function h(...Y){for(let J of Y)if(typeof J==="number")return J;return}function c(...Y){for(let J of Y)if(typeof J==="boolean")return J;return}export{E0 as applyAll};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{chmodSync as f,existsSync as t,mkdirSync as W,readFileSync as E,writeFileSync as K}from"node:fs";import{dirname as M,join as Q}from"node:path";import{homedir as w}from"node:os";import{dirname as z,join as b}from"node:path";var e=!1;var D={info(...s){if(!e)console.log("[dm-cliproxy]",...s)},warn(...s){if(!e)console.warn("[dm-cliproxy]",...s)},error(...s){if(!e)console.error("[dm-cliproxy]",...s)},debug(...s){if(!e&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...s)}};var J=b(w(),".dm","agent","dm-cliproxy"),$=b(J,"config.json"),R=[b(w(),".pi","agent","pi-cliproxyapi","config.json"),b(w(),".config","pi-cliproxyapi","config.json")];var v=Q(J,"discovery-cache.json");function A(){if(!t(v))return null;try{let s=JSON.parse(E(v,"utf8"));if(!s||typeof s.savedAt!=="number"||!s.discovery||!Array.isArray(s.discovery.builtinProviders)||!Array.isArray(s.discovery.customPool))return null;return{discovery:s.discovery,ageMs:Date.now()-s.savedAt}}catch(s){return D.warn("failed to read discovery cache:",s.message),null}}function d(s){try{W(M(v),{recursive:!0,mode:448}),f(M(v),448);let i={savedAt:Date.now(),discovery:s};K(v,JSON.stringify(i),{encoding:"utf8",mode:384})}catch(i){D.warn("failed to write discovery cache:",i.message)}}export{d as writeDiscoveryCache,A as readDiscoveryCache,v as DISCOVERY_CACHE_PATH};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{getModels as Ij}from"@duckmind/dm-ai/compat";var C$=new Set(["openai-completions","openai-responses","anthropic-messages"]);function v$($,j){let J=j.replace(/\/+$/,"");if($==="anthropic-messages")return J.replace(/\/v1$/,"");return J}function q0($,j){if(!$)return!0;for(let J of j)if(new RegExp("^"+J.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test($))return!0;return!1}var Qj=128000,zj=16000,qj={input:0,output:0,cacheRead:0,cacheWrite:0},Vj=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function H$($){return Vj.some((j)=>j.test($))}var Mj=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function W$($,j){let J=($??"").trim();return J?`${J}-${j}`:j}function V0($,j){let J=(j??"").trim(),Y=$.match(/^([a-z0-9]+-)(.*)$/);if(Y)return J?`${J}-${Y[1]}`:Y[1];return $}function M0($,j){for(let[J,Y,Z]of Mj)if(J.has($))return{slug:W$(j,Y),api:Z};return{slug:W$(j,"misc"),api:"openai-completions"}}function Dj($){return $.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((j)=>j[0].toUpperCase()+j.slice(1)).join(" ")}function Y$($){return{id:$,name:Dj($),contextWindow:Qj,maxTokens:zj,reasoning:H$($),cost:{...qj}}}import{execSync as Ej}from"node:child_process";import{randomUUID as D0}from"node:crypto";import{chmodSync as N$,constants as Uj,copyFileSync as E0,existsSync as k$,linkSync as Rj,mkdirSync as U0,readFileSync as Gj,rmSync as f$,writeFileSync as _j}from"node:fs";import{homedir as g$}from"node:os";import{dirname as V$,join as M$}from"node:path";import{fileURLToPath as Oj}from"node:url";var q$=!1;function u$($){q$=$}var B={info(...$){if(!q$)console.log("[dm-cliproxy]",...$)},warn(...$){if(!q$)console.warn("[dm-cliproxy]",...$)},error(...$){if(!q$)console.error("[dm-cliproxy]",...$)},debug(...$){if(!q$&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...$)}};var h$=M$(g$(),".dm","agent","dm-cliproxy"),C=M$(h$,"config.json"),Aj=[M$(g$(),".pi","agent","pi-cliproxyapi","config.json"),M$(g$(),".config","pi-cliproxyapi","config.json")];function nj(){return k$(M$(V$(Oj(import.meta.url)),"..",".git"))}function Wj($=Aj,j=C,J=nj()){if(k$(j))return;let Z=(typeof $==="string"?[$]:[...$]).find((z)=>k$(z));if(!Z)return;let X;try{U0(V$(j),{recursive:!0,mode:448}),N$(V$(j),448),X=`${j}.${process.pid}.${D0()}.tmp`,E0(Z,X,Uj.COPYFILE_EXCL),N$(X,384),Rj(X,j),f$(X),X=void 0,B.info("legacy config copied to",j)}catch(z){if(X)try{f$(X,{force:!0})}catch(Q){B.warn("failed to clean temporary config:",Q)}B.warn("failed to migrate legacy config:",z)}}var T$={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function o(){if(Wj(),!k$(C))return B.debug("config not found, using defaults at",C),structuredClone(T$);try{let $=JSON.parse(Gj(C,"utf8"));return Hj($)}catch($){return B.error("failed to read config:",$,"— using defaults"),structuredClone(T$)}}function B$($){U0(V$(C),{recursive:!0,mode:448}),N$(V$(C),448);let j=`${C}.${process.pid}.${D0()}.tmp`;try{_j(j,JSON.stringify($,null,2)+`
|
|
2
|
+
`,{encoding:"utf8",flag:"wx",mode:384}),E0(j,C),N$(C,384)}finally{f$(j,{force:!0})}B.info("config saved to",C)}function Hj($){if(!$||typeof $!=="object")return structuredClone(T$);let j=$,J=structuredClone(T$),Y=j.proxy??{};if(J.proxy.endpoint=typeof Y.endpoint==="string"?Y.endpoint:J.proxy.endpoint,J.proxy.apiKey=typeof Y.apiKey==="string"?Y.apiKey:"",typeof Y.usageKey==="string")J.proxy.usageKey=Y.usageKey;if(typeof Y.providerPrefix==="string"&&Y.providerPrefix.trim())J.proxy.providerPrefix=Y.providerPrefix.trim();if(j.builtinProviders&&typeof j.builtinProviders==="object")J.builtinProviders=j.builtinProviders;if(j.customProviders&&typeof j.customProviders==="object")J.customProviders=j.customProviders;if(Array.isArray(j.discoveryExcludes))J.discoveryExcludes=j.discoveryExcludes.filter((Z)=>typeof Z==="string");if(j.overrides&&typeof j.overrides==="object")J.overrides=j.overrides;if(typeof j.refreshIntervalMinutes==="number")J.refreshIntervalMinutes=j.refreshIntervalMinutes;if(typeof j.usageCacheTtlMs==="number")J.usageCacheTtlMs=j.usageCacheTtlMs;return J}function I($){if(!$)return"";let j=$.trim();if(j.startsWith("!"))try{return Ej(j.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(J){let Y=J?.stderr?.toString?.()?.trim()??J.message;return B.warn(`failed to resolve "!" config value (${j}): ${Y}`),""}if(j.startsWith("$"))return process.env[j.slice(1)]??"";return j}import{chmodSync as Nj,existsSync as b1,mkdirSync as kj,readFileSync as x1,writeFileSync as Tj}from"node:fs";import{dirname as R0,join as Bj}from"node:path";var p$=Bj(h$,"discovery-cache.json");function c$($){try{kj(R0(p$),{recursive:!0,mode:448}),Nj(R0(p$),448);let j={savedAt:Date.now(),discovery:$};Tj(p$,JSON.stringify(j),{encoding:"utf8",mode:384})}catch(j){B.warn("failed to write discovery cache:",j.message)}}var Z$="dm-cliproxy/0.3.5",Fj=5000;async function O0($,j){let J=new AbortController,Y=setTimeout(()=>J.abort(Error("timeout")),Fj);try{return await fetch($,{...j,signal:J.signal})}finally{clearTimeout(Y)}}function Kj($){return new URL("/.well-known/pi",new URL($).origin).toString()}async function Lj($){let j=Kj($.proxy.endpoint),J;try{J=await O0(j,{headers:{"User-Agent":Z$,Accept:"application/json"}})}catch(Q){return B.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!J.ok)return B.warn(`well-known returned ${J.status} — falling back to /v1/models`),null;let Y;try{Y=await J.json()}catch{return B.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return B.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let Z=[],X=Y.builtinProviders??{};for(let[Q,q]of Object.entries(X)){if(!q||!Array.isArray(q.models))continue;let V=q.models.map((D)=>({id:String(D.id),name:typeof D.name==="string"?D.name:String(D.id),reasoning:Boolean(D.reasoning??H$(String(D.id))),contextWindow:typeof D.contextWindow==="number"?D.contextWindow:200000,maxTokens:typeof D.maxTokens==="number"?D.maxTokens:16000,cost:D.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));Z.push({name:Q,api:q.api??"openai-responses",models:V})}let z=(Array.isArray(Y.customModelPool)?Y.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??H$(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:V0(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",$.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Y?.upstream?.upstreamVersion==="string"?Y.upstream.upstreamVersion:null,builtinProviders:Z,customPool:z,serverDiscoveryExcludes:Array.isArray(Y.discoveryExcludes)?Y.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Y?.counts?.upstreamTotal==="number"?Y.counts.upstreamTotal:0}}async function Sj($,j){let J=new URL("/v1/models",new URL($.proxy.endpoint).origin).toString(),Y=await O0(J,{headers:{Authorization:`Bearer ${j}`,Accept:"application/json","User-Agent":Z$}});if(!Y.ok)throw Error(`/v1/models returned ${Y.status}`);let Z=await Y.json();if(!Z?.data||!Array.isArray(Z.data))return[];return Z.data.map((X)=>({id:typeof X.id==="string"?X.id:"",owned_by:typeof X.owned_by==="string"?X.owned_by:""})).filter((X)=>X.id)}function Pj($,j){let J=j.discoveryExcludes,Y=new Map,Z=[],X=0;for(let z of $){if(X++,q0(z.id,J))continue;if(z.owned_by==="openai"){let D=Y$(z.id);G0(Y,"openai","openai-responses",_0(D));continue}if(z.owned_by==="anthropic"){let D=Y$(z.id);G0(Y,"anthropic","anthropic-messages",_0(D));continue}let{slug:Q,api:q}=M0(z.owned_by,j.proxy.providerPrefix),V=Y$(z.id);Z.push({id:z.id,name:V.name??z.id,reasoning:V.reasoning??!1,contextWindow:V.contextWindow??128000,maxTokens:V.maxTokens??16000,cost:V.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:q,suggestedProvider:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:Z,serverDiscoveryExcludes:[],upstreamTotal:X}}function G0($,j,J,Y){let Z=$.get(j);if(!Z)Z={name:j,api:J,models:[]},$.set(j,Z);Z.models.push(Y)}function _0($){return{id:$.id,name:$.name??$.id,reasoning:$.reasoning??!1,contextWindow:$.contextWindow??128000,maxTokens:$.maxTokens??16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function D$($,j){let J=await Lj($);if(J)return B.info(`discovery via /.well-known/pi: ${J.builtinProviders.length} builtin, ${J.customPool.length} custom`),c$(J),J;if(!j)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await Sj($,j),Z=Pj(Y,$);return B.info(`discovery via /v1/models: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),c$(Z),Z}function A0($){let j=new Set;for(let J of $.builtinProviders)for(let Y of J.models)j.add(Y.id);for(let J of $.customPool)j.add(J.id);return j}async function E$($,j,J){let Y={registered:[],skipped:[]},Z=A0(J),X=I(j.proxy.apiKey);if(!X)return B.warn("proxy apiKey is empty — dm.registerProvider calls will be skipped"),Y;let z=new Map;for(let q of J.builtinProviders)z.set(q.name,q.models.map((V)=>({id:V.id,name:V.name,reasoning:V.reasoning,contextWindow:V.contextWindow,maxTokens:V.maxTokens,cost:V.cost})));for(let[q,V]of Object.entries(j.builtinProviders)){if(!V?.enabled){Y.skipped.push({provider:q,reason:"disabled"});continue}if(!Array.isArray(V.models)||V.models.length===0){Y.skipped.push({provider:q,reason:"empty whitelist"});continue}let D=[];try{D=Ij(q)}catch{}let U=new Map(D.map((A)=>[A.id,A])),L=new Map((z.get(q)??[]).map((A)=>[A.id,A])),O=[];for(let A of V.models){if(!Z.has(A))continue;let H=U.get(A),P=L.get(A);if(H){O.push({id:H.id,name:H.name,reasoning:H.reasoning,contextWindow:H.contextWindow,maxTokens:H.maxTokens,cost:H.cost,input:H.input,api:H.api,thinkingLevelMap:H.thinkingLevelMap});continue}if(!P)continue;let p=q==="anthropic"?"anthropic-messages":V.apiOverride??"openai-responses";O.push({id:P.id,name:P.name,reasoning:P.reasoning,contextWindow:P.contextWindow,maxTokens:P.maxTokens,cost:P.cost,input:["text"],api:p})}if(O.length===0){Y.skipped.push({provider:q,reason:"no whitelisted models present on proxy"});continue}let _=V.apiOverride??O[0].api;if(!C$.has(_)){Y.skipped.push({provider:q,reason:`api "${_}" not in allowlist`});continue}let E=O.map((A)=>{let H=j.overrides[A.id]??{},P={id:A.id,name:typeof H.name==="string"?H.name:A.name,api:_,reasoning:typeof H.reasoning==="boolean"?H.reasoning:A.reasoning,input:A.input,cost:H.cost??A.cost,contextWindow:typeof H.contextWindow==="number"?H.contextWindow:A.contextWindow,maxTokens:typeof H.maxTokens==="number"?H.maxTokens:A.maxTokens};if(A.thinkingLevelMap)P.thinkingLevelMap=A.thinkingLevelMap;return P}),W={name:q,baseUrl:v$(_,j.proxy.endpoint),apiKey:X,authHeader:!0,api:_,models:E};$.registerProvider(q,W),Y.registered.push({provider:q,modelCount:E.length,api:_})}let Q=new Map(J.customPool.map((q)=>[q.id,q]));for(let[q,V]of Object.entries(j.customProviders)){if(!C$.has(V.api)){Y.skipped.push({provider:q,reason:`api "${V.api}" not in allowlist`});continue}let D=V.models.filter((O)=>Z.has(O.id));if(D.length===0){Y.skipped.push({provider:q,reason:"no configured models present on proxy"});continue}let U=D.map((O)=>{let _=Q.get(O.id),E=Y$(O.id),W=j.overrides[O.id]??{};return{id:O.id,name:O.name??_?.name??E.name??O.id,api:V.api,reasoning:bj(O.reasoning,_?.reasoning,E.reasoning,W.reasoning)??!1,input:["text"],cost:O.cost??_?.cost??E.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:n0(O.contextWindow,_?.contextWindow,E.contextWindow,W.contextWindow)??128000,maxTokens:n0(O.maxTokens,_?.maxTokens,E.maxTokens,W.maxTokens)??16000}}),L={name:q,baseUrl:v$(V.api,j.proxy.endpoint),apiKey:X,authHeader:!0,api:V.api,models:U};$.registerProvider(q,L),Y.registered.push({provider:q,modelCount:U.length,api:V.api})}return B.info(`applyAll: registered ${Y.registered.length} providers, skipped ${Y.skipped.length}`),Y}function n0(...$){for(let j of $)if(typeof j==="number")return j;return}function bj(...$){for(let j of $)if(typeof j==="boolean")return j;return}var xj=15000,U$=null;function X$(){U$=null}async function W0($,j,J={}){if(!J.force&&U$&&Date.now()-U$.fetchedAt<$.usageCacheTtlMs)return U$.doc;if(!j)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let Y=new URL("/api/usage",new URL($.proxy.endpoint).origin).toString(),Z=new AbortController,X=setTimeout(()=>Z.abort(Error("timeout")),xj),z;try{z=await fetch(Y,{headers:{"X-Plugin-Key":j,Accept:"application/json","User-Agent":Z$},signal:Z.signal})}finally{clearTimeout(X)}if(!z.ok)throw Error(`/api/usage returned ${z.status}`);let Q=await z.json();if(!Q||Q.schemaVersion!==1||!Array.isArray(Q.accounts))throw Error("/api/usage returned unexpected payload shape");return U$={fetchedAt:Date.now(),doc:Q},B.debug("usage fetched, accounts:",Q.accounts.length),Q}import{getKeybindings as A1,matchesKey as v}from"@duckmind/dm-tui";import{visibleWidth as m$}from"@duckmind/dm-tui";import{visibleWidth as H0}from"@duckmind/dm-tui";function F($,j){let J=H0($);if(J===j)return $;if(J<j)return $+" ".repeat(j-J);return l$($,j)}function l$($,j){if(j<=0)return"\x1B[0m";let J="",Y=0,Z=0;while(Z<$.length){let X=$[Z];if(X==="\x1B"&&$[Z+1]==="["){let Q=$.indexOf("m",Z+2);if(Q>=0){J+=$.slice(Z,Q+1),Z=Q+1;continue}}let z=H0(X);if(Y+z>j)break;J+=X,Y+=z,Z++}return`${J}\x1B[0m`}var yj="│",wj="╭",Cj="╮",vj="╰",uj="╯",R$="─";function i($,j){let J=Math.max(4,j.width);return[fj($,j.title,j.titleColor??"accent",J),...j.lines.map((Y)=>gj($,Y,J)),hj($,j.footer,J)]}function fj($,j,J,Y){let Z=j??"",X=m$(Z),z=Math.max(0,Y-3-X),Q=Z?$.bold($.fg(J,Z)):"",q=`${wj}${R$}${Q}${R$.repeat(z)}${Cj}`;return $.fg("borderAccent",q)}function gj($,j,J){let Y=Math.max(0,J-2),Z=$.fg("borderAccent",yj);return`${Z}${F(j,Y)}${Z}`}function hj($,j,J){let Y=`${vj}${R$}`,Z=`${uj}`,X=3;if(!j||!j.hint&&!j.badge){let _=Math.max(0,J-3);return $.fg("borderAccent",`${Y}${R$.repeat(_)}${Z}`)}let z=j.hint??"",Q=j.badge??"",q=m$(z),V=m$(Q),D=Math.max(0,J-3-q-V),U=$.fg("dim",z),L=Q?$.fg("muted",Q):"",O=R$.repeat(D);return`${$.fg("borderAccent",Y)}${U}${$.fg("borderAccent",O)}${L}${$.fg("borderAccent",Z)}`}function F$($){return Math.max(0,$-2)}import{existsSync as N0}from"node:fs";import{homedir as pj}from"node:os";import{getKeybindings as cj,Input as lj,matchesKey as mj}from"@duckmind/dm-tui";var rj=[{label:"endpoint",hint:"OpenAI-style base URL of your CliProxyAPI deployment, must include /v1",required:!0,validate:($)=>{try{if(!new URL($).pathname.endsWith("/v1"))return"must end with /v1";return null}catch{return"not a valid URL"}}},{label:"apiKey",hint:"CliProxyAPI bearer key. Accepts literal, $ENV_VAR, !cmd, or ~/path",required:!0},{label:"providerPrefix",hint:"Prefix for your custom provider names. Suggested groups become <prefix>-glm, <prefix>-gemini, etc. Use any short slug (letters/digits/dashes).",required:!0,validate:($)=>/^[a-z0-9][a-z0-9-]*$/i.test($)?null:"letters/digits/dashes only"},{label:"usageKey",hint:"Optional X-Plugin-Key for /api/usage. Leave blank to skip the Usage tab",required:!1}];async function G$($,j=!1){let J=o(),Y={endpoint:J.proxy.endpoint??"",apiKey:J.proxy.apiKey??"",providerPrefix:J.proxy.providerPrefix??"",usageKey:J.proxy.usageKey??""},Z=!1;for(let z of rj){let Q=j?Y[z.label]??z.initialValue??"":Y[z.label]??"";if(!j&&Q)continue;let q=await oj($,z,Q||z.initialValue||"");if(q===void 0){Z=!0;break}let V=q.trim();if(!V){if(z.required){$.ui.notify(`${z.label} is required — aborted`,"warning"),Z=!0;break}Y[z.label]="";continue}Y[z.label]=z.label==="providerPrefix"||z.label==="endpoint"?V:sj(V)}if(Z)return!1;let X={...J};if(X.proxy={...J.proxy,endpoint:Y.endpoint??"",apiKey:Y.apiKey??"",providerPrefix:Y.providerPrefix??""},Y.usageKey)X.proxy.usageKey=Y.usageKey;else delete X.proxy.usageKey;return B$(X),$.ui.notify(`saved to ${C}`,"info"),!0}function sj($){if($.startsWith("!")||$.startsWith("$"))return $;if($.startsWith("~/")){let j=$.replace(/^~/,pj());return N0(j)?`!cat ${$}`:$}if($.startsWith("/"))return N0($)?`!cat ${$}`:$;return $}async function oj($,j,J){return $.ui.custom((Y,Z,X,z)=>ij(Y,Z,j,J,z),{overlay:!0,overlayOptions:{width:100,maxHeight:"60%"}})}function ij($,j,J,Y,Z){let X=new lj;X.setValue(Y),X.focused=!0;let z=null,Q=(q)=>{if(!q&&!J.required){Z("");return}if(!q&&J.required){z="required field",$.requestRender();return}if(J.validate){let V=q.trim();if(V&&!V.startsWith("!")&&!V.startsWith("$")){let D=J.validate(V);if(D){z=D,$.requestRender();return}}}Z(q)};return X.onSubmit=Q,X.onEscape=()=>Z(void 0),{render(q){let V=F$(q),D=X.render(V-4),U=["",` ${j.fg("dim",J.hint)}`,"",...D.map((L)=>` ${j.fg("accent",`❯ ${L}`)}`),"",z?` ${j.fg("error",`! ${z}`)}`:` ${j.fg("dim","enter = save · esc = cancel")}`];return i(j,{width:q,title:` setup: ${J.label} `,lines:U,footer:{hint:" enter = save · esc = cancel "}})},invalidate(){X.invalidate()},handleInput(q){if(cj().matches(q,"tui.select.cancel")||mj(q,"escape")){Z(void 0);return}z=null,X.handleInput(q),$.requestRender()}}}import{visibleWidth as K$}from"@duckmind/dm-tui";function k0($,j,J,Y){let Z=$.fg("borderAccent","│"),X=j.map((z,Q)=>{let q=`${Q+1} ${z.label}`;return Q===J?$.bold($.fg("accent",` ${q} `)):$.fg("dim",` ${q} `)});return F(` ${X.join(Z)}`,Y)}function T0($,j,J){let Y=j.join($.fg("dim"," "));return F(` ${Y}`,J)}function B0($,j){return $.fg("borderAccent","─".repeat(Math.max(0,j)))}function d($,j,J){let Y=$.slice(j,j+J);while(Y.length<J)Y.push("");return Y}function L$($,j,J,Y,Z,X){if(Z<=Y)return 0;let z=Math.max(0,Z-Y);if(j<X)return 0;let Q=Math.max(0,Math.min(J,z)),q=Q+X;if($<q)Q=Math.max(0,$-X);let V=Q+Y-1;if(j>V)Q=Math.min(z,j-(Y-1));return Q}function S$($,j,J){let Y=Math.max(0,J-j);return Math.max(0,Math.min($,Y))}import{matchesKey as t}from"@duckmind/dm-tui";import{existsSync as dj,readFileSync as tj}from"node:fs";import{homedir as K0}from"node:os";import{join as L0}from"node:path";var aj=L0(K0(),".dm","models.json"),ej=L0(K0(),".dm","auth.json");function F0($){if(!dj($))return null;try{return JSON.parse(tj($,"utf8"))}catch{return null}}function S0($){let j=[],J=new Set([...Object.keys($.builtinProviders),...Object.keys($.customProviders)]),Y=F0(aj);if(Y&&typeof Y==="object"){for(let X of Object.keys(Y))if(J.has(X))j.push({kind:"models.json",provider:X,detail:`provider "${X}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let Z=F0(ej);if(Z&&typeof Z==="object"){for(let X of Object.keys(Z))if(J.has(X))j.push({kind:"auth.json",provider:X,detail:`provider "${X}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return j}function P0($){let{theme:j,cfg:J}=$,Y=0,Z=()=>{let Q=$.getDiscovery(),q=(_)=>j.fg("success",_),V=(_)=>j.fg("error",_),D=(_)=>j.fg("dim",_),U=[];U.push(`${D("endpoint")} ${J.proxy.endpoint||V("(unset)")}`),U.push(`${D("apiKey")} ${I(J.proxy.apiKey)?q("resolves"):V("empty after resolution")}`),U.push(`${D("usageKey")} ${J.proxy.usageKey?I(J.proxy.usageKey)?q("resolves"):V("set but empty"):D("not configured")}`),U.push(`${D("user-agent")} ${Z$}`),U.push(""),U.push(`${D("discovery")} source=${Q.source}`),U.push(`${D("upstream")} v=${Q.upstreamVersion??"(unknown)"} · ${Q.upstreamTotal} ids`);let L=Q.builtinProviders.map((_)=>`${_.name}=${_.models.length}`).join(", ")||D("(none)");U.push(`${D("built-in")} ${L}`),U.push(`${D("custom pool")} ${Q.customPool.length} models`);let O=S0(J);if(U.push(""),O.length===0)U.push(`${D("conflicts")} ${q("none")}`);else{U.push(`${D("conflicts")}`);for(let _ of O)U.push(` ${j.fg("warning",`[${_.kind}]`)} ${_.detail}`)}return U};return{id:"diagnostics",label:"Diagnostics",render:(Q,q)=>{let V=Z();return Y=S$(Y,q,V.length),d(V,Y,q).map((D)=>F(` ${D}`,Q))},handleInput:(Q)=>{let q=Z().length;if(t(Q,"up")||t(Q,"k"))return Y=Math.max(0,Y-1),!0;if(t(Q,"down")||t(Q,"j"))return Y=Math.min(Math.max(0,q-1),Y+1),!0;if(t(Q,"pageUp")||t(Q,"b"))return Y=Math.max(0,Y-10),!0;if(t(Q,"pageDown")||t(Q,"f"))return Y=Math.min(Math.max(0,q-1),Y+10),!0;return!1},footerHint:()=>" ↑↓ scroll · r refresh discovery "}}import{matchesKey as k}from"@duckmind/dm-tui";function r$($){let j=new Map,J=new Map;for(let Z of $.builtinProviders){let X=[];for(let z of Z.models)j.set(z.id,{id:z.id,name:z.name,suggestedApi:Z.api,subtitle:z.name&&z.name!==z.id?z.name:void 0,ownedBy:Z.name,reasoning:z.reasoning,contextWindow:z.contextWindow,maxTokens:z.maxTokens,cost:z.cost}),X.push(z.id);J.set(Z.name,X)}let Y=[];for(let Z of $.customPool){if(!j.has(Z.id))j.set(Z.id,{id:Z.id,name:Z.name,suggestedApi:Z.api,subtitle:Z.name&&Z.name!==Z.id?Z.name:void 0,origin:Z.suggestedProvider,ownedBy:Z.ownedBy,reasoning:Z.reasoning,contextWindow:Z.contextWindow,maxTokens:Z.maxTokens,cost:Z.cost});Y.push(Z.id)}return{byId:j,builtinModelIds:J,customPoolIds:Y}}function $1($){let j=new Map;for(let[J,Y]of Object.entries($.customProviders))for(let Z of Y.models)j.set(Z.id,J);return j}function $$($,j){if(j.kind==="builtin")return[...$.builtinProviders[j.name]?.models??[]];return $.customProviders[j.name]?.models.map((J)=>J.id)??[]}function I0($,j,J){if(j.kind==="builtin"){let X=J.builtinModelIds.get(j.name)??[],z=new Set($$($,j));return X.filter((Q)=>!z.has(Q))}let Y=$1($),Z=new Set($$($,j));return J.customPoolIds.filter((X)=>{if(Z.has(X))return!1;let z=Y.get(X);return z===void 0||z===j.name})}function j1($){return{id:$.id,name:$.name,contextWindow:$.contextWindow,maxTokens:$.maxTokens,reasoning:$.reasoning,cost:$.cost}}function b0($,j,J){if(j.kind==="builtin"){let Z=$.builtinProviders[j.name]??{enabled:!0,models:[]},X=new Set(Z.models);X.add(J.id),$.builtinProviders[j.name]={enabled:!0,apiOverride:Z.apiOverride??null,models:Array.from(X).sort()};return}for(let[Z,X]of Object.entries($.customProviders)){if(Z===j.name)continue;let z=X.models.findIndex((Q)=>Q.id===J.id);if(z>=0)X.models.splice(z,1)}let Y=$.customProviders[j.name]??{api:j.api,models:[]};if(!Y.models.some((Z)=>Z.id===J.id))Y.models.push(j1(J));$.customProviders[j.name]=Y}function x0($,j,J){if(j.kind==="builtin"){let Z=$.builtinProviders[j.name];if(!Z)return;Z.models=Z.models.filter((X)=>X!==J),Z.enabled=Z.models.length>0;return}let Y=$.customProviders[j.name];if(!Y)return;Y.models=Y.models.filter((Z)=>Z.id!==J)}function s$($,j){if($===j)return!0;let J=["openai-completions","openai-responses"];if(J.includes($)&&J.includes(j))return!0;return!1}function y0($,j){let J=new Map;for(let Y of $){let Z=j.byId.get(Y),X=Z?.ownedBy||Z?.origin||"misc",z=J.get(X)??[];z.push(Y),J.set(X,z)}return Array.from(J.entries()).sort((Y,Z)=>Y[0].localeCompare(Z[0])).map(([Y,Z])=>({label:Y,ids:Z}))}function w0($,j,J){let Y=J.trim().toLowerCase();if(!Y)return $;return $.filter((Z)=>{if(Z.toLowerCase().includes(Y))return!0;let X=j.byId.get(Z)?.name;return X?X.toLowerCase().includes(Y):!1})}import{getModels as J1,getProviders as Y1}from"@duckmind/dm-ai/compat";function o$($,j){let J=[],Y=new Set(j.builtinModelIds.keys()),Z=new Set(Y1()),X=new Set([...Y,...Z]);for(let z of Array.from(X).sort()){let Q=j.builtinModelIds.get(z);if(!Q||Q.length===0)continue;let q;try{let D=J1(z).find((U)=>Q.includes(U.id));if(D)q=D.api}catch{}if(!q){let V=Q[0];q=j.byId.get(V)?.suggestedApi??"openai-responses"}if(J.push({kind:"builtin",name:z,api:q,subtitle:`built-in · ${q}`}),!$.builtinProviders[z])$.builtinProviders[z]={enabled:!1,models:[]}}for(let z of Object.keys($.customProviders).sort()){let Q=$.customProviders[z];J.push({kind:"custom",name:z,api:Q.api,subtitle:`custom · ${Q.api}`})}return J}import{getKeybindings as Z1,matchesKey as Q$}from"@duckmind/dm-tui";async function C0($,j){return $.ui.custom((J,Y,Z,X)=>X1(Y,`Remove custom group “${j}”?`,"All model assignments in this group will be discarded.",X),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function X1($,j,J,Y){return{render(Z){return i($,{width:Z,title:" confirm ",titleColor:"error",lines:["",` ${$.bold(j)}`,` ${$.fg("dim",J)}`,""],footer:{hint:" y / enter = remove · n / esc = cancel "}})},invalidate(){},handleInput(Z){if(Z1().matches(Z,"tui.select.cancel")||Q$(Z,"escape")||Q$(Z,"n")||Q$(Z,"q")){Y(!1);return}if(Q$(Z,"y")||Q$(Z,"enter")||Q$(Z,"return")){Y(!0);return}}}}import{getKeybindings as Q1,Input as z1,matchesKey as q1}from"@duckmind/dm-tui";async function v0($,j){let J=W$(j,"group");return $.ui.custom((Y,Z,X,z)=>V1(Y,Z,J,z),{overlay:!0,overlayOptions:{width:80,maxHeight:"40%"}})}function V1($,j,J,Y){let Z=new z1;if(J)Z.setValue(J);Z.focused=!0;let X=null;return Z.onSubmit=(z)=>{let Q=z.trim();if(!/^[a-z0-9][a-z0-9._-]*$/i.test(Q)){X="letters / digits / dot / dash / underscore only",$.requestRender();return}Y(Q)},Z.onEscape=()=>Y(null),{render(z){let Q=F$(z),q=J?`name shown in /model picker, e.g. ${J}`:"letters / digits / dot / dash / underscore",V=Z.render(Q-4),D=["",` ${j.fg("dim",q)}`,"",...V.map((U)=>` ${j.fg("accent",`❯ ${U}`)}`),"",X?` ${j.fg("error",`! ${X}`)}`:""];return i(j,{width:z,title:" new custom group ",lines:D,footer:{hint:" enter = create · esc = cancel "}})},invalidate(){Z.invalidate()},handleInput(z){if(Q1().matches(z,"tui.select.cancel")||q1(z,"escape")){Y(null);return}X=null,Z.handleInput(z),$.requestRender()}}}import{visibleWidth as M1}from"@duckmind/dm-tui";function i$($,j,J){if(!j)return" ";if(J)return $.fg("accent","▶ ");return $.fg("muted","▸ ")}function u0($,j){let J=M1($);if(J===j)return $;if(J>j)return l$($,j);return F($,j)}function f0($,j,J){let{theme:Y,width:Z,isCursor:X,isFocused:z}=J,Q=i$(Y,X,z),q=$.kind==="builtin"?j.builtinProviders[$.name]?.models.length??0:j.customProviders[$.name]?.models.length??0,V=$.kind==="builtin"?Y.fg("accent","B"):Y.fg("warning","C"),D=`${Y.fg("dim","[")}${V}${Y.fg("dim","]")}`,U=q>0?Y.fg("success","●"):Y.fg("dim","○"),L=q>0?Y.fg("success",String(q).padStart(2)):Y.fg("dim"," 0"),O=X&&z?Y.bold(Y.fg("accent",$.name)):X?Y.bold($.name):$.name,_=Y.fg("dim",$.api),E=`${Q}${D} ${O} ${U}${L} ${_}`;return u0(E,Z)}function g0($,j,J,Y){let Z=i$($,j,J),X=j&&J?$.bold($.fg("accent","+ new custom group…")):$.fg("accent","+ new custom group…");return F(`${Z}${X}`,Y)}function d$($,j,J,Y,Z){let{theme:X,width:z,isCursor:Q,isFocused:q}=Z,V=i$(X,Q,q),D=J==="assigned"?X.fg("success","☑"):X.fg("dim","☐"),U=Y?` ${X.fg("warning","⚠")}`:"",L=Q&&q?X.fg("accent",$):$,O=j?.reasoning?` ${X.fg("accent","✨")}`:"",_=j?X.fg("muted",` · ${j.suggestedApi}`):X.fg("error"," · not on proxy"),E=`${V}${D} ${L}${U}${O}${_}`;return u0(E,z)}function h0($,j,J){let Y=`${$.fg("borderAccent","──")} ${$.fg("warning",j)} ${$.fg("borderAccent","──")}`;return F(` ${Y}`,J)}function t$($,j,J){return F(` ${$.fg("dim",j)}`,J)}function p0($,j,J,Y){let Z=Y?$.bold($.fg("accent","❚ ")):$.fg("dim"," ");return F(`${Z}${j}`,J)}function c0($){let{tui:j,theme:J,ctx:Y,cfg:Z}=$,X=$.onChange??(()=>{}),z=r$($.getDiscovery()),Q=o$(Z,z),q="providers",V=0,D=0,U=0,L=0,O=0,_=0,E="",W=!1,A=()=>{if(Q.length===0)return null;let M=Math.max(0,Math.min(V,Q.length-1));return Q[M]??null},H=(M)=>{let n=w0(I0(Z,M,z),z,E);return y0(n,z)},P=(M)=>H(M).flatMap((n)=>n.ids),p=()=>{Q=o$(Z,z);let M=Math.max(0,Q.length);if(V>M)V=M;let n=A();if(n){let S=$$(Z,n).length,N=P(n).length;if(D>=S)D=Math.max(0,S-1);if(U>=N)U=Math.max(0,N-1)}},P$=()=>{z=r$($.getDiscovery()),p()},_$=(M)=>{let n=["providers","assigned","pool"],S=n.indexOf(q);q=M?n[(S-1+n.length)%n.length]:n[(S+1)%n.length]},G=(M)=>{if(q==="providers"){let N=Q.length+1;V=Math.max(0,Math.min(V+M,N-1));return}let n=A();if(!n)return;if(q==="assigned"){let N=$$(Z,n).length;if(N===0)return;D=Math.max(0,Math.min(D+M,N-1));return}let S=P(n).length;if(S===0)return;U=Math.max(0,Math.min(U+M,S-1))},b=async()=>{if(q==="providers"){if(V===Q.length){let N=await v0(Y,Z.proxy.providerPrefix);if(N&&!Z.customProviders[N]){if(Z.customProviders[N]={api:"openai-completions",models:[]},X(),p(),V=Q.findIndex((K)=>K.kind==="custom"&&K.name===N),V<0)V=Q.length-1;q="pool"}j.requestRender();return}q="pool";return}let M=A();if(!M)return;if(q==="assigned"){let N=$$(Z,M)[D];if(!N)return;x0(Z,M,N),X(),p();return}let n=P(M)[U];if(!n)return;let S=z.byId.get(n);if(!S)return;b0(Z,M,S),X(),p()},l=async()=>{if(q!=="providers")return;let M=A();if(!M||M.kind!=="custom")return;if(!await C0(Y,M.name)){j.requestRender();return}if(delete Z.customProviders[M.name],X(),p(),V>=Q.length)V=Math.max(0,Q.length-1);j.requestRender()},u=(M,n)=>h(M,n);function h(M,n){let S=Math.max(70,M),N=Math.min(56,Math.max(34,Math.floor(S*0.4))),K=S-N-1,m=Math.max(8,n),r=Math.max(5,Math.floor((m-1)/2)),a$=m-r,c=A(),z$=0,I$=0,b$=0,e$=0,x$=0,$0=0,a=[];a.push(j$(" providers ",N,q==="providers"));for(let T=0;T<Q.length;T++){let f=Q[T],w=q==="providers"&&T===V;if(w)z$=a.length,I$=z$;a.push(f0(f,Z,{theme:J,width:N,isCursor:w,isFocused:q==="providers"}))}{let T=q==="providers"&&V===Q.length;if(T)z$=a.length,I$=z$;a.push(g0(J,T,q==="providers",N))}let e=[],jj=c?`assigned to ${J.bold(c.name)} ${J.fg("dim",`· ${c.api}`)}`:J.fg("dim","no provider selected");if(e.push(j$(" assigned ",K,q==="assigned")),e.push(p0(J,jj,K,q==="assigned")),c){let T=$$(Z,c);if(T.length===0)e.push(t$(J,"(nothing assigned yet)",K));for(let f=0;f<T.length;f++){let w=T[f],g=z.byId.get(w),n$=q==="assigned"&&f===D;if(n$)b$=e.length,e$=b$;let J$=g?!s$(c.api,g.suggestedApi):!1;e.push(d$(w,g,"assigned",J$,{theme:J,width:K,isCursor:n$,isFocused:q==="assigned"}))}}let s=[];if(s.push(x(K,q==="pool")),c){let T=H(c);if(T.reduce((w,g)=>w+g.ids.length,0)===0)s.push(t$(J,E?`(no matches for "${E}")`:"(no models available)",K));else{let w=0;for(let g of T){let n$=s.length;s.push(h0(J,g.label,K));for(let J$=0;J$<g.ids.length;J$++){let Q0=g.ids[J$],w$=z.byId.get(Q0),z0=q==="pool"&&w===U;if(z0)x$=s.length,$0=J$===0?n$:x$;let Xj=w$?!s$(c.api,w$.suggestedApi):!1;s.push(d$(Q0,w$,"pool",Xj,{theme:J,width:K,isCursor:z0,isFocused:q==="pool"})),w++}}}}let Jj=Math.max(1,a$-1),j0=L$(I$,z$,L,m,a.length,1),J0=L$(q==="assigned"?e$:0,q==="assigned"?b$:0,O,r,e.length,2),Y0=L$(q==="pool"?$0:0,q==="pool"?x$:0,_,Jj,s.length,1);L=j0,O=J0,_=Y0;let Z0=d(a,j0,m),Yj=d(e,J0,r),Zj=d(s,Y0,a$),X0=J.fg("borderAccent","│"),y$=[];for(let T=0;T<m;T++){let f=F(Z0[T]??"",N),w=T<r?Yj[T]:Zj[T-r],g=F(w,K);y$.push(`${f}${X0}${g}`)}let A$=r;if(A$>0&&A$<m){let T=F(Z0[A$]??"",N),f=J.fg("borderAccent","─".repeat(K));y$[A$]=`${T}${X0}${f}`}return y$}function j$(M,n,S){let N=S?J.bold(J.fg("accent",M)):J.fg("muted",M),K=J.fg("borderAccent","─".repeat(Math.max(0,n-K$(M)-1)));return F(`${N}${K}`,n)}function x(M,n){let N=n?J.bold(J.fg("accent"," available pool ")):J.fg("muted"," available pool "),K="";if(W)K=`${J.fg("dim"," /")}${J.fg("accent",E)}${J.fg("accent","█")} `;else if(E)K=`${J.fg("dim"," /")}${J.fg("warning",E)} `;let m=K$(" available pool ")+K$(K),r=J.fg("borderAccent","─".repeat(Math.max(0,M-m-1)));return F(`${N}${K}${r}`,M)}function O$(M){if(W){if(k(M,"escape"))return E="",W=!1,U=0,!0;if(k(M,"enter")||k(M,"return"))return W=!1,!0;if(k(M,"backspace")||k(M,"delete"))return E=E.slice(0,-1),U=0,!0;if(M.length===1&&M>=" "&&M!=="")return E+=M,U=0,!0;return!0}if(k(M,"tab"))return _$(!1),!0;if(k(M,"shift+tab"))return _$(!0),!0;if(k(M,"/"))return q="pool",W=!0,!0;if(k(M,"enter")||k(M,"return")||k(M,"space"))return b().then(()=>!0);if(q==="providers"&&(k(M,"d")||k(M,"delete")||k(M,"backspace")))return l().then(()=>!0);if(k(M,"up")||k(M,"k"))return G(-1),!0;if(k(M,"down")||k(M,"j"))return G(1),!0;if(k(M,"pageUp")||k(M,"b"))return G(-8),!0;if(k(M,"pageDown")||k(M,"f"))return G(8),!0;if(k(M,"left")||k(M,"h"))return q="providers",!0;if(k(M,"right")||k(M,"l")){if(q==="providers")q="assigned";else if(q==="assigned")q="pool";return!0}return!1}function $j(){if(W)return" type to filter · ↵ apply · esc clear ";return" tab ↔ panel · ↑↓ nav · ↵ move · / filter · d remove group "}return{id:"models",label:"Models",render:u,handleInput:O$,footerHint:$j,rebuild:P$}}import{matchesKey as y}from"@duckmind/dm-tui";var R={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",accent:"\x1B[38;5;111m",muted:"\x1B[38;5;245m",dim2:"\x1B[38;5;240m",green:"\x1B[38;5;114m",yellow:"\x1B[38;5;179m",red:"\x1B[38;5;167m",greenBg:"\x1B[48;5;22m",yellowBg:"\x1B[48;5;94m",redBg:"\x1B[48;5;52m"};function l0($,j={}){let J=[],Y=new Map,Z=0;for(let X of $.accounts){if(!j.showDisabled&&X.disabled){Z++;continue}let z=Y.get(X.provider)??[];z.push(X),Y.set(X.provider,z)}if(J.push(`${R.dim}generated ${$.generatedAt}${R.reset}`),$.unsupportedProviders.length>0)J.push(`${R.dim}providers without quota lookup:${R.reset} ${$.unsupportedProviders.join(", ")}`);if(Z>0)J.push(`${R.dim}hidden disabled accounts:${R.reset} ${Z} ${R.dim2}(press d to show)${R.reset}`);for(let[X,z]of Array.from(Y.entries()).sort()){J.push(""),J.push(`${R.bold}${R.accent}▌ ${X}${R.reset}`);for(let Q of z){if(J.push(E1(Q)),!Q.supported){J.push(` ${R.dim2}(provider not quota-aware)${R.reset}`);continue}if(Q.error){if(j.verbose)for(let V of D1(Q.error,88))J.push(` ${R.red}${V}${R.reset}`);continue}let q=Q.groups??[];if(q.length===0){J.push(` ${R.dim2}(no active quota windows)${R.reset}`);continue}for(let V of q)J.push(R1(V))}}return J.push(""),J.push(`${R.dim}legend:${R.reset} ${m0} ok ${r0} error/unavailable ${s0} disabled ${R.green}✓N${R.reset}/${R.red}✗N${R.reset} request counters ${R.dim}v = verbose, d = show disabled${R.reset}`),J}function D1($,j){if($.length<=j)return[$];let J=[],Y=$;while(Y.length>j){let Z=Y.lastIndexOf(" ",j);if(Z<j*0.6)Z=j;J.push(Y.slice(0,Z)),Y=Y.slice(Z).replace(/^\s+/,"")}if(Y)J.push(Y);return J}function E1($){let j=U1($),J=`${R.green}✓${$.success}${R.reset} ${R.red}✗${$.failed}${R.reset}`,Y=d0($.label,36);return` ${j} ${R.bold}${Y}${R.reset} ${J}`}var m0=`${R.green}●${R.reset}`,r0=`${R.yellow}⚠${R.reset}`,s0=`${R.dim2}⊘${R.reset}`;function U1($){if($.disabled)return s0;if($.unavailable||$.error||$.status&&$.status!=="active")return r0;return m0}function R1($){let j=i0($.remainingFraction),J=Math.round(j*100),Y=G1(j),Z=$.resetTime?` ${R.dim}reset ${O1($.resetTime)}${R.reset}`:"",X=d0($.label,28).padEnd(28," ");return` ${Y} ${_1(J,j)} ${X}${Z}`}function G1($){let j=i0($),J=Math.round(j*18),Y=o0(j),Z=R.dim2,X="█".repeat(J),z="░".repeat(18-J);return`${Z}[${Y}${X}${Z}${z}]${R.reset}`}function _1($,j){return`${o0(j)}${String($).padStart(3)}%${R.reset}`}function o0($){if($>=0.4)return R.green;if($>=0.15)return R.yellow;return R.red}function O1($){let j=Date.parse($);if(!Number.isFinite(j))return $;let J=j-Date.now();if(J<=0)return"now";let Y=Math.round(J/60000);if(Y<60)return`${Y}m`;let Z=Math.round(Y/60);if(Z<48)return`${Z}h`;return`${Math.round(Z/24)}d`}function i0($){return Math.max(0,Math.min(1,$))}function d0($,j){if($.length<=j)return $;return`${$.slice(0,j-1)}…`}function t0($){let{tui:j,theme:J,cfg:Y}=$,Z="idle",X=null,z="",Q=0,q=!1,V=!1,D=(E)=>{Z="loading",j.requestRender();let W=I(Y.proxy.usageKey);W0(Y,W,{force:E}).then((A)=>{X=A,Z="ready",Q=0,j.requestRender()}).catch((A)=>{z=A.message,Z="error",j.requestRender()})},U=()=>{if(Z==="idle"||Z==="loading")return[J.fg("dim"," loading usage…")];if(Z==="error")return[J.fg("error",` usage failed: ${z}`)];if(!X)return[J.fg("dim"," (no data)")];return l0(X,{showDisabled:q,verbose:V})};return{id:"usage",label:"Usage",render:(E,W)=>{let A=U();return Q=S$(Q,W,A.length),d(A,Q,W).map((H)=>F(` ${H}`,E))},handleInput:(E)=>{if(y(E,"d"))return q=!q,Q=0,!0;if(y(E,"v"))return V=!V,Q=0,!0;let W=U().length;if(y(E,"up")||y(E,"k"))return Q=Math.max(0,Q-1),!0;if(y(E,"down")||y(E,"j"))return Q=Math.min(Math.max(0,W-1),Q+1),!0;if(y(E,"pageUp")||y(E,"b"))return Q=Math.max(0,Q-10),!0;if(y(E,"pageDown")||y(E,"f"))return Q=Math.min(Math.max(0,W-1),Q+10),!0;if(y(E,"home")||y(E,"g"))return Q=0,!0;if(y(E,"end")||y(E,"shift+g"))return Q=Math.max(0,W-1),!0;return!1},footerHint:()=>{let E=q?J.fg("success","[d disabled]"):"d disabled",W=V?J.fg("success","[v verbose]"):"v verbose";return` ↑↓ scroll · ${E} · ${W} `},onActivate:()=>{if(Z==="idle")D(!1)},reload:()=>{if(X$(),Z!=="idle")D(!0)}}}function a0($){let{dm:j,ctx:J,tui:Y,theme:Z,cfg:X,done:z}=$,Q=$.discovery,q=!1,V="",D=c0({tui:Y,theme:Z,ctx:J,cfg:X,getDiscovery:()=>Q,onChange:()=>{q=!0,V=""}}),U=t0({tui:Y,theme:Z,cfg:X}),L=P0({theme:Z,cfg:X,getDiscovery:()=>Q}),O=[D,U,L],_=0,E=()=>O[_],W=(G)=>{if(G<0||G>=O.length||G===_)return;_=G,E().onActivate?.(),Y.requestRender()},A=()=>{V=Z.fg("dim","saving…"),B$(X),Y.requestRender(),E$(j,X,Q).then((G)=>{q=!1,V=Z.fg("success",`✓ settings saved · ${G.registered.length} registered, ${G.skipped.length} skipped`),Y.requestRender()}).catch((G)=>{V=Z.fg("error",`save failed: ${G.message}`),Y.requestRender()})},H=async()=>{V=Z.fg("dim","refreshing…"),Y.requestRender();try{let G=I(X.proxy.apiKey);Q=await D$(X,G),X$(),D.rebuild(),U.reload();let b=await E$(j,X,Q);V=Z.fg("success",`✓ refreshed · ${b.registered.length} providers (${Q.source})`)}catch(G){V=Z.fg("error",`refresh failed: ${G.message}`)}Y.requestRender()},P=async()=>{if(!await G$(J,!0)){Y.requestRender();return}let b=o();X.proxy={...X.proxy,...b.proxy},await H()},p=()=>{let G=X.proxy.endpoint||"(unset)",b=G.length>40?`…${G.slice(-39)}`:G,l=Boolean(I(X.proxy.apiKey)),u=0,h=0;for(let x of Object.values(X.builtinProviders)){if(x.enabled&&x.models.length>0)u++;h+=x.models.length}for(let x of Object.values(X.customProviders)){if(x.models.length>0)u++;h+=x.models.length}let j$=V?V:q?Z.fg("warning","● unsaved — press s to save"):Z.fg("dim","✓ saved");return[`${Z.fg("dim","endpoint")} ${b}`,`${Z.fg("dim","key")} ${l?Z.fg("success","✓"):Z.fg("error","✗")}`,`${Z.fg("dim","providers")} ${u}`,`${Z.fg("dim","models")} ${h}`,j$]},P$=(G)=>{let b=Y.rows??40,u=Math.max(16,Math.min(b-6,38))-2,h=Math.max(72,G-2),j$=Math.max(6,u-3),x=[];return x.push(T0(Z,p(),h)),x.push(k0(Z,O.map((O$)=>({id:O$.id,label:O$.label})),_,h)),x.push(B0(Z,h)),x.push(...E().render(h,j$)),i(Z,{width:G,title:" /cliproxy ",lines:x,footer:{hint:E().footerHint(),badge:" [ ] tab · r refresh · e setup · s save · q close "}})},_$=(G)=>{if(A1().matches(G,"tui.select.cancel")||v(G,"q")||v(G,"escape"))return z(),!0;if(v(G,"]")||v(G,"tab"))return W((_+1)%O.length),!0;if(v(G,"[")||v(G,"shift+tab"))return W((_-1+O.length)%O.length),!0;if(v(G,"1"))return W(0),!0;if(v(G,"2"))return W(1),!0;if(v(G,"3"))return W(2),!0;if(v(G,"r"))return H().then(()=>!0);if(v(G,"e"))return P().then(()=>!0);if(v(G,"s"))return A(),!0;return!1};return{render:P$,invalidate(){},handleInput(G){let b=E().handleInput(G);if(b instanceof Promise){V="",b.then((u)=>{if(u)Y.requestRender()});return}if(b){V="",Y.requestRender();return}let l=_$(G);if(l instanceof Promise)l.then((u)=>{if(u)Y.requestRender()});else if(l)Y.requestRender()}}}async function e0($,j,J,Y){if(!j.hasUI){j.ui.notify("interactive UI required for /cliproxy","warning");return}let Z=structuredClone(J);u$(!0);try{await j.ui.custom((X,z,Q,q)=>a0({dm:$,ctx:j,tui:X,theme:z,cfg:Z,discovery:Y,done:q}),{overlay:!0,overlayOptions:{width:170,maxHeight:"94%"}})}finally{u$(!1)}}function HJ($){$.registerCommand("cliproxy",{description:"Manage proxy models, usage, and diagnostics in one hub overlay",handler:n1.bind(null,$)}),$.registerCommand("cliproxy-setup",{description:"Set endpoint, API key, and (optional) usage key for the proxy",handler:W1.bind(null,$)})}async function n1($,j,J){let Y=o();if(!Y.proxy.endpoint||!I(Y.proxy.apiKey)){if(J.ui.notify("endpoint or API key not set — launching setup first","info"),!await G$(J,!0))return}let Z=o(),X=I(Z.proxy.apiKey),z;try{z=await D$(Z,X)}catch(Q){J.ui.notify(`discovery failed: ${Q.message}`,"error");return}await e0($,J,Z,z)}async function W1($,j,J){if(!await G$(J,!0))return;let Z=o();try{let X=await D$(Z,I(Z.proxy.apiKey)),z=await E$($,Z,X);X$(),J.ui.notify(`setup ok · ${z.registered.length} providers registered (source=${X.source})`,"info")}catch(X){J.ui.notify(`setup saved, but apply failed: ${X.message}`,"warning")}}export{HJ as registerCommands};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var K=new Set(["openai-completions","openai-responses","anthropic-messages"]);function h(b,c){let j=c.replace(/\/+$/,"");if(b==="anthropic-messages")return j.replace(/\/v1$/,"");return j}function M(b,c){if(!b)return!0;for(let j of c)if(new RegExp("^"+j.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test(b))return!0;return!1}var H=128000,J=16000,Q={input:0,output:0,cacheRead:0,cacheWrite:0},V=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function Y(b){return V.some((c)=>c.test(b))}var Z=[[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 q(b,c){let j=(b??"").trim();return j?`${j}-${c}`:c}function W(b,c){let j=(c??"").trim(),k=b.match(/^([a-z0-9]+-)(.*)$/);if(k)return j?`${j}-${k[1]}`:k[1];return b}function l(b,c){for(let[j,k,z]of Z)if(j.has(b))return{slug:q(c,k),api:z};return{slug:q(c,"misc"),api:"openai-completions"}}function $(b){return b.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((c)=>c[0].toUpperCase()+c.slice(1)).join(" ")}function y(b){return{id:b,name:$(b),contextWindow:H,maxTokens:J,reasoning:Y(b),cost:{...Q}}}export{q as withProviderPrefix,Y as reasoningFromId,$ as prettifyName,W as normalizeSuggestedProvider,y as modelDefaults,M as isExcluded,l as classifyCustom,h as baseUrlFor,J as DEFAULT_MAX_TOKENS,Q as DEFAULT_COST,H as DEFAULT_CONTEXT_WINDOW,K as ALLOWED_APIS};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{execSync as w}from"node:child_process";import{randomUUID as L}from"node:crypto";import{chmodSync as V,constants as k,copyFileSync as B,existsSync as R,linkSync as v,mkdirSync as U,readFileSync as x,rmSync as E,writeFileSync as O}from"node:fs";import{homedir as D}from"node:os";import{dirname as z,join as Y}from"node:path";import{fileURLToPath as T}from"node:url";var M=!1;var b={info(...K){if(!M)console.log("[dm-cliproxy]",...K)},warn(...K){if(!M)console.warn("[dm-cliproxy]",...K)},error(...K){if(!M)console.error("[dm-cliproxy]",...K)},debug(...K){if(!M&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...K)}};var A=Y(D(),".dm","agent","dm-cliproxy"),X=Y(A,"config.json"),G=[Y(D(),".pi","agent","pi-cliproxyapi","config.json"),Y(D(),".config","pi-cliproxyapi","config.json")];function N(){return R(Y(z(T(import.meta.url)),"..",".git"))}function I(K=G,J=X,Q=N()){if(R(J))return;let $=(typeof K==="string"?[K]:[...K]).find((q)=>R(q));if(!$)return;let Z;try{U(z(J),{recursive:!0,mode:448}),V(z(J),448),Z=`${J}.${process.pid}.${L()}.tmp`,B($,Z,k.COPYFILE_EXCL),V(Z,384),v(Z,J),E(Z),Z=void 0,b.info("legacy config copied to",J)}catch(q){if(Z)try{E(Z,{force:!0})}catch(H){b.warn("failed to clean temporary config:",H)}b.warn("failed to migrate legacy config:",q)}}var j={proxy:{endpoint:"",apiKey:""},builtinProviders:{},customProviders:{},discoveryExcludes:["*:*"],overrides:{},refreshIntervalMinutes:0,usageCacheTtlMs:30000};function s(){if(I(),!R(X))return b.debug("config not found, using defaults at",X),structuredClone(j);try{let K=JSON.parse(x(X,"utf8"));return _(K)}catch(K){return b.error("failed to read config:",K,"— using defaults"),structuredClone(j)}}function d(K){U(z(X),{recursive:!0,mode:448}),V(z(X),448);let J=`${X}.${process.pid}.${L()}.tmp`;try{O(J,JSON.stringify(K,null,2)+`
|
|
2
|
+
`,{encoding:"utf8",flag:"wx",mode:384}),B(J,X),V(X,384)}finally{E(J,{force:!0})}b.info("config saved to",X)}function _(K){if(!K||typeof K!=="object")return structuredClone(j);let J=K,Q=structuredClone(j),W=J.proxy??{};if(Q.proxy.endpoint=typeof W.endpoint==="string"?W.endpoint:Q.proxy.endpoint,Q.proxy.apiKey=typeof W.apiKey==="string"?W.apiKey:"",typeof W.usageKey==="string")Q.proxy.usageKey=W.usageKey;if(typeof W.providerPrefix==="string"&&W.providerPrefix.trim())Q.proxy.providerPrefix=W.providerPrefix.trim();if(J.builtinProviders&&typeof J.builtinProviders==="object")Q.builtinProviders=J.builtinProviders;if(J.customProviders&&typeof J.customProviders==="object")Q.customProviders=J.customProviders;if(Array.isArray(J.discoveryExcludes))Q.discoveryExcludes=J.discoveryExcludes.filter(($)=>typeof $==="string");if(J.overrides&&typeof J.overrides==="object")Q.overrides=J.overrides;if(typeof J.refreshIntervalMinutes==="number")Q.refreshIntervalMinutes=J.refreshIntervalMinutes;if(typeof J.usageCacheTtlMs==="number")Q.usageCacheTtlMs=J.usageCacheTtlMs;return Q}function m(K){if(!K)return"";let J=K.trim();if(J.startsWith("!"))try{return w(J.slice(1),{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}catch(Q){let W=Q?.stderr?.toString?.()?.trim()??Q.message;return b.warn(`failed to resolve "!" config value (${J}): ${W}`),""}if(J.startsWith("$"))return process.env[J.slice(1)]??"";return J}export{d as saveConfig,m as resolveConfigValue,I as migrateLegacyConfig,s as loadConfig,N as isLocalCheckout,G as LEGACY_CONFIG_PATHS,X as CONFIG_PATH,A as CONFIG_DIR};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as c,readFileSync as f}from"node:fs";import{homedir as d}from"node:os";import{join as a}from"node:path";var m=a(d(),".dm","models.json"),u=a(d(),".dm","auth.json");function s(o){if(!c(o))return null;try{return JSON.parse(f(o,"utf8"))}catch{return null}}function g(o){let n=[],i=new Set([...Object.keys(o.builtinProviders),...Object.keys(o.customProviders)]),r=s(m);if(r&&typeof r==="object"){for(let e of Object.keys(r))if(i.has(e))n.push({kind:"models.json",provider:e,detail:`provider "${e}" has user overrides in ~/.dm/models.json which DM merges on top of our registration`})}let t=s(u);if(t&&typeof t==="object"){for(let e of Object.keys(t))if(i.has(e))n.push({kind:"auth.json",provider:e,detail:`provider "${e}" has user-set credentials in ~/.dm/auth.json which take priority over our apiKey`})}return n}export{g as detectConflicts};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function E(v,J){if(!v)return!0;for(let Z of J)if(new RegExp("^"+Z.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$").test(v))return!0;return!1}var F=128000,N=16000,_={input:0,output:0,cacheRead:0,cacheWrite:0},x=[/.*-thinking$/,/^gpt-5(\.\d+)?(-.*)?$/,/^gemini-3(\.\d+)?(-.*)?$/];function W(v){return x.some((J)=>J.test(v))}var h=[[new Set(["zai"]),"glm","openai-completions"],[new Set(["Mistral"]),"mistral","openai-completions"],[new Set(["google","antigravity"]),"gemini","openai-completions"],[new Set(["Ollama","Ollama pay"]),"ollama","openai-completions"],[new Set(["Xiaomi"]),"mimo","openai-completions"],[new Set(["OpenRouter"]),"openrouter","openai-completions"],[new Set(["cerebras"]),"cerebras","openai-completions"]];function L(v,J){let Z=(v??"").trim();return Z?`${Z}-${J}`:J}function B(v,J){let Z=(J??"").trim(),Y=v.match(/^([a-z0-9]+-)(.*)$/);if(Y)return Z?`${Z}-${Y[1]}`:Y[1];return v}function C(v,J){for(let[Z,Y,V]of h)if(Z.has(v))return{slug:L(J,Y),api:V};return{slug:L(J,"misc"),api:"openai-completions"}}function T(v){return v.replace(/[/:]/g," ").split(/[-_]/).filter(Boolean).map((J)=>J[0].toUpperCase()+J.slice(1)).join(" ")}function q(v){return{id:v,name:T(v),contextWindow:F,maxTokens:N,reasoning:W(v),cost:{..._}}}import{chmodSync as b,existsSync as v0,mkdirSync as f,readFileSync as J0,writeFileSync as u}from"node:fs";import{dirname as O,join as c}from"node:path";import{homedir as R}from"node:os";import{dirname as d,join as H}from"node:path";var K=!1;var D={info(...v){if(!K)console.log("[dm-cliproxy]",...v)},warn(...v){if(!K)console.warn("[dm-cliproxy]",...v)},error(...v){if(!K)console.error("[dm-cliproxy]",...v)},debug(...v){if(!K&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...v)}};var k=H(R(),".dm","agent","dm-cliproxy"),r=H(k,"config.json"),a=[H(R(),".pi","agent","pi-cliproxyapi","config.json"),H(R(),".config","pi-cliproxyapi","config.json")];var w=c(k,"discovery-cache.json");function A(v){try{f(O(w),{recursive:!0,mode:448}),b(O(w),448);let J={savedAt:Date.now(),discovery:v};u(w,JSON.stringify(J),{encoding:"utf8",mode:384})}catch(J){D.warn("failed to write discovery cache:",J.message)}}var G="dm-cliproxy/0.3.5",y=5000;async function I(v,J){let Z=new AbortController,Y=setTimeout(()=>Z.abort(Error("timeout")),y);try{return await fetch(v,{...J,signal:Z.signal})}finally{clearTimeout(Y)}}function P(v){return new URL("/.well-known/pi",new URL(v).origin).toString()}async function n(v){let J=P(v.proxy.endpoint),Z;try{Z=await I(J,{headers:{"User-Agent":G,Accept:"application/json"}})}catch(Q){return D.warn("well-known fetch failed:",Q.message,"— falling back to /v1/models"),null}if(!Z.ok)return D.warn(`well-known returned ${Z.status} — falling back to /v1/models`),null;let Y;try{Y=await Z.json()}catch{return D.warn("well-known returned non-JSON — falling back to /v1/models"),null}if(!Y||Y.schemaVersion!==1)return D.warn("well-known schemaVersion != 1 — falling back to /v1/models"),null;let V=[],j=Y.builtinProviders??{};for(let[Q,X]of Object.entries(j)){if(!X||!Array.isArray(X.models))continue;let M=X.models.map(($)=>({id:String($.id),name:typeof $.name==="string"?$.name:String($.id),reasoning:Boolean($.reasoning??W(String($.id))),contextWindow:typeof $.contextWindow==="number"?$.contextWindow:200000,maxTokens:typeof $.maxTokens==="number"?$.maxTokens:16000,cost:$.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}));V.push({name:Q,api:X.api??"openai-responses",models:M})}let z=(Array.isArray(Y.customModelPool)?Y.customModelPool:[]).map((Q)=>({id:String(Q.id),name:typeof Q.name==="string"?Q.name:String(Q.id),reasoning:Boolean(Q.reasoning??W(String(Q.id))),contextWindow:typeof Q.contextWindow==="number"?Q.contextWindow:128000,maxTokens:typeof Q.maxTokens==="number"?Q.maxTokens:16000,cost:Q.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:Q.api??"openai-completions",suggestedProvider:B(typeof Q.suggestedProviderName==="string"?Q.suggestedProviderName:"misc",v.proxy.providerPrefix),ownedBy:typeof Q.owned_by==="string"?Q.owned_by:""}));return{source:"well-known",upstreamVersion:typeof Y?.upstream?.upstreamVersion==="string"?Y.upstream.upstreamVersion:null,builtinProviders:V,customPool:z,serverDiscoveryExcludes:Array.isArray(Y.discoveryExcludes)?Y.discoveryExcludes.filter((Q)=>typeof Q==="string"):[],upstreamTotal:typeof Y?.counts?.upstreamTotal==="number"?Y.counts.upstreamTotal:0}}async function p(v,J){let Z=new URL("/v1/models",new URL(v.proxy.endpoint).origin).toString(),Y=await I(Z,{headers:{Authorization:`Bearer ${J}`,Accept:"application/json","User-Agent":G}});if(!Y.ok)throw Error(`/v1/models returned ${Y.status}`);let V=await Y.json();if(!V?.data||!Array.isArray(V.data))return[];return V.data.map((j)=>({id:typeof j.id==="string"?j.id:"",owned_by:typeof j.owned_by==="string"?j.owned_by:""})).filter((j)=>j.id)}function s(v,J){let Z=J.discoveryExcludes,Y=new Map,V=[],j=0;for(let z of v){if(j++,E(z.id,Z))continue;if(z.owned_by==="openai"){let $=q(z.id);U(Y,"openai","openai-responses",S($));continue}if(z.owned_by==="anthropic"){let $=q(z.id);U(Y,"anthropic","anthropic-messages",S($));continue}let{slug:Q,api:X}=C(z.owned_by,J.proxy.providerPrefix),M=q(z.id);V.push({id:z.id,name:M.name??z.id,reasoning:M.reasoning??!1,contextWindow:M.contextWindow??128000,maxTokens:M.maxTokens??16000,cost:M.cost??{input:0,output:0,cacheRead:0,cacheWrite:0},api:X,suggestedProvider:Q,ownedBy:z.owned_by})}return{source:"v1-models",upstreamVersion:null,builtinProviders:Array.from(Y.values()),customPool:V,serverDiscoveryExcludes:[],upstreamTotal:j}}function U(v,J,Z,Y){let V=v.get(J);if(!V)V={name:J,api:Z,models:[]},v.set(J,V);V.models.push(Y)}function S(v){return{id:v.id,name:v.name??v.id,reasoning:v.reasoning??!1,contextWindow:v.contextWindow??128000,maxTokens:v.maxTokens??16000,cost:v.cost??{input:0,output:0,cacheRead:0,cacheWrite:0}}}async function D0(v,J){let Z=await n(v);if(Z)return D.info(`discovery via /.well-known/pi: ${Z.builtinProviders.length} builtin, ${Z.customPool.length} custom`),A(Z),Z;if(!J)throw Error("well-known unavailable AND proxy apiKey is empty — cannot fall back to /v1/models. Set proxy.apiKey in config.");let Y=await p(v,J),V=s(Y,v);return D.info(`discovery via /v1/models: ${V.builtinProviders.length} builtin, ${V.customPool.length} custom`),A(V),V}function M0(v){let J=new Set;for(let Z of v.builtinProviders)for(let Y of Z.models)J.add(Y.id);for(let Z of v.customPool)J.add(Z.id);return J}export{D0 as fetchDiscovery,M0 as discoveryToIdSet,G as PLUGIN_USER_AGENT};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{dirname as U,join as Y}from"node:path";import{homedir as r}from"node:os";import{dirname as z,join as e}from"node:path";var v=!1;var s={info(...n){if(!v)console.log("[dm-cliproxy]",...n)},warn(...n){if(!v)console.warn("[dm-cliproxy]",...n)},error(...n){if(!v)console.error("[dm-cliproxy]",...n)},debug(...n){if(!v&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...n)}};var D=e(r(),".dm","agent","dm-cliproxy"),h=e(D,"config.json"),q=[e(r(),".pi","agent","pi-cliproxyapi","config.json"),e(r(),".config","pi-cliproxyapi","config.json")];var H=Y(D,"discovery-cache.json");var J="dm-cliproxy/0.3.5";var Z=15000,c=null;function N(){c=null}async function F(n,o,V={}){if(!V.force&&c&&Date.now()-c.fetchedAt<n.usageCacheTtlMs)return c.doc;if(!o)throw Error("usage key not configured; set proxy.usageKey in config and rerun");let M=new URL("/api/usage",new URL(n.proxy.endpoint).origin).toString(),w=new AbortController,Q=setTimeout(()=>w.abort(Error("timeout")),Z),u;try{u=await fetch(M,{headers:{"X-Plugin-Key":o,Accept:"application/json","User-Agent":J},signal:w.signal})}finally{clearTimeout(Q)}if(!u.ok)throw Error(`/api/usage returned ${u.status}`);let t=await u.json();if(!t||t.schemaVersion!==1||!Array.isArray(t.accounts))throw Error("/api/usage returned unexpected payload shape");return c={fetchedAt:Date.now(),doc:t},s.debug("usage fetched, accounts:",t.accounts.length),t}export{F as fetchUsage,N as clearUsageCache};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var f=!1;function h(b){f=b}var j={info(...b){if(!f)console.log("[dm-cliproxy]",...b)},warn(...b){if(!f)console.warn("[dm-cliproxy]",...b)},error(...b){if(!f)console.error("[dm-cliproxy]",...b)},debug(...b){if(!f&&(process.env.DM_CLIPROXY_DEBUG||process.env.PI_CLIPROXYAPI_DEBUG))console.log("[dm-cliproxy]","[debug]",...b)}};export{h as setLogQuiet,j as log};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var O=["⡀","⠂","⣀","⣄","⣤","⣶","⣷","⣾"];function Y(j){if(j==="anthropic")return"claude";if(j==="openai")return"codex";return null}function Z(j){return!j.disabled&&!j.unavailable&&j.supported&&Array.isArray(j.groups)&&j.groups.length>0}function _(j){let k=`${j.id} ${j.label??""}`.toLowerCase();return k.includes("5h")||k.includes("five-hour")||k.includes("five hour")}function $(j){let k=`${j.id} ${j.label??""}`.toLowerCase();return k.includes("7d")||k.includes("seven-day")||k.includes("seven day")}function Q(j,k){let q=-1;for(let H of j){if(!Z(H))continue;let C=1/0;for(let z of H.groups??[])if(k(z)){if(z.remainingFraction<C)C=z.remainingFraction}if(C!==1/0&&C>q)q=C}if(q<0)return null;return{fraction:N(q)}}function N(j){return Math.max(0,Math.min(1,j))}function S(j){let k=Math.min(O.length-1,Math.floor(j*O.length));return O[k]}function J(j){if(j>=0.7)return"success";if(j>=0.3)return"warning";return"error"}function V(j){return Math.round(j*100)}function T(j,k,q){let H=Y(k);if(!H)return null;let C=j.accounts.filter((X)=>X.provider===H);if(C.length===0)return null;let z=Q(C,_),D=Q(C,$);if(!z&&!D)return null;let M=[q.fg("dim","\uDB81\uDE27")];if(z)M.push(`${q.fg("dim","5h")} ${q.fg(J(z.fraction),S(z.fraction))} ${q.fg(J(z.fraction),String(V(z.fraction)))}`);if(D)M.push(`${q.fg("dim","7d")} ${q.fg(J(D.fraction),S(D.fraction))} ${q.fg(J(D.fraction),String(V(D.fraction)))}`);return M.join(" ")}export{T as renderQuotaSegment,Y as providerToUsageKey};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{visibleWidth as X}from"@duckmind/dm-tui";import{visibleWidth as Y}from"@duckmind/dm-tui";function Z(j,q){let z=Y(j);if(z===q)return j;if(z<q)return j+" ".repeat(q-z);return N(j,q)}function N(j,q){if(q<=0)return"\x1B[0m";let z="",J=0,F=0;while(F<j.length){let O=j[F];if(O==="\x1B"&&j[F+1]==="["){let K=j.indexOf("m",F+2);if(K>=0){z+=j.slice(F,K+1),F=K+1;continue}}let M=Y(O);if(J+M>q)break;z+=O,J+=M,F++}return`${z}\x1B[0m`}var U="│",A="╭",I="╮",L="╰",C="╯",P="─";function W(j,q){let z=Math.max(4,q.width);return[S(j,q.title,q.titleColor??"accent",z),...q.lines.map((J)=>T(j,J,z)),V(j,q.footer,z)]}function S(j,q,z,J){let F=q??"",O=X(F),M=Math.max(0,J-3-O),K=F?j.bold(j.fg(z,F)):"",Q=`${A}${P}${K}${P.repeat(M)}${I}`;return j.fg("borderAccent",Q)}function T(j,q,z){let J=Math.max(0,z-2),F=j.fg("borderAccent",U);return`${F}${Z(q,J)}${F}`}function V(j,q,z){let J=`${L}${P}`,F=`${C}`,O=3;if(!q||!q.hint&&!q.badge){let G=Math.max(0,z-3);return j.fg("borderAccent",`${J}${P.repeat(G)}${F}`)}let M=q.hint??"",K=q.badge??"",Q=X(M),_=X(K),$=Math.max(0,z-3-Q-_),x=j.fg("dim",M),D=K?j.fg("muted",K):"",E=P.repeat($);return`${j.fg("borderAccent",J)}${x}${j.fg("borderAccent",E)}${D}${j.fg("borderAccent",F)}`}function R(j){return Math.max(0,j-2)}export{R as frameInner,W as frame};
|