@lmctl-ai/lmctl 0.1.60 → 0.1.61

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
@@ -2094,8 +2094,8 @@ List native provider sessions in scope, or list recent managed runs with --runs.
2094
2094
  `),0}async function oW(t,e={stdout:process.stdout,stderr:process.stderr}){if(t[0]==="--help"||t[0]==="-h"||t[0]==="help")return e.stdout.write(tf),0;let r,n;if(t.length===1){let d=Os(t[0]);if(d===null)return e.stderr.write(tf),2;r=d.teamfile,n=d.alias}else if(t.length===2)[r,n]=t;else return e.stderr.write(tf),2;let s;try{s=await L(e,d=>Ae(r,d))}catch(d){return Re(e,`${r}: ${d instanceof Error?d.message:String(d)}`)}let o;try{o=Ba(s,"utf8")}catch(d){return Re(e,`${r}: ${d instanceof Error?d.message:String(d)}`)}let i=o.split(`
2095
2095
  `),a=cW(i,n);if(a===void 0)return Re(e,`${n}: no active _MEMBER_ entry found`);let l=i[a];if(Bs(l,"teamfile")!==void 0)return Re(e,`${n}: refresh only applies to provider-backed members, not teamfile= members`);let c=(e.env??process.env)[qn],u=Bs(l,"sessionid");return c!==void 0&&c.length>0&&u===c?Re(e,`${n}: cannot refresh its own running session \u2014 a meta-Lead or the operator must run this refresh.`):(i[a]=HT(l,"sessionid"),a>0&&/^\s*#CreationTime:/u.test(i[a-1])&&i.splice(a-1,1),Ws(s,i.join(`
2096
2096
  `),"utf8"),UT([s],e))}function WT(t){return MU("sha256").update(t).digest("hex")}function BT(t,e){return{teamfile_path:e.teamfilePath,name:e.name,raw_text:e.rawText,raw_sha256:WT(e.rawText),registered_at:t?.registered_at??e.now,last_seeded_at:e.now}}function qT(t,e){let r=BT(t.getRootTeam(e.teamfilePath),e);return t.upsertRootTeam(r),r}function iW(t,e,r){let n=r.filter(a=>a.alias.toLowerCase()!=="lead").map(a=>{let l=a.teamfile!==void 0?`teamfile=${a.teamfile}`:`provider=${a.provider}`;return`- ${a.alias}: ${l}`}),s=n.length>0?n.join(`
2097
- `):"- (no non-Lead members)",o=r.find(a=>a.alias.toLowerCase()==="lead")?.provider??"",i=aW(o);return["lmctl seed initial connection only. Create or pin this provider session, then stop.","Do not inspect files, run commands, infer a task, delegate, edit, or begin work.","",`Teamfile path: ${t}`,"You are alias Lead for this AI-managed .lmctl team.","","Preferred delegation for non-instant work: tracked background submit.",`- Submit: lmctl chat "${t}" <alias> "your task here" --detach`,"- It returns a job id immediately, does not lock your session, and records progress.","- Check work with: lmctl jobs list or lmctl jobs watch <job_id>.","- MCP lmctl_chat is synchronous/blocking; use it only as a quick-ping or backup path.",'- Plain shell "&" is blind backgrounding; it gives no lmctl job id or completion signal.',i,"","Delegation is an ACTION, not a plan: to hand a member a task, submit the job or call the tool.","If you use lmctl_chat and it appears only after tool search, call it in the SAME turn and do not stop after discovering it or say you're about to call it.","","Team members:",s,"","Example MCP calls:",...r.filter(a=>a.alias.toLowerCase()!=="lead").map(a=>`lmctl_chat(team="${t}", alias="${a.alias}", prompt="your task here")`),"","If a member feels sluggish or starts drifting (degraded or off-track output):",` 1. Check ONE member's session health: lmctl health "${t}" <alias> (size/state \u2014 informational).`," 2. Make sure important state is captured in durable-memory/ \u2014 update it if not.",` 3. Replace its session: lmctl refresh "${t}" <alias> (re-seeds the member: drops chat history, re-reads durable-memory/). You cannot refresh your own Lead session \u2014 a meta-Lead or the operator does that.`,` Optional: lmctl tail "${t}" <alias> to inspect its recent messages while troubleshooting.`,"(These health/recovery commands are shell commands. For delegation, prefer --detach; lmctl_chat is the synchronous backup.)","","Full teamfile document at seed time:","```lmctl",e.trimEnd(),"```","","Remember this teamfile path. Do not ask the operator for it when asked to ping or delegate to members.","Reply exactly: ACK: teamfile context recorded."].join(`
2098
- `)}function aW(t){switch(t.toLowerCase()){case"claude":return"- Claude tip: run the submit as background Bash (run_in_background: true); the runtime notifies you when it completes.";case"copilot":return'- Copilot tip: run the submit via the bash tool async mode (mode:"async"); the runtime notifies you when it completes.';case"agy":return"- Antigravity tip: run the submit via run_command with WaitMsBeforeAsync (Background Tasks); the runtime notifies you when it completes.";case"qwen":return"- Qwen tip: run the submit via the monitor tool; it streams events and notifies you when it completes.";case"codex":return"- Codex note: no native completion push; submit with --detach, keep working, and pull status with lmctl jobs or lmctl jobs watch <job_id>.";case"gemini":return"- Gemini note: no native completion push; submit with --detach, keep working, and pull status with lmctl jobs or lmctl jobs watch <job_id>.";case"opencode":return"- OpenCode note: shell commands do not have a stable native completion push; submit with --detach and pull status with lmctl jobs or lmctl jobs watch <job_id>.";default:return"- If your provider has native background-shell completion, use it around the submit; otherwise use lmctl jobs to pull status."}}function lW(t){let e=new Map;for(let r=0;r<t.length;r+=1){let n=t[r];if(!/^\s*_MEMBER_\s+\S/.test(n))continue;let s=Bs(n,"alias");s!==void 0&&e.set(s.toLowerCase(),r)}return e}function cW(t,e){let r=e.toLowerCase();for(let n=0;n<t.length;n+=1){let s=t[n];if(/^\s*_MEMBER_\s+\S/u.test(s)&&Bs(s,"alias")?.toLowerCase()===r)return n}}function uW(t,e){for(let r of t.split(`
2097
+ `):"- (no non-Lead members)",o=r.find(a=>a.alias.toLowerCase()==="lead")?.provider??"",i=aW(o,t);return["lmctl seed initial connection only. Create or pin this provider session, then stop.","Do not inspect files, run commands, infer a task, delegate, edit, or begin work.","",`Teamfile path: ${t}`,"You are alias Lead for this AI-managed .lmctl team.","","Delegating in the background (non-blocking + completion signal):",`- Blocking command shape: lmctl chat "${t}" <alias> "your task here"`,`- Tracked submit shape: lmctl chat "${t}" <alias> "your task here" --detach`,"- MCP lmctl_chat is synchronous/blocking; use it only as a quick-ping or backup path.",'- Plain shell "&" is blind backgrounding; it gives no lmctl job id or completion signal.',"- lmctl jobs is the universal tracked portal for every provider: list jobs with lmctl jobs list, or watch one with lmctl jobs watch <job_id>.",i,"","Delegation is an ACTION, not a plan: to hand a member a task, submit the job or call the tool.","If you use lmctl_chat and it appears only after tool search, call it in the SAME turn and do not stop after discovering it or say you're about to call it.","","Team members:",s,"","Example MCP calls:",...r.filter(a=>a.alias.toLowerCase()!=="lead").map(a=>`lmctl_chat(team="${t}", alias="${a.alias}", prompt="your task here")`),"","If a member feels sluggish or starts drifting (degraded or off-track output):",` 1. Check ONE member's session health: lmctl health "${t}" <alias> (size/state \u2014 informational).`," 2. Make sure important state is captured in durable-memory/ \u2014 update it if not.",` 3. Replace its session: lmctl refresh "${t}" <alias> (re-seeds the member: drops chat history, re-reads durable-memory/). You cannot refresh your own Lead session \u2014 a meta-Lead or the operator does that.`,` Optional: lmctl tail "${t}" <alias> to inspect its recent messages while troubleshooting.`,"(These health/recovery commands are shell commands. For delegation, prefer native background lmctl chat when available, or --detach; lmctl_chat is the synchronous backup.)","","Full teamfile document at seed time:","```lmctl",e.trimEnd(),"```","","Remember this teamfile path. Do not ask the operator for it when asked to ping or delegate to members.","Reply exactly: ACK: teamfile context recorded."].join(`
2098
+ `)}function aW(t,e){let r=`lmctl chat "${e}" <alias> "your task here"`;switch(t.toLowerCase()){case"claude":return`- Claude tip: run the blocking command (${r}) as background Bash (run_in_background: true); the runtime re-invokes you with the reply when it completes.`;case"copilot":return`- Copilot tip: run the blocking command (${r}) via bash async mode (mode:"async"); the runtime notifies you with output when it completes.`;case"agy":return`- Antigravity tip: run the blocking command (${r}) via run_command with WaitMsBeforeAsync: 0 (Background Tasks); agy wakes you with the output when it completes.`;case"qwen":return`- Qwen tip: run the blocking command (${r}) via the monitor tool; it notifies you on completion.`;case"codex":return"- Codex note: no native completion push; submit with --detach, keep working, and pull status with lmctl jobs or lmctl jobs watch <job_id>.";case"gemini":return"- Gemini note: no native completion push; submit with --detach, keep working, and pull status with lmctl jobs or lmctl jobs watch <job_id>.";case"opencode":return"- OpenCode note: shell commands do not have a stable native completion push; submit with --detach and pull status with lmctl jobs or lmctl jobs watch <job_id>.";default:return"- If your provider has native background-shell completion, use it around the submit; otherwise use lmctl jobs to pull status."}}function lW(t){let e=new Map;for(let r=0;r<t.length;r+=1){let n=t[r];if(!/^\s*_MEMBER_\s+\S/.test(n))continue;let s=Bs(n,"alias");s!==void 0&&e.set(s.toLowerCase(),r)}return e}function cW(t,e){let r=e.toLowerCase();for(let n=0;n<t.length;n+=1){let s=t[n];if(/^\s*_MEMBER_\s+\S/u.test(s)&&Bs(s,"alias")?.toLowerCase()===r)return n}}function uW(t,e){for(let r of t.split(`
2099
2099
  `))if(/^\s*#?\s*_MEMBER_\s+\S/u.test(r)&&Bs(r,"alias")===e)return!0;return!1}function dW(t){return/^[A-Za-z][A-Za-z0-9_-]*$/u.test(t)}function Bs(t,e){let n=new RegExp(`(?:^|\\s)${e}=(?:"([^"]*)"|(\\S*))`).exec(t);return n===null?void 0:n[1]??n[2]??""}function fW(t,e,r){let n=`${e}=${af(r)}`,s=new RegExp(`(^|\\s)${e}=(?:"[^"]*"|\\S*)`);return s.test(t)?t.replace(s,(o,i)=>`${i}${n}`):`${t.trimEnd()} ${n}`}function HT(t,e){let r=new RegExp(`(^|\\s)${e}=(?:"[^"]*"|\\S*)`);return t.replace(r,"").replace(/\s+/gu," ").trimEnd()}function af(t){return/[\s"]/u.test(t)?`"${t.replace(/"/g,'\\"')}"`:t}function mW(t,e){let r=t.split(`
2100
2100
  `),n=-1;for(let a=r.length-1;a>=0;a-=1)if(/^\s*(?:_MEMBER_|_CONNECT_|_SKILL_)(?:\s|$)/u.test(r[a])){n=a;break}if(n>=0)return r.splice(n+1,0,e),r.join(`
2101
2101
  `);let s=r.length;for(;s>0&&r[s-1]==="";)s-=1;let o=r.slice(0,s).join(`
@@ -2172,10 +2172,10 @@ Examples:
2172
2172
  # How to delegate to a member (two equivalent ways - the CLI never needs a tool search):
2173
2173
  # MCP tool: lmctl_chat(team="${r}", alias="Coder", prompt="your task")
2174
2174
  # CLI shell: lmctl chat "${r}" Coder "your task"
2175
- # Preferred for non-instant work (non-blocking + tracked):
2175
+ # Durable tracked background work (especially when your provider has no native async shell):
2176
2176
  # lmctl chat "${r}" Coder "your task" --detach
2177
2177
  # lmctl jobs watch <job_id>
2178
- # Use lmctl jobs to list/check background delegations; use lmctl_chat only as a synchronous backup.
2178
+ # lmctl jobs is the universal portal for tracked delegations; use lmctl_chat only as a synchronous backup.
2179
2179
  # Warmup/connectivity check first: lmctl chat "${r}" Coder "reply OK"
2180
2180
  # If the lmctl_chat tool isn't immediately available in your session, just use the CLI form.
2181
2181
  # delegate implementation to Coder, and send completed work to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmctl-ai/lmctl",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
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",