@lmctl-ai/lmctl 0.1.155 → 0.1.156

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/README.md CHANGED
@@ -59,6 +59,9 @@ the provider or host runtime's own background/task surface when you need async
59
59
  execution.
60
60
  Daemon, web, and API surfaces are secondary integration paths; the CLI is the
61
61
  golden path for onboarding.
62
+ To inspect the daemon, run `lmctl api daemon state` while `lmctl serve` is
63
+ running; authenticate with `LMCTL_API_TOKEN=<token>` or start local serve with
64
+ `--insecure-no-auth`.
62
65
  Lintable teamfile templates for research, writing, and review teams ship in the
63
66
  [examples gallery](https://lmctl.com/examples/).
64
67
 
package/dist/cli/index.js CHANGED
@@ -1589,7 +1589,8 @@ ${r}`:r}function fp(e,t){let r=j0[t.tool];return r?new Promise((n,s)=>{let i=t.b
1589
1589
  `):t.stdout.write(`${JSON.stringify(f)}
1590
1590
  `)}else n.json?t.stdout.write(`${JSON.stringify(await l.json(),null,2)}
1591
1591
  `):(t.stdout.write(await l.text()),t.stdout.write(`
1592
- `));return 0}function O_(e){let t=j_(e);if(typeof t=="string")return t;let r=t.args,n=t.format!=="text",[s,...i]=r;return s===void 0?"usage: lmctl api <subcommand>":s==="status"?Vi(i,"/api/status",n):s==="projects"?Vi(i,"/api/projects",n):s==="teams"?Vi(i,"/api/teams",n):s==="workflows"?i[0]==="verify"?aA(i.slice(1),t.format):Vi(i,"/api/workflows",n):s==="workflow"?oA(i,n):s==="upload"?sA(i,n):s==="submit-job"?iA(i,n):s==="issues"?nA(i,n):s==="jobs"?is(i,"--status","/api/jobs","status",n):s==="job"?rA(i,n):s==="project"?lA(i,n):s==="artifact"?uA(i,n):s==="runs"?is(i,"--limit","/api/runs","limit",n,!0):s==="external-objects"?is(i,"--type","/api/external-objects","type",n):s==="external-signals"?R_(i,"--unhandled","/api/external-signals","unhandled",n):s==="attentions"||s==="attention"?i[0]==="ack"?fA(i,n):R_(i,"--unacked","/api/attentions","unacked",n):s==="stats"?mA(i,n):s==="daemon"?pA(i,n):s==="intake"?_A(i,n):s==="session"?hA(i,n):s==="run"?gA(i,t.format):s==="prs"?is(i,"--status","/api/submitted-prs","status",n):s==="pr"?eA(i,n):`unknown subcommand: ${s}`}function ar(e,t){let r={Accept:e};return t!==null&&t.length>0&&(r.Authorization=`Bearer ${t}`),r}function Lr(e){if(e.dal!==void 0)return Nc(e.dal,process.env,e);let t=Ie({path:le()});try{return Nc(t,process.env,e)}finally{t.close()}}function Nc(e,t,r){let n=[],s=e.getConfig("api.url"),i;s!==null?i=s:t.LMCTL_API_URL!==void 0&&t.LMCTL_API_URL.length>0?(i=t.LMCTL_API_URL,n.push("api.url")):i=Cx;let o=e.getConfig("api.token"),a;o!==null?a=o:t.LMCTL_API_TOKEN!==void 0&&t.LMCTL_API_TOKEN.length>0?(a=t.LMCTL_API_TOKEN,n.push("api.token")):a=null;for(let l of n)r.stderr.write(`note: ${Dx(l)} env var read; consider \`lmctl api config set ${l} ...\` to make this DB-canonical.
1592
+ `));return 0}function O_(e){let t=j_(e);if(typeof t=="string")return t;let r=t.args,n=t.format!=="text",[s,...i]=r;return s===void 0?"usage: lmctl api <subcommand>":s==="status"?Vi(i,"/api/status",n):s==="projects"?Vi(i,"/api/projects",n):s==="teams"?Vi(i,"/api/teams",n):s==="workflows"?i[0]==="verify"?aA(i.slice(1),t.format):Vi(i,"/api/workflows",n):s==="workflow"?oA(i,n):s==="upload"?sA(i,n):s==="submit-job"?iA(i,n):s==="issues"?nA(i,n):s==="jobs"?is(i,"--status","/api/jobs","status",n):s==="job"?rA(i,n):s==="project"?lA(i,n):s==="artifact"?uA(i,n):s==="runs"?is(i,"--limit","/api/runs","limit",n,!0):s==="external-objects"?is(i,"--type","/api/external-objects","type",n):s==="external-signals"?R_(i,"--unhandled","/api/external-signals","unhandled",n):s==="attentions"||s==="attention"?i[0]==="ack"?fA(i,n):R_(i,"--unacked","/api/attentions","unacked",n):s==="stats"?mA(i,n):s==="daemon"?pA(i,n):s==="intake"?_A(i,n):s==="session"?hA(i,n):s==="run"?gA(i,t.format):s==="prs"?is(i,"--status","/api/submitted-prs","status",n):s==="pr"?eA(i,n):`unknown subcommand: ${s}`}function ar(e,t){let r={Accept:e};return t!==null&&t.length>0&&(r.Authorization=`Bearer ${t}`),r}function Lr(e){if(e.dal!==void 0)return Nc(e.dal,process.env,e);let t=Ie({path:le()});try{return Nc(t,process.env,e)}finally{t.close()}}function Nc(e,t,r){let n=[],s=e.getConfig("api.url"),i;s!==null?i=s:t.LMCTL_API_URL!==void 0&&t.LMCTL_API_URL.length>0?(i=t.LMCTL_API_URL,n.push("api.url")):i=Cx;let o=e.getConfig("api.token"),a;t.LMCTL_API_TOKEN!==void 0&&t.LMCTL_API_TOKEN.length>0?(a=t.LMCTL_API_TOKEN,o===null?n.push("api.token"):o!==a&&r.stderr.write(`note: LMCTL_API_TOKEN env var overrides lmctl_config api.token for this API request.
1593
+ `)):o!==null?a=o:a=null;for(let l of n)r.stderr.write(`note: ${Dx(l)} env var read; consider \`lmctl api config set ${l} ...\` to make this DB-canonical.
1593
1594
  `);return{baseUrl:i,token:a}}function Dx(e){switch(e){case"api.port":return"LMCTL_API_PORT";case"api.token":return"LMCTL_API_TOKEN";case"api.url":return"LMCTL_API_URL";default:return`LMCTL_${e.replaceAll(".","_").toUpperCase()}`}}async function Px(e,t){let[r,...n]=e;if(r===void 0)return t.stderr.write(`usage: lmctl api config <get|set|list>
1594
1595
  `),2;let s=t.dal===void 0,i=t.dal??Ie({path:le()});try{if(r==="get"){if(n.length!==1)return t.stderr.write(`usage: lmctl api config get <key>
1595
1596
  `),2;let o=n[0];if(!Gi.has(o))return t.stderr.write(`error: unsupported config key: ${o} (Phase A keys: ${[...Gi].join(", ")})
@@ -1755,7 +1756,7 @@ without an HTTP round trip.
1755
1756
  ${t.map(r=>` line ${r.line}: ${r.message}`).join(`
1756
1757
  `)}`),this.issues=t,this.name="DslCompileError"}},mR=new Set(["lmctl/assert-repo-clean","lmctl/review","lmctl/consolidate","lmctl/interactive","lmctl/loop","lmctl/render-docx","lmctl/render-xlsx","lmctl/shell-step","lmctl/choice","lmctl/foreach","lmctl/subflow","lmctl/terminal","lmctl/trigger-schedule","lmctl/trigger-gh-issue"]),pR={"lmctl/consolidate":["ok"],"lmctl/interactive":["done"],"lmctl/loop":["ok"],"lmctl/foreach":["all_ok"]},ih=new Set(["requires","default_task_timeout_ms","errors","concurrency_key","concurrent_limit"]),oh={"trigger-schedule":"lmctl/trigger-schedule","trigger-gh-issue":"lmctl/trigger-gh-issue"}});import{readFileSync as gR}from"node:fs";function yR(){let e=process.env.LMCTL_DSL;return e===void 0?!0:!["0","false","off"].includes(e.trim().toLowerCase())}function wR(e){for(let t of e.split(`
1757
1758
  `)){let r=t.replace(/#.*/,"").trim();if(r.length!==0)return/^workflow\s+\S+\s+v\d+\s*$/.test(r)}return!1}function lt(e){if(typeof e=="string"&&yR()&&wR(e)){let r;try{r=ah(e)}catch(s){throw s instanceof dn?new Ht(s.issues.map(i=>({path:`dsl:${i.line}`,message:i.message}))):s}let n=It.safeParse(r);if(!n.success)throw new Ht(n.error.issues.map(s=>({path:s.path.length===0?"$":s.path.map(String).join("."),message:s.message})));return n.data}let t=no(TR(e));if(bR(t)&&t.definition_schema_version===3){let r=It.safeParse(t);if(!r.success)throw new Ht(r.error.issues.map(n=>({path:n.path.length===0?"$":n.path.map(String).join("."),message:n.message})));return r.data}return ER(t)}function ER(e){let t=to.safeParse(e);if(!t.success)throw new Ht(t.error.issues.map(s=>({path:s.path.length===0?"$":s.path.map(String).join("."),message:s.message})));let r=t.data,n=new Set(["Task","Pause","Parallel","LoopUntil","Pass","Fail","Succeed"]);for(let[s,i]of Object.entries(r.states))if(n.has(i.type))throw new Ht([{path:`states.${s}`,message:`v2 workflows (primitive_version: 2) may not use v1 primitive type: ${i.type}`}]);try{return Q_(r)}catch(s){throw s instanceof qt?new Fc(s):s}}function TR(e){if(typeof e!="string")return e;let t=e.trim();return e.includes(`
1758
- `)||t.startsWith("{")||t.startsWith("[")?dh(e):t.endsWith(".json")?dh(gR(t,"utf8")):e}function dh(e){return JSON.parse(e)}function bR(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}var Fc,Ht,ls=T(()=>{"use strict";ln();th();Pc();cn();ch();Fc=class extends Error{causeError;constructor(t){super("compiler emitted invalid atomic workflow"),this.causeError=t,this.name="CompilerInvariantError"}},Ht=class extends Error{issues;constructor(t){super("compound workflow validation failed"),this.issues=t,this.name="CompilerValidationError"}}});function so(e){let t=e.workflow?.concurrent_limit??1,r=e.job.concurrency_key_resolved??e.workflow?.concurrency_key??null;return r===null||r.trim().length===0?{concurrency_key:null,concurrent_limit:t}:{concurrency_key:SR(r,{job:{id:e.job.id,kind:e.job.source,source:e.job.source,source_ref:e.job.source_ref,payload:kR(e.job.payload)},project:e.project===null?null:{id:e.project.id,name:e.project.name}}),concurrent_limit:t}}function SR(e,t){return e.replace(/\{\{\s*([^}]+?)\s*\}\}/g,(r,n)=>{let s=vR(t,n.trim());return s==null?"":typeof s=="string"?s:typeof s=="number"||typeof s=="boolean"?String(s):JSON.stringify(s)})}function vR(e,t){let r=e;for(let n of t.split(".")){if(typeof r!="object"||r===null||!Object.prototype.hasOwnProperty.call(r,n))return;r=r[n]}return r}function kR(e){if(e===null||e.trim().length===0)return null;try{return JSON.parse(e)}catch{return e}}var Uc=T(()=>{"use strict"});var uh={};we(uh,{enqueueFromAgentOutput:()=>NR,enqueueFromGitHubIssue:()=>Wc,enqueueManual:()=>IR,enqueueScheduled:()=>xR});function Wc(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:t.workflow_id_override??null,source:"gh_issue",source_ref:t.issue_url,dedupe_key:t.dedupe_key??t.issue_url,payload:io(t.payload),concurrency_key:t.concurrency_key,priority:t.priority})}function IR(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"manual",source_ref:t.source_ref??null,dedupe_key:t.source_ref??null,payload:io(t.payload),concurrency_key:t.concurrency_key})}function NR(e,t){let r=t.sequence===void 0?`run:${t.parent_run_id}`:`run:${t.parent_run_id}:${t.sequence}`;return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"agent_output",source_ref:r,dedupe_key:r,available_at:t.available_at,payload:io(t.payload),concurrency_key:t.concurrency_key})}function xR(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"schedule",source_ref:t.source_ref,dedupe_key:t.source_ref,available_at:t.available_at,payload:io(t.payload),concurrency_key:t.concurrency_key})}function io(e){return e==null?null:typeof e=="string"?e:JSON.stringify(e)}function oo(e,t){let r=t.concurrency_key;if(r!==void 0)return e.enqueueJob({...t,concurrency_key:r});let n=e.getProject(t.project_id),s=n===null?null:t.workflow_id_override!==void 0&&t.workflow_id_override!==null?e.getWorkflow(t.workflow_id_override):e.getWorkflowByName(n.workflow_name);if(n===null||s===null)return e.enqueueJob(t);try{let i=lt(s.definition),o={id:-1,project_id:t.project_id,workflow_id_override:t.workflow_id_override??null,source:t.source,source_ref:t.source_ref??null,payload:t.payload??null,status:"queued",priority:t.priority??0,available_at:t.available_at??new Date().toISOString(),locked_by:null,locked_until:null,attempt_count:0,last_error:null,dedupe_key:t.dedupe_key??null,concurrency_key_resolved:null,enqueued_at:new Date().toISOString(),started_at:null,ended_at:null,run_id:null},a=so({workflow:i,job:o,project:n});return e.enqueueJob({...t,concurrency_key:a.concurrency_key})}catch{return e.enqueueJob(t)}}var Bc=T(()=>{"use strict";ls();Uc()});async function mh(e){let t=e.dal.listProjectWorkflows(e.project.id,{enabled_only:!0});if(t.length===0)return fh(e.dal,e.project.id,e.issue,e.issue.url,null,e.issue,void 0);let r={event:{kind:"github_issue",issue:e.issue}},n=[],s=0;for(let i of t){if(!await AR(i.condition,r))continue;let o=`${e.issue.url}#workflow:${i.workflow_id}`,a={issue:e.issue,...RR(i.parameters_override)},l=fh(e.dal,e.project.id,e.issue,o,i.workflow_id,a,-i.priority);n.push(...l.jobs),s+=l.new_jobs}return{jobs:n,new_jobs:s}}function fh(e,t,r,n,s,i,o){let a=e.findJobBySourceAndDedupe("gh_issue",n);return{jobs:[Wc(e,{project_id:t,issue_url:r.url,payload:i,workflow_id_override:s,dedupe_key:n,priority:o})],new_jobs:a===null?1:0}}async function AR(e,t){if(e===null||e.trim().length===0)return!0;try{return await $r(e,t)===!0}catch{return!1}}function RR(e){if(e===null||e.trim().length===0)return{};try{let t=JSON.parse(e);if(t!==null&&typeof t=="object"&&!Array.isArray(t))return t}catch{return{}}return{}}var ph=T(()=>{"use strict";os();Bc()});import{spawnSync as LR}from"node:child_process";async function $R(e){let t=e.labels??["bug"],r=e.state??"open",n=["issue","list","--repo",e.project.name,"--state",r,"--json","number,title,url,body,state,labels","--limit","100"];t.length>0&&n.splice(4,0,"--label",t.join(","));let s=LR(e.binary??"gh",n,{encoding:"utf8",timeout:e.timeoutMs??6e4,maxBuffer:10*1024*1024});if(s.error!==void 0)throw s.error;if(s.status!==0)throw new Error(`gh issue list failed: ${s.stderr??""}`.trim());let i;try{i=JSON.parse(s.stdout??"[]")}catch{throw new Error("gh issue list returned malformed JSON")}if(!CR(i))throw new Error("gh issue list returned unexpected JSON shape");let o=0;for(let a of i){let l=await mh({dal:e.dal,project:e.project,issue:MR(a)});o+=l.new_jobs}return{scanned:i.length,new_jobs:o}}async function ao(e){if(process.env.LMCTL_INTAKE_DISABLED==="1")return[];let t=[];for(let r of e.listProjectsWithIntakeEnabled()){let n=OR(r.intake_config);try{let s=await $R({dal:e,project:r,labels:n.labels,state:n.state});t.push({project_id:r.id,project_name:r.name,...s})}catch(s){let i=s instanceof Error?s.message:String(s);t.push({project_id:r.id,project_name:r.name,scanned:0,new_jobs:0,error:i});try{e.raiseAttention({kind:"daemon_intake_scan_failed",severity:"warn",project_id:r.id,payload:JSON.stringify({project_id:r.id,project_name:r.name,error:i})})}catch{}}}return t}function OR(e){if(e===null)return{};try{let t=JSON.parse(e);if(!qc(t))return{};let r=t.state==="open"||t.state==="closed"||t.state==="all"?t.state:void 0,n=Array.isArray(t.labels)?t.labels.filter(s=>typeof s=="string"&&s.length>0):void 0;return{scan_github_issues:t.scan_github_issues===!0,labels:n,state:r}}catch{return{}}}function CR(e){return Array.isArray(e)&&e.every(t=>{if(!qc(t))return!1;let r=t.labels;return typeof t.number=="number"&&typeof t.title=="string"&&typeof t.url=="string"&&(typeof t.body=="string"||t.body===null||t.body===void 0)&&(t.state===void 0||typeof t.state=="string")&&(r===void 0||Array.isArray(r)&&r.every(n=>typeof n=="string"?!0:qc(n)&&typeof n.name=="string"))})}function MR(e){let t=e.labels?.map(s=>typeof s=="string"?s:s.name),{labels:r,...n}=e;return t===void 0?n:{...n,labels:t}}function qc(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var Hc=T(()=>{"use strict";ph()});function hh(e){return async t=>DR(e.app,t,e.log!==void 0?{log:e.log}:{})}async function DR(e,t,r={}){let n=PR(t.path),s={"content-type":"application/json",...t.headers??{},[lo]:Jc},i={method:t.method,headers:s};t.body!==void 0&&t.method!=="GET"&&t.method!=="DELETE"&&(i.body=typeof t.body=="string"?t.body:JSON.stringify(t.body));let o=new Request(n,i),a=Date.now();try{let l=await e.fetch(o),c=await FR(l);if(r.log!==void 0){let d=Date.now()-a;r.log(`[mailbox-dispatch] ${t.method} ${_h(t.path)} \u2192 ${c.status} (${d}ms)`)}return c}catch(l){if(r.log!==void 0){let c=Date.now()-a;r.log(`[mailbox-dispatch] ${t.method} ${_h(t.path)} \u2192 ERR (${c}ms)`)}throw l}}function _h(e){let t=e.startsWith("/")?e:`/${e}`,r=t.search(/[?#]/);return r===-1?t:t.slice(0,r)}function PR(e){let t=e.startsWith("/")?e:`/${e}`;return`${jR}${t}`}async function FR(e){let t=await e.text(),r;if(t==="")r=void 0;else try{r=JSON.parse(t)}catch{r=t}let n={};e.headers.forEach((i,o)=>{o.toLowerCase()!==lo&&(n[o]=i)});let s={status:e.status};return Object.keys(n).length>0&&(s.headers=n),r!==void 0&&(s.body=r),s}var lo,Jc,jR,Xc=T(()=>{"use strict";lo="x-mailbox-channel",Jc="1",jR="http://mailbox.local"});import{createHash as gh,createHmac as UR,timingSafeEqual as WR}from"node:crypto";function yh(){return async(e,t)=>{let r=wh();if(r===null||XR(e.req.path)){await t();return}if(e.req.path.startsWith("/mailbox/")&&e.req.header(lo)===Jc){await t();return}let n=e.req.query("token");if(n!==void 0&&co(n,r)){Vc(e,r),await t();return}if(JR(e,r)){await t();return}return e.req.path.startsWith("/api/")||e.req.path.startsWith("/mailbox/")?e.json({error:"API requires auth; set LMCTL_API_TOKEN"},401):e.redirect("/login",302)}}function wh(){let e=process.env.LMCTL_API_TOKEN;return e&&e.length>0?e:null}function Eh(e){let t=wh();return t!==null&&co(e,t)}function Vc(e,t,r=new Date){e.header("Set-Cookie",`${Gc}=${qR(t,r)}; Path=/; HttpOnly; SameSite=Lax`)}function Th(e){e.header("Set-Cookie",`${Gc}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`)}function qR(e,t=new Date){let n=`auth=ok|${new Date(t.getTime()+BR*24*60*60*1e3).toISOString()}`;return Buffer.from(`${n}|${bh(e,n)}`,"utf8").toString("base64url")}function HR(e,t,r=new Date){let n;try{n=Buffer.from(e,"base64url").toString("utf8")}catch{return!1}let s=n.split("|");if(s.length!==3||s[0]!=="auth=ok")return!1;let i=new Date(s[1]);return Number.isNaN(i.getTime())||i.getTime()<=r.getTime()?!1:co(s[2],bh(t,`${s[0]}|${s[1]}`))}function co(e,t){return WR(gh("sha256").update(e).digest(),gh("sha256").update(t).digest())}function JR(e,t){let r=/^Bearer\s+(.+)$/i.exec(e.req.header("authorization")??"")?.[1];if(r!==void 0&&co(r,t))return!0;let n=GR(e.req.header("cookie")??"")[Gc];return n!==void 0&&HR(n,t)}function XR(e){return e==="/login"||e==="/logout"}function GR(e){let t={};for(let r of e.split(";")){let[n,...s]=r.trim().split("=");n===void 0||n.length===0||s.length===0||(t[n]=s.join("="))}return t}function bh(e,t){return UR("sha256",e).update(t).digest("hex")}var Gc,BR,Sh=T(()=>{"use strict";Xc();Gc="lmctl_next_session",BR=30});import{existsSync as un,mkdirSync as VR,readdirSync as KR,readFileSync as uo,unlinkSync as YR,writeFileSync as zc}from"node:fs";import{join as Or}from"node:path";function et(e){if(!zR.test(e))throw new Error(`invalid memory name "${e}": only alphanumeric characters, underscores, and hyphens are allowed`)}function kh(e,t){let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(r===null)return null;let n=r[1],s=r[2].trimStart(),i=n.match(/^type:\s*(.+)$/m),o=n.match(/^description:\s*(.+)$/m),a=i?.[1]?.trim()??"";return tL(a)?{name:e,type:a,description:o?.[1]?.trim()??null,body:s,created_at:vh,updated_at:vh}:null}function ZR(e,t,r,n){let s=r!==null?`
1759
+ `)||t.startsWith("{")||t.startsWith("[")?dh(e):t.endsWith(".json")?dh(gR(t,"utf8")):e}function dh(e){return JSON.parse(e)}function bR(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}var Fc,Ht,ls=T(()=>{"use strict";ln();th();Pc();cn();ch();Fc=class extends Error{causeError;constructor(t){super("compiler emitted invalid atomic workflow"),this.causeError=t,this.name="CompilerInvariantError"}},Ht=class extends Error{issues;constructor(t){super("compound workflow validation failed"),this.issues=t,this.name="CompilerValidationError"}}});function so(e){let t=e.workflow?.concurrent_limit??1,r=e.job.concurrency_key_resolved??e.workflow?.concurrency_key??null;return r===null||r.trim().length===0?{concurrency_key:null,concurrent_limit:t}:{concurrency_key:SR(r,{job:{id:e.job.id,kind:e.job.source,source:e.job.source,source_ref:e.job.source_ref,payload:kR(e.job.payload)},project:e.project===null?null:{id:e.project.id,name:e.project.name}}),concurrent_limit:t}}function SR(e,t){return e.replace(/\{\{\s*([^}]+?)\s*\}\}/g,(r,n)=>{let s=vR(t,n.trim());return s==null?"":typeof s=="string"?s:typeof s=="number"||typeof s=="boolean"?String(s):JSON.stringify(s)})}function vR(e,t){let r=e;for(let n of t.split(".")){if(typeof r!="object"||r===null||!Object.prototype.hasOwnProperty.call(r,n))return;r=r[n]}return r}function kR(e){if(e===null||e.trim().length===0)return null;try{return JSON.parse(e)}catch{return e}}var Uc=T(()=>{"use strict"});var uh={};we(uh,{enqueueFromAgentOutput:()=>NR,enqueueFromGitHubIssue:()=>Wc,enqueueManual:()=>IR,enqueueScheduled:()=>xR});function Wc(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:t.workflow_id_override??null,source:"gh_issue",source_ref:t.issue_url,dedupe_key:t.dedupe_key??t.issue_url,payload:io(t.payload),concurrency_key:t.concurrency_key,priority:t.priority})}function IR(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"manual",source_ref:t.source_ref??null,dedupe_key:t.source_ref??null,payload:io(t.payload),concurrency_key:t.concurrency_key})}function NR(e,t){let r=t.sequence===void 0?`run:${t.parent_run_id}`:`run:${t.parent_run_id}:${t.sequence}`;return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"agent_output",source_ref:r,dedupe_key:r,available_at:t.available_at,payload:io(t.payload),concurrency_key:t.concurrency_key})}function xR(e,t){return oo(e,{project_id:t.project_id,workflow_id_override:null,source:"schedule",source_ref:t.source_ref,dedupe_key:t.source_ref,available_at:t.available_at,payload:io(t.payload),concurrency_key:t.concurrency_key})}function io(e){return e==null?null:typeof e=="string"?e:JSON.stringify(e)}function oo(e,t){let r=t.concurrency_key;if(r!==void 0)return e.enqueueJob({...t,concurrency_key:r});let n=e.getProject(t.project_id),s=n===null?null:t.workflow_id_override!==void 0&&t.workflow_id_override!==null?e.getWorkflow(t.workflow_id_override):e.getWorkflowByName(n.workflow_name);if(n===null||s===null)return e.enqueueJob(t);try{let i=lt(s.definition),o={id:-1,project_id:t.project_id,workflow_id_override:t.workflow_id_override??null,source:t.source,source_ref:t.source_ref??null,payload:t.payload??null,status:"queued",priority:t.priority??0,available_at:t.available_at??new Date().toISOString(),locked_by:null,locked_until:null,attempt_count:0,last_error:null,dedupe_key:t.dedupe_key??null,concurrency_key_resolved:null,enqueued_at:new Date().toISOString(),started_at:null,ended_at:null,run_id:null},a=so({workflow:i,job:o,project:n});return e.enqueueJob({...t,concurrency_key:a.concurrency_key})}catch{return e.enqueueJob(t)}}var Bc=T(()=>{"use strict";ls();Uc()});async function mh(e){let t=e.dal.listProjectWorkflows(e.project.id,{enabled_only:!0});if(t.length===0)return fh(e.dal,e.project.id,e.issue,e.issue.url,null,e.issue,void 0);let r={event:{kind:"github_issue",issue:e.issue}},n=[],s=0;for(let i of t){if(!await AR(i.condition,r))continue;let o=`${e.issue.url}#workflow:${i.workflow_id}`,a={issue:e.issue,...RR(i.parameters_override)},l=fh(e.dal,e.project.id,e.issue,o,i.workflow_id,a,-i.priority);n.push(...l.jobs),s+=l.new_jobs}return{jobs:n,new_jobs:s}}function fh(e,t,r,n,s,i,o){let a=e.findJobBySourceAndDedupe("gh_issue",n);return{jobs:[Wc(e,{project_id:t,issue_url:r.url,payload:i,workflow_id_override:s,dedupe_key:n,priority:o})],new_jobs:a===null?1:0}}async function AR(e,t){if(e===null||e.trim().length===0)return!0;try{return await $r(e,t)===!0}catch{return!1}}function RR(e){if(e===null||e.trim().length===0)return{};try{let t=JSON.parse(e);if(t!==null&&typeof t=="object"&&!Array.isArray(t))return t}catch{return{}}return{}}var ph=T(()=>{"use strict";os();Bc()});import{spawnSync as LR}from"node:child_process";async function $R(e){let t=e.labels??["bug"],r=e.state??"open",n=["issue","list","--repo",e.project.name,"--state",r,"--json","number,title,url,body,state,labels","--limit","100"];t.length>0&&n.splice(4,0,"--label",t.join(","));let s=LR(e.binary??"gh",n,{encoding:"utf8",timeout:e.timeoutMs??6e4,maxBuffer:10*1024*1024});if(s.error!==void 0)throw s.error;if(s.status!==0)throw new Error(`gh issue list failed: ${s.stderr??""}`.trim());let i;try{i=JSON.parse(s.stdout??"[]")}catch{throw new Error("gh issue list returned malformed JSON")}if(!CR(i))throw new Error("gh issue list returned unexpected JSON shape");let o=0;for(let a of i){let l=await mh({dal:e.dal,project:e.project,issue:MR(a)});o+=l.new_jobs}return{scanned:i.length,new_jobs:o}}async function ao(e){if(process.env.LMCTL_INTAKE_DISABLED==="1")return[];let t=[];for(let r of e.listProjectsWithIntakeEnabled()){let n=OR(r.intake_config);try{let s=await $R({dal:e,project:r,labels:n.labels,state:n.state});t.push({project_id:r.id,project_name:r.name,...s})}catch(s){let i=s instanceof Error?s.message:String(s);t.push({project_id:r.id,project_name:r.name,scanned:0,new_jobs:0,error:i});try{e.raiseAttention({kind:"daemon_intake_scan_failed",severity:"warn",project_id:r.id,payload:JSON.stringify({project_id:r.id,project_name:r.name,error:i})})}catch{}}}return t}function OR(e){if(e===null)return{};try{let t=JSON.parse(e);if(!qc(t))return{};let r=t.state==="open"||t.state==="closed"||t.state==="all"?t.state:void 0,n=Array.isArray(t.labels)?t.labels.filter(s=>typeof s=="string"&&s.length>0):void 0;return{scan_github_issues:t.scan_github_issues===!0,labels:n,state:r}}catch{return{}}}function CR(e){return Array.isArray(e)&&e.every(t=>{if(!qc(t))return!1;let r=t.labels;return typeof t.number=="number"&&typeof t.title=="string"&&typeof t.url=="string"&&(typeof t.body=="string"||t.body===null||t.body===void 0)&&(t.state===void 0||typeof t.state=="string")&&(r===void 0||Array.isArray(r)&&r.every(n=>typeof n=="string"?!0:qc(n)&&typeof n.name=="string"))})}function MR(e){let t=e.labels?.map(s=>typeof s=="string"?s:s.name),{labels:r,...n}=e;return t===void 0?n:{...n,labels:t}}function qc(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}var Hc=T(()=>{"use strict";ph()});function hh(e){return async t=>DR(e.app,t,e.log!==void 0?{log:e.log}:{})}async function DR(e,t,r={}){let n=PR(t.path),s={"content-type":"application/json",...t.headers??{},[lo]:Jc},i={method:t.method,headers:s};t.body!==void 0&&t.method!=="GET"&&t.method!=="DELETE"&&(i.body=typeof t.body=="string"?t.body:JSON.stringify(t.body));let o=new Request(n,i),a=Date.now();try{let l=await e.fetch(o),c=await FR(l);if(r.log!==void 0){let d=Date.now()-a;r.log(`[mailbox-dispatch] ${t.method} ${_h(t.path)} \u2192 ${c.status} (${d}ms)`)}return c}catch(l){if(r.log!==void 0){let c=Date.now()-a;r.log(`[mailbox-dispatch] ${t.method} ${_h(t.path)} \u2192 ERR (${c}ms)`)}throw l}}function _h(e){let t=e.startsWith("/")?e:`/${e}`,r=t.search(/[?#]/);return r===-1?t:t.slice(0,r)}function PR(e){let t=e.startsWith("/")?e:`/${e}`;return`${jR}${t}`}async function FR(e){let t=await e.text(),r;if(t==="")r=void 0;else try{r=JSON.parse(t)}catch{r=t}let n={};e.headers.forEach((i,o)=>{o.toLowerCase()!==lo&&(n[o]=i)});let s={status:e.status};return Object.keys(n).length>0&&(s.headers=n),r!==void 0&&(s.body=r),s}var lo,Jc,jR,Xc=T(()=>{"use strict";lo="x-mailbox-channel",Jc="1",jR="http://mailbox.local"});import{createHash as gh,createHmac as UR,timingSafeEqual as WR}from"node:crypto";function yh(e={}){return async(t,r)=>{if(e.disabled===!0){await r();return}let n=wh();if(n===null||XR(t.req.path)){await r();return}if(t.req.path.startsWith("/mailbox/")&&t.req.header(lo)===Jc){await r();return}let s=t.req.query("token");if(s!==void 0&&co(s,n)){Vc(t,n),await r();return}if(JR(t,n)){await r();return}return t.req.path.startsWith("/api/")||t.req.path.startsWith("/mailbox/")?t.json({error:"API requires auth; set LMCTL_API_TOKEN"},401):t.redirect("/login",302)}}function wh(){let e=process.env.LMCTL_API_TOKEN;return e&&e.length>0?e:null}function Eh(e){let t=wh();return t!==null&&co(e,t)}function Vc(e,t,r=new Date){e.header("Set-Cookie",`${Gc}=${qR(t,r)}; Path=/; HttpOnly; SameSite=Lax`)}function Th(e){e.header("Set-Cookie",`${Gc}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`)}function qR(e,t=new Date){let n=`auth=ok|${new Date(t.getTime()+BR*24*60*60*1e3).toISOString()}`;return Buffer.from(`${n}|${bh(e,n)}`,"utf8").toString("base64url")}function HR(e,t,r=new Date){let n;try{n=Buffer.from(e,"base64url").toString("utf8")}catch{return!1}let s=n.split("|");if(s.length!==3||s[0]!=="auth=ok")return!1;let i=new Date(s[1]);return Number.isNaN(i.getTime())||i.getTime()<=r.getTime()?!1:co(s[2],bh(t,`${s[0]}|${s[1]}`))}function co(e,t){return WR(gh("sha256").update(e).digest(),gh("sha256").update(t).digest())}function JR(e,t){let r=/^Bearer\s+(.+)$/i.exec(e.req.header("authorization")??"")?.[1];if(r!==void 0&&co(r,t))return!0;let n=GR(e.req.header("cookie")??"")[Gc];return n!==void 0&&HR(n,t)}function XR(e){return e==="/login"||e==="/logout"}function GR(e){let t={};for(let r of e.split(";")){let[n,...s]=r.trim().split("=");n===void 0||n.length===0||s.length===0||(t[n]=s.join("="))}return t}function bh(e,t){return UR("sha256",e).update(t).digest("hex")}var Gc,BR,Sh=T(()=>{"use strict";Xc();Gc="lmctl_next_session",BR=30});import{existsSync as un,mkdirSync as VR,readdirSync as KR,readFileSync as uo,unlinkSync as YR,writeFileSync as zc}from"node:fs";import{join as Or}from"node:path";function et(e){if(!zR.test(e))throw new Error(`invalid memory name "${e}": only alphanumeric characters, underscores, and hyphens are allowed`)}function kh(e,t){let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(r===null)return null;let n=r[1],s=r[2].trimStart(),i=n.match(/^type:\s*(.+)$/m),o=n.match(/^description:\s*(.+)$/m),a=i?.[1]?.trim()??"";return tL(a)?{name:e,type:a,description:o?.[1]?.trim()??null,body:s,created_at:vh,updated_at:vh}:null}function ZR(e,t,r,n){let s=r!==null?`
1759
1760
  description: ${r}`:"";return`---
1760
1761
  name: ${e}${s}
1761
1762
  type: ${t}
@@ -1955,7 +1956,7 @@ ${p.text}`,["approve","request_changes"],!0,s,t.writes_to_project_path===!0)));i
1955
1956
  WHERE run_id = ?
1956
1957
  AND acknowledged_at IS NULL
1957
1958
  AND requires_user = 1
1958
- ORDER BY id DESC LIMIT 1`,t);return r.length===0?null:{kind:r[0].kind,attention_id:r[0].id}}var Jo=T(()=>{"use strict"});function bw(e,t){e.all("/runtime/*",r=>GM(r.req.raw,t))}async function GM(e,t){try{return Response.json(await VM(e,t))}catch(r){if(r instanceof se)return Response.json({error:r.message},{status:r.status});let n=r instanceof Error?r.message:String(r);return Response.json({error:n},{status:500})}}async function VM(e,t){let r=new URL(e.url),n=tj(t),s=r.pathname.split("/").filter(Boolean).map(decodeURIComponent);if(e.method==="GET"&&r.pathname==="/runtime/workspaces")return Dd(e),[{id:n.id,name:n.name}];if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="workspaces")return Xo(e,n.id,s[2]),KM(t.dal,n);if(e.method==="GET"&&s.length===5&&s[0]==="runtime"&&s[1]==="workspaces"&&s[3]==="projects"){Xo(e,n.id,s[2]);let i=pw(t.dal,s[4]);return mw(t.dal,n,i)}if(e.method==="GET"&&r.pathname==="/runtime/lead-teams")return Dd(e),t.dal.listTeams().map(i=>ej(i));if(e.method==="POST"&&s.length===4&&s[0]==="runtime"&&s[1]==="lead-teams"&&s[3]==="chat"){let i=_w(t.dal,hw(s[2])),o=await e.json();if(o.teamId!==`team:${i.name}`)throw new se(400,"runtime lead chat body does not match route team");return yw(e,n.id,o.context),gw(i,o.context)}if(e.method==="POST"&&s.length===4&&s[0]==="runtime"&&s[1]==="lead-teams"&&s[3]==="messages"){let i=_w(t.dal,hw(s[2])),o=await e.json();if(o.teamId!==`team:${i.name}`)throw new se(400,"runtime lead message body does not match route team");yw(e,n.id,o.context);let a=o.draft?.body;if(typeof a!="string"||a.length===0)throw new se(400,"runtime lead message requires draft.body");return gw(i,o.context,a)}if(e.method==="POST"&&s.length===6&&s[0]==="runtime"&&s[1]==="workspaces"&&s[3]==="projects"&&s[5]==="workflow-message"){Xo(e,n.id,s[2]);let i=pw(t.dal,s[4]),o=await e.json();if(o.workspaceId!==n.id||o.projectId!==i.name)throw new se(400,"runtime request body does not match route workspace/project");let a=o.draft?.body;if(typeof a!="string"||a.length===0)throw new se(400,"runtime workflow message requires draft.body");return ZM(t.dal,i,a),mw(t.dal,n,i)}if(e.method==="GET"&&r.pathname==="/runtime/templates")return bs(e,n.id),t.dal.listWorkflows().map(i=>rj(i));if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="templates"){bs(e,n.id);let i=sj(t.dal,s[2]);return nj(i)}if(e.method==="GET"&&r.pathname==="/runtime/runs"){bs(e,n.id);let i=r.searchParams.get("project"),o=r.searchParams.get("template");if(i!==null&&o!==null)throw new se(400,"conflicting_filters: ?project= and ?template= are mutually exclusive");return ij(t.dal,i,o).map(l=>Ew(t.dal,l))}if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="runs"){bs(e,n.id);let i=ww(t.dal,s[2]);return Ew(t.dal,i)}if(e.method==="GET"&&s.length===4&&s[0]==="runtime"&&s[1]==="runs"&&s[3]==="events"){bs(e,n.id);let i=ww(t.dal,s[2]),o=aj(t.dal,i);return{runId:Bd(i),events:o,...o.length>0?{cursor:o[o.length-1].id}:{}}}throw new se(404,`unknown runtime request: ${e.method} ${r.pathname}`)}function KM(e,t){return{id:t.id,name:t.name,projects:e.listProjects().map(r=>Sw(e,t,r))}}function mw(e,t,r){let n=Sw(e,t,r);return{...n,managedWorkflow:{...n.managedWorkflow,instance:YM(e,r),composerTarget:{kind:"workflow-initial",label:`Project Workflow: ${r.workflow_name}`,templateId:`template:${r.workflow_name}`,runId:n.managedWorkflow.runId}},workflowMessages:zM(e,r)}}function Sw(e,t,r){let n=vw(e,r.id),s=Fd(n);return{id:r.name,workspaceId:t.id,name:r.name,...r.description===null?{}:{description:r.description},status:s,managedWorkflow:{templateId:`template:${r.workflow_name}`,templateName:r.workflow_name,runId:n===null?`project:${r.id}:no-run`:`run:${n.id}`,status:s}}}function YM(e,t){let r=vw(e,t.id),n=r?.current_state??null;return{id:r===null?`project:${t.id}:no-run`:`run:${r.id}`,templateId:`template:${t.workflow_name}`,label:t.workflow_name,status:Fd(r),currentStepIds:n===null?[]:[n],...r?.started_at===void 0?{}:{createdAt:r.started_at},...r?.ended_at===null||r?.ended_at===void 0?{}:{updatedAt:r.ended_at}}}function zM(e,t){return e.query("SELECT * FROM attention WHERE project_id = ? ORDER BY id ASC LIMIT 50",t.id).map(n=>({id:`attention:${n.id}`,role:"event",author:"lmctl",timestamp:n.created_at,body:n.kind}))}function ZM(e,t,r){let n=QM(e,t.id);if(n!==null){let s=Ho(e,n.id);if(s?.kind==="workflow_escalation"){let i=e.resumeEscalation(s.attention_id,r);if(!i.resumed)throw new se(409,`workflow escalation resume failed: ${i.reason}`);return}if(s?.kind==="interactive_waiting_operator"){let i=kt(e,s.attention_id);if(i?.step_id===null||i?.step_id===void 0)throw new se(409,"interactive resume failed: missing step");let o=e.resumeInteractive(i.step_id,r,!0);if(!o.resumed)throw new se(409,`interactive resume failed: ${o.reason}`);return}}e.enqueueJob({project_id:t.id,source:"runtime-workflow-message",payload:JSON.stringify({prompt:r}),priority:0})}function vw(e,t){return e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? ORDER BY r.id DESC LIMIT 1",t)[0]??null}function QM(e,t){return e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? AND r.terminal_state IS NULL ORDER BY r.id DESC LIMIT 1",t)[0]??null}function Fd(e){return e===null?"queued":e.terminal_state===null?"running":e.terminal_state==="done"||e.terminal_state==="success"?"succeeded":e.terminal_state==="cancelled"||e.terminal_state==="aborted"?"cancelled":"failed"}function pw(e,t){let r=e.findProjectByName(t);if(r===null)throw new se(404,`project not found: ${t}`);return r}function _w(e,t){let r=e.listTeams().find(n=>n.name===t);if(r===void 0)throw new se(404,`team not found: ${t}`);return r}function hw(e){return e.startsWith("team:")?e.slice(5):e}function ej(e){return{id:`team:${e.name}`,name:e.name,teamfile:"",hasLead:!0,kind:e.name.toLowerCase().includes("manager")?"global-manager":"custom-ai-led"}}function gw(e,t,r){let n=new Date().toISOString(),s=r===void 0?[]:[{id:`lead:${e.id}:user:${Date.now()}`,role:"user",author:"operator",timestamp:n,body:r},{id:`lead:${e.id}:event:${Date.now()}`,role:"event",author:"lmctl",timestamp:n,body:"Lead-team mailbox request accepted by the runtime dispatcher."}];return{id:`lead-chat:${e.name}:${t?.scope??"global-admin"}:${t?.workspaceId??Tw}`,teamId:`team:${e.name}`,title:`${e.name} Lead`,messages:s,...t===void 0?{}:{context:t}}}function tj(e){let t=e.workspaceName??jt()??br.default;return{id:t,name:t}}function Dd(e){if(e.headers.get("x-lmctl-workspace-id")!==Tw)throw new se(400,"runtime request requires global-admin workspace identity")}function Xo(e,t,r){let n=e.headers.get("x-lmctl-workspace-id");if(n===null)throw new se(400,"runtime request requires workspace identity");if(r!==t||n!==t)throw new se(400,"runtime workspace identity does not match route")}function bs(e,t){let r=e.headers.get("x-lmctl-workspace-id");if(r===null)throw new se(400,"runtime request requires workspace identity");if(r!==t)throw new se(400,"runtime workspace identity does not match server workspace")}function yw(e,t,r){if(r?.scope==="workspace"){if(r.workspaceId===void 0)throw new se(400,"workspace manager context requires workspace identity");Xo(e,t,r.workspaceId);return}Dd(e)}function Ud(e){return`${En}${Wd(e.name)}`}function Wd(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"item"}function Bd(e){return`${Pd}${e.id}`}function rj(e){let t=Go(e.definition);return{id:Ud(e),name:e.name,...t.description===null?{}:{description:t.description}}}function nj(e){let t=Go(e.definition);return{id:Ud(e),name:e.name,...t.description===null?{}:{description:t.description},graph:t.graph}}function Go(e){let t;try{t=JSON.parse(e)}catch{return{description:null,graph:null,stepIds:[],nameToId:new Map}}if(t===null||typeof t!="object")return{description:null,graph:t,stepIds:[],nameToId:new Map};let r=t,n=typeof r.description=="string"?r.description:null,s=[],i=new Map;if(r.schema_version==="lmctl/v3"&&Array.isArray(r.steps)){let o=typeof r.entry_step_id=="string"?r.entry_step_id:null;for(let a of r.steps){let l=typeof a.id=="string"?a.id:null;l!==null&&(s.push(l),typeof a.name=="string"&&a.name.length>0&&i.set(a.name,l))}o!==null&&s.includes(o)&&s.sort((a,l)=>a===o?-1:l===o?1:0)}return{description:n,graph:t,stepIds:s,nameToId:i}}function sj(e,t){if(!t.startsWith(En))throw new se(404,`template not found: ${t}`);let r=t.slice(En.length),n=e.listWorkflows().filter(s=>Wd(s.name)===r);if(n.length===0)throw new se(404,`template not found: ${t}`);if(n.length>1){let s=n.map(i=>i.name).join(", ");throw new se(409,`template_id_ambiguous: ${t} matches multiple workflow names [${s}]; rename to ensure unique slugs`)}return n[0]}function ww(e,t){if(!t.startsWith(Pd))throw new se(404,`run not found: ${t}`);let r=t.slice(Pd.length);if(!/^[1-9]\d*$/.test(r))throw new se(404,`run not found: ${t}`);let n=Number.parseInt(r,10);if(!Number.isFinite(n)||n<=0||String(n)!==r)throw new se(404,`run not found: ${t}`);let s=e.getRun(n);if(s===null)throw new se(404,`run not found: ${t}`);return s}function ij(e,t,r){if(r!==null){if(!r.startsWith(En))return[];let s=r.slice(En.length),i=e.listWorkflows().filter(a=>Wd(a.name)===s).map(a=>a.id);if(i.length===0)return[];let o=i.map(()=>"?").join(", ");return e.query(`SELECT * FROM run WHERE workflow_id IN (${o}) ORDER BY id DESC LIMIT 200`,...i)}if(t===null)return e.query("SELECT * FROM run ORDER BY id DESC LIMIT 200");let n=e.findProjectByName(t);return n===null?[]:e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? ORDER BY r.id DESC LIMIT 200",n.id)}function Ew(e,t){let r=e.getWorkflow(t.workflow_id),n=Fd(t),s=oj(r,t);return{id:Bd(t),templateId:r===null?`${En}unknown`:Ud(r),label:r===null?`run ${t.id}`:`${r.name} #${t.id}`,status:n,createdAt:t.started_at,...t.ended_at===null?{}:{updatedAt:t.ended_at},currentStepIds:s}}function oj(e,t){if(t.current_state===null)return[];let r=t.current_state.startsWith("__paused__:")?t.current_state.slice(11):t.current_state;return e===null?[r]:[Go(e.definition).nameToId.get(r)??r]}function aj(e,t){let r=e.getWorkflow(t.workflow_id),n=r===null?{stepIds:[],nameToId:new Map}:Go(r.definition),s=c=>n.nameToId.get(c)??c,i=Bd(t),o=[];o.push({timestamp:t.started_at,type:"run.started",message:"Run started"});let a=e.listStepsForRun(t.id);for(let c of a){let d=s(c.state_name);if(o.push({timestamp:c.started_at,type:"step.started",stepId:d,message:`step ${c.state_name} started`}),c.ended_at!==null){let u=lj(c);o.push({timestamp:c.ended_at,type:u,stepId:d,...c.outcome===null?{}:{message:c.outcome},...c.status_detail===null?{}:{payload:{status_detail:c.status_detail}}})}else t.paused_at!==null&&c.id===a[a.length-1]?.id&&o.push({timestamp:t.paused_at,type:"step.paused",stepId:d})}let l=e.listSessionEvents(t.id);for(let c of l){let d=c.step_id===null?void 0:(()=>{let m=a.find(p=>p.id===c.step_id);return m===void 0?void 0:s(m.state_name)})(),u=new Date(c.timestamp_ms).toISOString(),f={kind:c.kind,session_event_id:c.id};if(c.payload.length>0)try{let m=JSON.parse(c.payload);m!==null&&typeof m=="object"&&!Array.isArray(m)&&(f={...f,...m})}catch{}o.push({timestamp:u,type:"message",...d===void 0?{}:{stepId:d},payload:f})}if(t.terminal_state!==null){let c=t.terminal_state==="done"||t.terminal_state==="success"?"run.completed":t.terminal_state==="cancelled"||t.terminal_state==="aborted"?"run.cancelled":"run.failed";o.push({timestamp:t.ended_at??t.started_at,type:c,message:t.terminal_state})}return o.sort((c,d)=>c.timestamp.localeCompare(d.timestamp)),o.map((c,d)=>({id:`${i}:evt:${d+1}`,runId:i,sequence:d+1,timestamp:c.timestamp,type:c.type,...c.stepId===void 0?{}:{stepId:c.stepId},...c.message===void 0?{}:{message:c.message},...c.payload===void 0?{}:{payload:c.payload}}))}function lj(e){if(e.outcome===null)return"step.failed";let t=e.status_detail;return t==="failed"||t==="error"||t==="aborted"?"step.failed":"step.completed"}var Tw,En,Pd,se,kw=T(()=>{"use strict";Je();Jo();Bt();Tw="global-admin";En="template:",Pd="run:";se=class extends Error{status;constructor(t,r){super(r),this.status=t}}});import{mkdirSync as cj,writeFileSync as dj}from"node:fs";import{randomUUID as Iw}from"node:crypto";import{dirname as uj,resolve as Vo,sep as Nw}from"node:path";async function Aw(e,t){let r;try{r=await e.req.parseBody({all:!1})}catch{return e.text("invalid multipart body",400)}let n=r.image;if(!hj(n))return e.text("missing image file",400);if(n.size>fj)return e.text("upload too large",413);let s=Buffer.from(await n.arrayBuffer()),i=gj(s);if(i===null||!(i in xw))return e.text("unsupported upload MIME type",415);if(n.type.length>0&&n.type!==i)return e.text("upload MIME type does not match file content",415);let o=mj(t,r.project);if(typeof o=="string")return e.text(o,404);let a=o===null?Vo(_j()):Vo(o.local_path),l=Vo(a,"uploads",Iw()),c=Vo(l,`${Iw()}${xw[i]}`);if(!pj(c,a))return e.text("invalid upload path",400);cj(l,{recursive:!0});let d=new Uint8Array(s.buffer,s.byteOffset,s.byteLength);dj(c,d);let u={path:c,size:s.byteLength,mime:i,project:o?.name??null};return e.json(u)}function mj(e,t){return t==null||t===""?null:typeof t!="string"?"invalid project":e.findProjectByName(t)??`project not found: ${t}`}function pj(e,t){let r=t.endsWith(Nw)?t:`${t}${Nw}`;return e.startsWith(r)}function _j(){return uj(le())}function hj(e){return typeof File<"u"&&e instanceof File}function gj(e){return e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71&&e[4]===13&&e[5]===10&&e[6]===26&&e[7]===10?"image/png":e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?"image/jpeg":e.length>=12&&e.subarray(0,4).toString("ascii")==="RIFF"&&e.subarray(8,12).toString("ascii")==="WEBP"?"image/webp":e.length>=12&&e.subarray(4,8).toString("ascii")==="ftyp"&&["heic","heix","hevc","hevx","mif1","msf1"].includes(e.subarray(8,12).toString("ascii"))?"image/heic":e.length>=5&&e.subarray(0,5).toString("ascii")==="%PDF-"?"application/pdf":null}var fj,xw,Rw=T(()=>{"use strict";Je();fj=10*1024*1024,xw={"image/png":".png","image/jpeg":".jpg","image/webp":".webp","image/heic":".heic","application/pdf":".pdf"}});import{existsSync as Ko}from"node:fs";import{basename as yj,dirname as wj,extname as Ej,isAbsolute as Tj,join as bj,relative as Sj}from"node:path";import{fileURLToPath as vj}from"node:url";import{Hono as kj}from"hono";import{serveStatic as Nt}from"@hono/node-server/serve-static";function Dw(e){let t=new kj,r=[],n=e.localWebui!==void 0?Hd(e.localWebui.webuiDir):Ij();if(e.localWebui!==void 0&&By(t,{s3:e.localWebui.localMailbox.s3,commands:e.localWebui.localMailbox.commands}),n!==null){let s=Nj();e.localWebui!==void 0?t.get("/config.json",s,i=>i.json({workspaceFetchMode:"local-mailbox",localMailbox:{base:"/local-mailbox",userId:"local",deviceId:"local"},mailboxPolling:{readIntervalSeconds:1,heartbeatIdleSeconds:1,backoffReadIntervalSeconds:1}})):e.webuiRuntimeConfig!==void 0&&t.get("/config.json",s,i=>i.json(e.webuiRuntimeConfig)),t.use("/dist/*",s,Nt({root:n})),t.use("/vendor/*",s,Nt({root:n})),t.use("/src/*",s,Nt({root:n})),t.get("/",s,Nt({root:n,path:"index.html"})),t.get("/admin",s,Nt({root:n,path:"index.html"})),t.get("/admin/*",s,Nt({root:n,path:"index.html"})),t.get("/terminal",s,Nt({root:n,path:"index.html"})),t.get("/terminal/*",s,Nt({root:n,path:"index.html"})),t.get("/chat",s,Nt({root:n,path:"index.html"})),t.get("/chat/*",s,Nt({root:n,path:"index.html"}))}else t.get("/",s=>s.html('<!doctype html><meta charset="utf-8"><title>lmctl</title><body style="font-family:system-ui;max-width:40rem;margin:4rem auto;padding:0 1rem;line-height:1.5"><h1>lmctl daemon</h1><p>This build does not bundle the local web console; the HTTP API is running on this port.</p><p>Open the hosted console at <a href="https://lmctl.ai/">https://lmctl.ai/</a> \u2014 it connects to this daemon via the cloud mailbox.</p></body>'));return t.use("*",yh()),t.get("/login",s=>s.html(Re("Login",`
1959
+ ORDER BY id DESC LIMIT 1`,t);return r.length===0?null:{kind:r[0].kind,attention_id:r[0].id}}var Jo=T(()=>{"use strict"});function bw(e,t){e.all("/runtime/*",r=>GM(r.req.raw,t))}async function GM(e,t){try{return Response.json(await VM(e,t))}catch(r){if(r instanceof se)return Response.json({error:r.message},{status:r.status});let n=r instanceof Error?r.message:String(r);return Response.json({error:n},{status:500})}}async function VM(e,t){let r=new URL(e.url),n=tj(t),s=r.pathname.split("/").filter(Boolean).map(decodeURIComponent);if(e.method==="GET"&&r.pathname==="/runtime/workspaces")return Dd(e),[{id:n.id,name:n.name}];if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="workspaces")return Xo(e,n.id,s[2]),KM(t.dal,n);if(e.method==="GET"&&s.length===5&&s[0]==="runtime"&&s[1]==="workspaces"&&s[3]==="projects"){Xo(e,n.id,s[2]);let i=pw(t.dal,s[4]);return mw(t.dal,n,i)}if(e.method==="GET"&&r.pathname==="/runtime/lead-teams")return Dd(e),t.dal.listTeams().map(i=>ej(i));if(e.method==="POST"&&s.length===4&&s[0]==="runtime"&&s[1]==="lead-teams"&&s[3]==="chat"){let i=_w(t.dal,hw(s[2])),o=await e.json();if(o.teamId!==`team:${i.name}`)throw new se(400,"runtime lead chat body does not match route team");return yw(e,n.id,o.context),gw(i,o.context)}if(e.method==="POST"&&s.length===4&&s[0]==="runtime"&&s[1]==="lead-teams"&&s[3]==="messages"){let i=_w(t.dal,hw(s[2])),o=await e.json();if(o.teamId!==`team:${i.name}`)throw new se(400,"runtime lead message body does not match route team");yw(e,n.id,o.context);let a=o.draft?.body;if(typeof a!="string"||a.length===0)throw new se(400,"runtime lead message requires draft.body");return gw(i,o.context,a)}if(e.method==="POST"&&s.length===6&&s[0]==="runtime"&&s[1]==="workspaces"&&s[3]==="projects"&&s[5]==="workflow-message"){Xo(e,n.id,s[2]);let i=pw(t.dal,s[4]),o=await e.json();if(o.workspaceId!==n.id||o.projectId!==i.name)throw new se(400,"runtime request body does not match route workspace/project");let a=o.draft?.body;if(typeof a!="string"||a.length===0)throw new se(400,"runtime workflow message requires draft.body");return ZM(t.dal,i,a),mw(t.dal,n,i)}if(e.method==="GET"&&r.pathname==="/runtime/templates")return bs(e,n.id),t.dal.listWorkflows().map(i=>rj(i));if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="templates"){bs(e,n.id);let i=sj(t.dal,s[2]);return nj(i)}if(e.method==="GET"&&r.pathname==="/runtime/runs"){bs(e,n.id);let i=r.searchParams.get("project"),o=r.searchParams.get("template");if(i!==null&&o!==null)throw new se(400,"conflicting_filters: ?project= and ?template= are mutually exclusive");return ij(t.dal,i,o).map(l=>Ew(t.dal,l))}if(e.method==="GET"&&s.length===3&&s[0]==="runtime"&&s[1]==="runs"){bs(e,n.id);let i=ww(t.dal,s[2]);return Ew(t.dal,i)}if(e.method==="GET"&&s.length===4&&s[0]==="runtime"&&s[1]==="runs"&&s[3]==="events"){bs(e,n.id);let i=ww(t.dal,s[2]),o=aj(t.dal,i);return{runId:Bd(i),events:o,...o.length>0?{cursor:o[o.length-1].id}:{}}}throw new se(404,`unknown runtime request: ${e.method} ${r.pathname}`)}function KM(e,t){return{id:t.id,name:t.name,projects:e.listProjects().map(r=>Sw(e,t,r))}}function mw(e,t,r){let n=Sw(e,t,r);return{...n,managedWorkflow:{...n.managedWorkflow,instance:YM(e,r),composerTarget:{kind:"workflow-initial",label:`Project Workflow: ${r.workflow_name}`,templateId:`template:${r.workflow_name}`,runId:n.managedWorkflow.runId}},workflowMessages:zM(e,r)}}function Sw(e,t,r){let n=vw(e,r.id),s=Fd(n);return{id:r.name,workspaceId:t.id,name:r.name,...r.description===null?{}:{description:r.description},status:s,managedWorkflow:{templateId:`template:${r.workflow_name}`,templateName:r.workflow_name,runId:n===null?`project:${r.id}:no-run`:`run:${n.id}`,status:s}}}function YM(e,t){let r=vw(e,t.id),n=r?.current_state??null;return{id:r===null?`project:${t.id}:no-run`:`run:${r.id}`,templateId:`template:${t.workflow_name}`,label:t.workflow_name,status:Fd(r),currentStepIds:n===null?[]:[n],...r?.started_at===void 0?{}:{createdAt:r.started_at},...r?.ended_at===null||r?.ended_at===void 0?{}:{updatedAt:r.ended_at}}}function zM(e,t){return e.query("SELECT * FROM attention WHERE project_id = ? ORDER BY id ASC LIMIT 50",t.id).map(n=>({id:`attention:${n.id}`,role:"event",author:"lmctl",timestamp:n.created_at,body:n.kind}))}function ZM(e,t,r){let n=QM(e,t.id);if(n!==null){let s=Ho(e,n.id);if(s?.kind==="workflow_escalation"){let i=e.resumeEscalation(s.attention_id,r);if(!i.resumed)throw new se(409,`workflow escalation resume failed: ${i.reason}`);return}if(s?.kind==="interactive_waiting_operator"){let i=kt(e,s.attention_id);if(i?.step_id===null||i?.step_id===void 0)throw new se(409,"interactive resume failed: missing step");let o=e.resumeInteractive(i.step_id,r,!0);if(!o.resumed)throw new se(409,`interactive resume failed: ${o.reason}`);return}}e.enqueueJob({project_id:t.id,source:"runtime-workflow-message",payload:JSON.stringify({prompt:r}),priority:0})}function vw(e,t){return e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? ORDER BY r.id DESC LIMIT 1",t)[0]??null}function QM(e,t){return e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? AND r.terminal_state IS NULL ORDER BY r.id DESC LIMIT 1",t)[0]??null}function Fd(e){return e===null?"queued":e.terminal_state===null?"running":e.terminal_state==="done"||e.terminal_state==="success"?"succeeded":e.terminal_state==="cancelled"||e.terminal_state==="aborted"?"cancelled":"failed"}function pw(e,t){let r=e.findProjectByName(t);if(r===null)throw new se(404,`project not found: ${t}`);return r}function _w(e,t){let r=e.listTeams().find(n=>n.name===t);if(r===void 0)throw new se(404,`team not found: ${t}`);return r}function hw(e){return e.startsWith("team:")?e.slice(5):e}function ej(e){return{id:`team:${e.name}`,name:e.name,teamfile:"",hasLead:!0,kind:e.name.toLowerCase().includes("manager")?"global-manager":"custom-ai-led"}}function gw(e,t,r){let n=new Date().toISOString(),s=r===void 0?[]:[{id:`lead:${e.id}:user:${Date.now()}`,role:"user",author:"operator",timestamp:n,body:r},{id:`lead:${e.id}:event:${Date.now()}`,role:"event",author:"lmctl",timestamp:n,body:"Lead-team mailbox request accepted by the runtime dispatcher."}];return{id:`lead-chat:${e.name}:${t?.scope??"global-admin"}:${t?.workspaceId??Tw}`,teamId:`team:${e.name}`,title:`${e.name} Lead`,messages:s,...t===void 0?{}:{context:t}}}function tj(e){let t=e.workspaceName??jt()??br.default;return{id:t,name:t}}function Dd(e){if(e.headers.get("x-lmctl-workspace-id")!==Tw)throw new se(400,"runtime request requires global-admin workspace identity")}function Xo(e,t,r){let n=e.headers.get("x-lmctl-workspace-id");if(n===null)throw new se(400,"runtime request requires workspace identity");if(r!==t||n!==t)throw new se(400,"runtime workspace identity does not match route")}function bs(e,t){let r=e.headers.get("x-lmctl-workspace-id");if(r===null)throw new se(400,"runtime request requires workspace identity");if(r!==t)throw new se(400,"runtime workspace identity does not match server workspace")}function yw(e,t,r){if(r?.scope==="workspace"){if(r.workspaceId===void 0)throw new se(400,"workspace manager context requires workspace identity");Xo(e,t,r.workspaceId);return}Dd(e)}function Ud(e){return`${En}${Wd(e.name)}`}function Wd(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"item"}function Bd(e){return`${Pd}${e.id}`}function rj(e){let t=Go(e.definition);return{id:Ud(e),name:e.name,...t.description===null?{}:{description:t.description}}}function nj(e){let t=Go(e.definition);return{id:Ud(e),name:e.name,...t.description===null?{}:{description:t.description},graph:t.graph}}function Go(e){let t;try{t=JSON.parse(e)}catch{return{description:null,graph:null,stepIds:[],nameToId:new Map}}if(t===null||typeof t!="object")return{description:null,graph:t,stepIds:[],nameToId:new Map};let r=t,n=typeof r.description=="string"?r.description:null,s=[],i=new Map;if(r.schema_version==="lmctl/v3"&&Array.isArray(r.steps)){let o=typeof r.entry_step_id=="string"?r.entry_step_id:null;for(let a of r.steps){let l=typeof a.id=="string"?a.id:null;l!==null&&(s.push(l),typeof a.name=="string"&&a.name.length>0&&i.set(a.name,l))}o!==null&&s.includes(o)&&s.sort((a,l)=>a===o?-1:l===o?1:0)}return{description:n,graph:t,stepIds:s,nameToId:i}}function sj(e,t){if(!t.startsWith(En))throw new se(404,`template not found: ${t}`);let r=t.slice(En.length),n=e.listWorkflows().filter(s=>Wd(s.name)===r);if(n.length===0)throw new se(404,`template not found: ${t}`);if(n.length>1){let s=n.map(i=>i.name).join(", ");throw new se(409,`template_id_ambiguous: ${t} matches multiple workflow names [${s}]; rename to ensure unique slugs`)}return n[0]}function ww(e,t){if(!t.startsWith(Pd))throw new se(404,`run not found: ${t}`);let r=t.slice(Pd.length);if(!/^[1-9]\d*$/.test(r))throw new se(404,`run not found: ${t}`);let n=Number.parseInt(r,10);if(!Number.isFinite(n)||n<=0||String(n)!==r)throw new se(404,`run not found: ${t}`);let s=e.getRun(n);if(s===null)throw new se(404,`run not found: ${t}`);return s}function ij(e,t,r){if(r!==null){if(!r.startsWith(En))return[];let s=r.slice(En.length),i=e.listWorkflows().filter(a=>Wd(a.name)===s).map(a=>a.id);if(i.length===0)return[];let o=i.map(()=>"?").join(", ");return e.query(`SELECT * FROM run WHERE workflow_id IN (${o}) ORDER BY id DESC LIMIT 200`,...i)}if(t===null)return e.query("SELECT * FROM run ORDER BY id DESC LIMIT 200");let n=e.findProjectByName(t);return n===null?[]:e.query("SELECT r.* FROM run r JOIN job j ON j.id = r.job_id WHERE j.project_id = ? ORDER BY r.id DESC LIMIT 200",n.id)}function Ew(e,t){let r=e.getWorkflow(t.workflow_id),n=Fd(t),s=oj(r,t);return{id:Bd(t),templateId:r===null?`${En}unknown`:Ud(r),label:r===null?`run ${t.id}`:`${r.name} #${t.id}`,status:n,createdAt:t.started_at,...t.ended_at===null?{}:{updatedAt:t.ended_at},currentStepIds:s}}function oj(e,t){if(t.current_state===null)return[];let r=t.current_state.startsWith("__paused__:")?t.current_state.slice(11):t.current_state;return e===null?[r]:[Go(e.definition).nameToId.get(r)??r]}function aj(e,t){let r=e.getWorkflow(t.workflow_id),n=r===null?{stepIds:[],nameToId:new Map}:Go(r.definition),s=c=>n.nameToId.get(c)??c,i=Bd(t),o=[];o.push({timestamp:t.started_at,type:"run.started",message:"Run started"});let a=e.listStepsForRun(t.id);for(let c of a){let d=s(c.state_name);if(o.push({timestamp:c.started_at,type:"step.started",stepId:d,message:`step ${c.state_name} started`}),c.ended_at!==null){let u=lj(c);o.push({timestamp:c.ended_at,type:u,stepId:d,...c.outcome===null?{}:{message:c.outcome},...c.status_detail===null?{}:{payload:{status_detail:c.status_detail}}})}else t.paused_at!==null&&c.id===a[a.length-1]?.id&&o.push({timestamp:t.paused_at,type:"step.paused",stepId:d})}let l=e.listSessionEvents(t.id);for(let c of l){let d=c.step_id===null?void 0:(()=>{let m=a.find(p=>p.id===c.step_id);return m===void 0?void 0:s(m.state_name)})(),u=new Date(c.timestamp_ms).toISOString(),f={kind:c.kind,session_event_id:c.id};if(c.payload.length>0)try{let m=JSON.parse(c.payload);m!==null&&typeof m=="object"&&!Array.isArray(m)&&(f={...f,...m})}catch{}o.push({timestamp:u,type:"message",...d===void 0?{}:{stepId:d},payload:f})}if(t.terminal_state!==null){let c=t.terminal_state==="done"||t.terminal_state==="success"?"run.completed":t.terminal_state==="cancelled"||t.terminal_state==="aborted"?"run.cancelled":"run.failed";o.push({timestamp:t.ended_at??t.started_at,type:c,message:t.terminal_state})}return o.sort((c,d)=>c.timestamp.localeCompare(d.timestamp)),o.map((c,d)=>({id:`${i}:evt:${d+1}`,runId:i,sequence:d+1,timestamp:c.timestamp,type:c.type,...c.stepId===void 0?{}:{stepId:c.stepId},...c.message===void 0?{}:{message:c.message},...c.payload===void 0?{}:{payload:c.payload}}))}function lj(e){if(e.outcome===null)return"step.failed";let t=e.status_detail;return t==="failed"||t==="error"||t==="aborted"?"step.failed":"step.completed"}var Tw,En,Pd,se,kw=T(()=>{"use strict";Je();Jo();Bt();Tw="global-admin";En="template:",Pd="run:";se=class extends Error{status;constructor(t,r){super(r),this.status=t}}});import{mkdirSync as cj,writeFileSync as dj}from"node:fs";import{randomUUID as Iw}from"node:crypto";import{dirname as uj,resolve as Vo,sep as Nw}from"node:path";async function Aw(e,t){let r;try{r=await e.req.parseBody({all:!1})}catch{return e.text("invalid multipart body",400)}let n=r.image;if(!hj(n))return e.text("missing image file",400);if(n.size>fj)return e.text("upload too large",413);let s=Buffer.from(await n.arrayBuffer()),i=gj(s);if(i===null||!(i in xw))return e.text("unsupported upload MIME type",415);if(n.type.length>0&&n.type!==i)return e.text("upload MIME type does not match file content",415);let o=mj(t,r.project);if(typeof o=="string")return e.text(o,404);let a=o===null?Vo(_j()):Vo(o.local_path),l=Vo(a,"uploads",Iw()),c=Vo(l,`${Iw()}${xw[i]}`);if(!pj(c,a))return e.text("invalid upload path",400);cj(l,{recursive:!0});let d=new Uint8Array(s.buffer,s.byteOffset,s.byteLength);dj(c,d);let u={path:c,size:s.byteLength,mime:i,project:o?.name??null};return e.json(u)}function mj(e,t){return t==null||t===""?null:typeof t!="string"?"invalid project":e.findProjectByName(t)??`project not found: ${t}`}function pj(e,t){let r=t.endsWith(Nw)?t:`${t}${Nw}`;return e.startsWith(r)}function _j(){return uj(le())}function hj(e){return typeof File<"u"&&e instanceof File}function gj(e){return e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71&&e[4]===13&&e[5]===10&&e[6]===26&&e[7]===10?"image/png":e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?"image/jpeg":e.length>=12&&e.subarray(0,4).toString("ascii")==="RIFF"&&e.subarray(8,12).toString("ascii")==="WEBP"?"image/webp":e.length>=12&&e.subarray(4,8).toString("ascii")==="ftyp"&&["heic","heix","hevc","hevx","mif1","msf1"].includes(e.subarray(8,12).toString("ascii"))?"image/heic":e.length>=5&&e.subarray(0,5).toString("ascii")==="%PDF-"?"application/pdf":null}var fj,xw,Rw=T(()=>{"use strict";Je();fj=10*1024*1024,xw={"image/png":".png","image/jpeg":".jpg","image/webp":".webp","image/heic":".heic","application/pdf":".pdf"}});import{existsSync as Ko}from"node:fs";import{basename as yj,dirname as wj,extname as Ej,isAbsolute as Tj,join as bj,relative as Sj}from"node:path";import{fileURLToPath as vj}from"node:url";import{Hono as kj}from"hono";import{serveStatic as Nt}from"@hono/node-server/serve-static";function Dw(e){let t=new kj,r=[],n=e.localWebui!==void 0?Hd(e.localWebui.webuiDir):Ij();if(e.localWebui!==void 0&&By(t,{s3:e.localWebui.localMailbox.s3,commands:e.localWebui.localMailbox.commands}),n!==null){let s=Nj();e.localWebui!==void 0?t.get("/config.json",s,i=>i.json({workspaceFetchMode:"local-mailbox",localMailbox:{base:"/local-mailbox",userId:"local",deviceId:"local"},mailboxPolling:{readIntervalSeconds:1,heartbeatIdleSeconds:1,backoffReadIntervalSeconds:1}})):e.webuiRuntimeConfig!==void 0&&t.get("/config.json",s,i=>i.json(e.webuiRuntimeConfig)),t.use("/dist/*",s,Nt({root:n})),t.use("/vendor/*",s,Nt({root:n})),t.use("/src/*",s,Nt({root:n})),t.get("/",s,Nt({root:n,path:"index.html"})),t.get("/admin",s,Nt({root:n,path:"index.html"})),t.get("/admin/*",s,Nt({root:n,path:"index.html"})),t.get("/terminal",s,Nt({root:n,path:"index.html"})),t.get("/terminal/*",s,Nt({root:n,path:"index.html"})),t.get("/chat",s,Nt({root:n,path:"index.html"})),t.get("/chat/*",s,Nt({root:n,path:"index.html"}))}else t.get("/",s=>s.html('<!doctype html><meta charset="utf-8"><title>lmctl</title><body style="font-family:system-ui;max-width:40rem;margin:4rem auto;padding:0 1rem;line-height:1.5"><h1>lmctl daemon</h1><p>This build does not bundle the local web console; the HTTP API is running on this port.</p><p>Open the hosted console at <a href="https://lmctl.ai/">https://lmctl.ai/</a> \u2014 it connects to this daemon via the cloud mailbox.</p></body>'));return t.use("*",yh({disabled:e.authDisabled})),t.get("/login",s=>s.html(Re("Login",`
1959
1960
  <h1>Login</h1>
1960
1961
  <form method="post" action="/login">
1961
1962
  <label>Token <input name="token" type="password"></label>
@@ -2055,14 +2056,15 @@ ${e.receipt}`:`relay delivery error: ${e.error}`}function HD(e,t){let r=t.LMCTL_
2055
2056
  `)}let a=r.noDaemon?void 0:AE({dal:n,intervalMs:vs()}),l=o!==void 0?{missing:[],tfstateCandidatesChecked:[]}:As({env:process.env});l.missing.length>0&&t.stderr.write(`[lmctl-next-agent] mailbox transport not configured: missing ${l.missing.join(", ")}; running without cloud sync`+(l.tfstatePathUsed===void 0?` (no terraform.tfstate found; checked ${l.tfstateCandidatesChecked.length} candidate path${l.tfstateCandidatesChecked.length===1?"":"s"})`:` (terraform.tfstate at ${l.tfstatePathUsed} did not supply the missing fields)`)+`
2056
2057
  `);let c=await nF({log:y=>t.stderr.write(`${y}
2057
2058
  `)}),d=new qo({adapterFactory:IT,publish:async()=>{throw new Error("persistent_publish_not_wired: mailbox runtime has not bound the publish hook yet")},log:y=>t.stderr.write(`${y}
2058
- `)}),u=Ur()?.device_id,f=Dw({dal:n,daemon:a,...l.config!==void 0?{webuiRuntimeConfig:tF(l.config,u)}:{},...c!==void 0?{terminalSessionManager:c}:{},persistentSessionManager:d,...o!==void 0?{localWebui:{webuiDir:o.webuiDir,localMailbox:{s3:o.s3,commands:o.commands}}}:{}}),m=process.env.LMCTL_USAGE_QUOTA_USD,p=m!==void 0&&m!==""?Number(m):NaN,h=Number.isFinite(p)&&p>0?p:void 0,g=await OT({dal:n,app:f,io:t,mailbox:l.config===void 0?void 0:{...l.config,cursorStore:n,chatLogTailStore:n,promptTriggerStore:n,usageStore:n,...h!==void 0?{usageQuotaUsd:h}:{},...u!==void 0?{deviceId:u}:{}},...o!==void 0?{localMailbox:{rootDir:o.rootDir,s3:o.s3,commands:o.commands,promptTriggerStore:n}}:{},...c!==void 0?{terminalSessionManager:c}:{},persistentSessionManager:d});await $T({dal:n,mailbox:g.mailbox,io:t});let{serve:_}=await import("@hono/node-server"),S=_({fetch:f.fetch,port:i.port,hostname:r.bind});return t.stdout.write(`listening on ${r.bind}:${i.port}
2059
+ `)}),u=Ur()?.device_id,f=Dw({dal:n,daemon:a,...l.config!==void 0?{webuiRuntimeConfig:tF(l.config,u)}:{},...c!==void 0?{terminalSessionManager:c}:{},persistentSessionManager:d,...o!==void 0?{localWebui:{webuiDir:o.webuiDir,localMailbox:{s3:o.s3,commands:o.commands}}}:{},authDisabled:r.insecureNoAuth}),m=process.env.LMCTL_USAGE_QUOTA_USD,p=m!==void 0&&m!==""?Number(m):NaN,h=Number.isFinite(p)&&p>0?p:void 0,g=await OT({dal:n,app:f,io:t,mailbox:l.config===void 0?void 0:{...l.config,cursorStore:n,chatLogTailStore:n,promptTriggerStore:n,usageStore:n,...h!==void 0?{usageQuotaUsd:h}:{},...u!==void 0?{deviceId:u}:{}},...o!==void 0?{localMailbox:{rootDir:o.rootDir,s3:o.s3,commands:o.commands,promptTriggerStore:n}}:{},...c!==void 0?{terminalSessionManager:c}:{},persistentSessionManager:d});await $T({dal:n,mailbox:g.mailbox,io:t});let{serve:_}=await import("@hono/node-server"),S=_({fetch:f.fetch,port:i.port,hostname:r.bind});return t.stdout.write(`listening on ${r.bind}:${i.port}
2059
2060
  `),await new Promise(y=>{let w=()=>{(async()=>(a!==void 0&&await a.stop(),S.close(),await g.stop(),c!==void 0&&await c.stop(),await d.stop(),n.close(),y()))()};process.once("SIGTERM",w),process.once("SIGINT",w)}),0}function tF(e,t){return{identityPoolId:e.identityPoolId,cognitoUserPoolId:e.cognitoUserPoolId,cognitoRegion:e.region,mailboxBucket:e.mailboxBucket,workspaceFetchMode:"mailbox",...t!==void 0?{deviceId:t}:{},...e.mailboxKey!==void 0?{mailboxKey:e.mailboxKey}:{},mailboxPolling:{...e.readIntervalMs!==void 0?{readIntervalSeconds:e.readIntervalMs/1e3}:{},...e.heartbeatIdleMs!==void 0?{heartbeatIdleSeconds:e.heartbeatIdleMs/1e3}:{},...e.backoffReadIntervalMs!==void 0?{backoffReadIntervalSeconds:e.backoffReadIntervalMs/1e3}:{}}}}async function $T(e){if(e.mailbox===void 0)return;let t={kind:"daemon_event",event:"workflows",ts:Date.now(),workflows:e.dal.listRootTeams().map(r=>({teamfile_path:r.teamfile_path,name:r.name,registered_at:r.registered_at,last_seeded_at:r.last_seeded_at}))};try{await e.mailbox.publishDaemonEvent(t)}catch(r){e.io?.stderr.write(`[mailbox] daemon_event workflows push failed: ${r instanceof Error?r.message:String(r)}
2060
2061
  `)}}async function OT(e){let t;if(e.mailbox!==void 0||e.localMailbox!==void 0)try{t=e.localMailbox!==void 0?await vT({...e.localMailbox,log:r=>e.io?.stderr.write(`${r}
2061
2062
  `),...e.terminalSessionManager!==void 0?{terminalSessionManager:e.terminalSessionManager}:{},...e.persistentSessionManager!==void 0?{persistentSessionManager:e.persistentSessionManager}:{}}):await ST({...e.mailbox,log:r=>e.io?.stderr.write(`${r}
2062
2063
  `),...e.terminalSessionManager!==void 0?{terminalSessionManager:e.terminalSessionManager}:{},...e.persistentSessionManager!==void 0?{persistentSessionManager:e.persistentSessionManager}:{}}),t.fetchClient.onRequest(hh({app:e.app,log:r=>e.io?.stderr.write(`${r}
2063
2064
  `)})),e.io?.stderr.write(`[mailbox] dg-2 agent runtime started (identity=${t.identityId})
2064
2065
  `)}catch(r){let n=r instanceof Error?r.message:String(r);e.io?.stderr.write(`[mailbox] dg-2 agent runtime NOT started: ${n}
2065
- `)}return{...t!==void 0?{mailbox:t}:{},async stop(){t!==void 0&&await t.stop()}}}function CT(e){let{dal:t,cli:r,env:n,parsed:s,io:i}=e,o=[],a,l=t.getConfig("api.port");if(r.portCli!==void 0)a=r.portCli;else if(l!==null){let m=Number(l);if(!Number.isInteger(m)||m<=0||m>65535)throw new Error(`invalid api.port in lmctl_config: ${l}`);a=m}else if(n.LMCTL_API_PORT!==void 0&&n.LMCTL_API_PORT.length>0){let m=Number(n.LMCTL_API_PORT);if(!Number.isInteger(m)||m<=0||m>65535)throw new Error(`invalid LMCTL_API_PORT: ${n.LMCTL_API_PORT}`);a=m,o.push("api.port")}else a=s.port;let c,d=t.getConfig("api.token");d!==null?c=d:n.LMCTL_API_TOKEN!==void 0&&n.LMCTL_API_TOKEN.length>0?(c=n.LMCTL_API_TOKEN,o.push("api.token")):(c=YP(32).toString("hex"),t.setConfig("api.token",c),i.stdout.write("Generated initial api.token; view via `lmctl api config get api.token`\n"));let u,f=t.getConfig("api.url");f!==null?u=f:n.LMCTL_API_URL!==void 0&&n.LMCTL_API_URL.length>0?(u=n.LMCTL_API_URL,o.push("api.url")):(u=`http://127.0.0.1:${a}`,t.setConfig("api.url",u));for(let m of o)i.stderr.write(`note: ${rF(m)} env var used as fallback for ${m}; consider \`lmctl api config set ${m} ...\` to make this DB-canonical.
2066
+ `)}return{...t!==void 0?{mailbox:t}:{},async stop(){t!==void 0&&await t.stop()}}}function CT(e){let{dal:t,cli:r,env:n,parsed:s,io:i}=e,o=[],a,l=t.getConfig("api.port");if(r.portCli!==void 0)a=r.portCli;else if(l!==null){let m=Number(l);if(!Number.isInteger(m)||m<=0||m>65535)throw new Error(`invalid api.port in lmctl_config: ${l}`);a=m}else if(n.LMCTL_API_PORT!==void 0&&n.LMCTL_API_PORT.length>0){let m=Number(n.LMCTL_API_PORT);if(!Number.isInteger(m)||m<=0||m>65535)throw new Error(`invalid LMCTL_API_PORT: ${n.LMCTL_API_PORT}`);a=m,o.push("api.port")}else a=s.port;let c,d=t.getConfig("api.token");n.LMCTL_API_TOKEN!==void 0&&n.LMCTL_API_TOKEN.length>0?(c=n.LMCTL_API_TOKEN,d===null?o.push("api.token"):d!==c&&i.stderr.write(`note: LMCTL_API_TOKEN env var overrides lmctl_config api.token for this serve process.
2067
+ `)):d!==null?c=d:(c=YP(32).toString("hex"),t.setConfig("api.token",c),i.stdout.write("Generated initial api.token; view via `lmctl api config get api.token`\n"));let u,f=t.getConfig("api.url");f!==null?u=f:n.LMCTL_API_URL!==void 0&&n.LMCTL_API_URL.length>0?(u=n.LMCTL_API_URL,o.push("api.url")):(u=`http://127.0.0.1:${a}`,t.setConfig("api.url",u));for(let m of o)i.stderr.write(`note: ${rF(m)} env var used as fallback for ${m}; consider \`lmctl api config set ${m} ...\` to make this DB-canonical.
2066
2068
  `);return{port:a,apiUrl:u,apiToken:c}}function rF(e){switch(e){case"api.port":return"LMCTL_API_PORT";case"api.token":return"LMCTL_API_TOKEN";case"api.url":return"LMCTL_API_URL";default:return`LMCTL_${e.replaceAll(".","_").toUpperCase()}`}}async function nF(e){let t;try{t=await import("node-pty")}catch(r){let n=r instanceof Error?r.message:String(r);e.log(`[dt-2] node-pty not available; terminal routes will return 503 (${n})`);return}return new Bo({pty:{spawn:t.spawn.bind(t)},publish:async()=>{throw new Error("terminal_publish_not_wired: mailbox runtime has not bound the publish hook yet")},log:e.log})}function sF(e){MT=e??Nu}function jT(e){let t=Object.keys(_a),r=MT(t),n=r.filter(i=>!i.found);if(n.length>0){for(let i of n)e.stderr.write(`error: ${AT(i)}
2067
2069
  `);throw e.stderr.write(`error: agent refusing to start; ensure missing provider CLIs are on PATH
2068
2070
  `),new ha(n)}let s=r.map(i=>i.provider).join(", ");e.stdout.write(`providers ready: ${s}
@@ -2076,6 +2078,10 @@ services. Help exits before any port binding or daemon startup.
2076
2078
  against the local filesystem (no S3, no Cognito) with a fixed
2077
2079
  local identity. Mailbox store defaults to
2078
2080
  ~/.lmctl/local-mailbox/ ($LMCTL_LOCAL_MAILBOX_DIR overrides).
2081
+
2082
+ Daemon state: lmctl api daemon state reads /api/daemon/state. Authenticate
2083
+ with LMCTL_API_TOKEN=<token> or run serve with --insecure-no-auth for a local
2084
+ unauthenticated daemon.
2079
2085
  `;ha=class extends Error{missing;constructor(t){let r=t.map(n=>n.provider).join(", ");super(`provider binary pre-flight failed: ${r}`),this.name="ProviderBinaryPreflightError",this.missing=t}},MT=Nu});import{existsSync as aF,mkdirSync as lF,readFileSync as cF,renameSync as dF,unlinkSync as uF,writeFileSync as fF}from"node:fs";import{homedir as qT}from"node:os";import{dirname as Rs,join as pt,resolve as mF}from"node:path";function Nn(e,t,r){let n=Rs(mF(r)),s=new Set,i=new Map;for(let o of t.members){if(s.add(o.provider),o.teamfile!==void 0)continue;let a=o.sessiondir??n,l=i.get(a)??new Set;l.add(o.provider),i.set(a,l)}for(let[o,a]of i.entries())gr(pt(o,".mcp.json"),"mcpServers",[vn(),kn()]),a.has("opencode")&&gr(pt(o,".opencode","opencode.json"),"mcp",[XT(),GT()]);for(let o of s)gF(o)}function JT(e=HT??qT()){return pt(e,".copilot","mcp-config.json")}function _F(e,t){rt.mkdirSync(Rs(e),{recursive:!0});let r=pt(Rs(e),`.mcp-config.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);try{rt.writeFileSync(r,`${JSON.stringify(t,null,2)}
2080
2086
  `,"utf8"),rt.renameSync(r,e)}catch(n){try{rt.unlinkSync(r)}catch{}throw n}}function hF(e,t){rt.mkdirSync(Rs(e),{recursive:!0});let r=pt(Rs(e),`.mcp-config.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);try{rt.writeFileSync(r,t,"utf8"),rt.renameSync(r,e)}catch(n){try{rt.unlinkSync(r)}catch{}throw n}}function gr(e,t,r){try{if(!rt.existsSync(e))return;let n=JSON.parse(rt.readFileSync(e,"utf8"));if(!In(n)||!In(n[t]))return;let s={...n[t]},i=[];for(let{name:o,shouldRemove:a}of r)Object.prototype.hasOwnProperty.call(s,o)&&a(s[o])&&(delete s[o],i.push(o));if(i.length===0)return;n[t]=s,_F(e,n),H({event:"mcp_cleanup",path:e,removed:i})}catch{}}function vn(){return{name:ya,shouldRemove:kF}}function XT(){return{name:ya,shouldRemove:IF}}function kn(){return{name:ga,shouldRemove:SF}}function GT(){return{name:ga,shouldRemove:vF}}function gF(e){let t=HT??qT();switch(e){case"copilot":gr(JT(t),"mcpServers",[vn(),kn()]);return;case"claude":gr(pt(t,".claude.json"),"mcpServers",[vn(),kn()]);return;case"gemini":gr(pt(t,".gemini","settings.json"),"mcpServers",[vn(),kn()]);return;case"qwen":gr(pt(t,".qwen","settings.json"),"mcpServers",[vn(),kn()]);return;case"agy":gr(pt(t,".gemini","antigravity-cli","settings.json"),"mcpServers",[vn(),kn()]);return;case"opencode":gr(pt(t,".config","opencode","opencode.json"),"mcp",[XT(),GT()]);return;case"codex":yF(pt(t,".codex","config.toml"));return;default:return}}function yF(e){try{if(!rt.existsSync(e))return;let t=rt.readFileSync(e,"utf8"),r=wF(t);if(r===null)return;let n=t.split(/\n/),s=[],i=new Set,o=!1,a;for(let l of n){let c=VT(l);if(c===null)return;if(c!==void 0){if(BT(c,r)){o=!0,a=c[1],i.add(a);continue}o=!1,a=void 0,s.push(l);continue}if(o){if(/^\s*(?:#.*)?$/.test(l)){s.push(l);continue}a!==void 0&&i.add(a);continue}let d=TF(l);if(d===null)return;if(d!==void 0&&BT(d,r)){i.add(d[1]);continue}s.push(l)}if(i.size===0)return;hF(e,s.join(`
2081
2087
  `)),H({event:"mcp_cleanup",path:e,removed:[...i]})}catch{}}function BT(e,t){return e.length<2||e[0]!=="mcp_servers"?!1:t.has(e[1])}function wF(e){let t=new Map,r;for(let s of e.split(/\n/)){let i=VT(s);if(i===null)return null;if(i!==void 0){r=i;continue}let o=s.indexOf("=");if(o<0)continue;let a=s.slice(0,o).trim(),l=s.slice(o+1).trim(),c=EF(a,r);if(c===null)return null;if(c===void 0||c.length!==3||c[0]!=="mcp_servers"||c[1]!==ga&&c[1]!==ya)continue;let d=t.get(c[1])??{};if(c[2]==="command"){let u=KT(l);if(u===null)return null;d.command=u}else if(c[2]==="args"){let u=bF(l);if(u===null)return null;d.args=u}t.set(c[1],d)}let n=new Set;for(let[s,i]of t.entries())s===ga&&zT(i.command,i.args)&&n.add(s),s===ya&&ZT(i.command,i.args)&&n.add(s);return n}function EF(e,t){if(e.startsWith("mcp_servers"))return wa(e);if(t===void 0||t.length<2||t[0]!=="mcp_servers")return;let r=wa(e);return r===null?null:[...t,...r]}function VT(e){if(!/^\s*\[/.test(e))return;let t=/^\s*\[([^\]\r\n]+)\]\s*(?:#.*)?$/.exec(e);return t===null?null:wa(t[1])}function TF(e){let t=e.indexOf("=");if(t<0)return;let r=e.slice(0,t).trim();if(!(r.length===0||!r.startsWith("mcp_servers")))return wa(r)}function wa(e){let t=[],r=0,n=()=>{for(;r<e.length&&/\s/.test(e[r]);)r+=1};for(;r<e.length;){if(n(),r>=e.length)return null;if(e[r]==='"'){r+=1;let s="",i=!1;for(;r<e.length;){let o=e[r];if(o==="\\"){if(r+1>=e.length)return null;s+=e[r+1],r+=2;continue}if(o==='"'){r+=1,i=!0;break}s+=o,r+=1}if(!i)return null;t.push(s)}else{let s=r;for(;r<e.length&&/[A-Za-z0-9_-]/.test(e[r]);)r+=1;if(r===s)return null;t.push(e.slice(s,r))}if(n(),r>=e.length)break;if(e[r]!==".")return null;r+=1}return t.length>0?t:null}function KT(e){let t=YT(e).trim();if(t.startsWith('"'))try{let r=JSON.parse(t);return typeof r=="string"?r:null}catch{return null}return t.startsWith("'")&&t.endsWith("'")&&t.length>=2?t.slice(1,-1):null}function bF(e){let t=YT(e).trim();if(!t.startsWith("[")||!t.endsWith("]"))return null;let r=t.slice(1,-1).trim();if(r.length===0)return[];let n=r.split(",").map(s=>KT(s.trim()));return n.some(s=>s===null)?null:n}function YT(e){let t;for(let r=0;r<e.length;r+=1){let n=e[r];if(t!==void 0){if(t==='"'&&n==="\\"){r+=1;continue}n===t&&(t=void 0);continue}if(n==='"'||n==="'"){t=n;continue}if(n==="#")return e.slice(0,r)}return e}function SF(e){return In(e)?e.type==="stdio"&&typeof e.command=="string"&&zT(e.command,e.args):!1}function vF(e){return!In(e)||!Array.isArray(e.command)?!1:e.command.length===2&&typeof e.command[0]=="string"&&typeof e.command[1]=="string"&&eb(e.command[0])&&e.command[1]==="mcp"||e.command.length===3&&typeof e.command[0]=="string"&&typeof e.command[1]=="string"&&typeof e.command[2]=="string"&&QT(e.command[0],[e.command[1],e.command[2]])}function kF(e){return In(e)?e.type==="stdio"&&ZT(e.command,e.args):!1}function IF(e){return!In(e)||!Array.isArray(e.command)?!1:e.command.length===2&&typeof e.command[0]=="string"&&typeof e.command[1]=="string"&&tb(e.command[0])&&e.command[1]==="mcp"}function zT(e,t){return eb(e)&&rb(t)||QT(e,t)}function ZT(e,t){return tb(e)&&rb(t)}function QT(e,t){return NF(e)&&Array.isArray(t)&&t.length===2&&xF(t[0])&&t[1]==="mcp"}function eb(e){return typeof e=="string"&&Au(e)==="lmctl"}function tb(e){return typeof e=="string"&&Au(e)==="lmctl0"}function NF(e){if(typeof e!="string")return!1;let t=Au(e).toLowerCase();return t==="node"||t==="node.exe"}function xF(e){if(typeof e!="string")return!1;let t=e.replace(/\\/g,"/");return t==="lmctl-cli/dist/index.js"||t.endsWith("/lmctl-cli/dist/index.js")}function Au(e){let t=e.replace(/\\/g,"/");return t.split("/").filter(n=>n.length>0).at(-1)??t}function rb(e){return Array.isArray(e)&&e.length===1&&e[0]==="mcp"}function In(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}var ga,ya,pF,rt,HT,Ls=T(()=>{"use strict";he();ga="lmctl",ya="lmctl0",pF={existsSync:aF,mkdirSync:lF,readFileSync:cF,writeFileSync:fF,renameSync:dF,unlinkSync:uF},rt=pF});function ib(e){let t=nb(e.registry,e.fromTeamfile);if(t===void 0)return xn(`sender team is not registered in policy graph: ${e.fromTeamfile}`);if(!sb(t,e.fromAlias))return xn(`sender alias "${e.fromAlias}" not found in ${e.fromTeamfile}`);let r=nb(e.registry,e.toTeamfile);return r===void 0?xn(`target team is not registered in policy graph: ${e.toTeamfile}`):sb(r,e.toAlias)?e.toTeamfile===e.fromTeamfile?{allowed:!0,outOfPolicy:!1,reason:"same team"}:t.leadAlias===null?xn(`sender team has no Lead: ${e.fromTeamfile}`):e.fromAlias!==t.leadAlias?xn(`cross-team sends may only originate from Lead; got "${e.fromAlias}" in ${e.fromTeamfile}`):{allowed:!0,outOfPolicy:!1,reason:"cross-team send from Lead"}:xn(`target alias "${e.toAlias}" not found in ${e.toTeamfile}`)}function nb(e,t){return e.teams.find(r=>r.teamfile===t)}function sb(e,t){return e.aliases.some(r=>r===t)}function xn(e){return{allowed:!1,outOfPolicy:!0,reason:e}}var ob=T(()=>{"use strict"});import{randomUUID as AF}from"node:crypto";import{hostname as ab,networkInterfaces as RF}from"node:os";function lb(e){let t=(e.now??new Date).toISOString();return{lock_id:AF(),teamfile:e.teamfile,alias:e.alias,holder_pid:e.pid??process.pid,holder_host:e.host??ab(),holder_ips:e.ips??MF(),started_at:t,last_heartbeat:t}}function cb(e=process.env){return db(e.LMCTL_TERMINAL_LOCK_HEARTBEAT_MS,LF)}function OF(e=process.env){return db(e.LMCTL_TERMINAL_LOCK_STALE_MS,$F)}function Ru(e,t={}){let r=t.now??new Date,n=t.localHost??ab(),s=t.staleMs??OF();if(e.holder_host===n)return(t.isProcessAlive??CF)(e.holder_pid)?{live:!0,reason:"local-pid-alive"}:{live:!1,reason:"dead-pid"};let i=Date.parse(e.last_heartbeat);return Number.isFinite(i)?r.getTime()-i<=s?{live:!0,reason:"remote-heartbeat-fresh"}:{live:!1,reason:"stale-heartbeat"}:{live:!1,reason:"stale-heartbeat"}}function Lu(e){return`${e.alias} is held by a terminal on ${e.holder_host} since ${e.started_at}; retry later`}function db(e,t){if(e===void 0||e.trim()==="")return t;let r=e.trim(),n=Number.parseInt(r,10);return!Number.isFinite(n)||n<=0||String(n)!==r?t:n}function CF(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(t){return(t!==null&&typeof t=="object"&&"code"in t?t.code:void 0)!=="ESRCH"}}function MF(){let e=new Set;for(let t of Object.values(RF()))for(let r of t??[])r.internal||e.add(r.address);return[...e].sort()}var LF,$F,$u=T(()=>{"use strict";LF=15e3,$F=12e4});function jF(e){return`lmctl ${e}: LMCTL_SELF_SESSIONID is not set \u2014 it looks like you are running lmctl
@@ -2155,7 +2161,7 @@ ${qu}`);if(n.positionals.length>2)return v(t,`unexpected argument: ${n.positiona
2155
2161
  `)}return m.errors>0?1:0}async function w1(e,t,r){return await O(e,n=>{let s=Ee(t,n);if(r!==void 0){let i=Pe(s,n);if(i.parseErrors.length>0)throw new ye(`lmctl: ${t}: ${i.parseErrors.join("; ")}`);let o=na(i,r);return o?.teamfile!==void 0?Hu(Rb(Ab(s),o.teamfile),n,new Set):[He(t,r,n)]}return Hu(s,n,new Set)})}function Hu(e,t,r){let n=Ee(e,t);if(r.has(n))return[];r.add(n);let s=Pe(n,t);if(s.parseErrors.length>0)throw new ye(`lmctl: ${n}: ${s.parseErrors.join("; ")}`);let i=[];for(let o of s.members){if(o.teamfile!==void 0){i.push(...Hu(Rb(Ab(n),o.teamfile),t,r));continue}o.session!==void 0&&i.push(He(n,o.alias,t))}return i}async function E1(e,t,r){let n;try{let a=await _t(t.sessionid,t.provider);if(a===null)return $t(t,"session_not_found",null,"session detail not found");n=Cs(a.messages)}catch(a){return $t(t,"load_error",null,a instanceof Error?a.message:String(a))}if(n===null)return $t(t,"not_limited",null,"no current session-limit marker");if(n.resets_at===null)return $t(t,"unknown_reset",n,"reset time could not be parsed");let s=Date.parse(n.resets_at);if(!Number.isFinite(s))return $t(t,"unknown_reset",n,"reset time could not be parsed");if(s>r.now.getTime())return $t(t,"not_due",n,`resets_at ${n.resets_at} is in the future`);let i=await O(e,a=>a.getAgentInflight(t.teamfile,t.alias));if(i!==null)return $t(t,"busy",n,`in-flight since ${i.started_at}`);if(r.dryRun)return $t(t,"would_recover",n,null);let o=await Sa({teamfile:t.teamfile,alias:t.alias,prompt:g1,permissionMode:"yolo",io:e,env:process.env});return o.status==="ok"||o.status==="stalled"?$t(t,"recovered",n,null):$t(t,o.status==="busy"?"busy":"send_error",n,o.message)}function $t(e,t,r,n){return{alias:e.alias,teamfile:e.teamfile,provider:e.provider,sessionid:e.sessionid,action:t,sessionLimit:r,reason:n}}function T1(e){let t=e.sessionLimit?.resets_at??"unknown",r=e.reason===null?"":` (${e.reason})`;return`${e.alias}: ${e.action} resets_at=${t}${r}
2156
2162
  `}var g1,qu,$b=T(()=>{"use strict";Fu();Br();Vt();Rt();Lt();Pu();Le();g1="Your session limit reset time has passed. Continue your work from the last actionable point.",qu=["usage: lmctl recover <teamfile> [--all|<alias>] [--dry-run] [--json]","","Wake team members whose latest provider output is a session-limit message","and whose resets_at time has passed. Defaults to the full teamfile report","subtree. A busy/in-flight member is skipped."].join(`
2157
2163
  `)});var Ms,s5,Ju=T(()=>{"use strict";Ms=[{name:"lmctl_chat",description:"Synchronous/blocking backup: send one prompt to a member of an AI-managed .lmctl team \u2014 addressed by teamfile path (team) and alias \u2014 and return the reply. This is the only MCP tool lmctl exposes. Prefer the CLI for normal delegation. For async or long-running work, use the provider or host runtime background/task surface around the blocking command.",inputSchema:{type:"object",properties:{team:{type:"string",description:"Path to .lmctl teamfile"},alias:{type:"string",description:"Target alias; omitted means Lead"},prompt:{type:"string",description:"Prompt text to send"}},required:["team","prompt"]},local:!0}],s5=Ms.length});import{spawn as b1}from"node:child_process";async function Cb(e,t,r){let n=v1.get(e);if(n===void 0)return{status:"error",code:404,message:`unknown tool: ${e}`};let s=t!==null&&typeof t=="object"&&!Array.isArray(t)?t:{};for(let i of n.inputSchema.required??[])if(s[i]===void 0)return{status:"error",code:400,message:`missing required parameter: ${i}`};return k1(n.name,s)}function k1(e,t){return e==="lmctl_chat"?I1(t):{status:"error",code:404,message:`unknown local tool: ${e}`}}function I1(e){let t=typeof e.prompt=="string"?e.prompt:"";if(t.length===0)return Promise.resolve({status:"error",code:400,message:"missing required parameter: prompt"});let r=typeof e.team=="string"?e.team:"";if(r.length===0)return Promise.resolve({status:"error",code:400,message:"missing required parameter: team"});let n=typeof e.alias=="string"&&e.alias.length>0?e.alias:"Lead",s=["chat",r,n,t];return ce()&&$e(JSON.stringify({event:"mcp_chat_spawn",team:r,alias:n})),N1(s,process.cwd())}function N1(e,t){return new Promise(r=>{let n=!1,s,i=d=>{n||(n=!0,s!==void 0&&clearTimeout(s),r(d))},o=b1("lmctl",e,{cwd:t,env:process.env,stdio:["ignore","pipe","pipe"]}),a=x1(process.env);s=setTimeout(()=>{try{o.kill("SIGTERM")}catch{}i({status:"error",code:124,message:`lmctl chat timed out after ${a}ms`})},a),s.unref?.();let l="",c="";o.stdout?.on("data",d=>{l+=d.toString("utf8")}),o.stderr?.on("data",d=>{c+=d.toString("utf8")}),o.on("error",d=>{i({status:"error",code:1,message:`failed to spawn lmctl chat: ${d.message}`})}),o.on("exit",d=>{if(d===0){ce()&&$e(JSON.stringify({event:"mcp_chat_payload",bytes:Buffer.byteLength(l,"utf8"),lines:l.split(`
2158
- `).length})),i({status:"ok",data:{text:l.trim()||"(empty response)"}});return}i({status:"error",code:d??1,message:c.trim()||`lmctl chat exited with code ${d}`})})})}function x1(e){let t=e.LMCTL_MCP_CHAT_TIMEOUT_MS;if(t===void 0||t.trim().length===0)return Ob;let r=Number(t);return!Number.isFinite(r)||r<=0?Ob:r}function Xu(e,t=process.env){let n=e.getConfig("api.url")??(t.LMCTL_API_URL!==void 0&&t.LMCTL_API_URL.length>0?t.LMCTL_API_URL:S1),i=e.getConfig("api.token")??(t.LMCTL_API_TOKEN!==void 0&&t.LMCTL_API_TOKEN.length>0?t.LMCTL_API_TOKEN:null);return{baseUrl:n,token:i}}var S1,Ob,v1,Gu=T(()=>{"use strict";Ju();he();S1="http://127.0.0.1:8787",Ob=30*60*1e3,v1=new Map(Ms.map(e=>[e.name,e]))});async function $1(e,t){let r=e.id===void 0,n=e.id??null;if(e.method==="exit")return r||t.io.write(Vu({jsonrpc:"2.0",id:n,result:null})),{kind:"exit"};if(e.method==="initialize")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{protocolVersion:A1,capabilities:{tools:{listChanged:!1}},serverInfo:{name:R1,version:L1}}}};if(e.method==="notifications/initialized")return{kind:"notification"};if(e.method==="shutdown")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:null}};if(e.method==="tools/list")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{tools:Ms.map(s=>({name:s.name,description:s.description,inputSchema:s.inputSchema}))}}};if(e.method==="tools/call"){let s=e.params!==null&&typeof e.params=="object"?e.params:{},i=typeof s.name=="string"?s.name:"",o=s.arguments,a=await Cb(i,o,t.dispatch),l=i==="lmctl_chat"&&a.status==="ok"&&a.data!==null&&typeof a.data=="object"&&typeof a.data.text=="string"?a.data.text:JSON.stringify(a);return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{isError:a.status==="error",content:[{type:"text",text:l}]}}}}return r?{kind:"notification"}:{kind:"response",message:{jsonrpc:"2.0",id:n,error:{code:-32601,message:`method not found: ${e.method}`}}}}function Vu(e){return`${JSON.stringify(e)}
2164
+ `).length})),i({status:"ok",data:{text:l.trim()||"(empty response)"}});return}i({status:"error",code:d??1,message:c.trim()||`lmctl chat exited with code ${d}`})})})}function x1(e){let t=e.LMCTL_MCP_CHAT_TIMEOUT_MS;if(t===void 0||t.trim().length===0)return Ob;let r=Number(t);return!Number.isFinite(r)||r<=0?Ob:r}function Xu(e,t=process.env){let n=e.getConfig("api.url")??(t.LMCTL_API_URL!==void 0&&t.LMCTL_API_URL.length>0?t.LMCTL_API_URL:S1),s=e.getConfig("api.token"),i=t.LMCTL_API_TOKEN!==void 0&&t.LMCTL_API_TOKEN.length>0?t.LMCTL_API_TOKEN:s;return{baseUrl:n,token:i}}var S1,Ob,v1,Gu=T(()=>{"use strict";Ju();he();S1="http://127.0.0.1:8787",Ob=30*60*1e3,v1=new Map(Ms.map(e=>[e.name,e]))});async function $1(e,t){let r=e.id===void 0,n=e.id??null;if(e.method==="exit")return r||t.io.write(Vu({jsonrpc:"2.0",id:n,result:null})),{kind:"exit"};if(e.method==="initialize")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{protocolVersion:A1,capabilities:{tools:{listChanged:!1}},serverInfo:{name:R1,version:L1}}}};if(e.method==="notifications/initialized")return{kind:"notification"};if(e.method==="shutdown")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:null}};if(e.method==="tools/list")return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{tools:Ms.map(s=>({name:s.name,description:s.description,inputSchema:s.inputSchema}))}}};if(e.method==="tools/call"){let s=e.params!==null&&typeof e.params=="object"?e.params:{},i=typeof s.name=="string"?s.name:"",o=s.arguments,a=await Cb(i,o,t.dispatch),l=i==="lmctl_chat"&&a.status==="ok"&&a.data!==null&&typeof a.data=="object"&&typeof a.data.text=="string"?a.data.text:JSON.stringify(a);return{kind:"response",message:{jsonrpc:"2.0",id:n,result:{isError:a.status==="error",content:[{type:"text",text:l}]}}}}return r?{kind:"notification"}:{kind:"response",message:{jsonrpc:"2.0",id:n,error:{code:-32601,message:`method not found: ${e.method}`}}}}function Vu(e){return`${JSON.stringify(e)}
2159
2165
  `}async function Mb(e,t){let r=!1,n="",s=!1,i=async o=>{let a=o.trim();if(a.length===0)return;let l;try{l=JSON.parse(a)}catch(d){e.io.write(Vu({jsonrpc:"2.0",id:null,error:{code:-32700,message:`parse error: ${d instanceof Error?d.message:String(d)}`}}));return}l.method==="shutdown"&&(r=!0);let c=await $1(l,e);c.kind==="response"?e.io.write(Vu(c.message)):c.kind==="exit"&&(s=!0)};return new Promise(o=>{let a=Promise.resolve(),l=!1,c=u=>{l||(l=!0,o(u))},d=()=>{let u=n.indexOf(`
2160
2166
  `);for(;u!==-1;){let f=n.slice(0,u);n=n.slice(u+1),a=a.then(()=>i(f)).then(()=>{s&&c(0)}),u=n.indexOf(`
2161
2167
  `)}};t.setEncoding("utf8"),t.on("data",u=>{n+=u,d()}),t.on("end",()=>{n.trim().length>0&&(a=a.then(()=>i(n))),a.finally(()=>c(0))}),t.on("error",u=>{e.io.log?.(`mcp: stdin error: ${u.message}
@@ -2322,7 +2328,7 @@ Show provider session details, team rollups, or managed run state/token totals.`
2322
2328
  [--recursive] [--all] [--format table|teamfile|json] [--json]
2323
2329
  lmctl ls --runs [--limit N] [--format table|json] [--json]
2324
2330
 
2325
- List native provider sessions in scope, or list recent managed runs with --runs.`,bW=50,xS=500});import{existsSync as Ds,readFileSync as LS}from"node:fs";import{homedir as NW}from"node:os";import{dirname as $S,resolve as $n}from"node:path";import{fileURLToPath as xW}from"node:url";function uf(e,t={}){let r=[],n=LW(t.modelSelectionDocPath);for(let s of e){let i=s.provider.trim().toLowerCase();if(s.effort&&i!=="opencode"&&i!=="lmplayer"&&i!=="qwen"&&r.push(`[${s.alias}] effort="${s.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),i==="qwen"&&s.effort&&r.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;r.push(`[${s.alias}] model="${s.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(i==="lmplayer"&&!s.model){r.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&&r.push(`[${s.alias}] effort="${s.effort}" has no effect without model= on an opencode member.`),!s.model){r.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=DW(t.opencodeConfigPath);if(!a.available){r.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 l=a.models.filter(c=>c.endsWith(`/${s.model}`));r.push(l.length>0?`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${l.join(" / ")}; set model=${l[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}r.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(!s.model)continue;let o=n.get(i);if(!o){r.push(`[${s.alias}] model="${s.model}" cannot be verified for provider "${i}": `+(La??"no tested models found in durable-memory/model_selection.md"));continue}o.includes(s.model)||r.push(`[${s.alias}] model="${s.model}" is not in the tested model list for provider "${i}". Valid tested models: ${FW(o)}`)}return r}function LW(e){if(!e&&js)return js;let t=new Map,r,n=e??$W();if(!Ds(n))return r=`${n} not found`,e||cf(t),e||(js=t),e||(La=r),t;let s;try{s=LS(n,"utf-8")}catch(i){return r=`${n} could not be read: ${i instanceof Error?i.message:String(i)}`,e||cf(t),e||(js=t),e||(La=r),t}for(let[i,o]of Object.entries(AW)){let a=MW(s,o),l=jW(a);l.length>0&&t.set(i,l)}return t.size===0&&(r=`${n} has no tested model rows`),!e&&t.size===0&&cf(t),e||(js=t),e||(La=r),t}function $W(){return OW($S(xW(import.meta.url)))}function OW(e){let t=CW(e);if(t){let n=$n(t,"durable-memory","model_selection.md");if(Ds(n))return n}let r=[$n(e,"..","..","durable-memory","model_selection.md"),$n(e,"..","..","..","durable-memory","model_selection.md")];for(let n of r)if(Ds(n))return n;return r[r.length-1]}function CW(e){let t=$n(e);for(;;){if(Ds($n(t,"package.json")))return t;let r=$S(t);if(r===t)return null;t=r}}function cf(e){for(let[t,r]of Object.entries(RW))e.set(t,r)}function MW(e,t){let n=new RegExp(`^## ${UW(t)}\\s*$`,"m").exec(e);if(!n)return"";let s=n.index+n[0].length,i=e.slice(s),o=/^##\s+/m.exec(i);return o?i.slice(0,o.index):i}function jW(e){let t=new Set;for(let r of e.split(/\r?\n/)){let n=r.trim();if(!n.startsWith("| `"))continue;let s=/^\|\s*`([^`]+)`\s*\|/.exec(n);if(!s)continue;let i=s[1].trim();i&&i!=="Configured `model="&&t.add(i)}return[...t]}function DW(e){let t=e??$n(NW(),".config","opencode","opencode.json");if(!Ds(t))return{available:!0,models:[]};let r;try{r=JSON.parse(LS(t,"utf-8"))}catch(n){return{available:!1,models:[],reason:`${t} could not be parsed: ${n instanceof Error?n.message:String(n)}`}}return{available:!0,models:PW(r)}}function PW(e){if(!df(e))return[];let t=Ra(e.provider)??Ra(e.providers);if(!t)return[];let r=new Set;for(let[n,s]of Object.entries(t)){if(!df(s))continue;let i=Ra(s.models)??Ra(s.model);if(i)for(let o of Object.keys(i))r.add(o.startsWith(`${n}/`)?o:`${n}/${o}`)}return[...r].sort()}function Ra(e){return df(e)?e:null}function df(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function FW(e){return e.length>0?e.join(", "):"(none)"}function UW(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var AW,RW,js,La,OS=T(()=>{"use strict";AW={claude:"Claude",codex:"Codex",gemini:"Gemini",qwen:"Qwen",agy:"Antigravity"},RW={claude:["claude-opus-4-6","claude-opus-4-7","claude-opus-4-8","claude-sonnet-4-6","claude-sonnet-5","claude-haiku-4-5","claude-fable-5"],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"],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"],agy:["gemini-1.5-flash","gemini-1.5-pro","gemini-3.5-flash","gemini-3.1-pro","gpt-oss-120b","gpt-4-turbo","gpt-4","gpt-3.5-turbo","claude-3-opus","claude-3-sonnet","claude-3-haiku"]},js=null});import{homedir as WW}from"node:os";import{basename as BW}from"node:path";function $a(e,t){let r=new Set;return{text:e.replace(HW,(s,i)=>{let o=i.trim(),a=qW[o];return a===void 0?(r.add(o),s):a(t)}),unknownNames:[...r].sort()}}function Oa(e){return{workdir:e.workdir,teamfile:e.teamfile,date:JW(e.date)}}function JW(e){return e.toISOString().slice(0,10)}var qW,HW,ff=T(()=>{"use strict";qW={workdir:e=>e.workdir,teamfile:e=>e.teamfile,teamname:e=>{let t=BW(e.teamfile);return t.endsWith(".lmctl")?t.slice(0,-6):t},home:()=>WW(),date:e=>e.date},HW=/{{\s*([A-Za-z0-9_-]+)\s*}}/g});var Us={};we(Us,{GEMINI_PROVIDER_NOTICE:()=>DS,_setLintSessiondirFsOpsForTests:()=>QW,_setTeamfileSeedForTests:()=>ZW,buildRootTeamRegistrationRow:()=>BS,registerRootTeam:()=>qS,runHire:()=>aB,runLint:()=>oB,runRefresh:()=>lB,runSeed:()=>US,sha256Text:()=>WS});import{createHash as XW}from"node:crypto";import{accessSync as GW,constants as CS,existsSync as VW,readFileSync as ja,realpathSync as _f,statSync as KW,writeFileSync as Ma}from"node:fs";import{dirname as Hr,resolve as jS}from"node:path";function ZW(e){PS=e??(async t=>{let{seed:r}=await Promise.resolve().then(()=>(vt(),uc)),n=await r(t);return n.success?{sessionId:n.sessionId,warnings:n.warnings}:{error:n.error??"provider seed failed"}})}function QW(e){qr=e===null?hf:{...hf,...e}}function eB(e,t){let r=Hr(t),n=new Set,s=[];for(let i of e){if(i.teamfile!==void 0)continue;let o=i.sessiondir??r,a=jS(o);if(n.has(a))continue;let l=tB(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 tB(e){try{if(qr.existsSync(e)){if(!qr.statSync(e).isDirectory())return"ENOTDIR";qr.accessSync(e,CS.W_OK);return}let t=sB(e);if(t===void 0)return;if(!qr.statSync(t).isDirectory())return"ENOTDIR";qr.accessSync(t,CS.W_OK);return}catch(t){return iB(t)??"permission check failed"}}function rB(e,t){let r=[];for(let n of e)n.teamfile!==void 0||n.sessiondir===void 0||FS(n.sessiondir,t)&&r.push(`${n.alias}: sessiondir equals the teamfile directory and is redundant; lmctl seed will remove it`);return r}function nB(e,t,r,n){let s=!1;for(let i of e){if(i.teamfile!==void 0||i.sessiondir===void 0||!FS(i.sessiondir,n))continue;let o=r.get(i.alias.toLowerCase());if(o===void 0)continue;let a=HS(t[o],"sessiondir");a!==t[o]&&(t[o]=a,s=!0),i.sessiondir=void 0}return s}function FS(e,t){return MS(e)===MS(t)}function MS(e){let t=jS(e);try{return _f(t)}catch{return t}}function sB(e){let t=e;for(;;){try{if(qr.existsSync(t))return t}catch{return}let r=Hr(t);if(r===t)return;t=r}}function iB(e){if(typeof e=="object"&&e!==null&&"code"in e){let t=e.code;if(typeof t=="string"&&t.length>0)return t}}async function oB(e,t={stdout:process.stdout,stderr:process.stderr}){if(e[0]==="--help"||e[0]==="-h"||e[0]==="help")return t.stdout.write(YW),0;if(e.length!==1)return t.stderr.write(`usage: lmctl lint <teamfile.lmctl>
2331
+ List native provider sessions in scope, or list recent managed runs with --runs.`,bW=50,xS=500});import{existsSync as Ds,readFileSync as LS}from"node:fs";import{homedir as NW}from"node:os";import{dirname as $S,resolve as $n}from"node:path";import{fileURLToPath as xW}from"node:url";function uf(e,t={}){let r=[],n=LW(t.modelSelectionDocPath);for(let s of e){let i=s.provider.trim().toLowerCase();if(s.effort&&i!=="opencode"&&i!=="lmplayer"&&i!=="qwen"&&r.push(`[${s.alias}] effort="${s.effort}" is ignored: effort selection is only supported for opencode and lmplayer.`),i==="qwen"&&s.effort&&r.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;r.push(`[${s.alias}] model="${s.model}" is ignored: copilot does not support lmctl model selection.`);continue}if(i==="lmplayer"&&!s.model){r.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&&r.push(`[${s.alias}] effort="${s.effort}" has no effect without model= on an opencode member.`),!s.model){r.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=DW(t.opencodeConfigPath);if(!a.available){r.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 l=a.models.filter(c=>c.endsWith(`/${s.model}`));r.push(l.length>0?`[${s.alias}] model="${s.model}" has no provider prefix \u2014 opencode model ids are <provider>/<model>. Your opencode.json declares it as ${l.join(" / ")}; set model=${l[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}r.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(!s.model)continue;let o=n.get(i);if(!o){r.push(`[${s.alias}] model="${s.model}" cannot be verified for provider "${i}": `+(La??"no tested models found in durable-memory/model_selection.md"));continue}o.includes(s.model)||r.push(`[${s.alias}] model="${s.model}" is not in the tested model list for provider "${i}". Valid tested models: ${FW(o)}`)}return r}function LW(e){if(!e&&js)return js;let t=new Map,r,n=e??$W();if(!Ds(n))return r=`${n} not found`,e||cf(t),e||(js=t),e||(La=r),t;let s;try{s=LS(n,"utf-8")}catch(i){return r=`${n} could not be read: ${i instanceof Error?i.message:String(i)}`,e||cf(t),e||(js=t),e||(La=r),t}for(let[i,o]of Object.entries(AW)){let a=MW(s,o),l=jW(a);l.length>0&&t.set(i,l)}return t.size===0&&(r=`${n} has no tested model rows`),!e&&t.size===0&&cf(t),e||(js=t),e||(La=r),t}function $W(){return OW($S(xW(import.meta.url)))}function OW(e){let t=CW(e);if(t){let n=$n(t,"durable-memory","model_selection.md");if(Ds(n))return n}let r=[$n(e,"..","..","durable-memory","model_selection.md"),$n(e,"..","..","..","durable-memory","model_selection.md")];for(let n of r)if(Ds(n))return n;return r[r.length-1]}function CW(e){let t=$n(e);for(;;){if(Ds($n(t,"package.json")))return t;let r=$S(t);if(r===t)return null;t=r}}function cf(e){for(let[t,r]of Object.entries(RW))e.set(t,r)}function MW(e,t){let n=new RegExp(`^## ${UW(t)}\\s*$`,"m").exec(e);if(!n)return"";let s=n.index+n[0].length,i=e.slice(s),o=/^##\s+/m.exec(i);return o?i.slice(0,o.index):i}function jW(e){let t=new Set;for(let r of e.split(/\r?\n/)){let n=r.trim();if(!n.startsWith("| `"))continue;let s=/^\|\s*`([^`]+)`\s*\|/.exec(n);if(!s)continue;let i=s[1].trim();i&&i!=="Configured `model="&&t.add(i)}return[...t]}function DW(e){let t=e??$n(NW(),".config","opencode","opencode.json");if(!Ds(t))return{available:!0,models:[]};let r;try{r=JSON.parse(LS(t,"utf-8"))}catch(n){return{available:!1,models:[],reason:`${t} could not be parsed: ${n instanceof Error?n.message:String(n)}`}}return{available:!0,models:PW(r)}}function PW(e){if(!df(e))return[];let t=Ra(e.provider)??Ra(e.providers);if(!t)return[];let r=new Set;for(let[n,s]of Object.entries(t)){if(!df(s))continue;let i=Ra(s.models)??Ra(s.model);if(i)for(let o of Object.keys(i))r.add(o.startsWith(`${n}/`)?o:`${n}/${o}`)}return[...r].sort()}function Ra(e){return df(e)?e:null}function df(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function FW(e){return e.length>0?e.join(", "):"(none)"}function UW(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var AW,RW,js,La,OS=T(()=>{"use strict";AW={claude:"Claude",codex:"Codex",gemini:"Gemini",qwen:"Qwen",agy:"Antigravity"},RW={claude:["claude-opus-4-6","claude-opus-4-7","claude-opus-4-8","claude-sonnet-4-6","claude-sonnet-5","claude-haiku-4-5","claude-fable-5"],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"],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"],agy:["Gemini 3.5 Flash (Medium)","Gemini 3.5 Flash (High)","Gemini 3.5 Flash (Low)","Gemini 3.1 Pro (Low)","Gemini 3.1 Pro (High)","Claude Sonnet 4.6 (Thinking)","Claude Opus 4.6 (Thinking)","GPT-OSS 120B (Medium)"]},js=null});import{homedir as WW}from"node:os";import{basename as BW}from"node:path";function $a(e,t){let r=new Set;return{text:e.replace(HW,(s,i)=>{let o=i.trim(),a=qW[o];return a===void 0?(r.add(o),s):a(t)}),unknownNames:[...r].sort()}}function Oa(e){return{workdir:e.workdir,teamfile:e.teamfile,date:JW(e.date)}}function JW(e){return e.toISOString().slice(0,10)}var qW,HW,ff=T(()=>{"use strict";qW={workdir:e=>e.workdir,teamfile:e=>e.teamfile,teamname:e=>{let t=BW(e.teamfile);return t.endsWith(".lmctl")?t.slice(0,-6):t},home:()=>WW(),date:e=>e.date},HW=/{{\s*([A-Za-z0-9_-]+)\s*}}/g});var Us={};we(Us,{GEMINI_PROVIDER_NOTICE:()=>DS,_setLintSessiondirFsOpsForTests:()=>QW,_setTeamfileSeedForTests:()=>ZW,buildRootTeamRegistrationRow:()=>BS,registerRootTeam:()=>qS,runHire:()=>aB,runLint:()=>oB,runRefresh:()=>lB,runSeed:()=>US,sha256Text:()=>WS});import{createHash as XW}from"node:crypto";import{accessSync as GW,constants as CS,existsSync as VW,readFileSync as ja,realpathSync as _f,statSync as KW,writeFileSync as Ma}from"node:fs";import{dirname as Hr,resolve as jS}from"node:path";function ZW(e){PS=e??(async t=>{let{seed:r}=await Promise.resolve().then(()=>(vt(),uc)),n=await r(t);return n.success?{sessionId:n.sessionId,warnings:n.warnings}:{error:n.error??"provider seed failed"}})}function QW(e){qr=e===null?hf:{...hf,...e}}function eB(e,t){let r=Hr(t),n=new Set,s=[];for(let i of e){if(i.teamfile!==void 0)continue;let o=i.sessiondir??r,a=jS(o);if(n.has(a))continue;let l=tB(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 tB(e){try{if(qr.existsSync(e)){if(!qr.statSync(e).isDirectory())return"ENOTDIR";qr.accessSync(e,CS.W_OK);return}let t=sB(e);if(t===void 0)return;if(!qr.statSync(t).isDirectory())return"ENOTDIR";qr.accessSync(t,CS.W_OK);return}catch(t){return iB(t)??"permission check failed"}}function rB(e,t){let r=[];for(let n of e)n.teamfile!==void 0||n.sessiondir===void 0||FS(n.sessiondir,t)&&r.push(`${n.alias}: sessiondir equals the teamfile directory and is redundant; lmctl seed will remove it`);return r}function nB(e,t,r,n){let s=!1;for(let i of e){if(i.teamfile!==void 0||i.sessiondir===void 0||!FS(i.sessiondir,n))continue;let o=r.get(i.alias.toLowerCase());if(o===void 0)continue;let a=HS(t[o],"sessiondir");a!==t[o]&&(t[o]=a,s=!0),i.sessiondir=void 0}return s}function FS(e,t){return MS(e)===MS(t)}function MS(e){let t=jS(e);try{return _f(t)}catch{return t}}function sB(e){let t=e;for(;;){try{if(qr.existsSync(t))return t}catch{return}let r=Hr(t);if(r===t)return;t=r}}function iB(e){if(typeof e=="object"&&e!==null&&"code"in e){let t=e.code;if(typeof t=="string"&&t.length>0)return t}}async function oB(e,t={stdout:process.stdout,stderr:process.stderr}){if(e[0]==="--help"||e[0]==="-h"||e[0]==="help")return t.stdout.write(YW),0;if(e.length!==1)return t.stderr.write(`usage: lmctl lint <teamfile.lmctl>
2326
2332
  `),2;let r=e[0],n;try{n=await O(t,c=>Ee(r,c))}catch(c){return Oe(t,`${r}: ${c instanceof Error?c.message:String(c)}`)}let s;try{s=De(n)}catch(c){return Oe(t,`${r}: ${c instanceof Error?c.message:String(c)}`)}let i=Yd(s,Hr(n)),o=uf(s.members),a=ja(n,"utf8"),l=$a(a,Oa({workdir:Hr(n),teamfile:n,date:new Date})).unknownNames;l.length>0&&o.push(`unknown template placeholder${l.length===1?"":"s"}: ${l.map(c=>`{{${c}}}`).join(", ")}`),o.push(...vl(s.members,Hr(n))),o.push(...eB(s.members,n)),o.push(...rB(s.members,Hr(n)));for(let c of i)t.stderr.write(`error: ${c.field}: ${c.message}
2327
2333
  `);for(let c of s.members)yf([c],t),c.session!==void 0&&c.session.length<Ps&&o.push(`${c.alias}: sessionid is shorter than ${Ps} chars; run lmctl seed to refresh it`);for(let c of o)t.stderr.write(`warning: ${c}
2328
2334
  `);return await O(t,c=>{TE(n,c,d=>t.stderr.write(`${d}
@@ -70,17 +70,14 @@ terminal resume plus one-shot `agy -p` turns.
70
70
 
71
71
  | Configured `model=` | Evidence |
72
72
  | --- | --- |
73
- | `gemini-1.5-flash` | Ported from lmctl0 tested-model catalog. |
74
- | `gemini-1.5-pro` | Ported from lmctl0 tested-model catalog. |
75
- | `gemini-3.5-flash` | Ported from lmctl0 tested-model catalog. |
76
- | `gemini-3.1-pro` | Ported from lmctl0 tested-model catalog. |
77
- | `gpt-oss-120b` | Ported from lmctl0 tested-model catalog. |
78
- | `gpt-4-turbo` | Ported from lmctl0 tested-model catalog. |
79
- | `gpt-4` | Ported from lmctl0 tested-model catalog. |
80
- | `gpt-3.5-turbo` | Ported from lmctl0 tested-model catalog. |
81
- | `claude-3-opus` | Ported from lmctl0 tested-model catalog. |
82
- | `claude-3-sonnet` | Ported from lmctl0 tested-model catalog. |
83
- | `claude-3-haiku` | Ported from lmctl0 tested-model catalog. |
73
+ | `Gemini 3.5 Flash (Medium)` | Observed from `agy models` on 2026-07-20. |
74
+ | `Gemini 3.5 Flash (High)` | Observed from `agy models` on 2026-07-20. |
75
+ | `Gemini 3.5 Flash (Low)` | Observed from `agy models` on 2026-07-20. |
76
+ | `Gemini 3.1 Pro (Low)` | Observed from `agy models` on 2026-07-20. |
77
+ | `Gemini 3.1 Pro (High)` | Observed from `agy models` on 2026-07-20. |
78
+ | `Claude Sonnet 4.6 (Thinking)` | Observed from `agy models` on 2026-07-20. |
79
+ | `Claude Opus 4.6 (Thinking)` | Observed from `agy models` on 2026-07-20. |
80
+ | `GPT-OSS 120B (Medium)` | Observed from `agy models` on 2026-07-20. |
84
81
 
85
82
  ## OpenCode
86
83
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmctl-ai/lmctl",
3
- "version": "0.1.155",
3
+ "version": "0.1.156",
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",