@lmctl-ai/lmctl 0.1.131 → 0.1.132

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
@@ -2400,7 +2400,7 @@ Examples:
2400
2400
 
2401
2401
  # Same shape, codex for the Lead and Reviewer2
2402
2402
  lmctl plan ./backend --provider codex
2403
- `});import{execFileSync as hB}from"node:child_process";import{resolve as XS}from"node:path";function gB(t){return t.filter(e=>e.state!=="retired")}function GS(t,e,r){if(r!==void 0){let a=e.findProjectByName(r);return a===null?v(t,`project not found: ${r}`):a}let n=t.cwd??process.cwd(),s;try{s=hB("git",["rev-parse","--show-toplevel"],{cwd:n,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return v(t,"not in a git repo; use --project <name>")}let i=XS(s),o=e.listProjects().find(a=>XS(a.local_path)===i);return o===void 0?v(t,"no lmctl project for this directory; use --project <name>"):o}function VS(t,e,r,n){if(n!==void 0){let i=e.findTeamByName(n);return i===null?v(t,`team not found: ${n}`):i}let s=e.getTeam(r.team_id);return s===null?v(t,`project ${r.name} has no assigned team; use --team <name>`):s}function KS(t,e,r,n){if(n!==void 0){let i=e.findTeamMemberByAlias(r.id,n);return i===null||i.state==="retired"?v(t,`member not found: ${n}`):i}let s=gB(e.listTeamMembers(r.id)).find(i=>i.role==="agent");return s===void 0?v(t,`team ${r.name} has no active agent member`):s}var YS=T(()=>{"use strict";Re()});var QS={};ye(QS,{SIZE_WARN_EST_TOKENS:()=>Ws,estimateTokens:()=>ZS,runTerminal:()=>TB});import{spawn as yB}from"node:child_process";import{statSync as wB}from"node:fs";async function TB(t,e){if(t.includes("--help")||t.includes("-h"))return NB(e);let r=Z(t,["--project","--team","--alias","--run"],["--size","--json","--help"]);if(r.error!==void 0)return v(e,r.error);let n=F(r,"--run");if(n!==void 0){let s=Number.parseInt(n,10);if(!Number.isFinite(s)||s<=0||String(s)!==n)return v(e,`invalid --run "${n}" (expected a positive integer run id)`);if(r.positionals.length>0)return v(e,"--run is mutually exclusive with positional <teamfile>[:alias]");let i=["--team","--project","--size","--json"];for(let o of i)if(o==="--size"||o==="--json"?G(r,o):F(r,o)!==void 0)return v(e,`--run is mutually exclusive with ${o}`);try{return await C(e,async o=>{let a=F(r,"--alias"),l=cw(o,s,a);return"err"in l?v(e,l.err):gf(e,{provider:l.ok.provider,sessionid:l.ok.sessionid,sessiondir:l.ok.sessiondir})})}catch(o){return Me(e,o)}}if(r.positionals.length>0){let s=["--team","--project","--size","--alias","--json"];for(let l of s)if(l==="--size"||l==="--json"?G(r,l):F(r,l)!==void 0)return v(e,`positional <teamfile>[:alias] is mutually exclusive with ${l} (alias is the SECOND POSITIONAL: \`terminal <teamfile> <alias>\`).`);if(r.positionals.length>2)return v(e,`too many positionals (${r.positionals.length}); expected <teamfile>[:alias] [alias]`);let i=r.positionals[0],o=r.positionals[1],a=gr(EB,{target:i,alias:o,flags:{}});return a.mode==="error"?v(e,a.message):a.mode!=="ai-team"?v(e,`internal: terminal positional yielded unexpected mode "${a.mode}"`):a.alias===void 0?v(e,"terminal: alias required for the teamfile target"):await C(e,l=>bB(e,a.teamfile,a.alias,l))}try{return await C(e,async s=>{let i=kB(e,s,r);if(typeof i=="number")return i;let o=F(r,"--alias");return G(r,"--size")?xB(e,s,i,o,G(r,"--json")):IB(e,s,i,o)})}catch(s){return Me(e,s)}}async function bB(t,e,r,n){let s;try{s=qe(e,r,n)}catch(d){return d instanceof ge?v(t,d.message):Me(t,d)}let i=_r(n,{receiver_teamfile:s.teamfile,receiver_alias:s.alias,sender_teamfile:s.teamfile,sender_alias:"terminal",ttlMs:hr()});if(!i.acquired)return v(t,`${s.alias} is busy/held by ${i.current.sender_alias} (${i.current.sender_teamfile}) since ${i.current.started_at}`);let o=eb({teamfile:s.teamfile,alias:s.alias}),a=null,l=null,c=null;try{n.setTerminalLock(o),l=SB(n,s),a=setInterval(()=>{try{!n.heartbeatTerminalLock(o.teamfile,o.alias,o.lock_id,new Date().toISOString())&&a!==null&&(clearInterval(a),a=null)}catch{}},tb()),a.unref?.();try{Sn(t,je(s.teamfile),s.teamfile)}catch{}return c=await gf(t,{provider:s.provider,sessionid:s.sessionid,sessiondir:s.sessiondir,isLead:s.isLead}),c}finally{a!==null&&clearInterval(a),n.clearTerminalLock(o.teamfile,o.alias,o.lock_id),n.releaseAgentInflight(i.lease),vB(n,l,c)}}function SB(t,e){try{return t.startTrackedInvocation({kind:"exec",origin:"operator",scope_teamfile:e.teamfile,from_identity:`${e.teamfile}:terminal`,target_teamfile:e.teamfile,target_alias:e.alias,root_teamfile:e.teamfile,cwd:e.sessiondir,command:`lmctl terminal ${e.teamfile} ${e.alias}`,holder_pid:process.pid,launch_source:"terminal",meta:JSON.stringify({provider:e.provider,sessionid:e.sessionid})}).id}catch{return null}}function vB(t,e,r){if(e!==null)try{t.finishTrackedInvocation(e,{status:r===0?"done":"error",exit_code:r,result_summary:r===0?"terminal session ended":null,error:r===0?null:`terminal exited with code ${r??"unknown"}`})}catch{}}async function gf(t,e){let{provider:r,sessionid:n,sessiondir:s}=e;if(!Ia(r))return v(t,`no resume incantation for provider "${r}"`);if(!yb.test(n))return v(t,"refusing to resume: malformed sessionid");let i=Uu(r,n,{isLead:e.isLead});if(i===null||i.length===0)return v(t,`no resume incantation for provider "${r}"`);let[o,...a]=i;return await new Promise(l=>{let c=yB(o,a,{stdio:"inherit",cwd:s,env:We(process.env,s,n,"terminal")});c.on("error",d=>{l(v(t,`failed to launch ${o}: ${d.message}`))}),c.on("exit",d=>l(d??0))})}function kB(t,e,r){let n=F(r,"--team");if(n!==void 0){let o=e.findTeamByName(n);return o===null?v(t,`team not found: ${n}`):o}let s=GS(t,e,F(r,"--project"));return typeof s=="number"?s:VS(t,e,s,void 0)}async function IB(t,e,r,n){let s=KS(t,e,r,n);if(typeof s=="number")return s;let i=s.sessionid;return i===null||i.trim().length===0?v(t,`member ${s.alias} has no session yet \u2014 run \`lmctl team seed ${r.name}\` first`):gf(t,{provider:Fe(s),sessionid:i,sessiondir:s.sessiondir})}function ZS(t){if(t&&Array.isArray(t.messages)&&t.messages.length>0){let r=t.messages.reduce((n,s)=>n+(s.content?.length??0),0);return{chars:r,est:Math.ceil(r/4),messages:t.messages.length,bytes:null}}let e=t?.filePath;if(e!==void 0)try{let r=wB(e).size;return{chars:r,est:Math.ceil(r/4),messages:t?.messages?.length??null,bytes:r}}catch{}return{chars:0,est:0,messages:null,bytes:null}}async function xB(t,e,r,n,s){let i;if(n!==void 0){let a=e.findTeamMemberByAlias(r.id,n);if(a===null||a.state==="retired")return v(t,`member not found: ${n}`);i=[a]}else i=e.listTeamMembers(r.id).filter(a=>a.state!=="retired"&&a.sessionid!==null);let o=[];for(let a of i){let l=a.sessionid;if(l===null)continue;let c=Fe(a),d=null;Ia(c)&&(d=await Qt(l,c));let u=ZS(d),f=u.est>Ws;o.push({alias:a.alias,provider:c,sessionid:l,messages:u.messages,bytes:u.bytes,est_tokens:u.est,estimate:!0,over_guide:f,resume_incantation:f?xa(c,l):null})}if(s)return ae(t,{estimate:!0,legend:zS,guide_tokens:Ws,members:o}),0;t.stdout.write(`session size \u2014 ESTIMATE only (nothing is changed automatically)
2403
+ `});import{execFileSync as hB}from"node:child_process";import{resolve as XS}from"node:path";function gB(t){return t.filter(e=>e.state!=="retired")}function GS(t,e,r){if(r!==void 0){let a=e.findProjectByName(r);return a===null?v(t,`project not found: ${r}`):a}let n=t.cwd??process.cwd(),s;try{s=hB("git",["rev-parse","--show-toplevel"],{cwd:n,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{return v(t,"terminal cannot infer a member from cwd because this directory is not in a git repo; use `lmctl terminal <teamfile> <alias>`")}let i=XS(s),o=e.listProjects().find(a=>XS(a.local_path)===i);return o===void 0?v(t,`terminal cannot infer a member from cwd ${i}; use \`lmctl terminal <teamfile> <alias>\``):o}function VS(t,e,r,n){if(n!==void 0){let i=e.findTeamByName(n);return i===null?v(t,`team not found: ${n}`):i}let s=e.getTeam(r.team_id);return s===null?v(t,`project ${r.name} has no assigned team; use --team <name>`):s}function KS(t,e,r,n){if(n!==void 0){let i=e.findTeamMemberByAlias(r.id,n);return i===null||i.state==="retired"?v(t,`member not found: ${n}`):i}let s=gB(e.listTeamMembers(r.id)).find(i=>i.role==="agent");return s===void 0?v(t,`team ${r.name} has no active agent member`):s}var YS=T(()=>{"use strict";Re()});var QS={};ye(QS,{SIZE_WARN_EST_TOKENS:()=>Ws,estimateTokens:()=>ZS,runTerminal:()=>TB});import{spawn as yB}from"node:child_process";import{statSync as wB}from"node:fs";async function TB(t,e){if(t.includes("--help")||t.includes("-h"))return NB(e);let r=Z(t,["--project","--team","--alias","--run"],["--size","--json","--help"]);if(r.error!==void 0)return v(e,r.error);let n=F(r,"--run");if(n!==void 0){let s=Number.parseInt(n,10);if(!Number.isFinite(s)||s<=0||String(s)!==n)return v(e,`invalid --run "${n}" (expected a positive integer run id)`);if(r.positionals.length>0)return v(e,"--run is mutually exclusive with positional <teamfile>[:alias]");let i=["--team","--project","--size","--json"];for(let o of i)if(o==="--size"||o==="--json"?G(r,o):F(r,o)!==void 0)return v(e,`--run is mutually exclusive with ${o}`);try{return await C(e,async o=>{let a=F(r,"--alias"),l=cw(o,s,a);return"err"in l?v(e,l.err):gf(e,{provider:l.ok.provider,sessionid:l.ok.sessionid,sessiondir:l.ok.sessiondir})})}catch(o){return Me(e,o)}}if(r.positionals.length>0){let s=["--team","--project","--size","--alias","--json"];for(let l of s)if(l==="--size"||l==="--json"?G(r,l):F(r,l)!==void 0)return v(e,`positional <teamfile>[:alias] is mutually exclusive with ${l} (alias is the SECOND POSITIONAL: \`terminal <teamfile> <alias>\`).`);if(r.positionals.length>2)return v(e,`too many positionals (${r.positionals.length}); expected <teamfile>[:alias] [alias]`);let i=r.positionals[0],o=r.positionals[1],a=gr(EB,{target:i,alias:o,flags:{}});return a.mode==="error"?v(e,a.message):a.mode!=="ai-team"?v(e,`internal: terminal positional yielded unexpected mode "${a.mode}"`):a.alias===void 0?v(e,"terminal: alias required for the teamfile target"):await C(e,l=>bB(e,a.teamfile,a.alias,l))}try{return await C(e,async s=>{let i=kB(e,s,r);if(typeof i=="number")return i;let o=F(r,"--alias");return G(r,"--size")?xB(e,s,i,o,G(r,"--json")):IB(e,s,i,o)})}catch(s){return Me(e,s)}}async function bB(t,e,r,n){let s;try{s=qe(e,r,n)}catch(d){return d instanceof ge?v(t,d.message):Me(t,d)}let i=_r(n,{receiver_teamfile:s.teamfile,receiver_alias:s.alias,sender_teamfile:s.teamfile,sender_alias:"terminal",ttlMs:hr()});if(!i.acquired)return v(t,`${s.alias} is busy/held by ${i.current.sender_alias} (${i.current.sender_teamfile}) since ${i.current.started_at}`);let o=eb({teamfile:s.teamfile,alias:s.alias}),a=null,l=null,c=null;try{n.setTerminalLock(o),l=SB(n,s),a=setInterval(()=>{try{!n.heartbeatTerminalLock(o.teamfile,o.alias,o.lock_id,new Date().toISOString())&&a!==null&&(clearInterval(a),a=null)}catch{}},tb()),a.unref?.();try{Sn(t,je(s.teamfile),s.teamfile)}catch{}return c=await gf(t,{provider:s.provider,sessionid:s.sessionid,sessiondir:s.sessiondir,isLead:s.isLead}),c}finally{a!==null&&clearInterval(a),n.clearTerminalLock(o.teamfile,o.alias,o.lock_id),n.releaseAgentInflight(i.lease),vB(n,l,c)}}function SB(t,e){try{return t.startTrackedInvocation({kind:"exec",origin:"operator",scope_teamfile:e.teamfile,from_identity:`${e.teamfile}:terminal`,target_teamfile:e.teamfile,target_alias:e.alias,root_teamfile:e.teamfile,cwd:e.sessiondir,command:`lmctl terminal ${e.teamfile} ${e.alias}`,holder_pid:process.pid,launch_source:"terminal",meta:JSON.stringify({provider:e.provider,sessionid:e.sessionid})}).id}catch{return null}}function vB(t,e,r){if(e!==null)try{t.finishTrackedInvocation(e,{status:r===0?"done":"error",exit_code:r,result_summary:r===0?"terminal session ended":null,error:r===0?null:`terminal exited with code ${r??"unknown"}`})}catch{}}async function gf(t,e){let{provider:r,sessionid:n,sessiondir:s}=e;if(!Ia(r))return v(t,`no resume incantation for provider "${r}"`);if(!yb.test(n))return v(t,"refusing to resume: malformed sessionid");let i=Uu(r,n,{isLead:e.isLead});if(i===null||i.length===0)return v(t,`no resume incantation for provider "${r}"`);let[o,...a]=i;return await new Promise(l=>{let c=yB(o,a,{stdio:"inherit",cwd:s,env:We(process.env,s,n,"terminal")});c.on("error",d=>{l(v(t,`failed to launch ${o}: ${d.message}`))}),c.on("exit",d=>l(d??0))})}function kB(t,e,r){let n=F(r,"--team");if(n!==void 0){let o=e.findTeamByName(n);return o===null?v(t,`team not found: ${n}`):o}let s=GS(t,e,F(r,"--project"));return typeof s=="number"?s:VS(t,e,s,void 0)}async function IB(t,e,r,n){let s=KS(t,e,r,n);if(typeof s=="number")return s;let i=s.sessionid;return i===null||i.trim().length===0?v(t,`member ${s.alias} has no session yet \u2014 run \`lmctl team seed ${r.name}\` first`):gf(t,{provider:Fe(s),sessionid:i,sessiondir:s.sessiondir})}function ZS(t){if(t&&Array.isArray(t.messages)&&t.messages.length>0){let r=t.messages.reduce((n,s)=>n+(s.content?.length??0),0);return{chars:r,est:Math.ceil(r/4),messages:t.messages.length,bytes:null}}let e=t?.filePath;if(e!==void 0)try{let r=wB(e).size;return{chars:r,est:Math.ceil(r/4),messages:t?.messages?.length??null,bytes:r}}catch{}return{chars:0,est:0,messages:null,bytes:null}}async function xB(t,e,r,n,s){let i;if(n!==void 0){let a=e.findTeamMemberByAlias(r.id,n);if(a===null||a.state==="retired")return v(t,`member not found: ${n}`);i=[a]}else i=e.listTeamMembers(r.id).filter(a=>a.state!=="retired"&&a.sessionid!==null);let o=[];for(let a of i){let l=a.sessionid;if(l===null)continue;let c=Fe(a),d=null;Ia(c)&&(d=await Qt(l,c));let u=ZS(d),f=u.est>Ws;o.push({alias:a.alias,provider:c,sessionid:l,messages:u.messages,bytes:u.bytes,est_tokens:u.est,estimate:!0,over_guide:f,resume_incantation:f?xa(c,l):null})}if(s)return ae(t,{estimate:!0,legend:zS,guide_tokens:Ws,members:o}),0;t.stdout.write(`session size \u2014 ESTIMATE only (nothing is changed automatically)
2404
2404
  `),t.stdout.write(`${zS}
2405
2405
  `);for(let a of o){let l=a.messages===null?"?":String(a.messages),c=a.bytes===null?"?":String(a.bytes);t.stdout.write(`${a.alias} ${a.provider} msgs=${l} bytes=${c} ~${a.est_tokens} tok (rough estimate)
2406
2406
  `),a.over_guide&&t.stdout.write(` \u26A0 ${a.alias}: estimated ~${a.est_tokens} tokens \u2014 ESTIMATE only, exceeds the 200K guide.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmctl-ai/lmctl",
3
- "version": "0.1.131",
3
+ "version": "0.1.132",
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",