@lmctl-ai/lmctl 0.2.23 → 0.2.24
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.
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* write it — plan.ts owns the actual write/lint/seed pipeline so the flags
|
|
7
7
|
* path and the wizard path behave identically after this point.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { loadModelSuggestions } from '../providers/model-suggestions.js';
|
|
10
10
|
import type { CliIo } from './common.js';
|
|
11
11
|
import { type MemberSpec } from './teamfile-template.js';
|
|
12
12
|
export interface PlanWizardInitial {
|
|
@@ -31,8 +31,8 @@ export interface PlanWizardOptions {
|
|
|
31
31
|
/** Preselected directory (positional arg); defaults to cwd. */
|
|
32
32
|
directory?: string;
|
|
33
33
|
initial?: PlanWizardInitial;
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
initConfigPath?: string;
|
|
35
|
+
loadModels?: typeof loadModelSuggestions;
|
|
36
36
|
/** Test seam — defaults to spawning $EDITOR synchronously on the temp file. */
|
|
37
37
|
editFile?: (path: string) => void;
|
|
38
38
|
env?: NodeJS.ProcessEnv;
|
package/dist/cli/plan.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* ids are never generated here — seeding is `lmctl seed`'s job, chained via
|
|
8
8
|
* `--seed` (lint first, refuse to seed when lint fails).
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
10
|
+
import type { loadModelSuggestions } from '../providers/model-suggestions.js';
|
|
11
11
|
import type { CliIo } from './common.js';
|
|
12
|
-
/** Test seams — fetch for --from URLs,
|
|
12
|
+
/** Test seams — fetch for --from URLs, model suggestions + editor for the wizard. */
|
|
13
13
|
export interface PlanDeps {
|
|
14
14
|
fetchFn?: typeof fetch;
|
|
15
|
-
|
|
15
|
+
loadModels?: typeof loadModelSuggestions;
|
|
16
16
|
editFile?: (path: string) => void;
|
|
17
17
|
/** Overrides stdin TTY detection (wizard auto-trigger). */
|
|
18
18
|
stdinIsTTY?: boolean;
|
package/dist/cli/script.js
CHANGED
|
@@ -2082,7 +2082,7 @@ To experiment with it manually: https://lmctl.com/lmctl/docs/manual-invocation`}
|
|
|
2082
2082
|
`),null}}async function rf(t,e,r){let n=ln(r.message),s=r.response===null?null:ln(r.response);try{await j(t,i=>i.finishTeamChatLog(e,{root_teamfile:r.root_teamfile,sender_teamfile:r.sender_teamfile,sender_alias:r.sender_alias,receiver_teamfile:r.receiver_teamfile,receiver_alias:r.receiver_alias,receiver_provider:r.receiver_provider,receiver_session_id:r.receiver_session_id,provider_prompt:r.message,message:n.text,response:s?.text??null,origin:r.origin,status:r.status,error_detail:r.error_detail,truncated:n.truncated||s?.truncated?1:0,created_at:new Date().toISOString()}))}catch(i){t.stderr.write(`warning: failed to finish chat log ${e}: ${i instanceof Error?i.message:String(i)}
|
|
2083
2083
|
`)}}async function PS(t,e,r){if(e!==null)try{await j(t,n=>{n.clearCurrentlyHandlingMessage(e.receiver_teamfile,e.receiver_alias,r)})}catch(n){t.stderr.write(`warning: failed to clear chat causal pointer: ${n instanceof Error?n.message:String(n)}
|
|
2084
2084
|
`)}}async function $S(t,e){let r=ln(e.message),n=e.response===null?null:ln(e.response);try{return await j(t,s=>s.insertTeamChatLog({root_teamfile:e.root_teamfile,sender_teamfile:e.sender_teamfile,sender_alias:e.sender_alias,receiver_teamfile:e.receiver_teamfile,receiver_alias:e.receiver_alias,receiver_provider:e.receiver_provider,receiver_session_id:e.receiver_session_id,provider_prompt:e.message,message:r.text,response:n?.text??null,origin:e.origin,status:e.status,error_detail:e.error_detail,truncated:r.truncated||n?.truncated?1:0,message_type:e.message_type??null,created_at:new Date().toISOString()}))}catch(s){return t.stderr.write(`warning: failed to record chat log: ${s instanceof Error?s.message:String(s)}
|
|
2085
|
-
`),null}}function Pt(t,e,r,n,s){t!==null||e===null||k({event:"chat_attempt_error",reason:s,root_teamfile:e.root_teamfile,sender_teamfile:e.sender_teamfile,sender_alias:e.sender_alias,receiver_teamfile:e.receiver_teamfile,receiver_alias:e.receiver_alias,origin:e.origin,error_detail:n,message_preview:an(r)})}function ln(t){return t.length<=ef?{text:t,truncated:!1}:{text:t.slice(0,ef),truncated:!0}}import{createHash as Hv}from"node:crypto";import{accessSync as Xv,constants as Xf,existsSync as qv,readFileSync as Gf,realpathSync as Ka,statSync as Gv,writeFileSync as qf}from"node:fs";import{dirname as Wt,resolve as Jf}from"node:path";import{spawnSync as Ga}from"node:child_process";import{existsSync as Mf,readFileSync as Ff}from"node:fs";import{homedir as Pf}from"node:os";import{resolve as Xa}from"node:path";import{mkdirSync as hf,readFileSync as US,renameSync as jS,writeFileSync as WS,existsSync as gf}from"node:fs";import{homedir as BS}from"node:os";import{dirname as _f,join as Hs,resolve as Xs}from"node:path";import{fileURLToPath as HS}from"node:url";var XS="https://lmctl.com/dataset/model_list.json",qS="https://lmctl.com/dataset/aliases.json",GS=1e3,JS=1e4,lf=6*60*60*1e3;function VS(){return Hs(BS(),".lmctl","cache","lmprice")}var Fa="model_list.json",Pa="aliases.json",yf="meta.json",KS="model_list.meta.json";function fr(t,e){return Hs(t,e)}function $t(t){try{return JSON.parse(US(t,"utf-8"))}catch{return null}}function Ef(t,e){let r=`${t}.tmp-${process.pid}`;WS(r,e),jS(r,t)}function Ma(t){return t===null||typeof t=="number"}function qs(t){if(typeof t!="object"||t===null)return!1;let e=t;return e.schema_version!==1||!Array.isArray(e.records)||e.records.length===0?!1:e.records.every(r=>{if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.source!="string"||typeof n.source_model_id!="string"||typeof n.pricing!="object"||n.pricing===null)return!1;let s=n.pricing;return Ma(s.input_per_1m_tokens)&&Ma(s.output_per_1m_tokens)&&Ma(s.input_cache_read_per_1m_tokens)})}var YS=new Set(["established","asserted","unresolved"]);function Gs(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.schema_version!==1||!Array.isArray(e.standards)||!Array.isArray(e.aliases))return!1;let r=e.standards.every(s=>{if(typeof s!="object"||s===null)return!1;let i=s;return typeof i.standard_slug=="string"&&(i.catalog_record_id===null||typeof i.catalog_record_id=="string")}),n=e.aliases.every(s=>{if(typeof s!="object"||s===null)return!1;let i=s;return typeof i.alias=="string"&&(i.standard_slug===null||typeof i.standard_slug=="string")&&typeof i.evidence=="string"&&YS.has(i.evidence)});return r&&n}function zS(t){let e=$t(fr(t,yf)),r={etag:typeof e?.model_list?.etag=="string"?e.model_list.etag:null,last_checked:typeof e?.model_list?.last_checked=="string"?e.model_list.last_checked:null},n={etag:typeof e?.aliases?.etag=="string"?e.aliases.etag:null,last_checked:typeof e?.aliases?.last_checked=="string"?e.aliases.last_checked:null};if(e===null){let s=$t(fr(t,KS));s&&(r.etag=typeof s.etag=="string"?s.etag:null,r.last_checked=typeof s.fetchedAt=="string"?s.fetchedAt:null)}return{model_list:r,aliases:n}}function QS(t){let e=zS(t),r=$t(fr(t,Fa)),n=$t(fr(t,Pa));return{catalog:qs(r)?r:null,aliases:Gs(n)?n:null,meta:e}}function ZS(t,e){try{hf(t,{recursive:!0}),Ef(fr(t,yf),JSON.stringify(e))}catch{}}function cf(t,e,r){try{hf(t,{recursive:!0}),Ef(fr(t,e),JSON.stringify(r))}catch{}}function ev(t,e){let r=tv(t),n=r?[Xs(r,"data",e)]:[Xs(t,"..","..","data",e)];for(let s of n)if(gf(s))return s;return null}function tv(t){let e=Xs(t);for(;;){if(gf(Xs(e,"package.json")))return e;let r=_f(e);if(r===e)return null;e=r}}function df(t,e,r){let n=r!==void 0?r:ev(t,e);return n===null?null:$t(n)}function rv(){let t=process.env.LMCTL_PRICE_TTL;if(t===void 0||t==="")return lf;let e=Number(t);return!Number.isFinite(e)||e<0?lf:e*1e3}function nv(){let t=process.env.LMCTL_PRICE_DATA;return t!==void 0&&t!==""?t:null}async function uf(t,e,r,n){try{let s=await t(e,{method:"HEAD",signal:AbortSignal.timeout(GS)});if(!s.ok)return{kind:"failed"};let i=s.headers.get("etag");if(r!==null&&i!==null&&i===n)return{kind:"match"};let o=await t(e,{signal:AbortSignal.timeout(JS)});return o.ok?{kind:"payload",payload:await o.json(),etag:o.headers.get("etag")??i}:{kind:"failed"}}catch{return{kind:"failed"}}}var $a=null;var mf=null;function Tf(t={}){return Object.keys(t).length===0?(mf??=ff(t),mf):ff(t)}async function ff(t){let e=_f(HS(import.meta.url)),r=t.pinDir!==void 0?t.pinDir:nv();if(r!==null&&r!==""){let g=$t(Hs(r,Fa)),T=$t(Hs(r,Pa));if(qs(g)&&Gs(T)){let h={catalog:g,aliases:T,source:"pinned",generatedAt:g.generated_at??null};return $a=h.generatedAt,h}return pf(t,e)}let n=t.fetchImpl??fetch,s=t.cacheDir??VS(),i=t.now??Date.now(),o=t.ttlMs??rv(),a=QS(s),l=(g,T)=>g!==null&&T.last_checked!==null&&i-Date.parse(T.last_checked)<o,c=a.catalog,u=a.aliases,d=!1,m={model_list:{...a.meta.model_list},aliases:{...a.meta.aliases}},p=!1;if(!l(c,a.meta.model_list)){let g=await uf(n,XS,c,a.meta.model_list.etag);g.kind==="match"?(m.model_list.last_checked=new Date(i).toISOString(),p=!0):g.kind==="payload"&&(m.model_list.last_checked=new Date(i).toISOString(),p=!0,qs(g.payload)&&(c=g.payload,g.etag!==null&&(m.model_list.etag=g.etag),cf(s,Fa,c),d=!0))}if(!l(u,a.meta.aliases)){let g=await uf(n,qS,u,a.meta.aliases.etag);g.kind==="match"?(m.aliases.last_checked=new Date(i).toISOString(),p=!0):g.kind==="payload"&&(m.aliases.last_checked=new Date(i).toISOString(),p=!0,Gs(g.payload)&&(u=g.payload,g.etag!==null&&(m.aliases.etag=g.etag),cf(s,Pa,u),d=!0))}if((p||d)&&ZS(s,m),c!==null||u!==null){let g={catalog:c,aliases:u,source:d?"network":"cache",generatedAt:c?.generated_at??null};return $a=g.generatedAt,g}return pf(t,e)}function pf(t,e){let r=df(e,"price-data.json",t.bundledPath),n=df(e,"price-aliases.json",t.bundledAliasesPath),s=qs(r)?r:null,i=Gs(n)?n:null,o={catalog:s,aliases:i,source:s!==null||i!==null?"bundled":"unavailable",generatedAt:s?.generated_at??null};return $a=o.generatedAt,o}function jt(t){return t.toLowerCase().replace(/(\d)\.(\d)/g,"$1-$2")}function Ut(t){let e=t.source_model_id.toLowerCase(),r=e.slice(e.lastIndexOf("/")+1);return jt(r)}function Sf(t){let e=new Set,r=n=>{let s=n.toLowerCase().split("/");for(let i=0;i<s.length;i+=1)e.add(jt(s.slice(i).join("/")))};return r(t.source_model_id),t.gateway_id&&r(t.gateway_id),e}function sv(t,e){let r=new Set,n=l=>{r.add(jt(l))},s=t.trim().toLowerCase(),i=null,o=s.indexOf(":");o>0&&!s.slice(0,o).includes("/")&&(i=s.slice(0,o),n(s),s=s.slice(o+1)),n(s);let a=s.slice(s.lastIndexOf("/")+1);n(a);for(let l of e)n(`${l}/${a}`);return i!==null&&n(`${i}/${a}`),[...r]}function pr(t){let e=n=>!(n.mode!==void 0&&n.mode!==null&&n.mode!=="chat"||t.nonChatName&&t.nonChatName.test(n.source_model_id.toLowerCase())),r=n=>e(n)&&t.family.test(n.source_model_id.toLowerCase());return{firstPartyProviders:t.firstPartyProviders,isChatModel:e,coversRecord:r,normalize:n=>sv(n,t.vendorPrefixes),matchRow(n,s){if(!r(n))return!1;let i=Sf(n);return s.some(o=>i.has(o))}}}var vf=pr({vendorPrefixes:["anthropic"],family:/claude/,firstPartyProviders:["anthropic"]}),bf=pr({vendorPrefixes:["openai"],family:/(^|\/)(gpt-|o\d|chatgpt|ft:gpt)|openai\//,firstPartyProviders:["openai"],nonChatName:/(^|[-/])(tts|transcribe(?:-\w+)?|realtime(?:-\w+)?|search(?:-\w+)*|image(?:-\w+)?|audio(?:-\w+)?|whisper(?:-\w+)?|dall-e(?:-\w+)?|embedding|moderation)(-|$)/}),If=pr({vendorPrefixes:["google","gemini"],family:/gemini|gemma/,firstPartyProviders:["gemini","google","vertex_ai-language-models"],nonChatName:/embedding|imagen|-image|tts|audio|veo|lyria|live|realtime|video/}),xf=pr({vendorPrefixes:["moonshot","moonshotai"],family:/kimi|moonshot/,firstPartyProviders:["moonshot"]}),Af=pr({vendorPrefixes:["dashscope","qwen"],family:/qwen/,firstPartyProviders:["dashscope"]}),kf=pr({vendorPrefixes:["deepseek","nousresearch"],family:/deepseek|nous|hermes-\d/,firstPartyProviders:["deepseek","nousresearch"]}),iv=/\s*\(([^()]+)\)\s*$/;function ov(t){let e=t.trim(),r=iv.exec(e);return r?{model:e.slice(0,r.index).trim(),effort:r[1].trim()}:{model:e,effort:null}}var av={"gemini 3.8 flash":"gemini-3.8-flash","gemini 3.7 flash":"gemini-3.7-flash","gemini 3.6 flash":"gemini-3.6-flash","gemini 3.1 pro":"gemini/gemini-3.1-pro-preview","claude sonnet 4.6":"claude-sonnet-4-6"},lv=["gemini","google","vertex_ai-language-models","anthropic"],cv={normalize(t){let{model:e}=ov(t),r=av[e.toLowerCase()];return r===void 0?[]:[jt(r)]},isChatModel(t){return t.mode===void 0||t.mode===null||t.mode==="chat"},coversRecord(t){return this.isChatModel(t)&&/gemini|claude/.test(t.source_model_id.toLowerCase())},matchRow(t,e){if(!this.coversRecord(t))return!1;let r=Sf(t);return e.some(n=>r.has(n))}},cn={claude:vf,codex:bf,gemini:If,agy:cv,kimi:xf,qwen:Af,hermes:kf},wf={claude:vf.firstPartyProviders,codex:bf.firstPartyProviders,gemini:If.firstPartyProviders,agy:lv,kimi:xf.firstPartyProviders,qwen:Af.firstPartyProviders,hermes:kf.firstPartyProviders};function dv(t,e,r){let n=e.trim().toLowerCase(),s=jt(n);if(r.records.some(o=>o.source_model_id.toLowerCase()===n&&t.matchRow(o,[s])))return!0;let i=t.normalize(e);return i.length>0&&r.records.some(o=>t.matchRow(o,i))}function uv(t,e,r){let n=[];for(let[s,i]of Object.entries(cn))s!==r&&dv(i,t,e)&&n.push(s);return n}function Js(t){return t==="moonshot"?0:t==="litellm"?1:t==="openrouter"?2:t==="manual"?3:4}function mv(t,e){return t.input_per_1m_tokens===e.input_per_1m_tokens&&t.output_per_1m_tokens===e.output_per_1m_tokens&&t.input_cache_read_per_1m_tokens===e.input_cache_read_per_1m_tokens}function fv(t){let e=new Map,r=[];for(let n of t){let s=n.source_model_id.toLowerCase(),i=s.lastIndexOf("/"),o=i===-1?"":s.slice(0,i+1),a=i===-1?s:s.slice(i+1),l=`${n.source}:${o}${jt(a)}`,c=e.get(l);if(c===void 0){e.set(l,n);continue}if(!mv(c.pricing,n.pricing)){r.push(n);continue}/\d\.\d/.test(c.source_model_id)&&!/\d\.\d/.test(n.source_model_id)&&e.set(l,n)}return[...e.values(),...r]}function pv(t){return{route:t.record_id??`${t.source}:${t.source_model_id}`,source:t.source,sourceModelId:t.source_model_id,provider:t.provider??null,pricing:t.pricing,estimated:t.source==="manual"}}function Rf(t,e){return t.map(pv).sort((r,n)=>{let s=Js(r.source)-Js(n.source);if(s!==0)return s;let i=r.provider!==null&&e.includes(r.provider)?0:1,o=n.provider!==null&&e.includes(n.provider)?0:1;return i!==o?i-o:r.sourceModelId.localeCompare(n.sourceModelId)})}function hv(t){return t.pricing.input_per_1m_tokens!==null&&t.pricing.output_per_1m_tokens!==null}function gv(t,e,r){let n=fv(t),s=Rf(n,r),o=n.find(a=>(a.record_id??`${a.source}:${a.source_model_id}`)===s[0].route)?.context_window?.input_tokens??void 0;return{id:s[0].sourceModelId,normalizedId:e,offers:s,...o!=null?{contextWindow:o}:{}}}function Ua(t,e,r){if(t.length===0)return{kind:"known-unpriced",id:e};let n=gv(t,e,r),s=n.offers.find(hv);return s===void 0?{kind:"known-unpriced",id:e}:s.estimated?{kind:"estimated",model:n}:{kind:"priced",model:n}}var ja=[];function _v(t,e){return t.standards.find(r=>r.standard_slug.toLowerCase()===e.toLowerCase())??null}function yv(t,e,r){let n=t.standard_slug;if(e===null||e.catalog_record_id===null)return{kind:"known-unpriced",id:n};let s=e.catalog_record_id.toLowerCase(),i=r.records.find(l=>(l.record_id??`${l.source}:${l.source_model_id}`).toLowerCase()===s);if(!i)return{kind:"known-unpriced",id:n};let o=Ut(i),a=r.records.filter(l=>Ut(l)!==o?!1:l.mode===void 0||l.mode===null||l.mode==="chat");return a.length===0?{kind:"known-unpriced",id:n}:Ua(a,o,ja)}function Ev(t,e,r,n){if(r===null||!Array.isArray(r.records))return{state:{kind:"no-catalog"},viaAlias:!1,pinRoute:null};if(n!==null){let T=[e.trim().toLowerCase()];T.push(`${t.toLowerCase()}/${T[0]}`);let h=n.aliases.find(f=>T.includes(f.alias.toLowerCase()));if(h){if(h.evidence==="unresolved"||h.standard_slug===null)return{state:{kind:"unresolved",alias:h.alias},viaAlias:!0,pinRoute:null};let f=_v(n,h.standard_slug);return{state:yv(h,f,r),viaAlias:!0,pinRoute:f?.catalog_record_id?.toLowerCase()??null}}}let s=cn[t];if(!s)return{state:{kind:"no-catalog"},viaAlias:!1,pinRoute:null};let i=e.trim().toLowerCase(),o=s.normalize(e),a=T=>({state:T,viaAlias:!1,pinRoute:null}),l=jt(i),c=r.records.filter(T=>T.source_model_id.toLowerCase()===i&&s.matchRow(T,[l]));if(c.length>0){let T=Ut(c[0]),h=r.records.filter(f=>s.matchRow(f,[T])&&Ut(f)===T);return a(Ua(h.length>0?h:c,T,wf[t]??ja))}let u=r.records.filter(T=>s.matchRow(T,o));if(u.length===0){let T=uv(e,r,t);return T.length>0?a({kind:"wrong-provider",declared:e,otherProviders:T}):a({kind:"unknown",declared:e})}let d=new Map;for(let T of u){let h=Ut(T),f=d.get(h);f?f.push(T):d.set(h,[T])}let m=wf[t]??ja,p=null,g=null;for(let T of d.values()){let h=Rf(T,m);(g===null||Tv(h[0],g[0],m)<0)&&(p=T,g=h)}return a(Ua(p,Ut(p[0]),m))}function Nf(t,e,r,n){return Ev(t,e,r,n).state}function Lf(t,e){let r=cn[e];if(!r)return null;let n=new Set;for(let s of t.records)r.coversRecord(s)&&n.add(Ut(s));return n.size}function Tv(t,e,r){let n=Js(t.source)-Js(e.source);if(n!==0)return n;let s=t.provider!==null&&r.includes(t.provider)?0:1,i=e.provider!==null&&r.includes(e.provider)?0:1;return s!==i?s-i:t.sourceModelId.localeCompare(e.sourceModelId)}var $f=new Set(Object.keys(cn).filter(t=>t!=="codex"&&t!=="kimi")),wv=/\d\.(?=\d)/,Sv=new Set(["claude","codex","gemini","qwen","kimi","agy"]),Cf=["deepseek-v4-flash","deepseek-v4-pro","deepseek-v4-flash-vision-exp"],Of=["deepseek-flash","deepseek-pro"],Df="gpt-5.3-codex-spark",vv=15e3;function hr(t,e){return e.code==="ETIMEDOUT"?`${t} did not respond within lint's own spawn timeout (${e.message}) \u2014 this does not mean the provider itself is unreachable, only that this specific check didn't finish in time.`:`${t} could not be run: ${e.message}`}function bv(){let t=Ga("agy",["models"],{encoding:"utf-8",timeout:vv});return{status:t.status,stdout:t.stdout??"",error:t.error}}var Wa=null;function Iv(t){let e=[];for(let r of t.split(/\r?\n/)){let n=r.trim(),s=n.indexOf(" ");if(s<0)continue;let i=n.slice(s+1).trim();i&&e.push(i)}return e}function xv(t){if(!t&&Wa)return Wa;let e=s=>(t||(Wa=s),s),r;try{r=(t??bv)()}catch(s){return e({available:!1,models:[],reason:s instanceof Error?hr("agy models",s):`agy models could not be run: ${String(s)}`})}if(r.error)return e({available:!1,models:[],reason:hr("agy models",r.error)});if(r.status!==0)return e({available:!1,models:[],reason:`agy models exited with status ${r.status??"unknown"}`});let n=Iv(r.stdout);return n.length===0?e({available:!1,models:[],reason:"agy models returned no models"}):e({available:!0,models:n})}var Av=5e3;function kv(){let t=Ga("codex",["debug","models"],{encoding:"utf-8",timeout:Av});return{status:t.status,stdout:t.stdout??"",error:t.error}}var Ba=null;function Rv(t){let e;try{e=JSON.parse(t)}catch{return}let r=e.models;if(!Array.isArray(r))return;let n=[];for(let s of r){if(!s||typeof s!="object")continue;let{slug:i,visibility:o}=s;typeof i=="string"&&o==="list"&&n.push(i)}return n}function Nv(t){if(!t&&Ba)return Ba;let e=s=>(t||(Ba=s),s),r;try{r=(t??kv)()}catch(s){return e({available:!1,models:[],reason:s instanceof Error?hr("codex debug models",s):`codex debug models could not be run: ${String(s)}`})}if(r.error)return e({available:!1,models:[],reason:hr("codex debug models",r.error)});if(r.status!==0)return e({available:!1,models:[],reason:`codex debug models exited with status ${r.status??"unknown"}`});let n=Rv(r.stdout);return n===void 0?e({available:!1,models:[],reason:"codex debug models did not return parseable JSON"}):n.length===0?e({available:!1,models:[],reason:"codex debug models returned no user-visible models"}):e({available:!0,models:n})}var Lv=5e3;function Cv(t){let e=Ga("opencode",["models",t],{encoding:"utf-8",timeout:Lv});return{status:e.status,stdout:e.stdout??"",error:e.error}}var Ha=new Map;function Ov(t,e){if(!e&&Ha.has(t))return Ha.get(t);let r=i=>(e||Ha.set(t,i),i),n;try{n=(e??Cv)(t)}catch(i){return r({available:!1,models:[],reason:i instanceof Error?hr(`opencode models ${t}`,i):`opencode models ${t} could not be run: ${String(i)}`})}if(n.error)return r({available:!1,models:[],reason:hr(`opencode models ${t}`,n.error)});if(n.status!==0)return r({available:!1,models:[],reason:`opencode models ${t} exited with status ${n.status??"unknown"}`});let s=n.stdout.split(/\r?\n/).map(i=>i.trim()).filter(i=>i.length>0);return s.length===0?r({available:!1,models:[],reason:`opencode models ${t} returned no models`}):r({available:!0,models:s})}function Ja(t,e={}){let r=[];for(let n of t){let s=n.provider.trim().toLowerCase();if(n.effort&&s!=="opencode"&&s!=="lmplayer"&&s!=="qwen"&&r.push(`[${n.alias}] effort="${n.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),s==="qwen"&&n.effort&&r.push(`[${n.alias}] effort="${n.effort}" is not a qwen CLI flag: Qwen Code does not expose reasoning-effort selection. Use a thinking/effort model id in model= instead.`),!n.model&&Sv.has(s)&&r.push(`[${n.alias}] provider=${s} has no model= \u2014 ${s} will use its own ambient default, which cannot be linted or priced and may not be the intended one. Set model= explicitly.`),s==="copilot"){if(!n.model)continue;r.push(`[${n.alias}] model="${n.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(s==="lmplayer"&&!n.model){r.push(`[${n.alias}] provider=lmplayer has no model= \u2014 lmplayer will choose its own default model, which may not be visible in the teamfile. Set model= explicitly (e.g. github-copilot/gpt-5.5).`);continue}if(s!=="lmplayer"){if(s==="opencode"){if(n.effort&&!n.model&&r.push(`[${n.alias}] effort="${n.effort}" has no effect without model= on an opencode member.`),!n.model){r.push(`[${n.alias}] provider=opencode has no model= \u2014 opencode will choose its own default model, which may not be servable and isn't visible in the teamfile. Set model= explicitly (e.g. github-copilot/gpt-5.5).`);continue}let i=Fv(e.opencodeConfigPath);if(!i.available){r.push(`[${n.alias}] model="${n.model}" cannot be verified for opencode: ${i.reason}.`);continue}if(i.models.includes(n.model)||/^github-copilot\/(gpt|gemini|o[0-9])/.test(n.model))continue;if(!n.model.includes("/")){let l=i.models.filter(c=>c.endsWith(`/${n.model}`));r.push(l.length>0?`[${n.alias}] model="${n.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${l.join(" / ")}; set model=${l[0]}.`:`[${n.alias}] model="${n.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model> (e.g. github-copilot/${n.model}). Declare it in ~/.config/opencode/opencode.json (see https://lmctl.com/examples/opencode.json).`);continue}let o=n.model.slice(0,n.model.indexOf("/")),a=Ov(o,e.opencodeModelsRunner);if(a.available&&a.models.includes(n.model))continue;if(a.available&&!a.models.includes(n.model)){r.push(`[${n.alias}] model="${n.model}" was not found in opencode's LOCALLY-VISIBLE live catalog for "${o}" (checked \`opencode models ${o}\`) -- this is unresolved, not a confirmed unavailability: it could mean opencode genuinely doesn't serve this model, OR that your local catalog/auth for "${o}" is stale/incomplete. Declaring it in opencode.json may or may not help; if it doesn't, check whether a non-opencode provider serves this model directly (e.g. \`lmctl lint\` with model= against provider=codex/claude/gemini/agy).`);continue}r.push(`[${n.alias}] model="${n.model}" is not declared in your opencode.json. opencode resolves github-copilot GPT/Gemini config-free, but copilot Claude and custom providers must be declared \u2014 copy https://lmctl.com/examples/opencode.json to ~/.config/opencode/opencode.json and adjust for your account.`);continue}if(s==="kimi"){if(!n.model)continue;let i=Dv(e.kimiConfigPath);i.available?i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not declared in Kimi's [models] config. Valid configured models: ${dn(i.models)}`):r.push(`[${n.alias}] model="${n.model}" cannot be verified for kimi: ${i.reason}.`);continue}if(s==="agy"){if(!n.model)continue;let i=xv(e.agyModelsRunner);i.available?i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in agy's live model catalog (\`agy models\`). Valid models: ${dn(i.models)}`):r.push(`[${n.alias}] model="${n.model}" cannot be verified for agy: ${i.reason}.`);continue}if(s==="dsh"){if(!n.model||Of.includes(n.model))continue;Cf.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in dsh's built-in catalog. Valid pinned models: ${dn(Cf)}. Valid server-resolved aliases (DeepSeek resolves these to its current model server-side -- pinning to a specific version instead is a DOWNGRADE, not a safer choice): ${dn(Of)}. The catalog is patchable via dsh profile overlays \u2014 a model added that way warns here even though it may resolve.`);continue}if(s==="hermes"){if(!n.model)continue;let i=n.model.indexOf(":");(i<=0||i===n.model.length-1)&&r.push(`[${n.alias}] model="${n.model}" should use <provider>:<model> from Hermes's ACP catalog. lmctl checks the shape only; provider and model availability are resolved by Hermes.`);continue}if(s!=="pi"){if(s==="codex"){if(!n.model)continue;n.model===Df&&r.push(`[${n.alias}] model="${Df}" is banned as a build model (operator, 2026-09-06) -- it's a fast/cheap classification model, not intended for build work, and there's no cost reason left to reach for it. Use model=gpt-5.6-sol (or leave model= unset) for build work; if this member genuinely does non-build/classification work, this warning can be ignored.`);let i=Nv(e.codexModelsRunner);if(!i.available){r.push(`[${n.alias}] model="${n.model}" cannot be verified for codex: ${i.reason}.`);continue}i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in codex's live model catalog (\`codex debug models\`). Valid models: ${dn(i.models)}`);continue}n.model&&($f.has(s)||r.push(`[${n.alias}] model="${n.model}" cannot be verified for provider "${s}": no model validation path exists for this provider.`))}}}return r}async function Uf(t,e={}){let r=t.filter(o=>o.model!==void 0&&$f.has(o.provider.trim().toLowerCase()));if(r.length===0)return{warnings:[],errors:[]};let n=e.snapshot??await Tf();if(n.catalog===null)return{warnings:[],errors:[]};let s=[],i=[];for(let o of r){let a=o.provider.trim().toLowerCase(),l=o.model,c=Nf(a,l,n.catalog,n.aliases);if(c.kind==="unknown"){let u=Lf(n.catalog,a)??0;s.push(`[${o.alias}] model "${l}" is unknown to the lmprice catalog for provider "${a}" (${u} known) -- not necessarily wrong: may be a model too new for lmprice to have published yet, or a typo. A matching lmprice catalog/alias entry would resolve this; lint cannot otherwise confirm whether ${a} accepts it.`)}else c.kind==="wrong-provider"?i.push({field:o.alias,message:`model "${l}" is not offered by provider "${a}" -- it is a recognized model, but only under: ${c.otherProviders.join(", ")}. Declare provider="${c.otherProviders[0]}" (or another listed provider), or use a model "${a}" actually offers.`}):c.kind==="known-unpriced"&&s.push(`[${o.alias}] model "${l}" is recognized in the lmprice catalog but has no price information \u2014 cost will be unavailable`);if(a==="claude"&&(c.kind==="priced"||c.kind==="known-unpriced"||c.kind==="estimated")&&wv.test(l)){let u=l.replace(/(\d)\.(?=\d)/g,"$1-");s.push(`[${o.alias}] model="${l}" matches the lmprice catalog only through its OpenRouter-style spelling ("." between version numbers); claude's own CLI expects "-" there and does an exact match, so it may reject this string verbatim even though lint recognizes it. If seed/chat fails with "issue with the selected model," try model="${u}" instead.`)}}return{warnings:s,errors:i}}async function jf(t,e={}){return(await Uf(t,e)).warnings}async function Wf(t,e={}){return(await Uf(t,e)).errors}function Dv(t){let e=process.env.KIMI_CODE_HOME||Xa(Pf(),".kimi-code"),r=t??Xa(e,"config.toml");if(!Mf(r))return{available:!1,models:[],reason:`${r} not found`};let n;try{n=Ff(r,"utf-8")}catch(i){return{available:!1,models:[],reason:`${r} could not be read: ${i instanceof Error?i.message:String(i)}`}}let s=new Set;for(let i of n.split(/\r?\n/)){if(/^\s*\[/.test(i)&&!/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.test(i))return{available:!1,models:[],reason:`${r} has an invalid TOML table header`};let o=/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.exec(i);if(!o)continue;let a=Mv(o[1]);if(o[1].trim().startsWith("models")&&a===null)return{available:!1,models:[],reason:`${r} has an invalid [models] table header`};a?.[0]==="models"&&a.length>=2&&s.add(a[1])}return s.size===0?{available:!1,models:[],reason:`${r} has no [models] entries`}:{available:!0,models:[...s].sort()}}function Mv(t){let e=[],r=0;for(;r<t.length;){for(;/\s/.test(t[r]??"");)r++;if(r>=t.length)break;let n="",s=t[r]==='"'||t[r]==="'"?t[r++]:void 0;if(s){for(;r<t.length&&t[r]!==s;)s==='"'&&t[r]==="\\"&&r+1<t.length&&r++,n+=t[r++];if(t[r]!==s)return null;r++}else{for(;r<t.length&&t[r]!==".";)n+=t[r++];n=n.trim()}if(!n)return null;for(e.push(n);/\s/.test(t[r]??"");)r++;if(r>=t.length)break;if(t[r]!==".")return null;r++}return e.length>0?e:null}function Fv(t){let e=t??Xa(Pf(),".config","opencode","opencode.json");if(!Mf(e))return{available:!0,models:[]};let r;try{r=JSON.parse(Ff(e,"utf-8"))}catch(n){return{available:!1,models:[],reason:`${e} could not be parsed: ${n instanceof Error?n.message:String(n)}`}}return{available:!0,models:Pv(r)}}function Pv(t){if(!qa(t))return[];let e=Vs(t.provider)??Vs(t.providers);if(!e)return[];let r=new Set;for(let[n,s]of Object.entries(e)){if(!qa(s))continue;let i=Vs(s.models)??Vs(s.model);if(i)for(let o of Object.keys(i))r.add(o.startsWith(`${n}/`)?o:`${n}/${o}`)}return[...r].sort()}function Vs(t){return qa(t)?t:null}function qa(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function dn(t){return t.length>0?t.join(", "):"(none)"}to();mo();import{homedir as $v}from"node:os";import{basename as Uv}from"node:path";var jv={workdir:t=>t.workdir,teamfile:t=>t.teamfile,teamname:t=>{let e=Uv(t.teamfile);return e.endsWith(".lmctl")?e.slice(0,-6):e},home:()=>$v(),date:t=>t.date},Wv=/{{\s*([A-Za-z0-9_-]+)\s*}}/g;function Bf(t,e){let r=new Set;return{text:t.replace(Wv,(s,i)=>{let o=i.trim(),a=jv[o];return a===void 0?(r.add(o),s):a(e)}),unknownNames:[...r].sort()}}function Hf(t){return{workdir:t.workdir,teamfile:t.teamfile,date:Bv(t.date)}}function Bv(t){return t.toISOString().slice(0,10)}ge();var mn=5;var Jv='notice: member "%s" uses provider=gemini \u2014 the Gemini CLI requires an API/enterprise Google account; personal Google subscriptions should use provider=agy (Antigravity).',Vv={existsSync:qv,statSync:Gv,accessSync:Xv},Kv=async t=>{let{seed:e}=await Promise.resolve().then(()=>(nn(),Jm)),r=await e(t);return r.success?{sessionId:r.sessionId,warnings:r.warnings}:{error:r.error??"provider seed failed"}},gr=Vv,Yv=us,Vf,Kf,Ks;function Yf(t){return jf(t,Ks!==void 0?{snapshot:Ks}:{})}function zf(t){return Wf(t,Ks!==void 0?{snapshot:Ks}:{})}async function zv(t,e,r){let n=t.filter(i=>i.teamfile===void 0&&i.provider.trim().toLowerCase()==="opencode"&&i.model!==void 0&&i.model.length>0);return(await Promise.all(n.map(async i=>({member:i,result:await Yv({cwd:i.sessiondir??e,model:i.model,...i.effort!==void 0?{effort:i.effort}:{},...r!==void 0?{env:r}:{}})})))).flatMap(({member:i,result:o})=>o.status==="rejected"?[`[${i.alias}] ${o.option}="${o.value}" rejected by opencode: ${o.error}`]:[])}function Qv(t,e){let r=Wt(e),n=new Set,s=[];for(let i of t){if(i.teamfile!==void 0)continue;let o=i.sessiondir??r,a=Jf(o);if(n.has(a))continue;let l=Zv(a);l!==void 0&&(n.add(a),s.push(`${i.alias}: sessiondir ${a} is not writable (seed would fail: ${l}) \u2014 fix permissions or set a writable sessiondir`))}return s}function Zv(t){try{if(gr.existsSync(t)){if(!gr.statSync(t).isDirectory())return"ENOTDIR";gr.accessSync(t,Xf.W_OK);return}let e=tb(t);if(e===void 0)return;if(!gr.statSync(e).isDirectory())return"ENOTDIR";gr.accessSync(e,Xf.W_OK);return}catch(e){return rb(e)??"permission check failed"}}function eb(t){let e=Jf(t);try{return Ka(e)}catch{return e}}function tb(t){let e=t;for(;;){try{if(gr.existsSync(e))return e}catch{return}let r=Wt(e);if(r===e)return;e=r}}function rb(t){if(typeof t=="object"&&t!==null&&"code"in t){let e=t.code;if(typeof e=="string"&&e.length>0)return e}}async function nb(t,e){let r;try{r=await j(e,l=>We(t,l))}catch(l){return{ok:!1,message:`${t}: ${l instanceof Error?l.message:String(l)}`}}let n;try{n=Ye(r)}catch(l){return{ok:!1,message:`${t}: ${l instanceof Error?l.message:String(l)}`}}let s=di(n,Wt(r));e.stderr.write(`notice: checking teamfile and models ...
|
|
2085
|
+
`),null}}function Pt(t,e,r,n,s){t!==null||e===null||k({event:"chat_attempt_error",reason:s,root_teamfile:e.root_teamfile,sender_teamfile:e.sender_teamfile,sender_alias:e.sender_alias,receiver_teamfile:e.receiver_teamfile,receiver_alias:e.receiver_alias,origin:e.origin,error_detail:n,message_preview:an(r)})}function ln(t){return t.length<=ef?{text:t,truncated:!1}:{text:t.slice(0,ef),truncated:!0}}import{createHash as Hv}from"node:crypto";import{accessSync as Xv,constants as Xf,existsSync as qv,readFileSync as Gf,realpathSync as Ka,statSync as Gv,writeFileSync as qf}from"node:fs";import{dirname as Wt,resolve as Jf}from"node:path";import{spawnSync as Ga}from"node:child_process";import{existsSync as Mf,readFileSync as Ff}from"node:fs";import{homedir as Pf}from"node:os";import{resolve as Xa}from"node:path";import{mkdirSync as hf,readFileSync as US,renameSync as jS,writeFileSync as WS,existsSync as gf}from"node:fs";import{homedir as BS}from"node:os";import{dirname as _f,join as Hs,resolve as Xs}from"node:path";import{fileURLToPath as HS}from"node:url";var XS="https://lmctl.com/dataset/model_list.json",qS="https://lmctl.com/dataset/aliases.json",GS=1e3,JS=1e4,lf=6*60*60*1e3;function VS(){return Hs(BS(),".lmctl","cache","lmprice")}var Fa="model_list.json",Pa="aliases.json",yf="meta.json",KS="model_list.meta.json";function fr(t,e){return Hs(t,e)}function $t(t){try{return JSON.parse(US(t,"utf-8"))}catch{return null}}function Ef(t,e){let r=`${t}.tmp-${process.pid}`;WS(r,e),jS(r,t)}function Ma(t){return t===null||typeof t=="number"}function qs(t){if(typeof t!="object"||t===null)return!1;let e=t;return e.schema_version!==1||!Array.isArray(e.records)||e.records.length===0?!1:e.records.every(r=>{if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.source!="string"||typeof n.source_model_id!="string"||typeof n.pricing!="object"||n.pricing===null)return!1;let s=n.pricing;return Ma(s.input_per_1m_tokens)&&Ma(s.output_per_1m_tokens)&&Ma(s.input_cache_read_per_1m_tokens)})}var YS=new Set(["established","asserted","unresolved"]);function Gs(t){if(typeof t!="object"||t===null)return!1;let e=t;if(e.schema_version!==1||!Array.isArray(e.standards)||!Array.isArray(e.aliases))return!1;let r=e.standards.every(s=>{if(typeof s!="object"||s===null)return!1;let i=s;return typeof i.standard_slug=="string"&&(i.catalog_record_id===null||typeof i.catalog_record_id=="string")}),n=e.aliases.every(s=>{if(typeof s!="object"||s===null)return!1;let i=s;return typeof i.alias=="string"&&(i.standard_slug===null||typeof i.standard_slug=="string")&&typeof i.evidence=="string"&&YS.has(i.evidence)});return r&&n}function zS(t){let e=$t(fr(t,yf)),r={etag:typeof e?.model_list?.etag=="string"?e.model_list.etag:null,last_checked:typeof e?.model_list?.last_checked=="string"?e.model_list.last_checked:null},n={etag:typeof e?.aliases?.etag=="string"?e.aliases.etag:null,last_checked:typeof e?.aliases?.last_checked=="string"?e.aliases.last_checked:null};if(e===null){let s=$t(fr(t,KS));s&&(r.etag=typeof s.etag=="string"?s.etag:null,r.last_checked=typeof s.fetchedAt=="string"?s.fetchedAt:null)}return{model_list:r,aliases:n}}function QS(t){let e=zS(t),r=$t(fr(t,Fa)),n=$t(fr(t,Pa));return{catalog:qs(r)?r:null,aliases:Gs(n)?n:null,meta:e}}function ZS(t,e){try{hf(t,{recursive:!0}),Ef(fr(t,yf),JSON.stringify(e))}catch{}}function cf(t,e,r){try{hf(t,{recursive:!0}),Ef(fr(t,e),JSON.stringify(r))}catch{}}function ev(t,e){let r=tv(t),n=r?[Xs(r,"data",e)]:[Xs(t,"..","..","data",e)];for(let s of n)if(gf(s))return s;return null}function tv(t){let e=Xs(t);for(;;){if(gf(Xs(e,"package.json")))return e;let r=_f(e);if(r===e)return null;e=r}}function df(t,e,r){let n=r!==void 0?r:ev(t,e);return n===null?null:$t(n)}function rv(){let t=process.env.LMCTL_PRICE_TTL;if(t===void 0||t==="")return lf;let e=Number(t);return!Number.isFinite(e)||e<0?lf:e*1e3}function nv(){let t=process.env.LMCTL_PRICE_DATA;return t!==void 0&&t!==""?t:null}async function uf(t,e,r,n){try{let s=await t(e,{method:"HEAD",signal:AbortSignal.timeout(GS)});if(!s.ok)return{kind:"failed"};let i=s.headers.get("etag");if(r!==null&&i!==null&&i===n)return{kind:"match"};let o=await t(e,{signal:AbortSignal.timeout(JS)});return o.ok?{kind:"payload",payload:await o.json(),etag:o.headers.get("etag")??i}:{kind:"failed"}}catch{return{kind:"failed"}}}var $a=null;var mf=null;function Tf(t={}){return Object.keys(t).length===0?(mf??=ff(t),mf):ff(t)}async function ff(t){let e=_f(HS(import.meta.url)),r=t.pinDir!==void 0?t.pinDir:nv();if(r!==null&&r!==""){let g=$t(Hs(r,Fa)),T=$t(Hs(r,Pa));if(qs(g)&&Gs(T)){let h={catalog:g,aliases:T,source:"pinned",generatedAt:g.generated_at??null};return $a=h.generatedAt,h}return pf(t,e)}let n=t.fetchImpl??fetch,s=t.cacheDir??VS(),i=t.now??Date.now(),o=t.ttlMs??rv(),a=QS(s),l=(g,T)=>g!==null&&T.last_checked!==null&&i-Date.parse(T.last_checked)<o,c=a.catalog,u=a.aliases,d=!1,m={model_list:{...a.meta.model_list},aliases:{...a.meta.aliases}},p=!1;if(!l(c,a.meta.model_list)){let g=await uf(n,XS,c,a.meta.model_list.etag);g.kind==="match"?(m.model_list.last_checked=new Date(i).toISOString(),p=!0):g.kind==="payload"&&(m.model_list.last_checked=new Date(i).toISOString(),p=!0,qs(g.payload)&&(c=g.payload,g.etag!==null&&(m.model_list.etag=g.etag),cf(s,Fa,c),d=!0))}if(!l(u,a.meta.aliases)){let g=await uf(n,qS,u,a.meta.aliases.etag);g.kind==="match"?(m.aliases.last_checked=new Date(i).toISOString(),p=!0):g.kind==="payload"&&(m.aliases.last_checked=new Date(i).toISOString(),p=!0,Gs(g.payload)&&(u=g.payload,g.etag!==null&&(m.aliases.etag=g.etag),cf(s,Pa,u),d=!0))}if((p||d)&&ZS(s,m),c!==null||u!==null){let g={catalog:c,aliases:u,source:d?"network":"cache",generatedAt:c?.generated_at??null};return $a=g.generatedAt,g}return pf(t,e)}function pf(t,e){let r=df(e,"price-data.json",t.bundledPath),n=df(e,"price-aliases.json",t.bundledAliasesPath),s=qs(r)?r:null,i=Gs(n)?n:null,o={catalog:s,aliases:i,source:s!==null||i!==null?"bundled":"unavailable",generatedAt:s?.generated_at??null};return $a=o.generatedAt,o}function jt(t){return t.toLowerCase().replace(/(\d)\.(\d)/g,"$1-$2")}function Ut(t){let e=t.source_model_id.toLowerCase(),r=e.slice(e.lastIndexOf("/")+1);return jt(r)}function Sf(t){let e=new Set,r=n=>{let s=n.toLowerCase().split("/");for(let i=0;i<s.length;i+=1)e.add(jt(s.slice(i).join("/")))};return r(t.source_model_id),t.gateway_id&&r(t.gateway_id),e}function sv(t,e){let r=new Set,n=l=>{r.add(jt(l))},s=t.trim().toLowerCase(),i=null,o=s.indexOf(":");o>0&&!s.slice(0,o).includes("/")&&(i=s.slice(0,o),n(s),s=s.slice(o+1)),n(s);let a=s.slice(s.lastIndexOf("/")+1);n(a);for(let l of e)n(`${l}/${a}`);return i!==null&&n(`${i}/${a}`),[...r]}function pr(t){let e=n=>!(n.mode!==void 0&&n.mode!==null&&n.mode!=="chat"||t.nonChatName&&t.nonChatName.test(n.source_model_id.toLowerCase())),r=n=>e(n)&&t.family.test(n.source_model_id.toLowerCase());return{firstPartyProviders:t.firstPartyProviders,isChatModel:e,coversRecord:r,normalize:n=>sv(n,t.vendorPrefixes),matchRow(n,s){if(!r(n))return!1;let i=Sf(n);return s.some(o=>i.has(o))}}}var vf=pr({vendorPrefixes:["anthropic"],family:/claude/,firstPartyProviders:["anthropic"]}),bf=pr({vendorPrefixes:["openai"],family:/(^|\/)(gpt-|o\d|chatgpt|ft:gpt)|openai\//,firstPartyProviders:["openai"],nonChatName:/(^|[-/])(tts|transcribe(?:-\w+)?|realtime(?:-\w+)?|search(?:-\w+)*|image(?:-\w+)?|audio(?:-\w+)?|whisper(?:-\w+)?|dall-e(?:-\w+)?|embedding|moderation)(-|$)/}),If=pr({vendorPrefixes:["google","gemini"],family:/gemini|gemma/,firstPartyProviders:["gemini","google","vertex_ai-language-models"],nonChatName:/embedding|imagen|-image|tts|audio|veo|lyria|live|realtime|video/}),xf=pr({vendorPrefixes:["moonshot","moonshotai"],family:/kimi|moonshot/,firstPartyProviders:["moonshot"]}),Af=pr({vendorPrefixes:["dashscope","qwen"],family:/qwen/,firstPartyProviders:["dashscope"]}),kf=pr({vendorPrefixes:["deepseek","nousresearch"],family:/deepseek|nous|hermes-\d/,firstPartyProviders:["deepseek","nousresearch"]}),iv=/\s*\(([^()]+)\)\s*$/;function ov(t){let e=t.trim(),r=iv.exec(e);return r?{model:e.slice(0,r.index).trim(),effort:r[1].trim()}:{model:e,effort:null}}var av={"gemini 3.8 flash":"gemini-3.8-flash","gemini 3.7 flash":"gemini-3.7-flash","gemini 3.6 flash":"gemini-3.6-flash","gemini 3.1 pro":"gemini/gemini-3.1-pro-preview","claude sonnet 4.6":"claude-sonnet-4-6"},lv=["gemini","google","vertex_ai-language-models","anthropic"],cv={normalize(t){let{model:e}=ov(t),r=av[e.toLowerCase()];return r===void 0?[]:[jt(r)]},isChatModel(t){return t.mode===void 0||t.mode===null||t.mode==="chat"},coversRecord(t){return this.isChatModel(t)&&/gemini|claude/.test(t.source_model_id.toLowerCase())},matchRow(t,e){if(!this.coversRecord(t))return!1;let r=Sf(t);return e.some(n=>r.has(n))}},cn={claude:vf,codex:bf,gemini:If,agy:cv,kimi:xf,qwen:Af,hermes:kf},wf={claude:vf.firstPartyProviders,codex:bf.firstPartyProviders,gemini:If.firstPartyProviders,agy:lv,kimi:xf.firstPartyProviders,qwen:Af.firstPartyProviders,hermes:kf.firstPartyProviders};function dv(t,e,r){let n=e.trim().toLowerCase(),s=jt(n);if(r.records.some(o=>o.source_model_id.toLowerCase()===n&&t.matchRow(o,[s])))return!0;let i=t.normalize(e);return i.length>0&&r.records.some(o=>t.matchRow(o,i))}function uv(t,e,r){let n=[];for(let[s,i]of Object.entries(cn))s!==r&&dv(i,t,e)&&n.push(s);return n}function Js(t){return t==="moonshot"?0:t==="litellm"?1:t==="openrouter"?2:t==="manual"?3:4}function mv(t,e){return t.input_per_1m_tokens===e.input_per_1m_tokens&&t.output_per_1m_tokens===e.output_per_1m_tokens&&t.input_cache_read_per_1m_tokens===e.input_cache_read_per_1m_tokens}function fv(t){let e=new Map,r=[];for(let n of t){let s=n.source_model_id.toLowerCase(),i=s.lastIndexOf("/"),o=i===-1?"":s.slice(0,i+1),a=i===-1?s:s.slice(i+1),l=`${n.source}:${o}${jt(a)}`,c=e.get(l);if(c===void 0){e.set(l,n);continue}if(!mv(c.pricing,n.pricing)){r.push(n);continue}/\d\.\d/.test(c.source_model_id)&&!/\d\.\d/.test(n.source_model_id)&&e.set(l,n)}return[...e.values(),...r]}function pv(t){return{route:t.record_id??`${t.source}:${t.source_model_id}`,source:t.source,sourceModelId:t.source_model_id,provider:t.provider??null,pricing:t.pricing,estimated:t.source==="manual"}}function Rf(t,e){return t.map(pv).sort((r,n)=>{let s=Js(r.source)-Js(n.source);if(s!==0)return s;let i=r.provider!==null&&e.includes(r.provider)?0:1,o=n.provider!==null&&e.includes(n.provider)?0:1;return i!==o?i-o:r.sourceModelId.localeCompare(n.sourceModelId)})}function hv(t){return t.pricing.input_per_1m_tokens!==null&&t.pricing.output_per_1m_tokens!==null}function gv(t,e,r){let n=fv(t),s=Rf(n,r),o=n.find(a=>(a.record_id??`${a.source}:${a.source_model_id}`)===s[0].route)?.context_window?.input_tokens??void 0;return{id:s[0].sourceModelId,normalizedId:e,offers:s,...o!=null?{contextWindow:o}:{}}}function Ua(t,e,r){if(t.length===0)return{kind:"known-unpriced",id:e};let n=gv(t,e,r),s=n.offers.find(hv);return s===void 0?{kind:"known-unpriced",id:e}:s.estimated?{kind:"estimated",model:n}:{kind:"priced",model:n}}var ja=[];function _v(t,e){return t.standards.find(r=>r.standard_slug.toLowerCase()===e.toLowerCase())??null}function yv(t,e,r){let n=t.standard_slug;if(e===null||e.catalog_record_id===null)return{kind:"known-unpriced",id:n};let s=e.catalog_record_id.toLowerCase(),i=r.records.find(l=>(l.record_id??`${l.source}:${l.source_model_id}`).toLowerCase()===s);if(!i)return{kind:"known-unpriced",id:n};let o=Ut(i),a=r.records.filter(l=>Ut(l)!==o?!1:l.mode===void 0||l.mode===null||l.mode==="chat");return a.length===0?{kind:"known-unpriced",id:n}:Ua(a,o,ja)}function Ev(t,e,r,n){if(r===null||!Array.isArray(r.records))return{state:{kind:"no-catalog"},viaAlias:!1,pinRoute:null};if(n!==null){let T=[e.trim().toLowerCase()];T.push(`${t.toLowerCase()}/${T[0]}`);let h=n.aliases.find(f=>T.includes(f.alias.toLowerCase()));if(h){if(h.evidence==="unresolved"||h.standard_slug===null)return{state:{kind:"unresolved",alias:h.alias},viaAlias:!0,pinRoute:null};let f=_v(n,h.standard_slug);return{state:yv(h,f,r),viaAlias:!0,pinRoute:f?.catalog_record_id?.toLowerCase()??null}}}let s=cn[t];if(!s)return{state:{kind:"no-catalog"},viaAlias:!1,pinRoute:null};let i=e.trim().toLowerCase(),o=s.normalize(e),a=T=>({state:T,viaAlias:!1,pinRoute:null}),l=jt(i),c=r.records.filter(T=>T.source_model_id.toLowerCase()===i&&s.matchRow(T,[l]));if(c.length>0){let T=Ut(c[0]),h=r.records.filter(f=>s.matchRow(f,[T])&&Ut(f)===T);return a(Ua(h.length>0?h:c,T,wf[t]??ja))}let u=r.records.filter(T=>s.matchRow(T,o));if(u.length===0){let T=uv(e,r,t);return T.length>0?a({kind:"wrong-provider",declared:e,otherProviders:T}):a({kind:"unknown",declared:e})}let d=new Map;for(let T of u){let h=Ut(T),f=d.get(h);f?f.push(T):d.set(h,[T])}let m=wf[t]??ja,p=null,g=null;for(let T of d.values()){let h=Rf(T,m);(g===null||Tv(h[0],g[0],m)<0)&&(p=T,g=h)}return a(Ua(p,Ut(p[0]),m))}function Nf(t,e,r,n){return Ev(t,e,r,n).state}function Lf(t,e){let r=cn[e];if(!r)return null;let n=new Set;for(let s of t.records)r.coversRecord(s)&&n.add(Ut(s));return n.size}function Tv(t,e,r){let n=Js(t.source)-Js(e.source);if(n!==0)return n;let s=t.provider!==null&&r.includes(t.provider)?0:1,i=e.provider!==null&&r.includes(e.provider)?0:1;return s!==i?s-i:t.sourceModelId.localeCompare(e.sourceModelId)}var $f=new Set(Object.keys(cn).filter(t=>t!=="codex"&&t!=="kimi")),wv=/\d\.(?=\d)/,Sv=new Set(["claude","codex","gemini","qwen","kimi","agy"]),Cf=["deepseek-v4-flash","deepseek-v4-pro","deepseek-v4-flash-vision-exp"],Of=["deepseek-flash","deepseek-pro"],Df="gpt-5.3-codex-spark",vv=15e3;function hr(t,e){return e.code==="ETIMEDOUT"?`${t} did not respond within lint's own spawn timeout (${e.message}) \u2014 this does not mean the provider itself is unreachable, only that this specific check didn't finish in time.`:`${t} could not be run: ${e.message}`}function bv(){let t=Ga("agy",["models"],{encoding:"utf-8",timeout:vv});return{status:t.status,stdout:t.stdout??"",error:t.error}}var Wa=null;function Iv(t){let e=[];for(let r of t.split(/\r?\n/)){let n=r.trim(),s=n.indexOf(" ");if(s<0)continue;let i=n.slice(s+1).trim();i&&e.push(i)}return e}function xv(t){if(!t&&Wa)return Wa;let e=s=>(t||(Wa=s),s),r;try{r=(t??bv)()}catch(s){return e({available:!1,models:[],reason:s instanceof Error?hr("agy models",s):`agy models could not be run: ${String(s)}`})}if(r.error)return e({available:!1,models:[],reason:hr("agy models",r.error)});if(r.status!==0)return e({available:!1,models:[],reason:`agy models exited with status ${r.status??"unknown"}`});let n=Iv(r.stdout);return n.length===0?e({available:!1,models:[],reason:"agy models returned no models"}):e({available:!0,models:n})}var Av=5e3;function kv(){let t=Ga("codex",["debug","models"],{encoding:"utf-8",timeout:Av});return{status:t.status,stdout:t.stdout??"",error:t.error}}var Ba=null;function Rv(t){let e;try{e=JSON.parse(t)}catch{return}let r=e.models;if(!Array.isArray(r))return;let n=[];for(let s of r){if(!s||typeof s!="object")continue;let{slug:i,visibility:o}=s;typeof i=="string"&&o==="list"&&n.push(i)}return n}function Nv(t){if(!t&&Ba)return Ba;let e=s=>(t||(Ba=s),s),r;try{r=(t??kv)()}catch(s){return e({available:!1,models:[],reason:s instanceof Error?hr("codex debug models",s):`codex debug models could not be run: ${String(s)}`})}if(r.error)return e({available:!1,models:[],reason:hr("codex debug models",r.error)});if(r.status!==0)return e({available:!1,models:[],reason:`codex debug models exited with status ${r.status??"unknown"}`});let n=Rv(r.stdout);return n===void 0?e({available:!1,models:[],reason:"codex debug models did not return parseable JSON"}):n.length===0?e({available:!1,models:[],reason:"codex debug models returned no user-visible models"}):e({available:!0,models:n})}var Lv=5e3;function Cv(t){let e=Ga("opencode",t?["models",t]:["models"],{encoding:"utf-8",timeout:Lv});return{status:e.status,stdout:e.stdout??"",error:e.error}}var Ha=new Map;function Ov(t,e){if(!e&&Ha.has(t))return Ha.get(t);let r=o=>(e||Ha.set(t,o),o),n=t?`opencode models ${t}`:"opencode models",s;try{s=(e??Cv)(t)}catch(o){return r({available:!1,models:[],reason:o instanceof Error?hr(n,o):`${n} could not be run: ${String(o)}`})}if(s.error)return r({available:!1,models:[],reason:hr(n,s.error)});if(s.status!==0)return r({available:!1,models:[],reason:`${n} exited with status ${s.status??"unknown"}`});let i=s.stdout.split(/\r?\n/).map(o=>o.trim()).filter(o=>o.length>0);return i.length===0?r({available:!1,models:[],reason:`${n} returned no models`}):r({available:!0,models:i})}function Ja(t,e={}){let r=[];for(let n of t){let s=n.provider.trim().toLowerCase();if(n.effort&&s!=="opencode"&&s!=="lmplayer"&&s!=="qwen"&&r.push(`[${n.alias}] effort="${n.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),s==="qwen"&&n.effort&&r.push(`[${n.alias}] effort="${n.effort}" is not a qwen CLI flag: Qwen Code does not expose reasoning-effort selection. Use a thinking/effort model id in model= instead.`),!n.model&&Sv.has(s)&&r.push(`[${n.alias}] provider=${s} has no model= \u2014 ${s} will use its own ambient default, which cannot be linted or priced and may not be the intended one. Set model= explicitly.`),s==="copilot"){if(!n.model)continue;r.push(`[${n.alias}] model="${n.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(s==="lmplayer"&&!n.model){r.push(`[${n.alias}] provider=lmplayer has no model= \u2014 lmplayer will choose its own default model, which may not be visible in the teamfile. Set model= explicitly (e.g. github-copilot/gpt-5.5).`);continue}if(s!=="lmplayer"){if(s==="opencode"){if(n.effort&&!n.model&&r.push(`[${n.alias}] effort="${n.effort}" has no effect without model= on an opencode member.`),!n.model){r.push(`[${n.alias}] provider=opencode has no model= \u2014 opencode will choose its own default model, which may not be servable and isn't visible in the teamfile. Set model= explicitly (e.g. github-copilot/gpt-5.5).`);continue}let i=Fv(e.opencodeConfigPath);if(!i.available){r.push(`[${n.alias}] model="${n.model}" cannot be verified for opencode: ${i.reason}.`);continue}if(i.models.includes(n.model)||/^github-copilot\/(gpt|gemini|o[0-9])/.test(n.model))continue;if(!n.model.includes("/")){let l=i.models.filter(c=>c.endsWith(`/${n.model}`));r.push(l.length>0?`[${n.alias}] model="${n.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${l.join(" / ")}; set model=${l[0]}.`:`[${n.alias}] model="${n.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model> (e.g. github-copilot/${n.model}). Declare it in ~/.config/opencode/opencode.json (see https://lmctl.com/examples/opencode.json).`);continue}let o=n.model.slice(0,n.model.indexOf("/")),a=Ov(o,e.opencodeModelsRunner);if(a.available&&a.models.includes(n.model))continue;if(a.available&&!a.models.includes(n.model)){r.push(`[${n.alias}] model="${n.model}" was not found in opencode's LOCALLY-VISIBLE live catalog for "${o}" (checked \`opencode models ${o}\`) -- this is unresolved, not a confirmed unavailability: it could mean opencode genuinely doesn't serve this model, OR that your local catalog/auth for "${o}" is stale/incomplete. Declaring it in opencode.json may or may not help; if it doesn't, check whether a non-opencode provider serves this model directly (e.g. \`lmctl lint\` with model= against provider=codex/claude/gemini/agy).`);continue}r.push(`[${n.alias}] model="${n.model}" is not declared in your opencode.json. opencode resolves github-copilot GPT/Gemini config-free, but copilot Claude and custom providers must be declared \u2014 copy https://lmctl.com/examples/opencode.json to ~/.config/opencode/opencode.json and adjust for your account.`);continue}if(s==="kimi"){if(!n.model)continue;let i=Dv(e.kimiConfigPath);i.available?i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not declared in Kimi's [models] config. Valid configured models: ${dn(i.models)}`):r.push(`[${n.alias}] model="${n.model}" cannot be verified for kimi: ${i.reason}.`);continue}if(s==="agy"){if(!n.model)continue;let i=xv(e.agyModelsRunner);i.available?i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in agy's live model catalog (\`agy models\`). Valid models: ${dn(i.models)}`):r.push(`[${n.alias}] model="${n.model}" cannot be verified for agy: ${i.reason}.`);continue}if(s==="dsh"){if(!n.model||Of.includes(n.model))continue;Cf.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in dsh's built-in catalog. Valid pinned models: ${dn(Cf)}. Valid server-resolved aliases (DeepSeek resolves these to its current model server-side -- pinning to a specific version instead is a DOWNGRADE, not a safer choice): ${dn(Of)}. The catalog is patchable via dsh profile overlays \u2014 a model added that way warns here even though it may resolve.`);continue}if(s==="hermes"){if(!n.model)continue;let i=n.model.indexOf(":");(i<=0||i===n.model.length-1)&&r.push(`[${n.alias}] model="${n.model}" should use <provider>:<model> from Hermes's ACP catalog. lmctl checks the shape only; provider and model availability are resolved by Hermes.`);continue}if(s!=="pi"){if(s==="codex"){if(!n.model)continue;n.model===Df&&r.push(`[${n.alias}] model="${Df}" is banned as a build model (operator, 2026-09-06) -- it's a fast/cheap classification model, not intended for build work, and there's no cost reason left to reach for it. Use model=gpt-5.6-sol (or leave model= unset) for build work; if this member genuinely does non-build/classification work, this warning can be ignored.`);let i=Nv(e.codexModelsRunner);if(!i.available){r.push(`[${n.alias}] model="${n.model}" cannot be verified for codex: ${i.reason}.`);continue}i.models.includes(n.model)||r.push(`[${n.alias}] model="${n.model}" is not in codex's live model catalog (\`codex debug models\`). Valid models: ${dn(i.models)}`);continue}n.model&&($f.has(s)||r.push(`[${n.alias}] model="${n.model}" cannot be verified for provider "${s}": no model validation path exists for this provider.`))}}}return r}async function Uf(t,e={}){let r=t.filter(o=>o.model!==void 0&&$f.has(o.provider.trim().toLowerCase()));if(r.length===0)return{warnings:[],errors:[]};let n=e.snapshot??await Tf();if(n.catalog===null)return{warnings:[],errors:[]};let s=[],i=[];for(let o of r){let a=o.provider.trim().toLowerCase(),l=o.model,c=Nf(a,l,n.catalog,n.aliases);if(c.kind==="unknown"){let u=Lf(n.catalog,a)??0;s.push(`[${o.alias}] model "${l}" is unknown to the lmprice catalog for provider "${a}" (${u} known) -- not necessarily wrong: may be a model too new for lmprice to have published yet, or a typo. A matching lmprice catalog/alias entry would resolve this; lint cannot otherwise confirm whether ${a} accepts it.`)}else c.kind==="wrong-provider"?i.push({field:o.alias,message:`model "${l}" is not offered by provider "${a}" -- it is a recognized model, but only under: ${c.otherProviders.join(", ")}. Declare provider="${c.otherProviders[0]}" (or another listed provider), or use a model "${a}" actually offers.`}):c.kind==="known-unpriced"&&s.push(`[${o.alias}] model "${l}" is recognized in the lmprice catalog but has no price information \u2014 cost will be unavailable`);if(a==="claude"&&(c.kind==="priced"||c.kind==="known-unpriced"||c.kind==="estimated")&&wv.test(l)){let u=l.replace(/(\d)\.(?=\d)/g,"$1-");s.push(`[${o.alias}] model="${l}" matches the lmprice catalog only through its OpenRouter-style spelling ("." between version numbers); claude's own CLI expects "-" there and does an exact match, so it may reject this string verbatim even though lint recognizes it. If seed/chat fails with "issue with the selected model," try model="${u}" instead.`)}}return{warnings:s,errors:i}}async function jf(t,e={}){return(await Uf(t,e)).warnings}async function Wf(t,e={}){return(await Uf(t,e)).errors}function Dv(t){let e=process.env.KIMI_CODE_HOME||Xa(Pf(),".kimi-code"),r=t??Xa(e,"config.toml");if(!Mf(r))return{available:!1,models:[],reason:`${r} not found`};let n;try{n=Ff(r,"utf-8")}catch(i){return{available:!1,models:[],reason:`${r} could not be read: ${i instanceof Error?i.message:String(i)}`}}let s=new Set;for(let i of n.split(/\r?\n/)){if(/^\s*\[/.test(i)&&!/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.test(i))return{available:!1,models:[],reason:`${r} has an invalid TOML table header`};let o=/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.exec(i);if(!o)continue;let a=Mv(o[1]);if(o[1].trim().startsWith("models")&&a===null)return{available:!1,models:[],reason:`${r} has an invalid [models] table header`};a?.[0]==="models"&&a.length>=2&&s.add(a[1])}return s.size===0?{available:!1,models:[],reason:`${r} has no [models] entries`}:{available:!0,models:[...s].sort()}}function Mv(t){let e=[],r=0;for(;r<t.length;){for(;/\s/.test(t[r]??"");)r++;if(r>=t.length)break;let n="",s=t[r]==='"'||t[r]==="'"?t[r++]:void 0;if(s){for(;r<t.length&&t[r]!==s;)s==='"'&&t[r]==="\\"&&r+1<t.length&&r++,n+=t[r++];if(t[r]!==s)return null;r++}else{for(;r<t.length&&t[r]!==".";)n+=t[r++];n=n.trim()}if(!n)return null;for(e.push(n);/\s/.test(t[r]??"");)r++;if(r>=t.length)break;if(t[r]!==".")return null;r++}return e.length>0?e:null}function Fv(t){let e=t??Xa(Pf(),".config","opencode","opencode.json");if(!Mf(e))return{available:!0,models:[]};let r;try{r=JSON.parse(Ff(e,"utf-8"))}catch(n){return{available:!1,models:[],reason:`${e} could not be parsed: ${n instanceof Error?n.message:String(n)}`}}return{available:!0,models:Pv(r)}}function Pv(t){if(!qa(t))return[];let e=Vs(t.provider)??Vs(t.providers);if(!e)return[];let r=new Set;for(let[n,s]of Object.entries(e)){if(!qa(s))continue;let i=Vs(s.models)??Vs(s.model);if(i)for(let o of Object.keys(i))r.add(o.startsWith(`${n}/`)?o:`${n}/${o}`)}return[...r].sort()}function Vs(t){return qa(t)?t:null}function qa(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function dn(t){return t.length>0?t.join(", "):"(none)"}to();mo();import{homedir as $v}from"node:os";import{basename as Uv}from"node:path";var jv={workdir:t=>t.workdir,teamfile:t=>t.teamfile,teamname:t=>{let e=Uv(t.teamfile);return e.endsWith(".lmctl")?e.slice(0,-6):e},home:()=>$v(),date:t=>t.date},Wv=/{{\s*([A-Za-z0-9_-]+)\s*}}/g;function Bf(t,e){let r=new Set;return{text:t.replace(Wv,(s,i)=>{let o=i.trim(),a=jv[o];return a===void 0?(r.add(o),s):a(e)}),unknownNames:[...r].sort()}}function Hf(t){return{workdir:t.workdir,teamfile:t.teamfile,date:Bv(t.date)}}function Bv(t){return t.toISOString().slice(0,10)}ge();var mn=5;var Jv='notice: member "%s" uses provider=gemini \u2014 the Gemini CLI requires an API/enterprise Google account; personal Google subscriptions should use provider=agy (Antigravity).',Vv={existsSync:qv,statSync:Gv,accessSync:Xv},Kv=async t=>{let{seed:e}=await Promise.resolve().then(()=>(nn(),Jm)),r=await e(t);return r.success?{sessionId:r.sessionId,warnings:r.warnings}:{error:r.error??"provider seed failed"}},gr=Vv,Yv=us,Vf,Kf,Ks;function Yf(t){return jf(t,Ks!==void 0?{snapshot:Ks}:{})}function zf(t){return Wf(t,Ks!==void 0?{snapshot:Ks}:{})}async function zv(t,e,r){let n=t.filter(i=>i.teamfile===void 0&&i.provider.trim().toLowerCase()==="opencode"&&i.model!==void 0&&i.model.length>0);return(await Promise.all(n.map(async i=>({member:i,result:await Yv({cwd:i.sessiondir??e,model:i.model,...i.effort!==void 0?{effort:i.effort}:{},...r!==void 0?{env:r}:{}})})))).flatMap(({member:i,result:o})=>o.status==="rejected"?[`[${i.alias}] ${o.option}="${o.value}" rejected by opencode: ${o.error}`]:[])}function Qv(t,e){let r=Wt(e),n=new Set,s=[];for(let i of t){if(i.teamfile!==void 0)continue;let o=i.sessiondir??r,a=Jf(o);if(n.has(a))continue;let l=Zv(a);l!==void 0&&(n.add(a),s.push(`${i.alias}: sessiondir ${a} is not writable (seed would fail: ${l}) \u2014 fix permissions or set a writable sessiondir`))}return s}function Zv(t){try{if(gr.existsSync(t)){if(!gr.statSync(t).isDirectory())return"ENOTDIR";gr.accessSync(t,Xf.W_OK);return}let e=tb(t);if(e===void 0)return;if(!gr.statSync(e).isDirectory())return"ENOTDIR";gr.accessSync(e,Xf.W_OK);return}catch(e){return rb(e)??"permission check failed"}}function eb(t){let e=Jf(t);try{return Ka(e)}catch{return e}}function tb(t){let e=t;for(;;){try{if(gr.existsSync(e))return e}catch{return}let r=Wt(e);if(r===e)return;e=r}}function rb(t){if(typeof t=="object"&&t!==null&&"code"in t){let e=t.code;if(typeof e=="string"&&e.length>0)return e}}async function nb(t,e){let r;try{r=await j(e,l=>We(t,l))}catch(l){return{ok:!1,message:`${t}: ${l instanceof Error?l.message:String(l)}`}}let n;try{n=Ye(r)}catch(l){return{ok:!1,message:`${t}: ${l instanceof Error?l.message:String(l)}`}}let s=di(n,Wt(r));e.stderr.write(`notice: checking teamfile and models ...
|
|
2086
2086
|
`);let i=Ja(n.members,{agyModelsRunner:Vf,codexModelsRunner:Kf});i.push(...await Yf(n.members)),s.push(...await zf(n.members));let o=Gf(r,"utf8"),a=Bf(o,Hf({workdir:Wt(r),teamfile:r,date:new Date})).unknownNames;a.length>0&&i.push(`unknown template placeholder${a.length===1?"":"s"}: ${a.map(l=>`{{${l}}}`).join(", ")}`),i.push(...eo(n.members,Wt(r))),i.push(...Qv(n.members,r)),i.push(...await zv(n.members,Wt(r),e.env));for(let l of s)e.stderr.write(`error: ${l.field}: ${l.message}
|
|
2087
2087
|
`);for(let l of n.members)Ya([l],e),l.session!==void 0&&l.session.length<mn&&i.push(`${l.alias}: sessionid is shorter than ${mn} chars; run lmctl seed to refresh it`);return{ok:!0,result:{config:n,absTeamfile:r,errors:s,warnings:i}}}var sb=/^\[([^\]]+)\]\s+(.*)$/s,ib=/^([^:\s][^:]*):\s+(.*)$/s;function ob(t,e){let r=sb.exec(t);if(r){let s=e.get(r[1].toLowerCase());if(s!==void 0)return{alias:s,message:r[2]}}let n=ib.exec(t);if(n){let s=e.get(n[1].toLowerCase());if(s!==void 0)return{alias:s,message:n[2]}}return{alias:"",message:t}}async function Qf(t,e){let r=await nb(t,e);if(!r.ok)return{status:"error",errors:[{alias:"",message:r.message}],warnings:[],counts:{errors:1,warnings:0}};let{config:n,errors:s,warnings:i}=r.result,o=new Map(n.members.map(c=>[c.alias.toLowerCase(),c.alias])),a=s.map(c=>({alias:o.get(c.field.toLowerCase())??"",message:c.message})),l=i.map(c=>ob(c,o));for(let c of l)e.stderr.write(`warning: ${c.alias?`${c.alias}: `:""}${c.message}
|
|
2088
2088
|
`);return e.stderr.write(`notice: ${a.length} error${a.length===1?"":"s"}, ${l.length} warning${l.length===1?"":"s"}
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
import { type CatalogSnapshot } from "../pricing.js";
|
|
2
2
|
import type { MemberConfig, TeamValidationError } from "./team-config.js";
|
|
3
|
+
/**
|
|
4
|
+
* dsh's real model catalog — the static DEFAULT_MODELS list baked into the
|
|
5
|
+
* shipped `@deepseek-ai/dsh-llm-deepseek` package (verified against dsh
|
|
6
|
+
* 0.1.1-rc.2; see backlog/DESIGN-add-dsh-provider.md). Hardcoded by
|
|
7
|
+
* deliberate choice: dsh has no kimi-style user-editable model config file
|
|
8
|
+
* to read live, and shelling out to `dsh --dump-config` would add a process
|
|
9
|
+
* spawn to every lint run only to report these same baked-in defaults. The
|
|
10
|
+
* catalog is patchable via dsh profile overlays, so a user-extended model
|
|
11
|
+
* will warn here even though it may resolve — the warning text says so.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DSH_MODELS: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Server-side resolving aliases: DeepSeek resolves these to whatever its
|
|
16
|
+
* CURRENT flash/pro model is (operator, 2026-09-16: "dsh have the default
|
|
17
|
+
* that I set as deepseek-flash, which deepseek link to the latest deepseek
|
|
18
|
+
* version: deepseek-4.1-flash. (server side resolve, not client side
|
|
19
|
+
* resolve)"). NOT pinned versions -- do not fold into DSH_MODELS above or
|
|
20
|
+
* present alongside it as an equivalent "valid model," because pinning to
|
|
21
|
+
* e.g. `deepseek-v4-flash` instead is an ACTIVE DOWNGRADE once DeepSeek
|
|
22
|
+
* moves the alias forward, not a safer choice. Real incident: this lint's
|
|
23
|
+
* old "Valid models: <pinned list>" wording steered an operator into doing
|
|
24
|
+
* exactly that once already, before being corrected. Six teams (math,
|
|
25
|
+
* memperf, backup, dsh_creator, localwebqa, and growing -- dsh is now a
|
|
26
|
+
* primary execution provider fleet-wide) use `deepseek-flash` deliberately.
|
|
27
|
+
*/
|
|
28
|
+
export declare const DSH_SERVER_RESOLVED_ALIASES: string[];
|
|
3
29
|
export interface AgyModelsRunResult {
|
|
4
30
|
status: number | null;
|
|
5
31
|
stdout: string;
|
|
6
32
|
error?: Error;
|
|
7
33
|
}
|
|
34
|
+
export declare function loadAgyModels(runner?: () => AgyModelsRunResult): OpenCodeModelResult;
|
|
8
35
|
export interface CodexModelsRunResult {
|
|
9
36
|
status: number | null;
|
|
10
37
|
stdout: string;
|
|
11
38
|
error?: Error;
|
|
12
39
|
}
|
|
40
|
+
export declare function loadCodexModels(runner?: () => CodexModelsRunResult): OpenCodeModelResult;
|
|
13
41
|
export interface OpencodeModelsRunResult {
|
|
14
42
|
status: number | null;
|
|
15
43
|
stdout: string;
|
|
16
44
|
error?: Error;
|
|
17
45
|
}
|
|
46
|
+
export declare function loadOpencodeLiveModels(provider: string, runner?: (provider: string) => OpencodeModelsRunResult): OpenCodeModelResult;
|
|
18
47
|
export declare function modelSelectionWarnings(members: MemberConfig[], opts?: {
|
|
19
48
|
opencodeConfigPath?: string;
|
|
20
49
|
kimiConfigPath?: string;
|
|
@@ -32,3 +61,10 @@ export declare function catalogModelWarnings(members: MemberConfig[], opts?: {
|
|
|
32
61
|
export declare function catalogModelErrors(members: MemberConfig[], opts?: {
|
|
33
62
|
snapshot?: CatalogSnapshot;
|
|
34
63
|
}): Promise<TeamValidationError[]>;
|
|
64
|
+
interface OpenCodeModelResult {
|
|
65
|
+
available: boolean;
|
|
66
|
+
models: string[];
|
|
67
|
+
reason?: string;
|
|
68
|
+
}
|
|
69
|
+
export declare function loadKimiModels(configPath?: string): OpenCodeModelResult;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CatalogDataLike } from './model-catalog.js';
|
|
2
|
+
export declare function isAggregatorProvider(provider: string): boolean;
|
|
3
|
+
export declare function catalogModelSuggestions(provider: string, catalog: CatalogDataLike): string[];
|
|
4
|
+
export declare function loadModelSuggestions(provider: string): Promise<string[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmctl-ai/lmctl",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.24",
|
|
4
4
|
"description": "A provider-agnostic control plane for teams of AI coding agents — across providers, with independent review and durable memory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://lmctl.com",
|