@lmctl-ai/lmctl 0.1.309 → 0.1.310

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/dist/cli/index.js CHANGED
@@ -3162,7 +3162,7 @@ copy, in that order.`});var CA={};oe(CA,{runLs:()=>kV});import{resolve as Ep}fro
3162
3162
  [--recursive] [--all] [--format table|teamfile|json] [--json]
3163
3163
  lmctl ls --runs [--limit N] [--format table|json] [--json]
3164
3164
 
3165
- List native provider sessions in scope, or list recent managed runs with --runs.`,SV=50,LA=500});import{spawnSync as jA}from"node:child_process";import{existsSync as ms,readFileSync as kp}from"node:fs";import{homedir as PA}from"node:os";import{dirname as FA,resolve as Xn}from"node:path";import{fileURLToPath as AV}from"node:url";function LV(){let t=jA("agy",["models"],{encoding:"utf-8",timeout:OV});return{status:t.status,stdout:t.stdout??"",error:t.error}}function CV(t){let e=[];for(let n of t.split(/\r?\n/)){let r=n.trim(),s=r.indexOf(" ");if(s<0)continue;let i=r.slice(s+1).trim();i&&e.push(i)}return e}function $V(t){if(!t&&Tp)return Tp;let e=s=>(t||(Tp=s),s),n;try{n=(t??LV)()}catch(s){return e({available:!1,models:[],reason:`agy models could not be run: ${s instanceof Error?s.message:String(s)}`})}if(n.error)return e({available:!1,models:[],reason:`agy models could not be run: ${n.error.message}`});if(n.status!==0)return e({available:!1,models:[],reason:`agy models exited with status ${n.status??"unknown"}`});let r=CV(n.stdout);return r.length===0?e({available:!1,models:[],reason:"agy models returned no models"}):e({available:!0,models:r})}function DV(t){let e=jA("opencode",["models",t],{encoding:"utf-8",timeout:MV});return{status:e.status,stdout:e.stdout??"",error:e.error}}function jV(t,e){if(!e&&vp.has(t))return vp.get(t);let n=i=>(e||vp.set(t,i),i),r;try{r=(e??DV)(t)}catch(i){return n({available:!1,models:[],reason:`opencode models ${t} could not be run: ${i instanceof Error?i.message:String(i)}`})}if(r.error)return n({available:!1,models:[],reason:`opencode models ${t} could not be run: ${r.error.message}`});if(r.status!==0)return n({available:!1,models:[],reason:`opencode models ${t} exited with status ${r.status??"unknown"}`});let s=r.stdout.split(/\r?\n/).map(i=>i.trim()).filter(i=>i.length>0);return s.length===0?n({available:!1,models:[],reason:`opencode models ${t} returned no models`}):n({available:!0,models:s})}function Ip(t,e={}){let n=[],r=PV(e.modelSelectionDocPath);for(let s of t){let i=s.provider.trim().toLowerCase();if(s.effort&&i!=="opencode"&&i!=="lmplayer"&&i!=="qwen"&&n.push(`[${s.alias}] effort="${s.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),i==="qwen"&&s.effort&&n.push(`[${s.alias}] effort="${s.effort}" is not a qwen CLI flag: Qwen Code does not expose reasoning-effort selection. Use a thinking/effort model id in model= instead.`),i==="copilot"){if(!s.model)continue;n.push(`[${s.alias}] model="${s.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(i==="lmplayer"&&!s.model){n.push(`[${s.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.4).`);continue}if(i==="lmplayer")continue;if(i==="opencode"){if(s.effort&&!s.model&&n.push(`[${s.alias}] effort="${s.effort}" has no effect without model= on an opencode member.`),!s.model){n.push(`[${s.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.4).`);continue}let a=JV(e.opencodeConfigPath);if(!a.available){n.push(`[${s.alias}] model="${s.model}" cannot be verified for opencode: ${a.reason}.`);continue}if(a.models.includes(s.model)||/^github-copilot\/(gpt|gemini|o[0-9])/.test(s.model))continue;if(!s.model.includes("/")){let u=a.models.filter(d=>d.endsWith(`/${s.model}`));n.push(u.length>0?`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${u.join(" / ")}; set model=${u[0]}.`:`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model> (e.g. github-copilot/${s.model}). Declare it in ~/.config/opencode/opencode.json (see https://lmctl.com/examples/opencode.json).`);continue}let l=s.model.slice(0,s.model.indexOf("/")),c=jV(l,e.opencodeModelsRunner);if(c.available&&!c.models.includes(s.model)){n.push(`[${s.alias}] model="${s.model}" was not found in opencode's LOCALLY-VISIBLE live catalog for "${l}" (checked \`opencode models ${l}\`) -- this is unresolved, not a confirmed unavailability: it could mean opencode genuinely doesn't serve this model, OR that your local catalog/auth for "${l}" 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}n.push(`[${s.alias}] model="${s.model}" is not declared in your opencode.json`+(c.available?" (opencode CAN serve it -- confirmed live via `opencode models`)":"")+". 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(i==="kimi"){if(!s.model)continue;let a=HV(e.kimiConfigPath);a.available?a.models.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not declared in Kimi's [models] config. Valid configured models: ${Gl(a.models)}`):n.push(`[${s.alias}] model="${s.model}" cannot be verified for kimi: ${a.reason}.`);continue}if(i==="agy"){if(!s.model)continue;let a=$V(e.agyModelsRunner);a.available?a.models.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in agy's live model catalog (\`agy models\`). Valid models: ${Gl(a.models)}`):n.push(`[${s.alias}] model="${s.model}" cannot be verified for agy: ${a.reason}.`);continue}if(i==="dsh"){if(!s.model)continue;MA.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in dsh's built-in catalog. Valid models: ${Gl(MA)}. The catalog is patchable via dsh profile overlays \u2014 a model added that way warns here even though it may resolve.`);continue}if(!s.model)continue;i==="codex"&&s.model===DA&&n.push(`[${s.alias}] model="${DA}" 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 o=r.get(i);if(!o){n.push(`[${s.alias}] model="${s.model}" cannot be verified for provider "${i}": `+(Kl??"no tested models found in durable-memory/model_selection.md"));continue}o.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in the tested model list for provider "${i}". Valid tested models: ${Gl(o)}`)}return n}function PV(t){if(!t&&Ri)return Ri;let e=new Map,n,r=t??FV();if(!ms(r))return n=`${r} not found`,t||Sp(e),t||(Ri=e),t||(Kl=n),e;let s;try{s=kp(r,"utf-8")}catch(i){return n=`${r} could not be read: ${i instanceof Error?i.message:String(i)}`,t||Sp(e),t||(Ri=e),t||(Kl=n),e}for(let[i,o]of Object.entries(xV)){let a=qV(s,o),l=BV(a);l.length>0&&e.set(i,l)}return e.size===0&&(n=`${r} has no tested model rows`),!t&&e.size===0&&Sp(e),t||(Ri=e),t||(Kl=n),e}function FV(){return UV(FA(AV(import.meta.url)))}function UV(t){let e=WV(t);if(e){let r=Xn(e,"durable-memory","model_selection.md");if(ms(r))return r}let n=[Xn(t,"..","..","durable-memory","model_selection.md"),Xn(t,"..","..","..","durable-memory","model_selection.md")];for(let r of n)if(ms(r))return r;return n[n.length-1]}function WV(t){let e=Xn(t);for(;;){if(ms(Xn(e,"package.json")))return e;let n=FA(e);if(n===e)return null;e=n}}function Sp(t){for(let[e,n]of Object.entries(RV))t.set(e,n)}function qV(t,e){let r=new RegExp(`^## ${KV(e)}\\s*$`,"m").exec(t);if(!r)return"";let s=r.index+r[0].length,i=t.slice(s),o=/^##\s+/m.exec(i);return o?i.slice(0,o.index):i}function BV(t){let e=new Set;for(let n of t.split(/\r?\n/)){let r=n.trim();if(!r.startsWith("| `"))continue;let s=/^\|\s*`([^`]+)`\s*\|/.exec(r);if(!s)continue;let i=s[1].trim();i&&i!=="Configured `model="&&e.add(i)}return[...e]}function HV(t){let e=process.env.KIMI_CODE_HOME||Xn(PA(),".kimi-code"),n=t??Xn(e,"config.toml");if(!ms(n))return{available:!1,models:[],reason:`${n} not found`};let r;try{r=kp(n,"utf-8")}catch(i){return{available:!1,models:[],reason:`${n} could not be read: ${i instanceof Error?i.message:String(i)}`}}let s=new Set;for(let i of r.split(/\r?\n/)){if(/^\s*\[/.test(i)&&!/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.test(i))return{available:!1,models:[],reason:`${n} has an invalid TOML table header`};let o=/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.exec(i);if(!o)continue;let a=XV(o[1]);if(o[1].trim().startsWith("models")&&a===null)return{available:!1,models:[],reason:`${n} has an invalid [models] table header`};a?.[0]==="models"&&a.length>=2&&s.add(a[1])}return s.size===0?{available:!1,models:[],reason:`${n} has no [models] entries`}:{available:!0,models:[...s].sort()}}function XV(t){let e=[],n=0;for(;n<t.length;){for(;/\s/.test(t[n]??"");)n++;if(n>=t.length)break;let r="",s=t[n]==='"'||t[n]==="'"?t[n++]:void 0;if(s){for(;n<t.length&&t[n]!==s;)s==='"'&&t[n]==="\\"&&n+1<t.length&&n++,r+=t[n++];if(t[n]!==s)return null;n++}else{for(;n<t.length&&t[n]!==".";)r+=t[n++];r=r.trim()}if(!r)return null;for(e.push(r);/\s/.test(t[n]??"");)n++;if(n>=t.length)break;if(t[n]!==".")return null;n++}return e.length>0?e:null}function JV(t){let e=t??Xn(PA(),".config","opencode","opencode.json");if(!ms(e))return{available:!0,models:[]};let n;try{n=JSON.parse(kp(e,"utf-8"))}catch(r){return{available:!1,models:[],reason:`${e} could not be parsed: ${r instanceof Error?r.message:String(r)}`}}return{available:!0,models:GV(n)}}function GV(t){if(!bp(t))return[];let e=Jl(t.provider)??Jl(t.providers);if(!e)return[];let n=new Set;for(let[r,s]of Object.entries(e)){if(!bp(s))continue;let i=Jl(s.models)??Jl(s.model);if(i)for(let o of Object.keys(i))n.add(o.startsWith(`${r}/`)?o:`${r}/${o}`)}return[...n].sort()}function Jl(t){return bp(t)?t:null}function bp(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function Gl(t){return t.length>0?t.join(", "):"(none)"}function KV(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xV,MA,DA,RV,OV,Tp,MV,vp,Ri,Kl,UA=E(()=>{"use strict";xV={claude:"Claude",codex:"Codex",gemini:"Gemini",qwen:"Qwen"},MA=["deepseek-v4-flash","deepseek-v4-pro","deepseek-v4-flash-vision-exp"],DA="gpt-5.3-codex-spark",RV={claude:["claude-opus-4-6","claude-opus-4-7","claude-opus-4-8","claude-opus-5","claude-sonnet-4-6","claude-sonnet-5","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"],codex:["gpt-5.2","gpt-5.4","gpt-5.5","gpt-5.6-sol","gpt-5.4-mini","gpt-5.3-codex","gpt-5.3-codex-spark","gpt-6-astra"],gemini:["gemini-3.1-pro-preview","gemini-3-flash-preview","gemini-3.1-flash-lite-preview","gemini-2.5-flash","gemini-2.5-flash-lite"],qwen:["qwen3.5-plus","qwen3.6-plus"]},OV=5e3;Tp=null;MV=5e3;vp=new Map;Ri=null});import{homedir as VV}from"node:os";import{basename as YV}from"node:path";function Vl(t,e){let n=new Set;return{text:t.replace(ZV,(s,i)=>{let o=i.trim(),a=zV[o];return a===void 0?(n.add(o),s):a(e)}),unknownNames:[...n].sort()}}function Yl(t){return{workdir:t.workdir,teamfile:t.teamfile,date:QV(t.date)}}function QV(t){return t.toISOString().slice(0,10)}var zV,ZV,Np=E(()=>{"use strict";zV={workdir:t=>t.workdir,teamfile:t=>t.teamfile,teamname:t=>{let e=YV(t.teamfile);return e.endsWith(".lmctl")?e.slice(0,-6):e},home:()=>VV(),date:t=>t.date},ZV=/{{\s*([A-Za-z0-9_-]+)\s*}}/g});var Ci={};oe(Ci,{GEMINI_PROVIDER_NOTICE:()=>HA,_setAgyModelsRunnerForTests:()=>o3,_setLintOpenCodeConfigProbeForTests:()=>c3,_setLintSessiondirFsOpsForTests:()=>l3,_setTeamfileSeedForTests:()=>a3,buildRootTeamRegistrationRow:()=>VA,registerRootTeam:()=>YA,runHire:()=>g3,runLint:()=>h3,runRefresh:()=>y3,runSeed:()=>GA,sha256Text:()=>KA});import{createHash as e3}from"node:crypto";import{accessSync as t3,constants as WA,existsSync as n3,readFileSync as Ql,realpathSync as Rp,statSync as r3,writeFileSync as Zl}from"node:fs";import{dirname as wr,resolve as BA}from"node:path";function o3(t){$p=t??void 0}function a3(t){XA=t??(async e=>{let{seed:n}=await Promise.resolve().then(()=>(mt(),eu)),r=await n(e);return r.success?{sessionId:r.sessionId,warnings:r.warnings}:{error:r.error??"provider seed failed"}})}function l3(t){yr=t===null?Op:{...Op,...t}}function c3(t){JA=t??zc}async function d3(t,e,n){let r=t.filter(i=>i.teamfile===void 0&&i.provider.trim().toLowerCase()==="opencode"&&i.model!==void 0&&i.model.length>0);return(await Promise.all(r.map(async i=>({member:i,result:await JA({cwd:i.sessiondir??e,model:i.model,...i.effort!==void 0?{effort:i.effort}:{},...n!==void 0?{env:n}:{}})})))).flatMap(({member:i,result:o})=>o.status==="rejected"?[`[${i.alias}] ${o.option}="${o.value}" rejected by opencode: ${o.error}`]:[])}function u3(t,e){let n=wr(e),r=new Set,s=[];for(let i of t){if(i.teamfile!==void 0)continue;let o=i.sessiondir??n,a=BA(o);if(r.has(a))continue;let l=f3(a);l!==void 0&&(r.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 f3(t){try{if(yr.existsSync(t)){if(!yr.statSync(t).isDirectory())return"ENOTDIR";yr.accessSync(t,WA.W_OK);return}let e=p3(t);if(e===void 0)return;if(!yr.statSync(e).isDirectory())return"ENOTDIR";yr.accessSync(e,WA.W_OK);return}catch(e){return _3(e)??"permission check failed"}}function m3(t){let e=BA(t);try{return Rp(e)}catch{return e}}function p3(t){let e=t;for(;;){try{if(yr.existsSync(e))return e}catch{return}let n=wr(e);if(n===e)return;e=n}}function _3(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 h3(t,e={stdout:process.stdout,stderr:process.stderr}){if(t[0]==="--help"||t[0]==="-h"||t[0]==="help")return e.stdout.write(s3),0;if(t.length!==1)return e.stderr.write(`usage: lmctl lint <teamfile.lmctl>
3165
+ List native provider sessions in scope, or list recent managed runs with --runs.`,SV=50,LA=500});import{spawnSync as jA}from"node:child_process";import{existsSync as ms,readFileSync as kp}from"node:fs";import{homedir as PA}from"node:os";import{dirname as FA,resolve as Xn}from"node:path";import{fileURLToPath as AV}from"node:url";function LV(){let t=jA("agy",["models"],{encoding:"utf-8",timeout:OV});return{status:t.status,stdout:t.stdout??"",error:t.error}}function CV(t){let e=[];for(let n of t.split(/\r?\n/)){let r=n.trim(),s=r.indexOf(" ");if(s<0)continue;let i=r.slice(s+1).trim();i&&e.push(i)}return e}function $V(t){if(!t&&Tp)return Tp;let e=s=>(t||(Tp=s),s),n;try{n=(t??LV)()}catch(s){return e({available:!1,models:[],reason:`agy models could not be run: ${s instanceof Error?s.message:String(s)}`})}if(n.error)return e({available:!1,models:[],reason:`agy models could not be run: ${n.error.message}`});if(n.status!==0)return e({available:!1,models:[],reason:`agy models exited with status ${n.status??"unknown"}`});let r=CV(n.stdout);return r.length===0?e({available:!1,models:[],reason:"agy models returned no models"}):e({available:!0,models:r})}function DV(t){let e=jA("opencode",["models",t],{encoding:"utf-8",timeout:MV});return{status:e.status,stdout:e.stdout??"",error:e.error}}function jV(t,e){if(!e&&vp.has(t))return vp.get(t);let n=i=>(e||vp.set(t,i),i),r;try{r=(e??DV)(t)}catch(i){return n({available:!1,models:[],reason:`opencode models ${t} could not be run: ${i instanceof Error?i.message:String(i)}`})}if(r.error)return n({available:!1,models:[],reason:`opencode models ${t} could not be run: ${r.error.message}`});if(r.status!==0)return n({available:!1,models:[],reason:`opencode models ${t} exited with status ${r.status??"unknown"}`});let s=r.stdout.split(/\r?\n/).map(i=>i.trim()).filter(i=>i.length>0);return s.length===0?n({available:!1,models:[],reason:`opencode models ${t} returned no models`}):n({available:!0,models:s})}function Ip(t,e={}){let n=[],r=PV(e.modelSelectionDocPath);for(let s of t){let i=s.provider.trim().toLowerCase();if(s.effort&&i!=="opencode"&&i!=="lmplayer"&&i!=="qwen"&&n.push(`[${s.alias}] effort="${s.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),i==="qwen"&&s.effort&&n.push(`[${s.alias}] effort="${s.effort}" is not a qwen CLI flag: Qwen Code does not expose reasoning-effort selection. Use a thinking/effort model id in model= instead.`),i==="copilot"){if(!s.model)continue;n.push(`[${s.alias}] model="${s.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(i==="lmplayer"&&!s.model){n.push(`[${s.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.4).`);continue}if(i==="lmplayer")continue;if(i==="opencode"){if(s.effort&&!s.model&&n.push(`[${s.alias}] effort="${s.effort}" has no effect without model= on an opencode member.`),!s.model){n.push(`[${s.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.4).`);continue}let a=JV(e.opencodeConfigPath);if(!a.available){n.push(`[${s.alias}] model="${s.model}" cannot be verified for opencode: ${a.reason}.`);continue}if(a.models.includes(s.model)||/^github-copilot\/(gpt|gemini|o[0-9])/.test(s.model))continue;if(!s.model.includes("/")){let u=a.models.filter(d=>d.endsWith(`/${s.model}`));n.push(u.length>0?`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${u.join(" / ")}; set model=${u[0]}.`:`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model> (e.g. github-copilot/${s.model}). Declare it in ~/.config/opencode/opencode.json (see https://lmctl.com/examples/opencode.json).`);continue}let l=s.model.slice(0,s.model.indexOf("/")),c=jV(l,e.opencodeModelsRunner);if(c.available&&c.models.includes(s.model))continue;if(c.available&&!c.models.includes(s.model)){n.push(`[${s.alias}] model="${s.model}" was not found in opencode's LOCALLY-VISIBLE live catalog for "${l}" (checked \`opencode models ${l}\`) -- this is unresolved, not a confirmed unavailability: it could mean opencode genuinely doesn't serve this model, OR that your local catalog/auth for "${l}" 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}n.push(`[${s.alias}] model="${s.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(i==="kimi"){if(!s.model)continue;let a=HV(e.kimiConfigPath);a.available?a.models.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not declared in Kimi's [models] config. Valid configured models: ${Gl(a.models)}`):n.push(`[${s.alias}] model="${s.model}" cannot be verified for kimi: ${a.reason}.`);continue}if(i==="agy"){if(!s.model)continue;let a=$V(e.agyModelsRunner);a.available?a.models.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in agy's live model catalog (\`agy models\`). Valid models: ${Gl(a.models)}`):n.push(`[${s.alias}] model="${s.model}" cannot be verified for agy: ${a.reason}.`);continue}if(i==="dsh"){if(!s.model)continue;MA.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in dsh's built-in catalog. Valid models: ${Gl(MA)}. The catalog is patchable via dsh profile overlays \u2014 a model added that way warns here even though it may resolve.`);continue}if(!s.model)continue;i==="codex"&&s.model===DA&&n.push(`[${s.alias}] model="${DA}" 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 o=r.get(i);if(!o){n.push(`[${s.alias}] model="${s.model}" cannot be verified for provider "${i}": `+(Kl??"no tested models found in durable-memory/model_selection.md"));continue}o.includes(s.model)||n.push(`[${s.alias}] model="${s.model}" is not in the tested model list for provider "${i}". Valid tested models: ${Gl(o)}`)}return n}function PV(t){if(!t&&Ri)return Ri;let e=new Map,n,r=t??FV();if(!ms(r))return n=`${r} not found`,t||Sp(e),t||(Ri=e),t||(Kl=n),e;let s;try{s=kp(r,"utf-8")}catch(i){return n=`${r} could not be read: ${i instanceof Error?i.message:String(i)}`,t||Sp(e),t||(Ri=e),t||(Kl=n),e}for(let[i,o]of Object.entries(xV)){let a=qV(s,o),l=BV(a);l.length>0&&e.set(i,l)}return e.size===0&&(n=`${r} has no tested model rows`),!t&&e.size===0&&Sp(e),t||(Ri=e),t||(Kl=n),e}function FV(){return UV(FA(AV(import.meta.url)))}function UV(t){let e=WV(t);if(e){let r=Xn(e,"durable-memory","model_selection.md");if(ms(r))return r}let n=[Xn(t,"..","..","durable-memory","model_selection.md"),Xn(t,"..","..","..","durable-memory","model_selection.md")];for(let r of n)if(ms(r))return r;return n[n.length-1]}function WV(t){let e=Xn(t);for(;;){if(ms(Xn(e,"package.json")))return e;let n=FA(e);if(n===e)return null;e=n}}function Sp(t){for(let[e,n]of Object.entries(RV))t.set(e,n)}function qV(t,e){let r=new RegExp(`^## ${KV(e)}\\s*$`,"m").exec(t);if(!r)return"";let s=r.index+r[0].length,i=t.slice(s),o=/^##\s+/m.exec(i);return o?i.slice(0,o.index):i}function BV(t){let e=new Set;for(let n of t.split(/\r?\n/)){let r=n.trim();if(!r.startsWith("| `"))continue;let s=/^\|\s*`([^`]+)`\s*\|/.exec(r);if(!s)continue;let i=s[1].trim();i&&i!=="Configured `model="&&e.add(i)}return[...e]}function HV(t){let e=process.env.KIMI_CODE_HOME||Xn(PA(),".kimi-code"),n=t??Xn(e,"config.toml");if(!ms(n))return{available:!1,models:[],reason:`${n} not found`};let r;try{r=kp(n,"utf-8")}catch(i){return{available:!1,models:[],reason:`${n} could not be read: ${i instanceof Error?i.message:String(i)}`}}let s=new Set;for(let i of r.split(/\r?\n/)){if(/^\s*\[/.test(i)&&!/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.test(i))return{available:!1,models:[],reason:`${n} has an invalid TOML table header`};let o=/^\s*\[\s*(.+?)\s*\]\s*(?:#.*)?$/.exec(i);if(!o)continue;let a=XV(o[1]);if(o[1].trim().startsWith("models")&&a===null)return{available:!1,models:[],reason:`${n} has an invalid [models] table header`};a?.[0]==="models"&&a.length>=2&&s.add(a[1])}return s.size===0?{available:!1,models:[],reason:`${n} has no [models] entries`}:{available:!0,models:[...s].sort()}}function XV(t){let e=[],n=0;for(;n<t.length;){for(;/\s/.test(t[n]??"");)n++;if(n>=t.length)break;let r="",s=t[n]==='"'||t[n]==="'"?t[n++]:void 0;if(s){for(;n<t.length&&t[n]!==s;)s==='"'&&t[n]==="\\"&&n+1<t.length&&n++,r+=t[n++];if(t[n]!==s)return null;n++}else{for(;n<t.length&&t[n]!==".";)r+=t[n++];r=r.trim()}if(!r)return null;for(e.push(r);/\s/.test(t[n]??"");)n++;if(n>=t.length)break;if(t[n]!==".")return null;n++}return e.length>0?e:null}function JV(t){let e=t??Xn(PA(),".config","opencode","opencode.json");if(!ms(e))return{available:!0,models:[]};let n;try{n=JSON.parse(kp(e,"utf-8"))}catch(r){return{available:!1,models:[],reason:`${e} could not be parsed: ${r instanceof Error?r.message:String(r)}`}}return{available:!0,models:GV(n)}}function GV(t){if(!bp(t))return[];let e=Jl(t.provider)??Jl(t.providers);if(!e)return[];let n=new Set;for(let[r,s]of Object.entries(e)){if(!bp(s))continue;let i=Jl(s.models)??Jl(s.model);if(i)for(let o of Object.keys(i))n.add(o.startsWith(`${r}/`)?o:`${r}/${o}`)}return[...n].sort()}function Jl(t){return bp(t)?t:null}function bp(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function Gl(t){return t.length>0?t.join(", "):"(none)"}function KV(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var xV,MA,DA,RV,OV,Tp,MV,vp,Ri,Kl,UA=E(()=>{"use strict";xV={claude:"Claude",codex:"Codex",gemini:"Gemini",qwen:"Qwen"},MA=["deepseek-v4-flash","deepseek-v4-pro","deepseek-v4-flash-vision-exp"],DA="gpt-5.3-codex-spark",RV={claude:["claude-opus-4-6","claude-opus-4-7","claude-opus-4-8","claude-opus-5","claude-sonnet-4-6","claude-sonnet-5","claude-haiku-4-5","claude-fable-5","claude-fable-5-1"],codex:["gpt-5.2","gpt-5.4","gpt-5.5","gpt-5.6-sol","gpt-5.4-mini","gpt-5.3-codex","gpt-5.3-codex-spark","gpt-6-astra"],gemini:["gemini-3.1-pro-preview","gemini-3-flash-preview","gemini-3.1-flash-lite-preview","gemini-2.5-flash","gemini-2.5-flash-lite"],qwen:["qwen3.5-plus","qwen3.6-plus"]},OV=5e3;Tp=null;MV=5e3;vp=new Map;Ri=null});import{homedir as VV}from"node:os";import{basename as YV}from"node:path";function Vl(t,e){let n=new Set;return{text:t.replace(ZV,(s,i)=>{let o=i.trim(),a=zV[o];return a===void 0?(n.add(o),s):a(e)}),unknownNames:[...n].sort()}}function Yl(t){return{workdir:t.workdir,teamfile:t.teamfile,date:QV(t.date)}}function QV(t){return t.toISOString().slice(0,10)}var zV,ZV,Np=E(()=>{"use strict";zV={workdir:t=>t.workdir,teamfile:t=>t.teamfile,teamname:t=>{let e=YV(t.teamfile);return e.endsWith(".lmctl")?e.slice(0,-6):e},home:()=>VV(),date:t=>t.date},ZV=/{{\s*([A-Za-z0-9_-]+)\s*}}/g});var Ci={};oe(Ci,{GEMINI_PROVIDER_NOTICE:()=>HA,_setAgyModelsRunnerForTests:()=>o3,_setLintOpenCodeConfigProbeForTests:()=>c3,_setLintSessiondirFsOpsForTests:()=>l3,_setTeamfileSeedForTests:()=>a3,buildRootTeamRegistrationRow:()=>VA,registerRootTeam:()=>YA,runHire:()=>g3,runLint:()=>h3,runRefresh:()=>y3,runSeed:()=>GA,sha256Text:()=>KA});import{createHash as e3}from"node:crypto";import{accessSync as t3,constants as WA,existsSync as n3,readFileSync as Ql,realpathSync as Rp,statSync as r3,writeFileSync as Zl}from"node:fs";import{dirname as wr,resolve as BA}from"node:path";function o3(t){$p=t??void 0}function a3(t){XA=t??(async e=>{let{seed:n}=await Promise.resolve().then(()=>(mt(),eu)),r=await n(e);return r.success?{sessionId:r.sessionId,warnings:r.warnings}:{error:r.error??"provider seed failed"}})}function l3(t){yr=t===null?Op:{...Op,...t}}function c3(t){JA=t??zc}async function d3(t,e,n){let r=t.filter(i=>i.teamfile===void 0&&i.provider.trim().toLowerCase()==="opencode"&&i.model!==void 0&&i.model.length>0);return(await Promise.all(r.map(async i=>({member:i,result:await JA({cwd:i.sessiondir??e,model:i.model,...i.effort!==void 0?{effort:i.effort}:{},...n!==void 0?{env:n}:{}})})))).flatMap(({member:i,result:o})=>o.status==="rejected"?[`[${i.alias}] ${o.option}="${o.value}" rejected by opencode: ${o.error}`]:[])}function u3(t,e){let n=wr(e),r=new Set,s=[];for(let i of t){if(i.teamfile!==void 0)continue;let o=i.sessiondir??n,a=BA(o);if(r.has(a))continue;let l=f3(a);l!==void 0&&(r.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 f3(t){try{if(yr.existsSync(t)){if(!yr.statSync(t).isDirectory())return"ENOTDIR";yr.accessSync(t,WA.W_OK);return}let e=p3(t);if(e===void 0)return;if(!yr.statSync(e).isDirectory())return"ENOTDIR";yr.accessSync(e,WA.W_OK);return}catch(e){return _3(e)??"permission check failed"}}function m3(t){let e=BA(t);try{return Rp(e)}catch{return e}}function p3(t){let e=t;for(;;){try{if(yr.existsSync(e))return e}catch{return}let n=wr(e);if(n===e)return;e=n}}function _3(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 h3(t,e={stdout:process.stdout,stderr:process.stderr}){if(t[0]==="--help"||t[0]==="-h"||t[0]==="help")return e.stdout.write(s3),0;if(t.length!==1)return e.stderr.write(`usage: lmctl lint <teamfile.lmctl>
3166
3166
  `),2;let n=t[0],r;try{r=await O(e,c=>ve(n,c))}catch(c){return Ue(e,`${n}: ${c instanceof Error?c.message:String(c)}`)}let s;try{s=Fe(r)}catch(c){return Ue(e,`${n}: ${c instanceof Error?c.message:String(c)}`)}let i=Uf(s,wr(r)),o=Ip(s.members,{agyModelsRunner:$p}),a=Ql(r,"utf8"),l=Vl(a,Yl({workdir:wr(r),teamfile:r,date:new Date})).unknownNames;l.length>0&&o.push(`unknown template placeholder${l.length===1?"":"s"}: ${l.map(c=>`{{${c}}}`).join(", ")}`),o.push(...Gc(s.members,wr(r))),o.push(...u3(s.members,r)),o.push(...await d3(s.members,wr(r),e.env));for(let c of i)e.stderr.write(`error: ${c.field}: ${c.message}
3167
3167
  `);for(let c of s.members)Cp([c],e),c.session!==void 0&&c.session.length<Oi&&o.push(`${c.alias}: sessionid is shorter than ${Oi} chars; run lmctl seed to refresh it`);for(let c of o)e.stderr.write(`warning: ${c}
3168
3168
  `);return i.length>0?1:(e.stdout.write(`ok
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmctl-ai/lmctl",
3
- "version": "0.1.309",
3
+ "version": "0.1.310",
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",