@lmctl-ai/lmctl 0.2.325 → 0.2.326

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/build-info.json CHANGED
@@ -1 +1 @@
1
- {"sha": "3e6472a30dd24a99ae131e1cb1e49708dba65004", "dirty": false, "builtAt": "2026-10-18T15:43:42.000Z"}
1
+ {"sha": "a0092afcf56296cfd6beb4ebb9ed5a47a256ce69", "dirty": false, "builtAt": "2026-10-18T16:07:07.000Z"}
@@ -428,7 +428,7 @@ fn clamp(val, low, high) {
428
428
  `)+(I.output.length>0?`
429
429
  `:""),D=I.exitCode!==void 0?I.exitCode:I.success&&!I.errors?.length?0:1,U={success:I.success&&D===0,stdout:M,output:[...I.output],value:I.value??null,exit_code:D,code:D,errors:I.errors??[]};for(let $ of[...I.errors??[],...I.diagnostics.filter(Z=>Z.severity==="error").map(Z=>Z.message)])this.recordedErrors.push($);return U})();{let I=k.run(w,{file:A,entryLocation:A,executionOrigin:kr({source_kind:"file",script_file:A,source_name:A,parent_run_id:this.executionOrigin?.run_id}),signal:this.abortSignal,platform:this.platform,noPreflight:this.noPreflight,hostContext:O,propertyStore:this.compileOptions?.propertyStore}),C=I.stdout??I.output.join(`
430
430
  `)+(I.output.length>0?`
431
- `:""),M=I.exitCode!==void 0?I.exitCode:I.success&&!I.errors?.length?0:1,D={success:I.success&&M===0,stdout:C,output:[...I.output],value:I.value??null,exit_code:M,code:M,errors:I.errors??[]};for(let U of[...I.errors??[],...I.diagnostics.filter($=>$.severity==="error").map($=>$.message)])this.recordedErrors.push(U);return D}},arity:E?.arity??{min:1,max:2},description:"Executes another LMScript file in-process and returns execution result with .stdout, .output, .success, .exit_code",isDefault:!0});let x=e.get("http_get");(!x||x.isDefault)&&this.hostFunctions.set("http_get",{...x,fn:R=>this.isAsync?fL(R):Zb(R),arity:x?.arity??1,description:"Downloads UTF-8 text from a public HTTP(S) URL",isDefault:!0});let S=e.get("sleep_ms");if((!S||S.isDefault)&&this.hostFunctions.set("sleep_ms",{...S,fn:R=>{if(typeof R!="number"||!Number.isFinite(R)||R<0)throw new Error("sleep_ms() duration must be a non-negative finite number");if(R>2147483647)throw new Error("sleep_ms() duration exceeds maximum supported timeout (2147483647 ms)");if(this.isAsync)return new Promise(O=>setTimeout(O,R));let N=Date.now()+R;for(;Date.now()<N;);return null},arity:S?.arity??1,description:"Sleeps for the specified milliseconds",isDefault:!0}),this.dry)for(let[R,N]of e)N.signature?.dryrunIndex!==void 0&&this.hostFunctions.set(R,N)}evaluateProgram(e){if(this.globalEnv=new yt,this.initialGlobals)for(let[r,s]of this.initialGlobals.entries())this.globalEnv.define(r,s);this.userFunctions.clear(),this.callDepth=0;for(let r of e.statements)r.kind==="FunctionDeclStmt"&&this.userFunctions.set(r.name,r);let n;for(let r of e.statements)r.kind!=="FunctionDeclStmt"&&(n=this.execStmt(r,this.globalEnv));return this.checkRootRemainder(e),n}enterRecover(e,n){if(n)throw new P("recover cannot be entered inside a parallel task",e.line,e.column,"RUNTIME",e.file);let r=this.recovery;if(r.entered.has(e))throw new P("recover statement already entered during this run",e.line,e.column,"RUNTIME",e.file);if(r.entered.add(e),r.active=!0,r.pending.length===0)return{start:0,consumed:!1};let s=r.pending.shift(),i=e.points.findIndex(o=>o.name===s);if(i<0)throw new P(`Unknown resumepoint '${s}' in entered recover; available: ${e.points.map(o=>o.name).join(", ")}`,e.line,e.column,"RUNTIME",e.file);return{start:i,consumed:!0}}enterPoint(e,n){this.recovery.stack.length=e,this.recovery.stack.push(n),this.publishResumepoint()}leaveRecover(e){this.recovery.stack.length=e,this.publishResumepoint()}publishResumepoint(){this.recovery.probe.currentPath=this.recovery.stack.length>0?this.recovery.stack.join("."):null,this.globalEnv.define("RESUMEPOINT",this.recovery.stack.length>0?this.recovery.stack.join("."):null)}checkRemainder(e){if(rt(this.abortSignal),this.recovery.pending.length>0)throw new P(`resumepoint path not consumed: ${this.recovery.pending.join(".")}`,e.line,e.column,"RUNTIME",e.file)}checkRootRemainder(e){if(rt(this.abortSignal),!(this.recordedErrors.length>0)&&this.recovery.pending.length>0)throw new P(`resumepoint path not consumed: ${this.recovery.pending.join(".")}`,e.line,e.column,"RUNTIME",e.file)}checkRecoverRead(e,n,r,s){let i=this.recoverScopedReads.get(r);if(!i)return;let o=this.recovery.envs.get(i);if(o&&n.resolveBinding(e)?.env!==o)throw new P(`Variable '${e}' was read before its binding was initialized`,s.line,s.column,"RUNTIME",s.file)}recoverWriteScope(e,n){let r=this.recoverScopedWrites.get(n)?.get(e);return r?this.recovery.envs.get(r):void 0}execStmt(e,n){let r=this.tracer;if(!r||e.kind==="BlockStmt"||e.kind==="FunctionDeclStmt"||e.kind==="ImportStmt"||e.kind==="PackageStmt")return this.execStmtCore(e,n);r.stmt(e,n),e.kind==="BreakStmt"?r.jump("break",e):e.kind==="ContinueStmt"&&r.jump("continue",e);try{return this.execStmtCore(e,n)}catch(s){throw s instanceof Qe?e.kind==="ReturnStmt"&&r.jump("return",e):s instanceof lt||s instanceof ct||r.raise(s,e),s}}execStmtCore(e,n){switch(this.dry?.at(e),rt(this.abortSignal),e.kind){case"PackageStmt":{if(e.nativeModule&&!this.dry){let r=this.nativeImports?.get(e.nativeModule)?.();if(ut(r))throw new P("Native import requires runAsync",e.line,e.column,"RUNTIME",e.file)}return}case"ImportStmt":return;case"BlockStmt":{let r=new yt(n);for(let s of e.statements)this.execStmt(s,r);return}case"VarDeclStmt":{let r=null;return e.initializer&&(r=this.evalExpr(e.initializer,n)),n.define(e.name,r),r}case"TupleVarDeclStmt":{let r=this.evalExpr(e.initializer,n);if(!Array.isArray(r))throw new P(`Cannot destructure non-array value (got ${typeof r})`,e.line,e.column,"RUNTIME",e.file);for(let s=0;s<e.names.length;s++){let i=s<r.length?r[s]:null;n.define(e.names[s],i)}return r}case"IfStmt":{let r=this.evalExpr(e.condition,n);return this.isTruthy(r)?(this.tracer?.branch("then",e.thenBranch,n),this.execStmt(e.thenBranch,n)):e.elseBranch?(this.tracer?.branch("else",e.elseBranch,n),this.execStmt(e.elseBranch,n)):void 0}case"WhileStmt":{let r=0,s=this.tracer,i=s?.loopEnter("while",e),o="done";try{for(;!this.dry?.loop(r,e)&&this.isTruthy(this.evalExpr(e.condition,n));){if(++r>1e6&&!this.dry)throw new P("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");s?.loopIter(i,r,e,n);try{this.execStmt(e.body,n)}catch(a){if(a instanceof lt){o="break";break}if(a instanceof ct)continue;throw a}}}catch(a){throw o=a instanceof Qe?"return":"raise",a}finally{s?.loopExit(i,r,o)}return}case"ForInStmt":{let r=Lb(this.evalExpr(e.iterable,n),e,this.dry),s=0,i=this.tracer,o=i?.loopEnter("foreach",e),a="done";try{for(let l=0;(l<r.length||this.dry&&s===this.dry.loopLimit)&&!this.dry?.loop(s,e);l++){let c=r[l];if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let u=new yt(n);u.define(e.name,c),i?.loopIter(o,s,e,u);try{if(e.body.kind==="BlockStmt")for(let d of e.body.statements)this.execStmt(d,u);else this.execStmt(e.body,u)}catch(d){if(d instanceof lt){a="break";break}if(d instanceof ct)continue;throw d}}}catch(l){throw a=l instanceof Qe?"return":"raise",l}finally{i?.loopExit(o,s,a)}return}case"ForStmt":{let r=new yt(n);e.init&&this.execStmt(e.init,r);let s=0,i=this.tracer,o=i?.loopEnter("for",e),a="done";try{for(;!this.dry?.loop(s,e);){if(e.condition){let l=this.evalExpr(e.condition,r);if(!this.isTruthy(l))break}if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");i?.loopIter(o,s,e,r);try{this.execStmt(e.body,r)}catch(l){if(l instanceof lt){a="break";break}if(!(l instanceof ct))throw l}if(this.dry?.loop(s,e))break;e.update&&this.evalExpr(e.update,r)}}catch(l){throw a=l instanceof Qe?"return":"raise",l}finally{i?.loopExit(o,s,a)}return}case"ReturnStmt":{let r=e.value?this.evalExpr(e.value,n):null;throw new Qe(r)}case"BreakStmt":throw new lt;case"ContinueStmt":throw new ct;case"SyncAssignStmt":case"SyncIndexAssignStmt":case"SyncCallStmt":throw new P("Synchronized statements require asynchronous execution via engine.runAsync()",e.line,e.column,"RUNTIME",e.file);case"ExprStmt":{if(e.expr.kind==="DataBlockExpr"&&e.expr.marker==="cmd"){let r=this.evalExpr(e.expr,n);return this.invokeNamed("system",[r],n,e.expr.line,e.expr.column,e.expr.file)}return this.evalExpr(e.expr,n)}case"RecoverStmt":{let r=this.enterRecover(e,!1),s=new yt(n);this.recovery.envs.set(e,s);let i=this.recovery.stack.length;try{for(let o=r.start;o<e.points.length;o++){let a=e.points[o];this.enterPoint(i,a.name);for(let l of a.statements)this.execStmt(l,s);r.consumed&&o===r.start&&this.checkRemainder(a)}}catch(o){throw Yt(this.recovery,o),o}finally{this.leaveRecover(i)}return}default:return}}evalExpr(e,n){switch(rt(this.abortSignal),e.kind){case"CommandExpr":{let r=[];for(let i of e.words){let o=[];for(let a of i.pieces)o.push(typeof a=="string"?a:this.evalExpr(a.expression,n));r.push(o)}let s=Ob(e,r);return e.mode==="cmd"?s:this.invokeNamed("system",[s],n,e.line,e.column,e.file)}case"InterpolatedStringExpr":{let r="";for(let s of e.parts)r+=typeof s=="string"?s:tp(this.evalExpr(s.expression,n),s);return r}case"ParallelExpr":throw new P("'parallel(...)' requires asynchronous execution via engine.runAsync()",e.line,e.column,"RUNTIME",e.file);case"LiteralExpr":return e.value;case"PathLiteralExpr":return $b(e,this.platform);case"DataBlockExpr":{let r=Jm(e,i=>this.evalExpr(i.value,n)),s=[];for(let i of e.lines)for(let o of i.pieces)typeof o!="string"&&s.push(this.evalExpr(o.expression,n));return kb(e,r,s,this.compileOptions)}case"IdentifierExpr":return this.resolveIdentifier(e.name,n,e);case"AssignExpr":{let r=this.evalExpr(e.value,n),s=this.recovery.active?this.recoverWriteScope(e.target,e):void 0;return s?s.define(e.target,r):n.set(e.target,r),r}case"TupleAssignExpr":{let r=this.evalExpr(e.value,n);if(!Array.isArray(r))throw new P(`Cannot destructure non-array value (got ${typeof r})`,e.line,e.column,"RUNTIME",e.file);for(let s=0;s<e.targets.length;s++){let i=s<r.length?r[s]:null,o=this.recovery.active?this.recoverWriteScope(e.targets[s],e):void 0;o?o.define(e.targets[s],i):n.set(e.targets[s],i)}return r}case"IndexAssignExpr":{let r=this.evalExpr(e.target,n),s=this.evalExpr(e.index,n),i=this.evalExpr(e.value,n);if(Array.isArray(r)||typeof r=="object"&&r!==null)return Array.isArray(r)&&typeof s=="number"&&s<0&&(s=r.length+s),dt(r,s,i),i;throw new P("Cannot index-assign to non-array / non-object",e.line,e.column,"RUNTIME",e.file)}case"GroupingExpr":return this.evalExpr(e.expression,n);case"TupleExpr":return e.elements.map(r=>this.evalExpr(r,n));case"ArrayExpr":return e.elements.map(r=>this.evalExpr(r,n));case"ObjectExpr":{let r={};for(let s of e.properties)dt(r,s.key,this.evalExpr(s.value,n));return r}case"IndexExpr":{let r=Jl(e);if(r)try{this.dry&&this.dry.at(e);let o=this.dry?.prepareProperties(r);if(ut(o))throw o.catch(()=>{}),Error("Async properties require dryRunAsync");return At(this.dry?this.dry.propertyView:this.resolveIdentifier("PROPS",n,e),r)}catch(o){throw this.dry?new P(o instanceof Error?o.message:String(o),e.line,e.column,"RUNTIME",e.file):o}let s=this.evalExpr(e.target,n),i=this.evalExpr(e.index,n);if(s==null)throw new P("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Yn.has(s)?Bb(s,i,e,this.dry):Db(s,i,e)}case"MethodCallExpr":{let r=this.evalExpr(e.receiver,n),s=e.args.map(i=>this.evalExpr(i,n));return Fb(r,e,s)}case"UnaryExpr":{let r=this.evalExpr(e.operand,n),s=e.operator;if(s==="!")return!this.isTruthy(r);if(s==="-")return-r;throw new P(`Unknown unary operator: ${s}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let r=this.evalExpr(e.condition,n);return this.isTruthy(r)?this.evalExpr(e.trueArm,n):this.evalExpr(e.falseArm,n)}case"BinaryExpr":{if(e.operator==="&&"){let o=this.evalExpr(e.left,n);return this.isTruthy(o)?this.evalExpr(e.right,n):o}if(e.operator==="||"){let o=this.evalExpr(e.left,n);return this.isTruthy(o)?o:this.evalExpr(e.right,n)}let r=this.evalExpr(e.left,n),s=this.evalExpr(e.right,n),i=e.operator;switch(i){case"+":return typeof r=="string"||typeof s=="string"?String(r)+String(s):r+s;case"-":return r-s;case"*":return r*s;case"/":if(s===0)throw new P("Division by zero",e.line,e.column,"RUNTIME",e.file);return r/s;case"%":return r%s;case"==":return r===s;case"!=":return r!==s;case"<":return r<s;case"<=":return r<=s;case">":return r>s;case">=":return r>=s;default:throw new P(`Unknown binary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let r=e.args.map(s=>this.evalExpr(s,n));return this.recovery.active&&!this.userFunctions.has(e.callee)&&!this.hostFunctions.has(e.callee)&&this.checkRecoverRead(e.callee,n,e,e),this.invokeNamed(this.resolveCallTarget(e.callee,n),r,n,e.line,e.column,e.file)}}}resolveIdentifier(e,n,r){if(this.recovery.active&&this.checkRecoverRead(e,n,r,r),n.has(e)){let s=n.get(e);if(s&&typeof s=="object"&&cp.has(s)){this.dry&&this.dry.at(r);try{let i=cp.get(s)();return ut(i)?i.catch(o=>{throw new P(String(o.message??o),r.line,r.column,"RUNTIME",r.file)}):i}catch(i){throw new P(String(i.message??i),r.line,r.column,"RUNTIME",r.file)}}return s}if(this.userFunctions.has(e)||this.hostFunctions.has(e))return new Qn(e);throw new P(`Variable '${e}' was read before its binding was initialized`,r.line,r.column,"RUNTIME",r.file)}resolveCallTarget(e,n){if(this.userFunctions.has(e)||this.hostFunctions.has(e))return e;let r=n.get(e);return r instanceof Qn?r.name:e}invokeNamed(e,n,r,s,i,o){let a=this.tracer,l=this.userFunctions.get(e);if(!a||!l&&!this.hostFunctions.has(e))return this.invokeNamedCore(e,n,r,s,i,o);a.call(e,l?l.params.map((u,d)=>({name:u,value:n[d]})):n.map(u=>({value:u})),!l,l);let c;try{c=this.invokeNamedCore(e,n,r,s,i,o)}catch(u){throw u instanceof Qe||u instanceof lt||u instanceof ct||a.raise(u,{line:s,column:i,file:o}),a.ret(null,!0,u),u}return a.ret(c),c}invokeNamedCore(e,n,r,s,i,o){if(this.dry?.at({line:s,column:i,file:o}),rt(this.abortSignal),this.userFunctions.has(e)){let a=this.userFunctions.get(e);if(this.callDepth++,this.callDepth>Ml)throw this.callDepth--,new P(`Execution fuel exhausted: maximum function call depth exceeded (${Ml})`,s,i,"RUNTIME",o);let l=new yt(this.globalEnv,!0);for(let c=0;c<a.params.length;c++)l.define(a.params[c],n[c]);try{for(let c of a.body.statements)this.execStmt(c,l)}catch(c){if(c instanceof Qe)return c.value;throw c}finally{this.callDepth--}return null}if(this.hostFunctions.has(e)){let a=this.hostFunctions.get(e);try{if(a[Ge]?.control==="warning"){Co(a,n);let u=String(this.dry?mn(n)[0]:n[0]);return this.warningDiagnostics.push({severity:"warning",message:u,line:s,column:i,file:o}),u}if(this.dry){let u=Hb(a,n,e,{line:s,column:i,file:o},this.dry,this.platform);if(u.skip)return u.value;let d=Io(a,u.args);if(this.dry.check(),ut(d)&&(Promise.resolve(d).catch(()=>{}),this.dry.fail("Async host requires dryRunAsync",{line:s,column:i,file:o})),this.dry.failure)throw new Qt(this.dry.failure.message);return ws(d)&&this.dry.fail("Dry host returned a live or unsupported capability",{line:s,column:i,file:o}),a[Ge]?.taints===!1&&this.dry.captureOutput(e,d),u.handled&&this.dry.record(e,u.publicArgs,{line:s,column:i,file:o},"handled",void 0,u.taints),d}let l=Co(a,n);if(a.returnsResource)throw new P(`'${e}' returns a resource and requires engine.runAsync(); the synchronous engine.run refuses to call it`,s,i,"RUNTIME",o);rt(this.abortSignal);let c=Io(a,l);if(a.returnsResource&&ut(c))throw c.then(u=>{try{u&&typeof u.finalizeSync=="function"?u.finalizeSync():u&&typeof u.close=="function"&&u.close()}catch{}},()=>{}),new Error("returns a resource asynchronously; use engine.runAsync()");return c}catch(l){throw this.dry?.captureFailure(l,{line:s,column:i,file:o}),l instanceof Bt||l?.name==="LMScriptExit"||l?.isControlFlow?l:new P(`Error in host function '${e}': ${l?.message||String(l)}`,s,i,"RUNTIME",o)}}throw r.has(e)?new P(`'${e}' is not a function`,s,i,"RUNTIME",o):new P(ci(e,"Undefined function"),s,i,"RUNTIME",o)}ownerFor(e,n){let r=this.resources.scopeFor(e),s=this.temporaryScopes.get(n),i=s&&s[s.length-1];return i&&i.base===r?i:r}pushTemporaryScope(e,n){let r=this.temporaryScopes.get(e);r?r.push(n):this.temporaryScopes.set(e,[n])}popTemporaryScope(e){let n=this.temporaryScopes.get(e);n?.pop(),n&&n.length===0&&this.temporaryScopes.delete(e)}async execLoopBodyAsync(e,n,r){await this.execStmtAsync(e,n,r)}resourceError(e,n,r){return new P(`Resource ${this.resources.describe(e)} ${n}`,r.line,r.column,"RUNTIME",r.file)}refuseResource(e,n,r){if(Oe(e))throw this.resourceError(e,n,r)}bindResource(e,n,r,s){let i=this.resources.bind(e,n,r);if(i)throw new P(i.charAt(0).toUpperCase()+i.slice(1),s.line,s.column,"RUNTIME",s.file)}async resourceCallArgs(e,n,r,s,i,o){if(!r.some(Oe))return r;let a={line:s,column:i,file:o};if(!e.usesResource&&!e.closesResource)throw this.resourceError(r.find(Oe),`cannot be passed to '${n}'`,a);let l=[];for(let c of r){if(!Oe(c)){l.push(c);continue}let u=this.resources.lookup(c);if(!u)throw this.resourceError(c,`cannot be used by '${n}': it belongs to another run`,a);if(e.closesResource)this.resources.borrow(c),await this.resources.close(u,r.slice(1));else if(u.state!=="open")throw this.resourceError(c,`is ${u.state==="closing"?"closing":"closed"}: '${n}' cannot use it`,a);this.resources.borrow(c),l.push(u.raw)}return l}registerHostResource(e,n,r,s,i,o){if(e==null)return e;if(typeof e!="object"||typeof e.close!="function"||typeof e.id!="string"&&typeof e.id!="number"||String(e.id)==="")throw new Error("a returnsResource host must return null or an object with a close method and a stable id");return this.resources.register(e,n,`${o??"<main>"}:${s}:${i}`,r)}isTruthy(e){return!(e==null||e===!1||e===0||e==="")}async evaluateProgramAsync(e){if(this.globalEnv=new yt,this.initialGlobals)for(let[s,i]of this.initialGlobals.entries())this.globalEnv.define(s,i);this.userFunctions.clear(),this.asyncCallDepth.clear();for(let s of e.statements)s.kind==="FunctionDeclStmt"&&this.userFunctions.set(s.name,s);let n=this.nextTaskId++;this.recovery.rootTaskId=n;let r;try{for(let s of e.statements)s.kind!=="FunctionDeclStmt"&&(r=await this.execStmtAsync(s,this.globalEnv,n))}catch(s){throw Yt(this.recovery,s),this.resources.root.failure=ys(s),s}finally{await this.resources.drain(this.resources.root)}if(this.checkRootRemainder(e),Oe(r))r=null;else if(Wb()){let s=ws(r);if(s)throw new P(Oe(s)?`Resource ${this.resources.describe(s)} cannot leave the run inside the result value`:Xm(s,"run"),1,1,"RUNTIME")}return r}coOf(e){return e===this.recovery.rootTaskId?"main":"t"+e}async execStmtAsync(e,n,r){let s=this.tracer;if(!s||e.kind==="BlockStmt"||e.kind==="FunctionDeclStmt"||e.kind==="ImportStmt"||e.kind==="PackageStmt")return this.execStmtAsyncCore(e,n,r);let i=this.coOf(r);s.stmt(e,n,i),e.kind==="BreakStmt"?s.jump("break",e,i):e.kind==="ContinueStmt"&&s.jump("continue",e,i);try{return await this.execStmtAsyncCore(e,n,r)}catch(o){throw o instanceof Qe?e.kind==="ReturnStmt"&&s.jump("return",e,i):o instanceof lt||o instanceof ct||s.raise(o,e,i),o}}async execStmtAsyncCore(e,n,r){switch(this.dry?.at(e),rt(this.abortSignal),e.kind){case"PackageStmt":{e.nativeModule&&!this.dry&&await this.nativeImports?.get(e.nativeModule)?.();return}case"ImportStmt":return;case"BlockStmt":{let s=new yt(n);if(!this.resourcesEnabled){for(let o of e.statements)await this.execStmtAsync(o,s,r);return}let i=this.resources.enterScope(s,this.ownerFor(n,r),"block");try{for(let o of e.statements)await this.execStmtAsync(o,s,r)}catch(o){throw Yt(this.recovery,o),i.failure=ys(o),o}finally{i.records.length>0&&await this.resources.drain(i)}return}case"VarDeclStmt":{let s=null;return e.initializer&&(s=await this.evalExprAsync(e.initializer,n,r)),Oe(s)&&this.bindResource(s,n,e.name,e),n.define(e.name,s),s}case"TupleVarDeclStmt":{let s=await this.evalExprAsync(e.initializer,n,r);if(Array.isArray(s))for(let i=0;i<e.names.length&&i<s.length;i++)this.bindResource(s[i],n,e.names[i],e);if(!Array.isArray(s))throw new P(`Cannot destructure non-array value (got ${typeof s})`,e.line,e.column,"RUNTIME",e.file);for(let i=0;i<e.names.length;i++){let o=i<s.length?s[i]:null;n.define(e.names[i],o)}return s}case"IfStmt":{let s=await this.evalExprAsync(e.condition,n,r);return this.isTruthy(s)?(this.tracer?.branch("then",e.thenBranch,n,this.coOf(r)),await this.execStmtAsync(e.thenBranch,n,r)):e.elseBranch?(this.tracer?.branch("else",e.elseBranch,n,this.coOf(r)),await this.execStmtAsync(e.elseBranch,n,r)):void 0}case"WhileStmt":{let s=0,i=this.tracer,o=this.coOf(r),a=i?.loopEnter("while",e,o),l="done";try{for(;!this.dry?.loop(s,e)&&this.isTruthy(await this.evalExprAsync(e.condition,n,r));){if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");i?.loopIter(a,s,e,n,o);try{this.resourcesEnabled?await this.execLoopBodyAsync(e.body,n,r):await this.execStmtAsync(e.body,n,r)}catch(c){if(c instanceof lt){l="break";break}if(c instanceof ct)continue;throw c}}}catch(c){throw l=c instanceof Qe?"return":"raise",c}finally{i?.loopExit(a,s,l,o)}return}case"ForInStmt":{let s=Lb(await this.evalExprAsync(e.iterable,n,r),e,this.dry),i=0,o=this.tracer,a=this.coOf(r),l=o?.loopEnter("foreach",e,a),c="done";try{for(let u=0;(u<s.length||this.dry&&i===this.dry.loopLimit)&&!this.dry?.loop(i,e);u++){let d=s[u];if(++i>1e6&&!this.dry)throw new P("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let m=new yt(n);m.define(e.name,d),o?.loopIter(l,i,e,m,a);let p=this.resourcesEnabled?this.resources.enterScope(m,this.ownerFor(n,r),"iteration"):void 0;try{try{if(e.body.kind==="BlockStmt")for(let f of e.body.statements)await this.execStmtAsync(f,m,r);else await this.execStmtAsync(e.body,m,r)}catch(f){throw Yt(this.recovery,f),p&&(p.failure=ys(f)),f}finally{p&&p.records.length>0&&await this.resources.drain(p)}}catch(f){if(f instanceof lt){c="break";break}if(f instanceof ct)continue;throw f}}}catch(u){throw c=u instanceof Qe?"return":"raise",u}finally{o?.loopExit(l,i,c,a)}return}case"ForStmt":{let s=new yt(n),i=this.resourcesEnabled?this.resources.enterScope(s,this.ownerFor(n,r),"for"):void 0;try{e.init&&await this.execStmtAsync(e.init,s,r);let o=0,a=this.tracer,l=this.coOf(r),c=a?.loopEnter("for",e,l),u="done";try{for(;!this.dry?.loop(o,e);){if(e.condition){let d=await this.evalExprAsync(e.condition,s,r);if(!this.isTruthy(d))break}if(++o>1e6&&!this.dry)throw new P("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");a?.loopIter(c,o,e,s,l);try{this.resourcesEnabled?await this.execLoopBodyAsync(e.body,s,r):await this.execStmtAsync(e.body,s,r)}catch(d){if(d instanceof lt){u="break";break}if(!(d instanceof ct))throw d}if(this.dry?.loop(o,e))break;e.update&&await this.evalExprAsync(e.update,s,r)}}catch(d){throw u=d instanceof Qe?"return":"raise",d}finally{a?.loopExit(c,o,u,l)}}catch(o){throw Yt(this.recovery,o),i&&(i.failure=ys(o)),o}finally{i&&i.records.length>0&&await this.resources.drain(i)}return}case"ReturnStmt":{let s=e.value?await this.evalExprAsync(e.value,n,r):null;throw Oe(s)&&this.refuseResource(s,"cannot be returned: a resource stays with its owner (return copied data instead)",e),new Qe(s)}case"BreakStmt":throw new lt;case"ContinueStmt":throw new ct;case"SyncAssignStmt":{let s=this.recovery.active?this.recoverWriteScope(e.target,e):void 0,i=s?{env:s,name:e.target}:n.resolveBinding(e.target);if(!i)throw new P(`Synchronized assignment target '${e.target}' is not defined`,e.line,e.column,"RUNTIME",e.file);let o=`bind:${i.env.id}:${i.name}`;await this.lockManager.getBindingLock(o).withLock(async()=>{let l=await this.evalExprAsync(e.value,n,r);this.bindResource(l,i.env,i.name,e),i.env.define(i.name,l)},r);return}case"SyncIndexAssignStmt":{let s=await this.evalExprAsync(e.target,n,r);if(s==null||typeof s!="object"&&typeof s!="function")throw new P("Cannot perform synchronized assignment on non-object",e.line,e.column,"RUNTIME",e.file);await this.lockManager.getObjectLock(s).withLock(async()=>{let o=await this.evalExprAsync(e.index,n,r),a=await this.evalExprAsync(e.value,n,r);this.refuseResource(s,"cannot be modified",e),this.refuseResource(o,"cannot be used as a map key",e),this.refuseResource(a,"cannot be stored in a container",e),Array.isArray(s)&&typeof o=="number"&&o<0&&(o=s.length+o),dt(s,o,a)},r);return}case"SyncCallStmt":{let s=e.call;if(s.args.length===0)throw new P("Synchronized call requires at least one argument (the target container)",e.line,e.column,"RUNTIME",e.file);let i=this.hostFunctions.get(s.callee);if(!i||!i.isContainerMutation)throw new P(`Function '${s.callee}' is not an authorized container mutation operation`,e.line,e.column,"RUNTIME",e.file);let o=await this.evalExprAsync(s.args[0],n,r);if(o==null||typeof o!="object"&&typeof o!="function")throw new P("Target of synchronized call must be an array or map",e.line,e.column,"RUNTIME",e.file);await this.lockManager.getObjectLock(o).withLock(async()=>{let l=[];for(let c=1;c<s.args.length;c++)l.push(await this.evalExprAsync(s.args[c],n,r));await this.invokeCallAsync(s.callee,[o,...l],n,e.line,e.column,r,e.file)},r);return}case"ExprStmt":{if(e.expr.kind==="DataBlockExpr"&&e.expr.marker==="cmd"){let s=await this.evalExprAsync(e.expr,n,r);return await this.invokeCallAsync("system",[s],n,e.expr.line,e.expr.column,r,e.expr.file)}return await this.evalExprAsync(e.expr,n,r)}case"RecoverStmt":{let s=this.enterRecover(e,r!==this.recovery.rootTaskId),i=new yt(n);this.recovery.envs.set(e,i);let o=this.resourcesEnabled?this.resources.enterScope(i,this.ownerFor(n,r),"block"):void 0,a=this.recovery.stack.length;try{for(let l=s.start;l<e.points.length;l++){let c=e.points[l];this.enterPoint(a,c.name);for(let u of c.statements)await this.execStmtAsync(u,i,r);s.consumed&&l===s.start&&this.checkRemainder(c)}}catch(l){throw Yt(this.recovery,l),o&&(o.failure=ys(l)),l}finally{try{o&&o.records.length>0&&await this.resources.drain(o)}finally{this.leaveRecover(a)}}return}default:return}}async evalExprAsync(e,n,r){switch(rt(this.abortSignal),e.kind){case"CommandExpr":{let s=[];for(let o of e.words){let a=[];for(let l of o.pieces)a.push(typeof l=="string"?l:await this.evalExprAsync(l.expression,n,r));s.push(a)}let i=Ob(e,s);return e.mode==="cmd"?i:await this.invokeCallAsync("system",[i],n,e.line,e.column,r,e.file)}case"InterpolatedStringExpr":{let s="";for(let i of e.parts){if(typeof i=="string"){s+=i;continue}let o=await this.evalExprAsync(i.expression,n,r);this.refuseResource(o,"cannot be converted to text",i.expression),s+=tp(o,i)}return s}case"LiteralExpr":return e.value;case"PathLiteralExpr":return $b(e,this.platform);case"DataBlockExpr":{let s={};for(let o of e.options)s[o.name]=await this.evalExprAsync(o.value,n,r);let i=[];for(let o of e.lines)for(let a of o.pieces)typeof a!="string"&&i.push(await this.evalExprAsync(a.expression,n,r));return kb(e,Jm(e,o=>s[o.name]),i,this.compileOptions)}case"IdentifierExpr":return this.resolveIdentifier(e.name,n,e);case"AssignExpr":{let s=await this.evalExprAsync(e.value,n,r),i=this.recovery.active?this.recoverWriteScope(e.target,e):void 0;return Oe(s)&&this.bindResource(s,i??n.writeTarget(e.target),e.target,e),i?i.define(e.target,s):n.set(e.target,s),s}case"TupleAssignExpr":{let s=await this.evalExprAsync(e.value,n,r);if(!Array.isArray(s))throw new P(`Cannot destructure non-array value (got ${typeof s})`,e.line,e.column,"RUNTIME",e.file);for(let i=0;i<e.targets.length;i++){let o=i<s.length?s[i]:null,a=this.recovery.active?this.recoverWriteScope(e.targets[i],e):void 0;Oe(o)&&this.bindResource(o,a??n.writeTarget(e.targets[i]),e.targets[i],e),a?a.define(e.targets[i],o):n.set(e.targets[i],o)}return s}case"IndexAssignExpr":{let s=await this.evalExprAsync(e.target,n,r),i=await this.evalExprAsync(e.index,n,r),o=await this.evalExprAsync(e.value,n,r);if(this.refuseResource(s,"cannot be modified",e),this.refuseResource(i,"cannot be used as a map key",e),this.refuseResource(o,"cannot be stored in a container",e),Array.isArray(s)||typeof s=="object"&&s!==null)return Array.isArray(s)&&typeof i=="number"&&i<0&&(i=s.length+i),dt(s,i,o),o;throw new P("Cannot index-assign to non-array / non-object",e.line,e.column,"RUNTIME",e.file)}case"GroupingExpr":return await this.evalExprAsync(e.expression,n,r);case"TupleExpr":{let s=[];for(let i of e.elements){let o=await this.evalExprAsync(i,n,r);this.refuseResource(o,"cannot be stored in a container",i),s.push(o)}return s}case"ArrayExpr":{let s=[];for(let i of e.elements){let o=await this.evalExprAsync(i,n,r);this.refuseResource(o,"cannot be stored in a container",i),s.push(o)}return s}case"ObjectExpr":{let s={};for(let i of e.properties){let o=await this.evalExprAsync(i.value,n,r);this.refuseResource(o,"cannot be stored in a container",i.value),dt(s,i.key,o)}return s}case"ParallelExpr":{if(e.tasks.length===0)return[];let s=this.asyncCallDepth.get(r)??0,i=async u=>{let d=this.nextTaskId++;this.asyncCallDepth.set(d,s);let m=this.resourcesEnabled?this.resources.temporaryScope(this.ownerFor(n,r),"task",this.resources.scopeFor(n)):void 0;m&&this.pushTemporaryScope(d,m);try{let p=await this.evalExprAsync(u,n,d),f=Wb()?ws(p):void 0;if(f)throw new P(Oe(f)?`Resource ${this.resources.describe(f)} cannot be a parallel task result: it stays with the task that opened it`:Xm(f,"parallel task"),u.line,u.column,"RUNTIME",u.file);return p}catch(p){throw this.dry?.captureFailure(p,u),Yt(this.recovery,p),m&&(m.failure=ys(p)),p}finally{m&&(this.popTemporaryScope(d),m.records.length>0&&await this.resources.drain(m))}};if(this.dry){let u=[];for(let d of e.tasks)this.dry.at(d),u.push(await i(d));return u}let o=e.tasks.map(i),a=await Promise.allSettled(o),l=[],c;for(let u of a)u.status==="fulfilled"?l.push(u.value):c||(c=u.reason);if(c)throw c;return l}case"IndexExpr":{let s=Jl(e);if(s)try{return this.dry&&(this.dry.at(e),await this.dry.prepareProperties(s)),At(this.dry?this.dry.propertyView:await this.resolveIdentifier("PROPS",n,e),s)}catch(a){throw this.dry?new P(a instanceof Error?a.message:String(a),e.line,e.column,"RUNTIME",e.file):a}let i=await this.evalExprAsync(e.target,n,r),o=await this.evalExprAsync(e.index,n,r);if(this.refuseResource(o,"cannot be used as a map key",e),Oe(i)){if(o==="id")return i.id;throw this.resourceError(i,`has no readable field '${String(o)}' (only id)`,e)}if(i==null)throw new P("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Yn.has(i)?Bb(i,o,e,this.dry):Db(i,o,e)}case"MethodCallExpr":{let s=await this.evalExprAsync(e.receiver,n,r),i=[];for(let o of e.args)i.push(await this.evalExprAsync(o,n,r));return this.refuseResource(s,"has no methods",e),Fb(s,e,i)}case"UnaryExpr":{let s=await this.evalExprAsync(e.operand,n,r),i=e.operator;if(i==="!")return!this.isTruthy(s);if(this.refuseResource(s,"cannot be used in arithmetic",e),i==="-")return-s;throw new P(`Unknown unary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let s=await this.evalExprAsync(e.condition,n,r);return this.isTruthy(s)?await this.evalExprAsync(e.trueArm,n,r):await this.evalExprAsync(e.falseArm,n,r)}case"BinaryExpr":{if(e.operator==="&&"){let a=await this.evalExprAsync(e.left,n,r);return this.isTruthy(a)?await this.evalExprAsync(e.right,n,r):a}if(e.operator==="||"){let a=await this.evalExprAsync(e.left,n,r);return this.isTruthy(a)?a:await this.evalExprAsync(e.right,n,r)}let s=await this.evalExprAsync(e.left,n,r),i=await this.evalExprAsync(e.right,n,r),o=e.operator;switch((Oe(s)||Oe(i))&&o!=="=="&&o!=="!="&&(this.refuseResource(s,`cannot be used with '${o}' (only ==, != and truth tests)`,e),this.refuseResource(i,`cannot be used with '${o}' (only ==, != and truth tests)`,e)),o){case"+":return typeof s=="string"||typeof i=="string"?String(s)+String(i):s+i;case"-":return s-i;case"*":return s*i;case"/":if(i===0)throw new P("Division by zero",e.line,e.column,"RUNTIME",e.file);return s/i;case"%":return s%i;case"==":return s===i;case"!=":return s!==i;case"<":return s<i;case"<=":return s<=i;case">":return s>i;case">=":return s>=i;default:throw new P(`Unknown binary operator: ${o}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let s=[];for(let i of e.args)s.push(await this.evalExprAsync(i,n,r));return this.recovery.active&&!this.userFunctions.has(e.callee)&&!this.hostFunctions.has(e.callee)&&this.checkRecoverRead(e.callee,n,e,e),await this.invokeCallAsync(e.callee,s,n,e.line,e.column,r,e.file)}}}async invokeCallAsync(e,n,r,s,i,o,a){let l=this.tracer,c=this.resolveCallTarget(e,r),u=this.userFunctions.get(c);if(!l||!u&&!this.hostFunctions.has(c))return this.invokeCallAsyncCore(e,n,r,s,i,o,a);let d=this.coOf(o);l.call(c,u?u.params.map((p,f)=>({name:p,value:n[f]})):n.map(p=>({value:p})),!u,u,d);let m;try{m=await this.invokeCallAsyncCore(e,n,r,s,i,o,a)}catch(p){throw p instanceof Qe||p instanceof lt||p instanceof ct||l.raise(p,{line:s,column:i,file:a},d),l.ret(null,!0,p,d),p}return l.ret(m,!1,void 0,d),m}async invokeCallAsyncCore(e,n,r,s,i,o,a){this.dry?.at({line:s,column:i,file:a});let l=this.resolveCallTarget(e,r);if(rt(this.abortSignal),this.userFunctions.has(l)){let c=this.userFunctions.get(l),u=(this.asyncCallDepth.get(o)??0)+1;if(this.asyncCallDepth.set(o,u),u>Ml)throw this.asyncCallDepth.set(o,u-1),new P(`Execution fuel exhausted: maximum function call depth exceeded (${Ml})`,s,i,"RUNTIME",a);let d=new yt(this.globalEnv,!0),m=this.resourcesEnabled?this.resources.enterScope(d,this.ownerFor(r,o),`function ${l}`):void 0;for(let p=0;p<c.params.length;p++)m&&this.resources.borrow(n[p]),d.define(c.params[p],n[p]);try{for(let p of c.body.statements)await this.execStmtAsync(p,d,o)}catch(p){if(p instanceof Qe)return p.value;throw this.dry?.captureFailure(p),Yt(this.recovery,p),m&&(m.failure=ys(p)),p}finally{m&&m.records.length>0&&await this.resources.drain(m),this.asyncCallDepth.set(o,u-1)}return null}if(this.hostFunctions.has(l)){let c=this.hostFunctions.get(l);try{if(c[Ge]?.control==="warning"){Co(c,n);let g=String(this.dry?mn(n)[0]:n[0]);return this.warningDiagnostics.push({severity:"warning",message:g,line:s,column:i,file:a}),g}if(this.dry){let g=Hb(c,n,l,{line:s,column:i,file:a},this.dry,this.platform);if(g.skip)return g.value;let h=await this.dry.wait(Io(c,g.args));if(this.dry.failure)throw new Qt(this.dry.failure.message);return ws(h)&&this.dry.fail("Dry host returned a live or unsupported capability",{line:s,column:i,file:a}),c[Ge]?.taints===!1&&this.dry.captureOutput(l,h),g.handled&&this.dry.record(l,g.publicArgs,{line:s,column:i,file:a},"handled",void 0,g.taints),h}let u=Co(c,n),d=eM(u)?await this.resourceCallArgs(c,l,u,s,i,a):u,p=c.returnsResource||c.usesResource||c.closesResource?yv.run({runtime:this.resources,scope:this.ownerFor(r,o),site:(a??"<main>")+":"+s+":"+i},()=>Io(c,d)):Io(c,d),f=p instanceof Promise?await p:p;return c.returnsResource?this.registerHostResource(f,l,this.ownerFor(r,o),s,i,a):f}catch(u){throw this.dry?.captureFailure(u,{line:s,column:i,file:a}),u instanceof Bt||u?.name==="LMScriptExit"||u?.isControlFlow?u:new P(`Error in host function '${l}': ${u?.message||String(u)}`,s,i,"RUNTIME",a)}}throw r.has(l)?new P(`'${l}' is not a function`,s,i,"RUNTIME",a):new P(ci(l,"Undefined function"),s,i,"RUNTIME",a)}getRecordedErrors(){return[...this.recordedErrors]}},tM=[{name:"if",category:"Language Constructs",signature:"if (condition) { ... } else { ... }",description:"Conditional branching flow control.",example:'if (x > 0) { print("yes"); } else { print("no"); }'},{name:"while",category:"Language Constructs",signature:"while (condition) { ... }",description:"Looping flow control that repeats while condition is true.",example:"while (i < 10) { i = i + 1; }"},{name:"for",category:"Language Constructs",signature:"for (x in expr) { ... }; for (init; condition; update) { ... }",description:"For-in visits a snapshot of list values, map keys or string Unicode code points with a fresh local binding. C-style loops remain supported; use let for an isolated counter.",example:"for (let i = 0; i < len(arr); i = i + 1) { print(arr[i]); }"},{name:"fn",category:"Language Constructs",signature:"fn name(arg1, arg2) { ... }",description:"Defines a custom function. Function bodies establish an isolated local variable scope for assignments, preventing accidental mutation of caller variables.",example:"fn add(a, b) { return a + b; }"},{name:"import",category:"Language Constructs",signature:'import "path"',description:"Imports and executes another script file.",example:'import "utils.lm"'},{name:"parallel",category:"Language Constructs",signature:"parallel([ call1(), call2() ])",description:"Executes an array of function calls concurrently, returning an array of results.",example:'(a,b) = parallel([ system(["echo", "1"]), system(["echo", "2"]) ]);'},{name:"sync",category:"Language Constructs",signature:"sync expr",description:"Forces sequential execution of an assignment or container mutation inside a parallel block.",example:'sync push(results, "done");'},{name:"break",category:"Language Constructs",signature:"break",description:"Exits the innermost loop.",example:"while (true) { break; }"},{name:"continue",category:"Language Constructs",signature:"continue",description:"Skips to the next iteration of the innermost loop.",example:"for (let i = 0; i < 2; i = i + 1) { if (i == 0) { continue; } }"},{name:"return",category:"Language Constructs",signature:"return expr",description:"Returns a value from a function or script.",example:"return 42;"}],nM=[{name:"sha256",category:"Math & Utilities",signature:"sha256(text: string): string",description:"Lowercase SHA-256 hex of UTF-8 bytes; rejects non-string inputs.",example:'sha256("abc");'},{name:"read_file",category:"File I/O",signature:"read_file(path: string): string",description:"Reads the entire contents of a file as a UTF-8 string.",example:'content = read_file("config.json");'},{name:"read",category:"File I/O",signature:"read(path: string): string",description:"Reads the entire contents of a file as a UTF-8 string (alias for read_file).",example:'content = read("data.txt");'},{name:"read_lines",category:"File I/O",signature:"read_lines(path: string): array",description:"Reads a file and returns an array of string lines.",example:'lines = read_lines("items.txt");'},{name:"write_lines",category:"File I/O",signature:"write_lines(path: string, lines: array): boolean",description:"Writes an array of lines to a file with trailing newline, round-tripping with read_lines.",example:'write_lines("out.txt", ["a", "b"]);'},{name:"glob",category:"File I/O",signature:"glob(pattern: string): array",description:"Finds files matching a glob pattern and returns an array of matching paths.",example:'files = glob("teams/*.lmctl");'},{name:"list_dir",category:"File I/O",signature:"list_dir(path: string): array",description:"Lists filenames in a directory.",example:'entries = list_dir(".");'},{name:"parse_file_blocks",category:"Agent Files",signature:"parse_file_blocks(text: string): array",description:"Parses `=== FILE: relative/path ===` ... `=== END ===` blocks into [{path, content}]. Prose around blocks and whitespace around marker lines are ignored; content wrapped in exactly one markdown fence is unwrapped; content gets a final newline. Incomplete blocks (no END before the next FILE marker or the end of text) are dropped, so a truncated reply yields only its complete files.",example:"files = parse_file_blocks(reply);"},{name:"format_file_blocks",category:"Agent Files",signature:"format_file_blocks(files: array): string",description:"Formats [{path, content}] as file blocks; parse_file_blocks(format_file_blocks(files)) returns files (content normalised to end in a newline). Fence-wrapped content gets an outer fence; content containing a marker line is an error.",example:"context = format_file_blocks(read_tree(dir));"},{name:"write_files",category:"Agent Files",signature:"write_files(dir: string, files: array): map",description:"Writes [{path, content}] under dir (created if missing), each file atomically (temporary file + rename, mode of a replaced file kept). Rejects, never writes: empty, absolute, backslash or '..' paths, any .git segment, a path through a symlink leaving dir, a symlink or directory target, non-string content. Returns {written: [relative paths], rejected: [{path, reason}]}; under --dry-run the same classification with dry: true and nothing created.",example:'res = write_files(dir, parse_file_blocks(reply)); println("wrote", len(res.written));'},{name:"read_tree",category:"Agent Files",signature:"read_tree(dir: string, [options: map]): array",description:"Reads text files under dir as [{path, content}] sorted by path, relative with / separators. Skips symlinks, binary/non-UTF-8 files, files over maxBytes (default 262144) and the default ignores .git, node_modules, dist, build, target, .mp, __pycache__, *.lock, package-lock.json. Options: ignore (extra patterns), include (only matching files), maxBytes. A pattern without / matches a single name, with / the whole relative path; * ? ** globs. A missing dir reads as [].",example:'listing = format_file_blocks(read_tree(dir, {ignore: ["*.md"]}));'},{name:"kv_from_last_paragraph",category:"Agent Files",signature:"kv_from_last_paragraph(text: string): map",description:"Parses `key: value` lines (key [A-Za-z_][A-Za-z0-9_-]*, optional - or * bullet, value in one pair of backticks unwrapped, empty values skipped) of the last blank-line-separated paragraph; the last occurrence of a key wins and missing keys are absent. Trailing paragraphs without any key: value line are skipped as chatter, looking at most 3 paragraphs back; a paragraph holding a file-block marker stops the search.",example:'cfg = kv_from_last_paragraph(reply); if (has_key(cfg, "build_command")) { println(cfg.build_command); }'},{name:"split_command",category:"Agent Files",signature:"split_command(text: string): array",description:"Splits one command line into argv with POSIX quoting (single quotes, double quotes, backslash). Unquoted | & ; < > ( ) ` $, $ or ` inside double quotes, a word-start #, a newline and a leading NAME=value are errors, so model-supplied commands run through system() with shell:false and no shell semantics. Globs and ~ stay literal.",example:'res = system(split_command("npm run build"), {cwd: dir});'},{name:"write_file",category:"File I/O",signature:"write_file(path: string, content: any): boolean",description:"Writes content to a file, creating or overwriting it.",example:'write_file("out.txt", "hello");'},{name:"savedsl",category:"File I/O",signature:"savedsl(dsl: dsl, path: string): boolean",description:"EXPERIMENTAL (poc/dsl-router): writes the opaque value of a _dsl_ block as a portable bytecode file (big-endian, SHA-256-bound to its schema), atomically via a temp file and rename; a dry run writes nothing.",example:'savedsl(router, "build/router.dslb");'},{name:"write",category:"File I/O",signature:"write(path: string, content: any): boolean",description:"Writes content to a file (alias for write_file).",example:'write("out.txt", "data");'},{name:"append_file",category:"File I/O",signature:"append_file(path: string, content: any): boolean",description:"Appends string content to the end of a file.",example:'append_file("log.txt", "step completed\\n");'},{name:"read_json",category:"File I/O",signature:"read_json(path: string): any",description:"Reads a JSON file from disk and parses it into an object or array.",example:'data = read_json("package.json");'},{name:"write_json",category:"File I/O",signature:"write_json(path: string, data: any, [indent: number = 2]): boolean",description:"Serializes data as formatted JSON and writes it to a file.",example:'write_json("out.json", { "status": "ok" }, 2);'},{name:"read_csv",category:"File I/O",signature:'read_csv(path: string, [hasHeader: boolean = true], [delimiter: string = ","]): array',description:"Reads an RFC 4180 CSV file and parses it into an array of objects or rows.",example:'rows = read_csv("data.csv");'},{name:"write_csv",category:"File I/O",signature:'write_csv(path: string, data: array, [delimiter: string = ","]): boolean',description:"Serializes an array of objects or rows to CSV and writes to a file.",example:'write_csv("out.csv", [{ name: "Alice", age: 30 }]);'},{name:"csv_parse",category:"File I/O",signature:'csv_parse(text: string, [hasHeader: boolean = true], [delimiter: string = ","]): array',description:"Parses inline CSV text into an array of objects or rows.",example:'records = csv_parse("name,score\\nBob,95");'},{name:"csv_stringify",category:"File I/O",signature:'csv_stringify(data: array, [delimiter: string = ","]): string',description:"Serializes an array of objects or rows into RFC 4180 CSV text.",example:"csv_text = csv_stringify(records);"},{name:"file_exists",category:"File I/O",signature:"file_exists(path: string): boolean",description:"Checks if a file exists at the given path.",example:'if (file_exists("log.txt")) { print("found"); }'},{name:"temp_file",category:"File I/O",signature:"temp_file(): string",description:"Creates an empty temporary file and returns its absolute path.",example:"tmp = temp_file();"},{name:"write_file_exclusive",category:"File I/O",signature:"write_file_exclusive(path: string, content: any): boolean",description:"Creates a new file exclusively; errors if it already exists.",example:'write_file_exclusive("new.txt", "hello");'},{name:"mkdir",category:"File I/O",signature:"mkdir(dirPath: string, [recursive: boolean = true]): boolean",description:"Creates a directory, recursively by default.",example:'mkdir("out/logs");'},{name:"rmdir",category:"File I/O",signature:"rmdir(dirPath: string, [recursive: boolean = false]): boolean",description:"Removes a directory; pass true to remove a non-empty directory recursively.",example:'rmdir("out/logs", true);'},{name:"copy_file",category:"File I/O",signature:"copy_file(src: string, dest: string): boolean",description:"Copies a file to a new path.",example:'copy_file("a.txt", "b.txt");'},{name:"move_file",category:"File I/O",signature:"move_file(src: string, dest: string): boolean",description:"Moves/renames a file.",example:'move_file("draft.txt", "final.txt");'},{name:"basename",category:"File I/O",signature:"basename(filePath: string, [ext: string]): string",description:"Returns the last path segment, optionally stripping a trailing extension.",example:'name = basename("/a/b/c.txt", ".txt");'},{name:"dirname",category:"File I/O",signature:"dirname(filePath: string): string",description:"Returns the directory portion of a path.",example:'dir = dirname("/a/b/c.txt");'},{name:"path_join",category:"File I/O",signature:"path_join(...parts: string): string",description:"Joins path segments using the OS-native separator; no arguments returns dot.",example:'p = path_join("a", "b", "c.txt");'},{name:"abs_path",category:"File I/O",signature:"abs_path(filePath: string): string",description:"Resolves a path to an absolute path.",example:'p = abs_path("relative/file.txt");'},{name:"env",category:"System & Process",signature:"env(name: string, [fallback: any = null]): any",description:"Reads an environment variable, or a fallback if unset.",example:'home = env("HOME");'},{name:"getenv",category:"System & Process",signature:"getenv(name: string, [fallback: any = null]): any",description:"Reads an environment variable, or a fallback if unset (alias for env).",example:'home = getenv("HOME");'},{name:"set_env",category:"System & Process",signature:"set_env(name: string, value: any): boolean",description:"Sets an environment variable for this process and its children.",example:'set_env("DEBUG", "1");'},{name:"enumerate",category:"Lists & Arrays",signature:"enumerate(arr: array): array",description:"Returns an array of [index, value] pairs, JS/Python-familiar alongside zip (Rule 1, operator 2026-09-29).",example:'pairs = enumerate(["a", "b"]);'},{name:"items",category:"Maps & Key-Value",signature:"items(obj: object): array",description:"Returns an array of [key, value] pairs for an object (alias for entries).",example:"pairs = items({ a: 1, b: 2 });"},{name:"getstr",category:"Maps & Key-Value",signature:'getstr(obj: any, path: string|array, [fallback: string = ""]): string',description:'Typed form of get(): reads a string field, fallback (default "") when missing or null. A present number/bool is stringified (str(null) would instead return the 4-char string "null" -- getstr never does that). Pass a non-"" fallback (e.g. "?") when "missing" needs to read differently from a real empty string.',example:'dir = getstr(req, "dir");'},{name:"getnum",category:"Maps & Key-Value",signature:"getnum(obj: any, path: string|array, [fallback: number = 0]): number",description:"Typed form of get(): reads a numeric field, coercing a present value with num(); fallback when missing or null.",example:'count = getnum(req, "count", 1);'},{name:"getbool",category:"Maps & Key-Value",signature:"getbool(obj: any, path: string|array, [fallback: boolean = false]): boolean",description:'Typed form of get(): reads a boolean field. The strings "true"/"false" (any case) parse as booleans; fallback when missing or null.',example:'seed = getbool(req, "seed", true);'},{name:"getlist",category:"Maps & Key-Value",signature:"getlist(obj: any, path: string|array, [fallback: array = []]): array",description:"Typed form of get(): reads an array field, fallback (default []) when missing, null, or not actually an array.",example:'reviewers = getlist(req, "reviewers");'},{name:"require",category:"System & Process",signature:"require(value: any, message: string): any",description:'Validates a request-form field in one line: if value is missing ("", null, [], or false), reports through injected diagnostics/captured errors and stops with exit 1; otherwise returns value unchanged so it composes with getstr/getnum/getbool/getlist.',example:'dir = require(getstr(req, "dir"), "missing required field: dir");'},{name:"regex_test",category:"Strings",signature:"regex_test(s: string, pattern: string, [flags: string]): boolean",description:"Tests a JavaScript regex against text.",example:'regex_test("abc", "a");'},{name:"regex_match",category:"Strings",signature:"regex_match(s: string, pattern: string, [flags: string]): array|null",description:"Returns first [full_match, group1, ...], including with g; missing optional groups become null. Rejects sticky y.",example:'regex_match("a1 b2", "([a-z])([0-9])", "g");'},{name:"regex_find_all",category:"Strings",signature:"regex_find_all(s: string, pattern: string, [flags: string]): array",description:"Returns capture arrays for matches; zero-width progress follows code points in u/v modes. Rejects sticky y.",example:'regex_find_all("a1 b2", "([a-z])([0-9])");'},{name:"regex_replace",category:"Strings",signature:"regex_replace(s: string, pattern: string, replacement: string, [flags: string]): string",description:"JavaScript regex replacement with $1 captures; use g for repeated replacement.",example:'regex_replace("a1", "([a-z])([0-9])", "$2$1");'},{name:"split_regex",category:"Strings",signature:"split_regex(s: string, pattern: string, [flags: string]): array",description:"Splits using JavaScript regex semantics.",example:'split_regex("a b", " +");'},{name:"split",category:"Strings",signature:"split(s: string, delimiter: string): array",description:"Splits a string by delimiter into an array of substrings.",example:'parts = split("a,b,c", ",");'},{name:"sprintf",category:"Strings",signature:"sprintf(template: string, ...args: any): string",description:"Formats %s, %d, %f and %% with optional decimal width and .precision, - left alignment and 0 numeric padding. String precision truncates; integer precision pads digits; float precision rounds (0..100). Bare %f keeps normal number text. Width/other precision limit: 10000. Unsupported directives and missing values are errors; extra arguments are ignored.",example:'s = sprintf("%05.2f|%s|%d", 3.14159, "x", 42);'},{name:"lines",category:"Strings",signature:"lines(s: string): array",description:"Splits a string into an array of lines.",example:'arr = lines("line1\\nline2");'},{name:"last_line_as_status",category:"Strings",signature:"last_line_as_status(s: string): string|null",description:"Returns the state word (DONE, NOTHING_TO_DO, BLOCKED, OTHER) from the last 3 non-blank lines of a string, or null if absent or conflicting.",example:"status = last_line_as_status(reply);"},{name:"words",category:"Strings",signature:"words(s: string): array",description:"Splits a string into non-whitespace words.",example:'w = words("hello world from lmscript");'},{name:"join",category:"Strings",signature:"join(arr: array, [separator: string]): string",description:"Joins array elements into a string separated by delimiter.",example:'s = join(["apple", "banana"], ", ");'},{name:"trim",category:"Strings",signature:"trim(s: string): string",description:"Trims whitespace from both ends of a string.",example:'clean = trim(" hello ");'},{name:"strip",category:"Strings",signature:"strip(s: string): string",description:"Trims whitespace from both ends of a string (alias for trim).",example:'clean = strip(" hello ");'},{name:"trim_start",category:"Strings",signature:"trim_start(s: string): string",description:"Trims whitespace from the beginning of a string.",example:'s = trim_start(" hello");'},{name:"lstrip",category:"Strings",signature:"lstrip(s: string): string",description:"Trims whitespace from the beginning of a string (alias for trim_start).",example:'s = lstrip(" hello");'},{name:"trim_end",category:"Strings",signature:"trim_end(s: string): string",description:"Trims whitespace from the end of a string.",example:'s = trim_end("hello ");'},{name:"rstrip",category:"Strings",signature:"rstrip(s: string): string",description:"Trims whitespace from the end of a string (alias for trim_end).",example:'s = rstrip("hello ");'},{name:"to_upper",category:"Strings",signature:"to_upper(s: string): string",description:"Converts all characters in string to uppercase.",example:'u = to_upper("hello");'},{name:"upper",category:"Strings",signature:"upper(s: string): string",description:"Converts all characters in string to uppercase (alias for to_upper).",example:'u = upper("hello");'},{name:"to_lower",category:"Strings",signature:"to_lower(s: string): string",description:"Converts all characters in string to lowercase.",example:'l = to_lower("HELLO");'},{name:"lower",category:"Strings",signature:"lower(s: string): string",description:"Converts all characters in string to lowercase (alias for to_lower).",example:'l = lower("HELLO");'},{name:"upper_first",category:"Strings",signature:"upper_first(s: string): string",description:"Capitalizes the first character of a string.",example:'c = upper_first("hello");'},{name:"title_case",category:"Strings",signature:"title_case(s: string): string",description:"Converts words in a string to Title Case.",example:'t = title_case("hello world");'},{name:"contains",category:"Strings",signature:"contains(haystack: string|array, needle: any): boolean",description:"Checks if a string or array contains an item or substring.",example:'if (contains("hello", "ell")) { print("matched"); }'},{name:"includes",category:"Strings",signature:"includes(haystack: string|array, needle: any): boolean",description:"Alias for contains.",example:'if (includes([1, 2, 3], 2)) { print("found"); }'},{name:"starts_with",category:"Strings",signature:"starts_with(s: string, prefix: string): boolean",description:"Checks if a string starts with the given prefix.",example:'if (starts_with("prefix_name", "prefix_")) { ... }'},{name:"startswith",category:"Strings",signature:"startswith(s: string, prefix: string): boolean",description:"Checks if a string starts with the given prefix (alias for starts_with).",example:'if (startswith("prefix_name", "prefix_")) { ... }'},{name:"ends_with",category:"Strings",signature:"ends_with(s: string, suffix: string): boolean",description:"Checks if a string ends with the given suffix.",example:'if (ends_with("file.txt", ".txt")) { ... }'},{name:"endswith",category:"Strings",signature:"endswith(s: string, suffix: string): boolean",description:"Checks if a string ends with the given suffix (alias for ends_with).",example:'if (endswith("file.txt", ".txt")) { ... }'},{name:"index_of",category:"Strings",signature:"index_of(haystack: string|array, needle: any, [fromIndex: number]): number",description:"Finds the first index of a substring or item, or -1 if not found.",example:'idx = index_of("banana", "a");'},{name:"last_index_of",category:"Strings",signature:"last_index_of(haystack: string|array, needle: any): number",description:"Finds the last index of a substring or item, or -1 if not found.",example:'idx = last_index_of("banana", "a");'},{name:"count_matches",category:"Strings",signature:"count_matches(s: string, sub: string): number",description:"Counts non-overlapping occurrences of a substring.",example:'n = count_matches("banana", "a");'},{name:"substr",category:"Strings",signature:"substr(s: string, start: number, [length: number]): string",description:"Returns a substring by start and optional length; negative starts count from the end and clamp at zero. Nonpositive lengths return empty text.",example:'sub = substr("hello", 1, 3);'},{name:"substring",category:"Strings",signature:"substring(s: string, start: number, [end: number]): string",description:"Returns a substring between start and end indices.",example:'sub = substring("hello", 1, 4);'},{name:"slice",category:"Strings",signature:"slice(target: string|array, start: number, [end: number]): string|array",description:"Extracts a section of a string or array.",example:"part = slice([1, 2, 3, 4], 1, 3);"},{name:"char_at",category:"Strings",signature:"char_at(s: string, index: number): string",description:"Returns the character at the specified index.",example:'c = char_at("hello", 0);'},{name:"char_code",category:"Strings",signature:"char_code(s: string, [index: number = 0]): number",description:"Returns the UTF-16 code unit at index.",example:'code = char_code("A");'},{name:"from_char_code",category:"Strings",signature:"from_char_code(...codes: number): string",description:"Returns string from character codes.",example:"s = from_char_code(65, 66, 67);"},{name:"replace",category:"Strings",signature:"replace(s: string, search: string, replacement: string): string",description:"Replaces the first occurrence of search substring.",example:'s = replace("hello world", "world", "lmscript");'},{name:"replace_all",category:"Strings",signature:"replace_all(s: string, search: string, replacement: string): string",description:"Replaces all occurrences of search substring.",example:'s = replace_all("foo bar foo", "foo", "baz");'},{name:"repeat",category:"Strings",signature:"repeat(s: string, count: number): string",description:"Repeats a string count times.",example:'stars = repeat("*", 10);'},{name:"pad_start",category:"Strings",signature:'pad_start(s: string, targetLength: number, [padChar: string = " "]): string',description:"Left-pads string to target length.",example:'num_str = pad_start("5", 3, "0");'},{name:"pad_end",category:"Strings",signature:'pad_end(s: string, targetLength: number, [padChar: string = " "]): string',description:"Right-pads string to target length.",example:'row = pad_end("title", 20, ".");'},{name:"reverse_str",category:"Strings",signature:"reverse_str(s: string): string",description:"Reverses characters in a string.",example:'rev = reverse_str("abc");'},{name:"is_empty",category:"Strings",signature:"is_empty(val: any): boolean",description:"Literal emptiness: null, empty string, empty array or empty map; whitespace-only strings are not empty. Use is_blank for whitespace.",example:'if (is_empty(arr)) { print("empty"); }'},{name:"is_digit",category:"Strings",signature:"is_digit(s: string): boolean",description:"Checks if a string contains only digits.",example:'if (is_digit("123")) { print("all digits"); }'},{name:"is_alpha",category:"Strings",signature:"is_alpha(s: string): boolean",description:"Checks if a string contains only alphabetic characters.",example:'if (is_alpha("abc")) { ... }'},{name:"is_alnum",category:"Strings",signature:"is_alnum(s: string): boolean",description:"Checks if a string contains only letters and digits.",example:'if (is_alnum("item42")) { ... }'},{name:"format",category:"Strings",signature:"format(template: string, ...args: any): string",description:"Formats a template string replacing {{}} brace escapes, positional {0}, auto {}, and {key} map placeholders.",example:'msg = format("Hello, {}! You have {} tasks.", "User", 3);'},{name:"warning",category:"System & Process",signature:"warning(message: any): string",description:"Adds a located warning without failing execution or simulating an effect.",example:'warning("Review this input");'},{name:"which",category:"System & Process",signature:"which(name: string): string|null",description:"Returns the first executable absolute path from invocation PATH/cwd, or null, without spawning.",example:'tool = which("node");'},{name:"cmd_render",category:"System & Process",signature:"cmd_render(argv: array, [dialect: string]): string",description:"Renders string/number argv for posix, windows or powershell; default windows on win32, otherwise posix. Output only; never used for execution.",example:'text = cmd_render(["git", "status"], "posix");'},{name:"len",category:"Lists & Arrays",signature:"len(item: any): number",description:"Returns the length of a string, array, or number of object keys.",example:"n = len([10, 20, 30]);"},{name:"push",category:"Lists & Arrays",signature:"push(arr: array, ...items: any): array",description:"Appends an element to the end of an array and returns the array.",example:'push(items, "new_item");'},{name:"pop",category:"Lists & Arrays",signature:"pop(arr: array): any",description:"Removes and returns the last element of an array.",example:"last = pop(items);"},{name:"shift",category:"Lists & Arrays",signature:"shift(arr: array): any",description:"Removes and returns the first element of an array.",example:"first = shift(items);"},{name:"unshift",category:"Lists & Arrays",signature:"unshift(arr: array, ...items: any): array",description:"Prepends an element to the beginning of an array.",example:'unshift(items, "header");'},{name:"insert",category:"Lists & Arrays",signature:"insert(arr: array, index: number, item: any): array",description:"Inserts an element at the specified index in an array.",example:'insert(items, 1, "inserted");'},{name:"remove_at",category:"Lists & Arrays",signature:"remove_at(arr: array, index: number): any",description:"Removes and returns the element at the specified index.",example:"removed = remove_at(items, 0);"},{name:"concat",category:"Lists & Arrays",signature:"concat(first: array, ...more: array): array",description:"Concatenates two or more arrays into a new array.",example:"all = concat(arr1, arr2);"},{name:"reverse",category:"Lists & Arrays",signature:"reverse(arr: array): array",description:"Reverses elements of an array in place.",example:"reverse(items);"},{name:"sort",category:"Lists & Arrays",signature:"sort(arr: array, [key: string]): array",description:"Sorts array elements numerically, alphabetically, or by object key.",example:'sorted = sort(users, "age");'},{name:"unique",category:"Lists & Arrays",signature:"unique(arr: array): array",description:"Returns a new array with duplicate elements removed.",example:"deduped = unique([1, 2, 2, 3]);"},{name:"flatten",category:"Lists & Arrays",signature:"flatten(arr: array): array",description:"Flattens a nested array by one level.",example:"flat = flatten([[1, 2], [3, 4]]);"},{name:"first",category:"Lists & Arrays",signature:"first(arr: array): any",description:"Returns the first element of an array, or null if empty.",example:"top = first(items);"},{name:"last",category:"Lists & Arrays",signature:"last(arr: array): any",description:"Returns the last element of an array, or null if empty.",example:"tail = last(items);"},{name:"sum",category:"Lists & Arrays",signature:"sum(arr: array): number",description:"Computes the arithmetic sum of numeric elements in an array.",example:"total = sum([1, 2, 3, 4]);"},{name:"avg",category:"Lists & Arrays",signature:"avg(arr: array): number",description:"Computes the arithmetic mean of numeric elements in an array.",example:"mean = avg([10, 20, 30]);"},{name:"range",category:"Lists & Arrays",signature:"range(start: number, [end: number], [step: number = 1]): array",description:"Generates an array of numbers from start to end by step.",example:"nums = range(0, 5);"},{name:"keys",category:"Maps & Key-Value",signature:"keys(obj: object): array",description:"Returns an array of own property keys of an object.",example:"k = keys({ a: 1, b: 2 });"},{name:"values",category:"Maps & Key-Value",signature:"values(obj: object): array",description:"Returns an array of own property values of an object.",example:"v = values({ a: 1, b: 2 });"},{name:"entries",category:"Maps & Key-Value",signature:"entries(obj: object): array",description:"Returns an array of [key, value] pairs for an object.",example:"pairs = entries({ a: 1, b: 2 });"},{name:"from_entries",category:"Maps & Key-Value",signature:"from_entries(pairs: array): object",description:"Constructs an object from an array of [key, value] pairs.",example:'obj = from_entries([["name", "Bob"], ["age", 25]]);'},{name:"has_key",category:"Maps & Key-Value",signature:"has_key(obj: object, key: string): boolean",description:"Checks if an object has the specified own property key.",example:'if (has_key(config, "port")) { ... }'},{name:"get",category:"Maps & Key-Value",signature:"get(obj: any, path: string|array, [defaultVal: any]): any",description:"Retrieves a nested property safely using a dot or array path.",example:'val = get(config, "database.host", "localhost");'},{name:"set",category:"Maps & Key-Value",signature:"set(obj: object, path: string|array, value: any): object",description:"Sets a nested property on an object using a dot or array path.",example:'set(config, "server.port", 8080);'},{name:"delete_key",category:"Maps & Key-Value",signature:"delete_key(obj: object, key: string): object",description:"Deletes a key from an object.",example:'delete_key(data, "temp");'},{name:"merge",category:"Maps & Key-Value",signature:"merge(a: object, b: object): object",description:"Shallow merges two objects into a new object.",example:"combined = merge(defaults, overrides);"},{name:"clone",category:"Maps & Key-Value",signature:"clone(val: any): any",description:"Deep clones an object or array via JSON serialization.",example:"copy = clone(original);"},{name:"json_parse",category:"JSON & Data",signature:"json_parse(str: string): any",description:"Alias for json.",example:"data = json_parse(text);"},{name:"json_parse_safe",category:"JSON & Data",signature:"json_parse_safe(str: string, [fallback: any = null]): any",description:'Safely parses JSON with markdown fence and preamble tolerance, returning fallback on failure without throwing. Use a custom sentinel (e.g. "PARSE_FAILED") to distinguish parse failure from valid JSON null.',example:'data = json_parse_safe(llm_output, "PARSE_FAILED"); if (data == "PARSE_FAILED") { print("parse failed"); }'},{name:"json_stringify",category:"JSON & Data",signature:"json_stringify(val: any, [indent: number = 0]): string",description:"Serializes a value to compact JSON by default; optional indent formats the output.",example:"text = json_stringify(obj, 2);"},{name:"pluck",category:"JSON & Data",signature:"pluck(arr: array, key: string): array",description:"Extracts the specified key from each object in an array.",example:'names = pluck(users, "name");'},{name:"filter_by",category:"JSON & Data",signature:"filter_by(arr: array, key: string, value: any): array",description:"Filters an array of objects where item[key] == value.",example:'active = filter_by(users, "active", true);'},{name:"find_by",category:"JSON & Data",signature:"find_by(arr: array, key: string, value: any): any",description:"Finds the first object in an array where item[key] == value.",example:'user = find_by(users, "id", 42);'},{name:"num",category:"Math",signature:"num(val: any): number",description:"Converts a value to a numeric type.",example:'n = num("42.5");'},{name:"round",category:"Math",signature:"round(n: number): number",description:"Rounds a number to the nearest integer.",example:"r = round(3.7);"},{name:"floor",category:"Math",signature:"floor(n: number): number",description:"Returns the largest integer less than or equal to a number.",example:"f = floor(3.9);"},{name:"ceil",category:"Math",signature:"ceil(n: number): number",description:"Returns the smallest integer greater than or equal to a number.",example:"c = ceil(3.1);"},{name:"min",category:"Math",signature:"min(...nums: number|array): number",description:"Returns the minimum value from numbers or a number array.",example:"m = min(10, 5, 20);"},{name:"max",category:"Math",signature:"max(...nums: number|array): number",description:"Returns the maximum value from numbers or a number array.",example:"m = max([10, 5, 20]);"},{name:"abs",category:"Math",signature:"abs(n: number): number",description:"Returns the absolute value of a number.",example:"a = abs(-42);"},{name:"sqrt",category:"Math",signature:"sqrt(n: number): number",description:"Returns the square root of a number.",example:"s = sqrt(16);"},{name:"pow",category:"Math",signature:"pow(base: number, exp: number): number",description:"Calculates base raised to exponent.",example:"p = pow(2, 8);"},{name:"random",category:"Math",signature:"random(): number",description:"Returns a pseudo-random floating point number in [0, 1).",example:"r = random();"},{name:"system",category:"System & Process",signature:"system(argv: array, [timeoutMs: number = 60000 | options: map]): SystemResult",description:"Executes a non-empty string/number argv list directly with shell:false, returning a structured process execution record. The second argument is a timeout in milliseconds or an options map {cwd, timeoutMs, stdin}; a cwd that does not exist gives a result with code null and an error field instead of a failure.",parameters:[{name:"argv",type:"array",description:"Non-empty argv list of strings/numbers; NUL and an empty program are errors"},{name:"timeoutMs|options",type:"number|map",description:"(optional) Timeout in milliseconds (default: 60000), or options {cwd: string (relative to the invocation directory), timeoutMs: number (default 60000), stdin: string}; unknown keys are errors"}],returns:{type:"SystemResult",description:"{ stdout: string, stderr: string, code: number|null, signal: string|null, timed_out: bool, duration_ms: number, pid: number|null, error?: string }"},example:'res = system(["git", "log", "-n", "1"], {cwd: "."}); if (res.code == 0) { print(res.stdout); }'},{name:"prompt_human",category:"System & Process",signature:"prompt_human([question: string], [options: map]): string|null; prompt_human(session: map, [options: map]): map",description:"Pauses execution to prompt an operator on terminal stdin or dedicated directory, returning the entered input line or decision map, or null if stdin is closed/non-interactive.",example:'guidance = prompt_human("Enter instructions (or Enter to halt): "); if (guidance != null) { process(guidance); }'},{name:"prompt_human_config",category:"System & Process",signature:"prompt_human_config([config: map|string], [dir: string]): map",description:"Configures prompt_human mode ('interactive' or 'file' with dedicated directory, timeout_ms, poll_ms). Returns current configuration map.",example:'prompt_human_config({ dir: "/tmp/handoffs", timeout_ms: 60000 });'},{name:"error",category:"System & Process",signature:"error(value: any, ...args: any): string",description:"Formats and logs an error to stderr and records it for the execution error summary.",example:'error("Operation failed:", reason);'},{name:"exit",category:"System & Process",signature:"exit([code: number = 0]): never",description:"Terminates script execution immediately with exit code.",example:"exit(0);"},{name:"print",category:"System & Process",signature:"print(...args: any): string",description:"Formats values into an output-log entry rendered as a line by the CLI. Returns the formatted text without adding a newline.",example:'print("Result:", val);'},{name:"printf",category:"System & Process",signature:"printf(template: string, ...args: any): string",description:"Formats %s, %d, %f and %% with the sprintf width and precision rules and writes exactly that text to stdout: nothing is added, so end the format with \\n to finish the line.",example:'printf("%s scored %d\\n", "Alice", 95);'},{name:"println",category:"System & Process",signature:"println(...args: any): string",description:"Alias of print: both log formatted values rendered as a line by the CLI and return text without adding a newline.",example:'println("Done.");'},{name:"sleep_ms",category:"System & Process",signature:"sleep_ms(ms: number): void",description:"Pauses execution for specified milliseconds.",example:"sleep_ms(1000);"},{name:"now",category:"System & Process",signature:"now(): number",description:"Returns current epoch in milliseconds.",example:"t = now();"},{name:"timestamp",category:"System & Process",signature:"timestamp(): number",description:"Returns current Unix epoch in whole seconds.",example:"t = timestamp();"},{name:"date",category:"System & Process",signature:"date([epochMs: number]): string",description:"Returns an ISO 8601 date-time string for now or a supplied epoch-millisecond value.",example:"created = date(0);"},{name:"strftime",category:"System & Process",signature:"strftime(epochMs: number, fmt: string): string",description:"Takes epoch milliseconds first and format second, using local time. Supports %Y, %m, %d, %H, %M, %S and %% only; other tokens remain literal. Invalid dates or argument types are errors.",example:'s = strftime(now(), "%Y-%m-%d");'},{name:"coalesce",category:"System & Process",signature:"coalesce(...values: any): any",description:"Returns the first non-null/non-undefined argument, else null (including no arguments).",example:'v = coalesce(a, b, "default");'},{name:"if_null",category:"System & Process",signature:"if_null(val: any, fallback: any): any",description:"Returns fallback if val is null/undefined, else val.",example:'v = if_null(maybe_null, "default");'},{name:"if_else",category:"System & Process",signature:"if_else(cond: any, thenVal: any, elseVal: any): any",description:"Eager compatibility helper: returns thenVal if cond is truthy, else elseVal; all three arguments are evaluated. Use condition ? thenVal : elseVal for lazy selection.",example:'label = if_else(count > 0, "some", "none");'},{name:"str",category:"System & Process",signature:"str(val: any): string",description:"Converts lists and plain maps to compact JSON using the f-string collection rule; scalars retain normal text. Cyclic or lossy collections are errors. Does not change + coercion.",example:"s = str(123);"},{name:"is_array",category:"System & Process",signature:"is_array(val: any): boolean",description:"Checks if a value is an array (type-check alias over type()).",example:"if (is_array(val)) { ... }"},{name:"is_string",category:"System & Process",signature:"is_string(val: any): boolean",description:"Checks if a value is a string (type-check alias over type()).",example:"if (is_string(val)) { ... }"},{name:"is_number",category:"System & Process",signature:"is_number(val: any): boolean",description:"Checks if a value is a number (type-check alias over type()).",example:"if (is_number(val)) { ... }"},{name:"is_map",category:"System & Process",signature:"is_map(val: any): boolean",description:"Checks if a value is a map/object (type-check alias over type()).",example:"if (is_map(val)) { ... }"},{name:"is_function",category:"System & Process",signature:"is_function(val: any): boolean",description:"Checks if a value is a first-class function reference (type-check alias over type()).",example:"if (is_function(val)) { ... }"},{name:"type",category:"System & Process",signature:"type(val: any): string",description:"Returns the runtime type of a value ('string', 'number', 'boolean', 'array', 'object', 'null', 'function').",example:"t = type(data);"},{name:"assert",category:"System & Process",signature:"assert(condition: any, [message: string]): boolean",description:"Throws an error if condition is falsy.",example:'assert(len(items) > 0, "Items list must not be empty");'},{name:"http_get",category:"System & Process",signature:"http_get(url: string): string",description:"Performs HTTP(S) GET request and returns response body string.",example:'html = http_get("https://example.com");'}],rM=[{name:"is_blank",category:"Strings",signature:"is_blank(s: any): boolean",description:"Returns true if string is null, empty, or whitespace only.",example:'if (is_blank(user_input)) { println("input required"); }'},{name:"chunk",category:"Lists & Arrays",signature:"chunk(arr: array, size: number): array",description:"Splits an array into chunks of specified size.",example:"batches = chunk(items, 10);"},{name:"compact",category:"Lists & Arrays",signature:"compact(arr: array): array",description:"Returns a new array with all null elements removed.",example:"valid = compact([1, null, 2, null, 3]);"},{name:"zip",category:"Lists & Arrays",signature:"zip(arr1: array, arr2: array): array",description:"Combines two arrays into an array of pairs [[a1, b1], [a2, b2], ...].",example:'pairs = zip(["a", "b"], [1, 2]);'},{name:"take",category:"Lists & Arrays",signature:"take(arr: array, n: number): array",description:"Returns the first n elements of an array.",example:"first_three = take(items, 3);"},{name:"drop",category:"Lists & Arrays",signature:"drop(arr: array, n: number): array",description:"Returns a new array with the first n elements omitted.",example:"rest = drop(items, 3);"},{name:"clamp",category:"Math",signature:"clamp(val: number, low: number, high: number): number",description:"Restricts a numeric value to lie within [low, high] bounds.",example:"bounded = clamp(score, 0, 100);"}];Rr=class t{hostFunctions=new Map;functionDocs=new Map;registeredModules=new Map;functionOriginModule=new Map;currentRegisteringModule="core";outputLogs=[];isAsyncMode=!1;promptHumanConfig={mode:"interactive"};hostCatalog=new Map;nativeCatalog=new Map;builtinProviders=new Map;hostResolver;reservedFunctionPrefixes;builtinProviderNames;constructor(e={}){this.hostResolver=e.resolveHostModule,this.registeredModules.set("core",{name:"core",description:"LMScript core language built-ins and standard library"}),this.registerPredefinedFunctions();for(let[n,r]of[["get_property",{min:1,max:2}],["has_property",1],["get_properties",{min:0,max:1}],["set_property",2]])this.registerFunction(n,()=>{throw Error("Property store is not running")},r,"Read or overlay hierarchical run-local properties; no persistence");this.registerFunction("expand",()=>{throw Error("Template resolver is not running")},{min:1,max:2},"Expand simple references from explicit vars, PROPS paths and invocation ARGV; inserted text is opaque"),this.registerFunction("warning",n=>String(n),1,{description:"Adds a located non-failure warning",isDefault:!0,returnType:"string"}),this.registerFunction("which",n=>Um(n,process.cwd(),process.env),1,{description:"Finds the first executable path without spawning",isDefault:!0,returnType:"string|null"});for(let n of["print","println","printf"]){let r=this.hostFunctions.get(n),s=[{name:"dryrun",type:"boolean",optional:!0},...n==="printf"?[{name:"format",type:"string"}]:[],{name:"values",type:"any",rest:!0}],i=dn(n,{min:n==="printf"?2:0},s,"string",r.doc),o=r.fn;n==="printf"?r.fn=(a,...l)=>a?Ul(l[0],l.slice(1),"printf"):o(...l):r.fn=(a,...l)=>a?l.map(c=>typeof c=="object"?JSON.stringify(c):String(c)).join(" "):o(...l),Object.assign(r,{params:i.nativeParams,arity:i.nativeArity,signature:i,returnType:"string"})}for(let[n,r]of this.hostFunctions){let s=rp[n];s&&(r[Ge]=s)}this.registerDefaultDocs();for(let[n,r,s]of[["get_property","get_property(key, [default])","Returns a copied property value; absent keys are errors unless a default is supplied."],["has_property","has_property(key)","Tests property presence; missing/invalid profile errors remain loud."],["get_properties","get_properties([prefix])","Returns a detached nested property table copy."],["set_property","set_property(key, value)","Returns the previous value and changes only the run-local overlay; invocation facts are read-only."]])this.functionDocs.set(n,{name:n,signature:r,description:s,module:"core",category:"Properties"});this.functionDocs.set("expand",{name:"expand",signature:"expand(text, [vars])",description:"Resolve ${name} from an explicit vars map, ${PROPS.path}, and ${ARGV[n]}; $${ escapes, no caller-local capture or recursive expansion.",module:"core",category:"Strings"})}registerDefaultDocs(){for(let e of tM)this.functionDocs.set(e.name,{...e,module:e.module??"core"});for(let e of nM)this.registerFunctionDoc({...e,module:e.module??"core"});for(let e of rM)this.functionDocs.set(e.name,{...e,module:e.module??"core"})}registerFunctionDoc(e){let n=Wm({...e,module:e.module??this.currentRegisteringModule});this.functionDocs.set(e.name,n);let r=this.hostFunctions.get(e.name);return r&&this.hostFunctions.set(e.name,{...r,doc:n,signature:dn(e.name,r.arity,r.params,r.returnType,n)}),this}registerModule(e,n){if(this.registeredModules.has(e.name))throw new Error(`Module '${e.name}' is already registered`);this.registeredModules.set(e.name,e);let r=this.currentRegisteringModule;this.currentRegisteringModule=e.name;try{if(e.docs)for(let s of e.docs)this.registerFunctionDoc({...s,module:s.module??e.name});typeof e.register=="function"&&e.register(this,n)}finally{this.currentRegisteringModule=r}return this}getModules(){return Array.from(this.registeredModules.values())}getModule(e){return this.registeredModules.get(e)}getFunctionsByModule(e){return this.getFunctionDocs().filter(n=>(n.module??"core").toLowerCase()===e.toLowerCase())}getFunctionDocs(){return[...this.functionDocs.keys()].map(e=>this.getFunctionDoc(e))}getFunctionDoc(e){let n=this.functionDocs.get(e),r=this.hostFunctions.get(e)?.signature;return!n||!r?n:{...n,...r.returnType?{returns:{type:r.returnType,description:n.returns?.description??"Declared result type"}}:{},...r.dryrunIndex===void 0?{}:{signature:e+"("+r.publicParams.map(s=>s.rest?"..."+s.name:s.optional?"["+s.name+"]":s.name).join(", ")+")",parameters:n.parameters?.filter(s=>s.name!=="dryrun")}}}getFunctionCategories(){let e=new Set;for(let n of this.functionDocs.values())e.add(n.category);return Array.from(e)}getFunctionsByCategory(e){return Array.from(this.functionDocs.values()).filter(n=>n.category.toLowerCase()===e.toLowerCase())}registerPredefinedFunctions(){this.registerFunction("read_file",e=>j.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read",e=>j.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read_lines",e=>{let n=j.readFileSync(e,"utf-8"),r=n.length>0;return n.endsWith(`\r
431
+ `:""),M=I.exitCode!==void 0?I.exitCode:I.success&&!I.errors?.length?0:1,D={success:I.success&&M===0,stdout:C,output:[...I.output],value:I.value??null,exit_code:M,code:M,errors:I.errors??[]};for(let U of[...I.errors??[],...I.diagnostics.filter($=>$.severity==="error").map($=>$.message)])this.recordedErrors.push(U);return D}},arity:E?.arity??{min:1,max:2},description:"Executes another LMScript file in-process and returns execution result with .stdout, .output, .success, .exit_code",isDefault:!0});let x=e.get("http_get");(!x||x.isDefault)&&this.hostFunctions.set("http_get",{...x,fn:R=>this.isAsync?fL(R):Zb(R),arity:x?.arity??1,description:"Downloads UTF-8 text from a public HTTP(S) URL",isDefault:!0});let S=e.get("sleep_ms");if((!S||S.isDefault)&&this.hostFunctions.set("sleep_ms",{...S,fn:R=>{if(typeof R!="number"||!Number.isFinite(R)||R<0)throw new Error("sleep_ms() duration must be a non-negative finite number");if(R>2147483647)throw new Error("sleep_ms() duration exceeds maximum supported timeout (2147483647 ms)");if(this.isAsync)return new Promise(O=>setTimeout(O,R));let N=Date.now()+R;for(;Date.now()<N;);return null},arity:S?.arity??1,description:"Sleeps for the specified milliseconds",isDefault:!0}),this.dry)for(let[R,N]of e)N.signature?.dryrunIndex!==void 0&&this.hostFunctions.set(R,N)}evaluateProgram(e){if(this.globalEnv=new yt,this.initialGlobals)for(let[r,s]of this.initialGlobals.entries())this.globalEnv.define(r,s);this.userFunctions.clear(),this.callDepth=0;for(let r of e.statements)r.kind==="FunctionDeclStmt"&&this.userFunctions.set(r.name,r);let n;for(let r of e.statements)r.kind!=="FunctionDeclStmt"&&(n=this.execStmt(r,this.globalEnv));return this.checkRootRemainder(e),n}enterRecover(e,n){if(n)throw new P("recover cannot be entered inside a parallel task",e.line,e.column,"RUNTIME",e.file);let r=this.recovery;if(r.entered.has(e))throw new P("recover statement already entered during this run",e.line,e.column,"RUNTIME",e.file);if(r.entered.add(e),r.active=!0,r.pending.length===0)return{start:0,consumed:!1};let s=r.pending.shift(),i=e.points.findIndex(o=>o.name===s);if(i<0)throw new P(`Unknown resumepoint '${s}' in entered recover; available: ${e.points.map(o=>o.name).join(", ")}`,e.line,e.column,"RUNTIME",e.file);return{start:i,consumed:!0}}enterPoint(e,n){this.recovery.stack.length=e,this.recovery.stack.push(n),this.publishResumepoint()}leaveRecover(e){this.recovery.stack.length=e,this.publishResumepoint()}publishResumepoint(){this.recovery.probe.currentPath=this.recovery.stack.length>0?this.recovery.stack.join("."):null,this.globalEnv.define("RESUMEPOINT",this.recovery.stack.length>0?this.recovery.stack.join("."):null)}checkRemainder(e){if(rt(this.abortSignal),this.recovery.pending.length>0)throw new P(`resumepoint path not consumed: ${this.recovery.pending.join(".")}`,e.line,e.column,"RUNTIME",e.file)}checkRootRemainder(e){if(rt(this.abortSignal),!(this.recordedErrors.length>0)&&this.recovery.pending.length>0)throw new P(`resumepoint path not consumed: ${this.recovery.pending.join(".")}`,e.line,e.column,"RUNTIME",e.file)}checkRecoverRead(e,n,r,s){let i=this.recoverScopedReads.get(r);if(!i)return;let o=this.recovery.envs.get(i);if(o&&n.resolveBinding(e)?.env!==o)throw new P(`Variable '${e}' was read before its binding was initialized`,s.line,s.column,"RUNTIME",s.file)}recoverWriteScope(e,n){let r=this.recoverScopedWrites.get(n)?.get(e);return r?this.recovery.envs.get(r):void 0}execStmt(e,n){let r=this.tracer;if(!r||e.kind==="BlockStmt"||e.kind==="FunctionDeclStmt"||e.kind==="ImportStmt"||e.kind==="PackageStmt")return this.execStmtCore(e,n);r.stmt(e,n),e.kind==="BreakStmt"?r.jump("break",e):e.kind==="ContinueStmt"&&r.jump("continue",e);try{return this.execStmtCore(e,n)}catch(s){throw s instanceof Qe?e.kind==="ReturnStmt"&&r.jump("return",e):s instanceof lt||s instanceof ct||r.raise(s,e),s}}execStmtCore(e,n){switch(this.dry?.at(e),rt(this.abortSignal),e.kind){case"PackageStmt":{if(e.nativeModule&&!this.dry){let r=this.nativeImports?.get(e.nativeModule)?.();if(ut(r))throw new P("Native import requires runAsync",e.line,e.column,"RUNTIME",e.file)}return}case"ImportStmt":return;case"BlockStmt":{let r=new yt(n);for(let s of e.statements)this.execStmt(s,r);return}case"VarDeclStmt":{let r=null;return e.initializer&&(r=this.evalExpr(e.initializer,n)),n.define(e.name,r),r}case"TupleVarDeclStmt":{let r=this.evalExpr(e.initializer,n);if(!Array.isArray(r))throw new P(`Cannot destructure non-array value (got ${typeof r})`,e.line,e.column,"RUNTIME",e.file);for(let s=0;s<e.names.length;s++){let i=s<r.length?r[s]:null;n.define(e.names[s],i)}return r}case"IfStmt":{let r=this.evalExpr(e.condition,n);return this.isTruthy(r)?(this.tracer?.branch("then",e.thenBranch,n),this.execStmt(e.thenBranch,n)):e.elseBranch?(this.tracer?.branch("else",e.elseBranch,n),this.execStmt(e.elseBranch,n)):void 0}case"WhileStmt":{let r=0,s=this.tracer,i=s?.loopEnter("while",e),o="done";try{for(;!this.dry?.loop(r,e)&&this.isTruthy(this.evalExpr(e.condition,n));){if(++r>1e6&&!this.dry)throw new P("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");s?.loopIter(i,r,e,n);try{this.execStmt(e.body,n)}catch(a){if(a instanceof lt){o="break";break}if(a instanceof ct)continue;throw a}}}catch(a){throw o=a instanceof Qe?"return":"raise",a}finally{s?.loopExit(i,r,o)}return}case"ForInStmt":{let r=Lb(this.evalExpr(e.iterable,n),e,this.dry),s=0,i=this.tracer,o=i?.loopEnter("foreach",e),a="done";try{for(let l=0;(l<r.length||this.dry&&s===this.dry.loopLimit)&&!this.dry?.loop(s,e);l++){let c=r[l];if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let u=new yt(n);u.define(e.name,c),i?.loopIter(o,s,e,u);try{if(e.body.kind==="BlockStmt")for(let d of e.body.statements)this.execStmt(d,u);else this.execStmt(e.body,u)}catch(d){if(d instanceof lt){a="break";break}if(d instanceof ct)continue;throw d}}}catch(l){throw a=l instanceof Qe?"return":"raise",l}finally{i?.loopExit(o,s,a)}return}case"ForStmt":{let r=new yt(n);e.init&&this.execStmt(e.init,r);let s=0,i=this.tracer,o=i?.loopEnter("for",e),a="done";try{for(;!this.dry?.loop(s,e);){if(e.condition){let l=this.evalExpr(e.condition,r);if(!this.isTruthy(l))break}if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");i?.loopIter(o,s,e,r);try{this.execStmt(e.body,r)}catch(l){if(l instanceof lt){a="break";break}if(!(l instanceof ct))throw l}if(this.dry?.loop(s,e))break;e.update&&this.evalExpr(e.update,r)}}catch(l){throw a=l instanceof Qe?"return":"raise",l}finally{i?.loopExit(o,s,a)}return}case"ReturnStmt":{let r=e.value?this.evalExpr(e.value,n):null;throw new Qe(r)}case"BreakStmt":throw new lt;case"ContinueStmt":throw new ct;case"SyncAssignStmt":case"SyncIndexAssignStmt":case"SyncCallStmt":throw new P("Synchronized statements require asynchronous execution via engine.runAsync()",e.line,e.column,"RUNTIME",e.file);case"ExprStmt":{if(e.expr.kind==="DataBlockExpr"&&e.expr.marker==="cmd"){let r=this.evalExpr(e.expr,n);return this.invokeNamed("system",[r],n,e.expr.line,e.expr.column,e.expr.file)}return this.evalExpr(e.expr,n)}case"RecoverStmt":{let r=this.enterRecover(e,!1),s=new yt(n);this.recovery.envs.set(e,s);let i=this.recovery.stack.length;try{for(let o=r.start;o<e.points.length;o++){let a=e.points[o];this.enterPoint(i,a.name);for(let l of a.statements)this.execStmt(l,s);r.consumed&&o===r.start&&this.checkRemainder(a)}}catch(o){throw Yt(this.recovery,o),o}finally{this.leaveRecover(i)}return}default:return}}evalExpr(e,n){switch(rt(this.abortSignal),e.kind){case"CommandExpr":{let r=[];for(let i of e.words){let o=[];for(let a of i.pieces)o.push(typeof a=="string"?a:this.evalExpr(a.expression,n));r.push(o)}let s=Ob(e,r);return e.mode==="cmd"?s:this.invokeNamed("system",[s],n,e.line,e.column,e.file)}case"InterpolatedStringExpr":{let r="";for(let s of e.parts)r+=typeof s=="string"?s:tp(this.evalExpr(s.expression,n),s);return r}case"ParallelExpr":throw new P("'parallel(...)' requires asynchronous execution via engine.runAsync()",e.line,e.column,"RUNTIME",e.file);case"LiteralExpr":return e.value;case"PathLiteralExpr":return $b(e,this.platform);case"DataBlockExpr":{let r=Jm(e,i=>this.evalExpr(i.value,n)),s=[];for(let i of e.lines)for(let o of i.pieces)typeof o!="string"&&s.push(this.evalExpr(o.expression,n));return kb(e,r,s,this.compileOptions)}case"IdentifierExpr":return this.resolveIdentifier(e.name,n,e);case"AssignExpr":{let r=this.evalExpr(e.value,n),s=this.recovery.active?this.recoverWriteScope(e.target,e):void 0;return s?s.define(e.target,r):n.set(e.target,r),r}case"TupleAssignExpr":{let r=this.evalExpr(e.value,n);if(!Array.isArray(r))throw new P(`Cannot destructure non-array value (got ${typeof r})`,e.line,e.column,"RUNTIME",e.file);for(let s=0;s<e.targets.length;s++){let i=s<r.length?r[s]:null,o=this.recovery.active?this.recoverWriteScope(e.targets[s],e):void 0;o?o.define(e.targets[s],i):n.set(e.targets[s],i)}return r}case"IndexAssignExpr":{let r=this.evalExpr(e.target,n),s=this.evalExpr(e.index,n),i=this.evalExpr(e.value,n);if(Array.isArray(r)||typeof r=="object"&&r!==null)return Array.isArray(r)&&typeof s=="number"&&s<0&&(s=r.length+s),dt(r,s,i),i;throw new P("Cannot index-assign to non-array / non-object",e.line,e.column,"RUNTIME",e.file)}case"GroupingExpr":return this.evalExpr(e.expression,n);case"TupleExpr":return e.elements.map(r=>this.evalExpr(r,n));case"ArrayExpr":return e.elements.map(r=>this.evalExpr(r,n));case"ObjectExpr":{let r={};for(let s of e.properties)dt(r,s.key,this.evalExpr(s.value,n));return r}case"IndexExpr":{let r=Jl(e);if(r)try{this.dry&&this.dry.at(e);let o=this.dry?.prepareProperties(r);if(ut(o))throw o.catch(()=>{}),Error("Async properties require dryRunAsync");return At(this.dry?this.dry.propertyView:this.resolveIdentifier("PROPS",n,e),r)}catch(o){throw this.dry?new P(o instanceof Error?o.message:String(o),e.line,e.column,"RUNTIME",e.file):o}let s=this.evalExpr(e.target,n),i=this.evalExpr(e.index,n);if(s==null)throw new P("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Yn.has(s)?Bb(s,i,e,this.dry):Db(s,i,e)}case"MethodCallExpr":{let r=this.evalExpr(e.receiver,n),s=e.args.map(i=>this.evalExpr(i,n));return Fb(r,e,s)}case"UnaryExpr":{let r=this.evalExpr(e.operand,n),s=e.operator;if(s==="!")return!this.isTruthy(r);if(s==="-")return-r;throw new P(`Unknown unary operator: ${s}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let r=this.evalExpr(e.condition,n);return this.isTruthy(r)?this.evalExpr(e.trueArm,n):this.evalExpr(e.falseArm,n)}case"BinaryExpr":{if(e.operator==="&&"){let o=this.evalExpr(e.left,n);return this.isTruthy(o)?this.evalExpr(e.right,n):o}if(e.operator==="||"){let o=this.evalExpr(e.left,n);return this.isTruthy(o)?o:this.evalExpr(e.right,n)}let r=this.evalExpr(e.left,n),s=this.evalExpr(e.right,n),i=e.operator;switch(i){case"+":return typeof r=="string"||typeof s=="string"?String(r)+String(s):r+s;case"-":return r-s;case"*":return r*s;case"/":if(s===0)throw new P("Division by zero",e.line,e.column,"RUNTIME",e.file);return r/s;case"%":return r%s;case"==":return r===s;case"!=":return r!==s;case"<":return r<s;case"<=":return r<=s;case">":return r>s;case">=":return r>=s;default:throw new P(`Unknown binary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let r=e.args.map(s=>this.evalExpr(s,n));return this.recovery.active&&!this.userFunctions.has(e.callee)&&!this.hostFunctions.has(e.callee)&&this.checkRecoverRead(e.callee,n,e,e),this.invokeNamed(this.resolveCallTarget(e.callee,n),r,n,e.line,e.column,e.file)}}}resolveIdentifier(e,n,r){if(this.recovery.active&&this.checkRecoverRead(e,n,r,r),n.has(e)){let s=n.get(e);if(s&&typeof s=="object"&&cp.has(s)){this.dry&&this.dry.at(r);try{let i=cp.get(s)();return ut(i)?i.catch(o=>{throw new P(String(o.message??o),r.line,r.column,"RUNTIME",r.file)}):i}catch(i){throw new P(String(i.message??i),r.line,r.column,"RUNTIME",r.file)}}return s}if(this.userFunctions.has(e)||this.hostFunctions.has(e))return new Qn(e);throw new P(`Variable '${e}' was read before its binding was initialized`,r.line,r.column,"RUNTIME",r.file)}resolveCallTarget(e,n){if(this.userFunctions.has(e)||this.hostFunctions.has(e))return e;let r=n.get(e);return r instanceof Qn?r.name:e}invokeNamed(e,n,r,s,i,o){let a=this.tracer,l=this.userFunctions.get(e);if(!a||!l&&!this.hostFunctions.has(e))return this.invokeNamedCore(e,n,r,s,i,o);a.call(e,l?l.params.map((u,d)=>({name:u,value:n[d]})):n.map(u=>({value:u})),!l,l);let c;try{c=this.invokeNamedCore(e,n,r,s,i,o)}catch(u){throw u instanceof Qe||u instanceof lt||u instanceof ct||a.raise(u,{line:s,column:i,file:o}),a.ret(null,!0,u),u}return a.ret(c),c}invokeNamedCore(e,n,r,s,i,o){if(this.dry?.at({line:s,column:i,file:o}),rt(this.abortSignal),this.userFunctions.has(e)){let a=this.userFunctions.get(e);if(this.callDepth++,this.callDepth>Ml)throw this.callDepth--,new P(`Execution fuel exhausted: maximum function call depth exceeded (${Ml})`,s,i,"RUNTIME",o);let l=new yt(this.globalEnv,!0);for(let c=0;c<a.params.length;c++)l.define(a.params[c],n[c]);try{for(let c of a.body.statements)this.execStmt(c,l)}catch(c){if(c instanceof Qe)return c.value;throw c}finally{this.callDepth--}return null}if(this.hostFunctions.has(e)){let a=this.hostFunctions.get(e);try{if(a[Ge]?.control==="warning"){Co(a,n);let u=String(this.dry?mn(n)[0]:n[0]);return this.warningDiagnostics.push({severity:"warning",message:u,line:s,column:i,file:o}),u}if(this.dry){let u=Hb(a,n,e,{line:s,column:i,file:o},this.dry,this.platform);if(u.skip)return u.value;let d=Io(a,u.args);if(this.dry.check(),ut(d)&&(Promise.resolve(d).catch(()=>{}),this.dry.fail("Async host requires dryRunAsync",{line:s,column:i,file:o})),this.dry.failure)throw new Qt(this.dry.failure.message);return ws(d)&&this.dry.fail("Dry host returned a live or unsupported capability",{line:s,column:i,file:o}),a[Ge]?.taints===!1&&this.dry.captureOutput(e,d),u.handled&&this.dry.record(e,u.publicArgs,{line:s,column:i,file:o},"handled",void 0,u.taints),d}let l=Co(a,n);if(a.returnsResource)throw new P(`'${e}' returns a resource and requires engine.runAsync(); the synchronous engine.run refuses to call it`,s,i,"RUNTIME",o);rt(this.abortSignal);let c=Io(a,l);if(a.returnsResource&&ut(c))throw c.then(u=>{try{u&&typeof u.finalizeSync=="function"?u.finalizeSync():u&&typeof u.close=="function"&&u.close()}catch{}},()=>{}),new Error("returns a resource asynchronously; use engine.runAsync()");return c}catch(l){throw this.dry?.captureFailure(l,{line:s,column:i,file:o}),l instanceof Bt||l?.name==="LMScriptExit"||l?.isControlFlow?l:new P(`Error in host function '${e}': ${l?.message||String(l)}`,s,i,"RUNTIME",o)}}throw r.has(e)?new P(`'${e}' is not a function`,s,i,"RUNTIME",o):new P(ci(e,"Undefined function"),s,i,"RUNTIME",o)}ownerFor(e,n){let r=this.resources.scopeFor(e),s=this.temporaryScopes.get(n),i=s&&s[s.length-1];return i&&i.base===r?i:r}pushTemporaryScope(e,n){let r=this.temporaryScopes.get(e);r?r.push(n):this.temporaryScopes.set(e,[n])}popTemporaryScope(e){let n=this.temporaryScopes.get(e);n?.pop(),n&&n.length===0&&this.temporaryScopes.delete(e)}async execLoopBodyAsync(e,n,r){await this.execStmtAsync(e,n,r)}resourceError(e,n,r){return new P(`Resource ${this.resources.describe(e)} ${n}`,r.line,r.column,"RUNTIME",r.file)}refuseResource(e,n,r){if(Oe(e))throw this.resourceError(e,n,r)}bindResource(e,n,r,s){let i=this.resources.bind(e,n,r);if(i)throw new P(i.charAt(0).toUpperCase()+i.slice(1),s.line,s.column,"RUNTIME",s.file)}async resourceCallArgs(e,n,r,s,i,o){if(!r.some(Oe))return r;let a={line:s,column:i,file:o};if(!e.usesResource&&!e.closesResource)throw this.resourceError(r.find(Oe),`cannot be passed to '${n}'`,a);let l=[];for(let c of r){if(!Oe(c)){l.push(c);continue}let u=this.resources.lookup(c);if(!u)throw this.resourceError(c,`cannot be used by '${n}': it belongs to another run`,a);if(e.closesResource)this.resources.borrow(c),await this.resources.close(u,r.slice(1));else if(u.state!=="open")throw this.resourceError(c,`is ${u.state==="closing"?"closing":"closed"}: '${n}' cannot use it`,a);this.resources.borrow(c),l.push(u.raw)}return l}registerHostResource(e,n,r,s,i,o){if(e==null)return e;if(typeof e!="object"||typeof e.close!="function"||typeof e.id!="string"&&typeof e.id!="number"||String(e.id)==="")throw new Error("a returnsResource host must return null or an object with a close method and a stable id");return this.resources.register(e,n,`${o??"<main>"}:${s}:${i}`,r)}isTruthy(e){return!(e==null||e===!1||e===0||e==="")}async evaluateProgramAsync(e){if(this.globalEnv=new yt,this.initialGlobals)for(let[s,i]of this.initialGlobals.entries())this.globalEnv.define(s,i);this.userFunctions.clear(),this.asyncCallDepth.clear();for(let s of e.statements)s.kind==="FunctionDeclStmt"&&this.userFunctions.set(s.name,s);let n=this.nextTaskId++;this.recovery.rootTaskId=n;let r;try{for(let s of e.statements)s.kind!=="FunctionDeclStmt"&&(r=await this.execStmtAsync(s,this.globalEnv,n))}catch(s){throw Yt(this.recovery,s),this.resources.root.failure=ys(s),s}finally{await this.resources.drain(this.resources.root)}if(this.checkRootRemainder(e),Oe(r))r=null;else if(Wb()){let s=ws(r);if(s)throw new P(Oe(s)?`Resource ${this.resources.describe(s)} cannot leave the run inside the result value`:Xm(s,"run"),1,1,"RUNTIME")}return r}coOf(e){return e===this.recovery.rootTaskId?"main":"t"+e}async execStmtAsync(e,n,r){let s=this.tracer;if(!s||e.kind==="BlockStmt"||e.kind==="FunctionDeclStmt"||e.kind==="ImportStmt"||e.kind==="PackageStmt")return this.execStmtAsyncCore(e,n,r);let i=this.coOf(r);s.stmt(e,n,i),e.kind==="BreakStmt"?s.jump("break",e,i):e.kind==="ContinueStmt"&&s.jump("continue",e,i);try{return await this.execStmtAsyncCore(e,n,r)}catch(o){throw o instanceof Qe?e.kind==="ReturnStmt"&&s.jump("return",e,i):o instanceof lt||o instanceof ct||s.raise(o,e,i),o}}async execStmtAsyncCore(e,n,r){switch(this.dry?.at(e),rt(this.abortSignal),e.kind){case"PackageStmt":{e.nativeModule&&!this.dry&&await this.nativeImports?.get(e.nativeModule)?.();return}case"ImportStmt":return;case"BlockStmt":{let s=new yt(n);if(!this.resourcesEnabled){for(let o of e.statements)await this.execStmtAsync(o,s,r);return}let i=this.resources.enterScope(s,this.ownerFor(n,r),"block");try{for(let o of e.statements)await this.execStmtAsync(o,s,r)}catch(o){throw Yt(this.recovery,o),i.failure=ys(o),o}finally{i.records.length>0&&await this.resources.drain(i)}return}case"VarDeclStmt":{let s=null;return e.initializer&&(s=await this.evalExprAsync(e.initializer,n,r)),Oe(s)&&this.bindResource(s,n,e.name,e),n.define(e.name,s),s}case"TupleVarDeclStmt":{let s=await this.evalExprAsync(e.initializer,n,r);if(Array.isArray(s))for(let i=0;i<e.names.length&&i<s.length;i++)this.bindResource(s[i],n,e.names[i],e);if(!Array.isArray(s))throw new P(`Cannot destructure non-array value (got ${typeof s})`,e.line,e.column,"RUNTIME",e.file);for(let i=0;i<e.names.length;i++){let o=i<s.length?s[i]:null;n.define(e.names[i],o)}return s}case"IfStmt":{let s=await this.evalExprAsync(e.condition,n,r);return this.isTruthy(s)?(this.tracer?.branch("then",e.thenBranch,n,this.coOf(r)),await this.execStmtAsync(e.thenBranch,n,r)):e.elseBranch?(this.tracer?.branch("else",e.elseBranch,n,this.coOf(r)),await this.execStmtAsync(e.elseBranch,n,r)):void 0}case"WhileStmt":{let s=0,i=this.tracer,o=this.coOf(r),a=i?.loopEnter("while",e,o),l="done";try{for(;!this.dry?.loop(s,e)&&this.isTruthy(await this.evalExprAsync(e.condition,n,r));){if(++s>1e6&&!this.dry)throw new P("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");i?.loopIter(a,s,e,n,o);try{this.resourcesEnabled?await this.execLoopBodyAsync(e.body,n,r):await this.execStmtAsync(e.body,n,r)}catch(c){if(c instanceof lt){l="break";break}if(c instanceof ct)continue;throw c}}}catch(c){throw l=c instanceof Qe?"return":"raise",c}finally{i?.loopExit(a,s,l,o)}return}case"ForInStmt":{let s=Lb(await this.evalExprAsync(e.iterable,n,r),e,this.dry),i=0,o=this.tracer,a=this.coOf(r),l=o?.loopEnter("foreach",e,a),c="done";try{for(let u=0;(u<s.length||this.dry&&i===this.dry.loopLimit)&&!this.dry?.loop(i,e);u++){let d=s[u];if(++i>1e6&&!this.dry)throw new P("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let m=new yt(n);m.define(e.name,d),o?.loopIter(l,i,e,m,a);let p=this.resourcesEnabled?this.resources.enterScope(m,this.ownerFor(n,r),"iteration"):void 0;try{try{if(e.body.kind==="BlockStmt")for(let f of e.body.statements)await this.execStmtAsync(f,m,r);else await this.execStmtAsync(e.body,m,r)}catch(f){throw Yt(this.recovery,f),p&&(p.failure=ys(f)),f}finally{p&&p.records.length>0&&await this.resources.drain(p)}}catch(f){if(f instanceof lt){c="break";break}if(f instanceof ct)continue;throw f}}}catch(u){throw c=u instanceof Qe?"return":"raise",u}finally{o?.loopExit(l,i,c,a)}return}case"ForStmt":{let s=new yt(n),i=this.resourcesEnabled?this.resources.enterScope(s,this.ownerFor(n,r),"for"):void 0;try{e.init&&await this.execStmtAsync(e.init,s,r);let o=0,a=this.tracer,l=this.coOf(r),c=a?.loopEnter("for",e,l),u="done";try{for(;!this.dry?.loop(o,e);){if(e.condition){let d=await this.evalExprAsync(e.condition,s,r);if(!this.isTruthy(d))break}if(++o>1e6&&!this.dry)throw new P("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");a?.loopIter(c,o,e,s,l);try{this.resourcesEnabled?await this.execLoopBodyAsync(e.body,s,r):await this.execStmtAsync(e.body,s,r)}catch(d){if(d instanceof lt){u="break";break}if(!(d instanceof ct))throw d}if(this.dry?.loop(o,e))break;e.update&&await this.evalExprAsync(e.update,s,r)}}catch(d){throw u=d instanceof Qe?"return":"raise",d}finally{a?.loopExit(c,o,u,l)}}catch(o){throw Yt(this.recovery,o),i&&(i.failure=ys(o)),o}finally{i&&i.records.length>0&&await this.resources.drain(i)}return}case"ReturnStmt":{let s=e.value?await this.evalExprAsync(e.value,n,r):null;throw Oe(s)&&this.refuseResource(s,"cannot be returned: a resource stays with its owner (return copied data instead)",e),new Qe(s)}case"BreakStmt":throw new lt;case"ContinueStmt":throw new ct;case"SyncAssignStmt":{let s=this.recovery.active?this.recoverWriteScope(e.target,e):void 0,i=s?{env:s,name:e.target}:n.resolveBinding(e.target);if(!i)throw new P(`Synchronized assignment target '${e.target}' is not defined`,e.line,e.column,"RUNTIME",e.file);let o=`bind:${i.env.id}:${i.name}`;await this.lockManager.getBindingLock(o).withLock(async()=>{let l=await this.evalExprAsync(e.value,n,r);this.bindResource(l,i.env,i.name,e),i.env.define(i.name,l)},r);return}case"SyncIndexAssignStmt":{let s=await this.evalExprAsync(e.target,n,r);if(s==null||typeof s!="object"&&typeof s!="function")throw new P("Cannot perform synchronized assignment on non-object",e.line,e.column,"RUNTIME",e.file);await this.lockManager.getObjectLock(s).withLock(async()=>{let o=await this.evalExprAsync(e.index,n,r),a=await this.evalExprAsync(e.value,n,r);this.refuseResource(s,"cannot be modified",e),this.refuseResource(o,"cannot be used as a map key",e),this.refuseResource(a,"cannot be stored in a container",e),Array.isArray(s)&&typeof o=="number"&&o<0&&(o=s.length+o),dt(s,o,a)},r);return}case"SyncCallStmt":{let s=e.call;if(s.args.length===0)throw new P("Synchronized call requires at least one argument (the target container)",e.line,e.column,"RUNTIME",e.file);let i=this.hostFunctions.get(s.callee);if(!i||!i.isContainerMutation)throw new P(`Function '${s.callee}' is not an authorized container mutation operation`,e.line,e.column,"RUNTIME",e.file);let o=await this.evalExprAsync(s.args[0],n,r);if(o==null||typeof o!="object"&&typeof o!="function")throw new P("Target of synchronized call must be an array or map",e.line,e.column,"RUNTIME",e.file);await this.lockManager.getObjectLock(o).withLock(async()=>{let l=[];for(let c=1;c<s.args.length;c++)l.push(await this.evalExprAsync(s.args[c],n,r));await this.invokeCallAsync(s.callee,[o,...l],n,e.line,e.column,r,e.file)},r);return}case"ExprStmt":{if(e.expr.kind==="DataBlockExpr"&&e.expr.marker==="cmd"){let s=await this.evalExprAsync(e.expr,n,r);return await this.invokeCallAsync("system",[s],n,e.expr.line,e.expr.column,r,e.expr.file)}return await this.evalExprAsync(e.expr,n,r)}case"RecoverStmt":{let s=this.enterRecover(e,r!==this.recovery.rootTaskId),i=new yt(n);this.recovery.envs.set(e,i);let o=this.resourcesEnabled?this.resources.enterScope(i,this.ownerFor(n,r),"block"):void 0,a=this.recovery.stack.length;try{for(let l=s.start;l<e.points.length;l++){let c=e.points[l];this.enterPoint(a,c.name);for(let u of c.statements)await this.execStmtAsync(u,i,r);s.consumed&&l===s.start&&this.checkRemainder(c)}}catch(l){throw Yt(this.recovery,l),o&&(o.failure=ys(l)),l}finally{try{o&&o.records.length>0&&await this.resources.drain(o)}finally{this.leaveRecover(a)}}return}default:return}}async evalExprAsync(e,n,r){switch(rt(this.abortSignal),e.kind){case"CommandExpr":{let s=[];for(let o of e.words){let a=[];for(let l of o.pieces)a.push(typeof l=="string"?l:await this.evalExprAsync(l.expression,n,r));s.push(a)}let i=Ob(e,s);return e.mode==="cmd"?i:await this.invokeCallAsync("system",[i],n,e.line,e.column,r,e.file)}case"InterpolatedStringExpr":{let s="";for(let i of e.parts){if(typeof i=="string"){s+=i;continue}let o=await this.evalExprAsync(i.expression,n,r);this.refuseResource(o,"cannot be converted to text",i.expression),s+=tp(o,i)}return s}case"LiteralExpr":return e.value;case"PathLiteralExpr":return $b(e,this.platform);case"DataBlockExpr":{let s={};for(let o of e.options)s[o.name]=await this.evalExprAsync(o.value,n,r);let i=[];for(let o of e.lines)for(let a of o.pieces)typeof a!="string"&&i.push(await this.evalExprAsync(a.expression,n,r));return kb(e,Jm(e,o=>s[o.name]),i,this.compileOptions)}case"IdentifierExpr":return this.resolveIdentifier(e.name,n,e);case"AssignExpr":{let s=await this.evalExprAsync(e.value,n,r),i=this.recovery.active?this.recoverWriteScope(e.target,e):void 0;return Oe(s)&&this.bindResource(s,i??n.writeTarget(e.target),e.target,e),i?i.define(e.target,s):n.set(e.target,s),s}case"TupleAssignExpr":{let s=await this.evalExprAsync(e.value,n,r);if(!Array.isArray(s))throw new P(`Cannot destructure non-array value (got ${typeof s})`,e.line,e.column,"RUNTIME",e.file);for(let i=0;i<e.targets.length;i++){let o=i<s.length?s[i]:null,a=this.recovery.active?this.recoverWriteScope(e.targets[i],e):void 0;Oe(o)&&this.bindResource(o,a??n.writeTarget(e.targets[i]),e.targets[i],e),a?a.define(e.targets[i],o):n.set(e.targets[i],o)}return s}case"IndexAssignExpr":{let s=await this.evalExprAsync(e.target,n,r),i=await this.evalExprAsync(e.index,n,r),o=await this.evalExprAsync(e.value,n,r);if(this.refuseResource(s,"cannot be modified",e),this.refuseResource(i,"cannot be used as a map key",e),this.refuseResource(o,"cannot be stored in a container",e),Array.isArray(s)||typeof s=="object"&&s!==null)return Array.isArray(s)&&typeof i=="number"&&i<0&&(i=s.length+i),dt(s,i,o),o;throw new P("Cannot index-assign to non-array / non-object",e.line,e.column,"RUNTIME",e.file)}case"GroupingExpr":return await this.evalExprAsync(e.expression,n,r);case"TupleExpr":{let s=[];for(let i of e.elements){let o=await this.evalExprAsync(i,n,r);this.refuseResource(o,"cannot be stored in a container",i),s.push(o)}return s}case"ArrayExpr":{let s=[];for(let i of e.elements){let o=await this.evalExprAsync(i,n,r);this.refuseResource(o,"cannot be stored in a container",i),s.push(o)}return s}case"ObjectExpr":{let s={};for(let i of e.properties){let o=await this.evalExprAsync(i.value,n,r);this.refuseResource(o,"cannot be stored in a container",i.value),dt(s,i.key,o)}return s}case"ParallelExpr":{if(e.tasks.length===0)return[];let s=this.asyncCallDepth.get(r)??0,i=async u=>{let d=this.nextTaskId++;this.asyncCallDepth.set(d,s);let m=this.resourcesEnabled?this.resources.temporaryScope(this.ownerFor(n,r),"task",this.resources.scopeFor(n)):void 0;m&&this.pushTemporaryScope(d,m);try{let p=await this.evalExprAsync(u,n,d),f=Wb()?ws(p):void 0;if(f)throw new P(Oe(f)?`Resource ${this.resources.describe(f)} cannot be a parallel task result: it stays with the task that opened it`:Xm(f,"parallel task"),u.line,u.column,"RUNTIME",u.file);return p}catch(p){throw this.dry?.captureFailure(p,u),Yt(this.recovery,p),m&&(m.failure=ys(p)),p}finally{m&&(this.popTemporaryScope(d),m.records.length>0&&await this.resources.drain(m))}};if(this.dry){let u=[];for(let d of e.tasks)this.dry.at(d),u.push(await i(d));return u}let o=e.tasks.map(i),a=await Promise.allSettled(o),l=[],c;for(let u of a)u.status==="fulfilled"?l.push(u.value):c||(c=u.reason);if(c)throw c;return l}case"IndexExpr":{let s=Jl(e);if(s)try{return this.dry&&(this.dry.at(e),await this.dry.prepareProperties(s)),At(this.dry?this.dry.propertyView:await this.resolveIdentifier("PROPS",n,e),s)}catch(a){throw this.dry?new P(a instanceof Error?a.message:String(a),e.line,e.column,"RUNTIME",e.file):a}let i=await this.evalExprAsync(e.target,n,r),o=await this.evalExprAsync(e.index,n,r);if(this.refuseResource(o,"cannot be used as a map key",e),Oe(i)){if(o==="id")return i.id;throw this.resourceError(i,`has no readable field '${String(o)}' (only id)`,e)}if(i==null)throw new P("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Yn.has(i)?Bb(i,o,e,this.dry):Db(i,o,e)}case"MethodCallExpr":{let s=await this.evalExprAsync(e.receiver,n,r),i=[];for(let o of e.args)i.push(await this.evalExprAsync(o,n,r));return this.refuseResource(s,"has no methods",e),Fb(s,e,i)}case"UnaryExpr":{let s=await this.evalExprAsync(e.operand,n,r),i=e.operator;if(i==="!")return!this.isTruthy(s);if(this.refuseResource(s,"cannot be used in arithmetic",e),i==="-")return-s;throw new P(`Unknown unary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let s=await this.evalExprAsync(e.condition,n,r);return this.isTruthy(s)?await this.evalExprAsync(e.trueArm,n,r):await this.evalExprAsync(e.falseArm,n,r)}case"BinaryExpr":{if(e.operator==="&&"){let a=await this.evalExprAsync(e.left,n,r);return this.isTruthy(a)?await this.evalExprAsync(e.right,n,r):a}if(e.operator==="||"){let a=await this.evalExprAsync(e.left,n,r);return this.isTruthy(a)?a:await this.evalExprAsync(e.right,n,r)}let s=await this.evalExprAsync(e.left,n,r),i=await this.evalExprAsync(e.right,n,r),o=e.operator;switch((Oe(s)||Oe(i))&&o!=="=="&&o!=="!="&&(this.refuseResource(s,`cannot be used with '${o}' (only ==, != and truth tests)`,e),this.refuseResource(i,`cannot be used with '${o}' (only ==, != and truth tests)`,e)),o){case"+":return typeof s=="string"||typeof i=="string"?String(s)+String(i):s+i;case"-":return s-i;case"*":return s*i;case"/":if(i===0)throw new P("Division by zero",e.line,e.column,"RUNTIME",e.file);return s/i;case"%":return s%i;case"==":return s===i;case"!=":return s!==i;case"<":return s<i;case"<=":return s<=i;case">":return s>i;case">=":return s>=i;default:throw new P(`Unknown binary operator: ${o}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let s=[];for(let i of e.args)s.push(await this.evalExprAsync(i,n,r));return this.recovery.active&&!this.userFunctions.has(e.callee)&&!this.hostFunctions.has(e.callee)&&this.checkRecoverRead(e.callee,n,e,e),await this.invokeCallAsync(e.callee,s,n,e.line,e.column,r,e.file)}}}async invokeCallAsync(e,n,r,s,i,o,a){let l=this.tracer,c=this.resolveCallTarget(e,r),u=this.userFunctions.get(c);if(!l||!u&&!this.hostFunctions.has(c))return this.invokeCallAsyncCore(e,n,r,s,i,o,a);let d=this.coOf(o);l.call(c,u?u.params.map((p,f)=>({name:p,value:n[f]})):n.map(p=>({value:p})),!u,u,d);let m;try{m=await this.invokeCallAsyncCore(e,n,r,s,i,o,a)}catch(p){throw p instanceof Qe||p instanceof lt||p instanceof ct||l.raise(p,{line:s,column:i,file:a},d),l.ret(null,!0,p,d),p}return l.ret(m,!1,void 0,d),m}async invokeCallAsyncCore(e,n,r,s,i,o,a){this.dry?.at({line:s,column:i,file:a});let l=this.resolveCallTarget(e,r);if(rt(this.abortSignal),this.userFunctions.has(l)){let c=this.userFunctions.get(l),u=(this.asyncCallDepth.get(o)??0)+1;if(this.asyncCallDepth.set(o,u),u>Ml)throw this.asyncCallDepth.set(o,u-1),new P(`Execution fuel exhausted: maximum function call depth exceeded (${Ml})`,s,i,"RUNTIME",a);let d=new yt(this.globalEnv,!0),m=this.resourcesEnabled?this.resources.enterScope(d,this.ownerFor(r,o),`function ${l}`):void 0;for(let p=0;p<c.params.length;p++)m&&this.resources.borrow(n[p]),d.define(c.params[p],n[p]);try{for(let p of c.body.statements)await this.execStmtAsync(p,d,o)}catch(p){if(p instanceof Qe)return p.value;throw this.dry?.captureFailure(p),Yt(this.recovery,p),m&&(m.failure=ys(p)),p}finally{m&&m.records.length>0&&await this.resources.drain(m),this.asyncCallDepth.set(o,u-1)}return null}if(this.hostFunctions.has(l)){let c=this.hostFunctions.get(l);try{if(c[Ge]?.control==="warning"){Co(c,n);let g=String(this.dry?mn(n)[0]:n[0]);return this.warningDiagnostics.push({severity:"warning",message:g,line:s,column:i,file:a}),g}if(this.dry){let g=Hb(c,n,l,{line:s,column:i,file:a},this.dry,this.platform);if(g.skip)return g.value;let h=await this.dry.wait(Io(c,g.args));if(this.dry.failure)throw new Qt(this.dry.failure.message);return ws(h)&&this.dry.fail("Dry host returned a live or unsupported capability",{line:s,column:i,file:a}),c[Ge]?.taints===!1&&this.dry.captureOutput(l,h),g.handled&&this.dry.record(l,g.publicArgs,{line:s,column:i,file:a},"handled",void 0,g.taints),h}let u=Co(c,n),d=eM(u)?await this.resourceCallArgs(c,l,u,s,i,a):u,p=c.returnsResource||c.usesResource||c.closesResource?yv.run({runtime:this.resources,scope:this.ownerFor(r,o),site:(a??"<main>")+":"+s+":"+i},()=>Io(c,d)):Io(c,d),f=p instanceof Promise?await p:p;return c.returnsResource?this.registerHostResource(f,l,this.ownerFor(r,o),s,i,a):f}catch(u){throw this.dry?.captureFailure(u,{line:s,column:i,file:a}),u instanceof Bt||u?.name==="LMScriptExit"||u?.isControlFlow?u:new P(`Error in host function '${l}': ${u?.message||String(u)}`,s,i,"RUNTIME",a)}}throw r.has(l)?new P(`'${l}' is not a function`,s,i,"RUNTIME",a):new P(ci(l,"Undefined function"),s,i,"RUNTIME",a)}getRecordedErrors(){return[...this.recordedErrors]}},tM=[{name:"if",category:"Language Constructs",signature:"if (condition) { ... } else { ... }",description:"Conditional branching flow control.",example:'if (x > 0) { print("yes"); } else { print("no"); }'},{name:"while",category:"Language Constructs",signature:"while (condition) { ... }",description:"Looping flow control that repeats while condition is true.",example:"while (i < 10) { i = i + 1; }"},{name:"for",category:"Language Constructs",signature:"for (x in expr) { ... }; for (init; condition; update) { ... }",description:"For-in visits a snapshot of list values, map keys or string Unicode code points with a fresh local binding. C-style loops remain supported; use let for an isolated counter.",example:"for (let i = 0; i < len(arr); i = i + 1) { print(arr[i]); }"},{name:"fn",category:"Language Constructs",signature:"fn name(arg1, arg2) { ... }",description:"Defines a custom function. Function bodies establish an isolated local variable scope for assignments, preventing accidental mutation of caller variables.",example:"fn add(a, b) { return a + b; }"},{name:"import",category:"Language Constructs",signature:'import "path"',description:"Imports and executes another script file.",example:'import "utils.lm"'},{name:"parallel",category:"Language Constructs",signature:"parallel([ call1(), call2() ])",description:"Executes an array of function calls concurrently, returning an array of results.",example:'(a,b) = parallel([ system(["echo", "1"]), system(["echo", "2"]) ]);'},{name:"sync",category:"Language Constructs",signature:"sync expr",description:"Forces sequential execution of an assignment or container mutation inside a parallel block.",example:'sync push(results, "done");'},{name:"break",category:"Language Constructs",signature:"break",description:"Exits the innermost loop.",example:"while (true) { break; }"},{name:"continue",category:"Language Constructs",signature:"continue",description:"Skips to the next iteration of the innermost loop.",example:"for (let i = 0; i < 2; i = i + 1) { if (i == 0) { continue; } }"},{name:"return",category:"Language Constructs",signature:"return expr",description:"Returns a value from a function or script.",example:"return 42;"}],nM=[{name:"sha256",category:"Math & Utilities",signature:"sha256(text: string): string",description:"Lowercase SHA-256 hex of UTF-8 bytes; rejects non-string inputs.",example:'sha256("abc");'},{name:"read_file",category:"File I/O",signature:"read_file(path: string): string",description:"Reads the entire contents of a file as a UTF-8 string.",example:'content = read_file("config.json");'},{name:"read",category:"File I/O",signature:"read(path: string): string",description:"Reads the entire contents of a file as a UTF-8 string (alias for read_file).",example:'content = read("data.txt");'},{name:"read_lines",category:"File I/O",signature:"read_lines(path: string): array",description:"Reads a file and returns an array of string lines.",example:'lines = read_lines("items.txt");'},{name:"write_lines",category:"File I/O",signature:"write_lines(path: string, lines: array): boolean",description:"Writes an array of lines to a file with trailing newline, round-tripping with read_lines.",example:'write_lines("out.txt", ["a", "b"]);'},{name:"glob",category:"File I/O",signature:"glob(pattern: string): array",description:"Finds files matching a glob pattern and returns an array of matching paths.",example:'files = glob("teams/*.lmctl");'},{name:"list_dir",category:"File I/O",signature:"list_dir(path: string): array",description:"Lists filenames in a directory.",example:'entries = list_dir(".");'},{name:"parse_file_blocks",category:"Agent Files",signature:"parse_file_blocks(text: string): array",description:"Parses `=== FILE: relative/path ===` ... `=== END ===` blocks into [{path, content}]. Prose around blocks and whitespace around marker lines are ignored; content wrapped in exactly one markdown fence is unwrapped; content gets a final newline. Incomplete blocks (no END before the next FILE marker or the end of text) are dropped, so a truncated reply yields only its complete files.",example:"files = parse_file_blocks(reply);"},{name:"format_file_blocks",category:"Agent Files",signature:"format_file_blocks(files: array): string",description:"Formats [{path, content}] as file blocks; parse_file_blocks(format_file_blocks(files)) returns files (content normalised to end in a newline). Fence-wrapped content gets an outer fence; content containing a marker line is an error.",example:"context = format_file_blocks(read_tree(dir));"},{name:"write_files",category:"Agent Files",signature:"write_files(dir: string, files: array): map",description:"Writes [{path, content}] under dir (created if missing), each file atomically (temporary file + rename, mode of a replaced file kept). Rejects, never writes: empty, absolute, backslash or '..' paths, any .git segment, a path through a symlink leaving dir, a symlink or directory target, non-string content. Returns {written: [relative paths], rejected: [{path, reason}]}; under --dry-run the same classification with dry: true and nothing created.",example:'res = write_files(dir, parse_file_blocks(reply)); println("wrote", len(res.written));'},{name:"read_tree",category:"Agent Files",signature:"read_tree(dir: string, [options: map]): array",description:"Reads text files under dir as [{path, content}] sorted by path, relative with / separators. Skips symlinks, binary/non-UTF-8 files, files over maxBytes (default 262144) and the default ignores .git, node_modules, dist, build, target, .mp, __pycache__, *.lock, package-lock.json. Options: ignore (extra patterns), include (only matching files), maxBytes. A pattern without / matches a single name, with / the whole relative path; * ? ** globs. A missing dir reads as [].",example:'listing = format_file_blocks(read_tree(dir, {ignore: ["*.md"]}));'},{name:"kv_from_last_paragraph",category:"Agent Files",signature:"kv_from_last_paragraph(text: string): map",description:"Parses `key: value` lines (key [A-Za-z_][A-Za-z0-9_-]*, optional - or * bullet, value in one pair of backticks unwrapped, empty values skipped) of the last blank-line-separated paragraph; the last occurrence of a key wins and missing keys are absent. Trailing paragraphs without any key: value line are skipped as chatter, looking at most 3 paragraphs back; a paragraph holding a file-block marker stops the search.",example:'cfg = kv_from_last_paragraph(reply); if (has_key(cfg, "build_command")) { println(cfg.build_command); }'},{name:"split_command",category:"Agent Files",signature:"split_command(text: string): array",description:"Splits one command line into argv with POSIX quoting (single quotes, double quotes, backslash). Unquoted | & ; < > ( ) ` $, $ or ` inside double quotes, a word-start #, a newline and a leading NAME=value are errors, so model-supplied commands run through system() with shell:false and no shell semantics. Globs and ~ stay literal.",example:'res = system(split_command("npm run build"), {cwd: dir});'},{name:"write_file",category:"File I/O",signature:"write_file(path: string, content: any): boolean",description:"Writes content to a file, creating or overwriting it.",example:'write_file("out.txt", "hello");'},{name:"savedsl",category:"File I/O",signature:"savedsl(dsl: dsl, path: string): boolean",description:"EXPERIMENTAL (lmctlhq/poc-web): writes the opaque value of a _dsl_ block as a portable bytecode file (big-endian, SHA-256-bound to its schema), atomically via a temp file and rename; a dry run writes nothing.",example:'savedsl(router, "build/router.dslb");'},{name:"write",category:"File I/O",signature:"write(path: string, content: any): boolean",description:"Writes content to a file (alias for write_file).",example:'write("out.txt", "data");'},{name:"append_file",category:"File I/O",signature:"append_file(path: string, content: any): boolean",description:"Appends string content to the end of a file.",example:'append_file("log.txt", "step completed\\n");'},{name:"read_json",category:"File I/O",signature:"read_json(path: string): any",description:"Reads a JSON file from disk and parses it into an object or array.",example:'data = read_json("package.json");'},{name:"write_json",category:"File I/O",signature:"write_json(path: string, data: any, [indent: number = 2]): boolean",description:"Serializes data as formatted JSON and writes it to a file.",example:'write_json("out.json", { "status": "ok" }, 2);'},{name:"read_csv",category:"File I/O",signature:'read_csv(path: string, [hasHeader: boolean = true], [delimiter: string = ","]): array',description:"Reads an RFC 4180 CSV file and parses it into an array of objects or rows.",example:'rows = read_csv("data.csv");'},{name:"write_csv",category:"File I/O",signature:'write_csv(path: string, data: array, [delimiter: string = ","]): boolean',description:"Serializes an array of objects or rows to CSV and writes to a file.",example:'write_csv("out.csv", [{ name: "Alice", age: 30 }]);'},{name:"csv_parse",category:"File I/O",signature:'csv_parse(text: string, [hasHeader: boolean = true], [delimiter: string = ","]): array',description:"Parses inline CSV text into an array of objects or rows.",example:'records = csv_parse("name,score\\nBob,95");'},{name:"csv_stringify",category:"File I/O",signature:'csv_stringify(data: array, [delimiter: string = ","]): string',description:"Serializes an array of objects or rows into RFC 4180 CSV text.",example:"csv_text = csv_stringify(records);"},{name:"file_exists",category:"File I/O",signature:"file_exists(path: string): boolean",description:"Checks if a file exists at the given path.",example:'if (file_exists("log.txt")) { print("found"); }'},{name:"temp_file",category:"File I/O",signature:"temp_file(): string",description:"Creates an empty temporary file and returns its absolute path.",example:"tmp = temp_file();"},{name:"write_file_exclusive",category:"File I/O",signature:"write_file_exclusive(path: string, content: any): boolean",description:"Creates a new file exclusively; errors if it already exists.",example:'write_file_exclusive("new.txt", "hello");'},{name:"mkdir",category:"File I/O",signature:"mkdir(dirPath: string, [recursive: boolean = true]): boolean",description:"Creates a directory, recursively by default.",example:'mkdir("out/logs");'},{name:"rmdir",category:"File I/O",signature:"rmdir(dirPath: string, [recursive: boolean = false]): boolean",description:"Removes a directory; pass true to remove a non-empty directory recursively.",example:'rmdir("out/logs", true);'},{name:"copy_file",category:"File I/O",signature:"copy_file(src: string, dest: string): boolean",description:"Copies a file to a new path.",example:'copy_file("a.txt", "b.txt");'},{name:"move_file",category:"File I/O",signature:"move_file(src: string, dest: string): boolean",description:"Moves/renames a file.",example:'move_file("draft.txt", "final.txt");'},{name:"basename",category:"File I/O",signature:"basename(filePath: string, [ext: string]): string",description:"Returns the last path segment, optionally stripping a trailing extension.",example:'name = basename("/a/b/c.txt", ".txt");'},{name:"dirname",category:"File I/O",signature:"dirname(filePath: string): string",description:"Returns the directory portion of a path.",example:'dir = dirname("/a/b/c.txt");'},{name:"path_join",category:"File I/O",signature:"path_join(...parts: string): string",description:"Joins path segments using the OS-native separator; no arguments returns dot.",example:'p = path_join("a", "b", "c.txt");'},{name:"abs_path",category:"File I/O",signature:"abs_path(filePath: string): string",description:"Resolves a path to an absolute path.",example:'p = abs_path("relative/file.txt");'},{name:"env",category:"System & Process",signature:"env(name: string, [fallback: any = null]): any",description:"Reads an environment variable, or a fallback if unset.",example:'home = env("HOME");'},{name:"getenv",category:"System & Process",signature:"getenv(name: string, [fallback: any = null]): any",description:"Reads an environment variable, or a fallback if unset (alias for env).",example:'home = getenv("HOME");'},{name:"set_env",category:"System & Process",signature:"set_env(name: string, value: any): boolean",description:"Sets an environment variable for this process and its children.",example:'set_env("DEBUG", "1");'},{name:"enumerate",category:"Lists & Arrays",signature:"enumerate(arr: array): array",description:"Returns an array of [index, value] pairs, JS/Python-familiar alongside zip (Rule 1, operator 2026-09-29).",example:'pairs = enumerate(["a", "b"]);'},{name:"items",category:"Maps & Key-Value",signature:"items(obj: object): array",description:"Returns an array of [key, value] pairs for an object (alias for entries).",example:"pairs = items({ a: 1, b: 2 });"},{name:"getstr",category:"Maps & Key-Value",signature:'getstr(obj: any, path: string|array, [fallback: string = ""]): string',description:'Typed form of get(): reads a string field, fallback (default "") when missing or null. A present number/bool is stringified (str(null) would instead return the 4-char string "null" -- getstr never does that). Pass a non-"" fallback (e.g. "?") when "missing" needs to read differently from a real empty string.',example:'dir = getstr(req, "dir");'},{name:"getnum",category:"Maps & Key-Value",signature:"getnum(obj: any, path: string|array, [fallback: number = 0]): number",description:"Typed form of get(): reads a numeric field, coercing a present value with num(); fallback when missing or null.",example:'count = getnum(req, "count", 1);'},{name:"getbool",category:"Maps & Key-Value",signature:"getbool(obj: any, path: string|array, [fallback: boolean = false]): boolean",description:'Typed form of get(): reads a boolean field. The strings "true"/"false" (any case) parse as booleans; fallback when missing or null.',example:'seed = getbool(req, "seed", true);'},{name:"getlist",category:"Maps & Key-Value",signature:"getlist(obj: any, path: string|array, [fallback: array = []]): array",description:"Typed form of get(): reads an array field, fallback (default []) when missing, null, or not actually an array.",example:'reviewers = getlist(req, "reviewers");'},{name:"require",category:"System & Process",signature:"require(value: any, message: string): any",description:'Validates a request-form field in one line: if value is missing ("", null, [], or false), reports through injected diagnostics/captured errors and stops with exit 1; otherwise returns value unchanged so it composes with getstr/getnum/getbool/getlist.',example:'dir = require(getstr(req, "dir"), "missing required field: dir");'},{name:"regex_test",category:"Strings",signature:"regex_test(s: string, pattern: string, [flags: string]): boolean",description:"Tests a JavaScript regex against text.",example:'regex_test("abc", "a");'},{name:"regex_match",category:"Strings",signature:"regex_match(s: string, pattern: string, [flags: string]): array|null",description:"Returns first [full_match, group1, ...], including with g; missing optional groups become null. Rejects sticky y.",example:'regex_match("a1 b2", "([a-z])([0-9])", "g");'},{name:"regex_find_all",category:"Strings",signature:"regex_find_all(s: string, pattern: string, [flags: string]): array",description:"Returns capture arrays for matches; zero-width progress follows code points in u/v modes. Rejects sticky y.",example:'regex_find_all("a1 b2", "([a-z])([0-9])");'},{name:"regex_replace",category:"Strings",signature:"regex_replace(s: string, pattern: string, replacement: string, [flags: string]): string",description:"JavaScript regex replacement with $1 captures; use g for repeated replacement.",example:'regex_replace("a1", "([a-z])([0-9])", "$2$1");'},{name:"split_regex",category:"Strings",signature:"split_regex(s: string, pattern: string, [flags: string]): array",description:"Splits using JavaScript regex semantics.",example:'split_regex("a b", " +");'},{name:"split",category:"Strings",signature:"split(s: string, delimiter: string): array",description:"Splits a string by delimiter into an array of substrings.",example:'parts = split("a,b,c", ",");'},{name:"sprintf",category:"Strings",signature:"sprintf(template: string, ...args: any): string",description:"Formats %s, %d, %f and %% with optional decimal width and .precision, - left alignment and 0 numeric padding. String precision truncates; integer precision pads digits; float precision rounds (0..100). Bare %f keeps normal number text. Width/other precision limit: 10000. Unsupported directives and missing values are errors; extra arguments are ignored.",example:'s = sprintf("%05.2f|%s|%d", 3.14159, "x", 42);'},{name:"lines",category:"Strings",signature:"lines(s: string): array",description:"Splits a string into an array of lines.",example:'arr = lines("line1\\nline2");'},{name:"last_line_as_status",category:"Strings",signature:"last_line_as_status(s: string): string|null",description:"Returns the state word (DONE, NOTHING_TO_DO, BLOCKED, OTHER) from the last 3 non-blank lines of a string, or null if absent or conflicting.",example:"status = last_line_as_status(reply);"},{name:"words",category:"Strings",signature:"words(s: string): array",description:"Splits a string into non-whitespace words.",example:'w = words("hello world from lmscript");'},{name:"join",category:"Strings",signature:"join(arr: array, [separator: string]): string",description:"Joins array elements into a string separated by delimiter.",example:'s = join(["apple", "banana"], ", ");'},{name:"trim",category:"Strings",signature:"trim(s: string): string",description:"Trims whitespace from both ends of a string.",example:'clean = trim(" hello ");'},{name:"strip",category:"Strings",signature:"strip(s: string): string",description:"Trims whitespace from both ends of a string (alias for trim).",example:'clean = strip(" hello ");'},{name:"trim_start",category:"Strings",signature:"trim_start(s: string): string",description:"Trims whitespace from the beginning of a string.",example:'s = trim_start(" hello");'},{name:"lstrip",category:"Strings",signature:"lstrip(s: string): string",description:"Trims whitespace from the beginning of a string (alias for trim_start).",example:'s = lstrip(" hello");'},{name:"trim_end",category:"Strings",signature:"trim_end(s: string): string",description:"Trims whitespace from the end of a string.",example:'s = trim_end("hello ");'},{name:"rstrip",category:"Strings",signature:"rstrip(s: string): string",description:"Trims whitespace from the end of a string (alias for trim_end).",example:'s = rstrip("hello ");'},{name:"to_upper",category:"Strings",signature:"to_upper(s: string): string",description:"Converts all characters in string to uppercase.",example:'u = to_upper("hello");'},{name:"upper",category:"Strings",signature:"upper(s: string): string",description:"Converts all characters in string to uppercase (alias for to_upper).",example:'u = upper("hello");'},{name:"to_lower",category:"Strings",signature:"to_lower(s: string): string",description:"Converts all characters in string to lowercase.",example:'l = to_lower("HELLO");'},{name:"lower",category:"Strings",signature:"lower(s: string): string",description:"Converts all characters in string to lowercase (alias for to_lower).",example:'l = lower("HELLO");'},{name:"upper_first",category:"Strings",signature:"upper_first(s: string): string",description:"Capitalizes the first character of a string.",example:'c = upper_first("hello");'},{name:"title_case",category:"Strings",signature:"title_case(s: string): string",description:"Converts words in a string to Title Case.",example:'t = title_case("hello world");'},{name:"contains",category:"Strings",signature:"contains(haystack: string|array, needle: any): boolean",description:"Checks if a string or array contains an item or substring.",example:'if (contains("hello", "ell")) { print("matched"); }'},{name:"includes",category:"Strings",signature:"includes(haystack: string|array, needle: any): boolean",description:"Alias for contains.",example:'if (includes([1, 2, 3], 2)) { print("found"); }'},{name:"starts_with",category:"Strings",signature:"starts_with(s: string, prefix: string): boolean",description:"Checks if a string starts with the given prefix.",example:'if (starts_with("prefix_name", "prefix_")) { ... }'},{name:"startswith",category:"Strings",signature:"startswith(s: string, prefix: string): boolean",description:"Checks if a string starts with the given prefix (alias for starts_with).",example:'if (startswith("prefix_name", "prefix_")) { ... }'},{name:"ends_with",category:"Strings",signature:"ends_with(s: string, suffix: string): boolean",description:"Checks if a string ends with the given suffix.",example:'if (ends_with("file.txt", ".txt")) { ... }'},{name:"endswith",category:"Strings",signature:"endswith(s: string, suffix: string): boolean",description:"Checks if a string ends with the given suffix (alias for ends_with).",example:'if (endswith("file.txt", ".txt")) { ... }'},{name:"index_of",category:"Strings",signature:"index_of(haystack: string|array, needle: any, [fromIndex: number]): number",description:"Finds the first index of a substring or item, or -1 if not found.",example:'idx = index_of("banana", "a");'},{name:"last_index_of",category:"Strings",signature:"last_index_of(haystack: string|array, needle: any): number",description:"Finds the last index of a substring or item, or -1 if not found.",example:'idx = last_index_of("banana", "a");'},{name:"count_matches",category:"Strings",signature:"count_matches(s: string, sub: string): number",description:"Counts non-overlapping occurrences of a substring.",example:'n = count_matches("banana", "a");'},{name:"substr",category:"Strings",signature:"substr(s: string, start: number, [length: number]): string",description:"Returns a substring by start and optional length; negative starts count from the end and clamp at zero. Nonpositive lengths return empty text.",example:'sub = substr("hello", 1, 3);'},{name:"substring",category:"Strings",signature:"substring(s: string, start: number, [end: number]): string",description:"Returns a substring between start and end indices.",example:'sub = substring("hello", 1, 4);'},{name:"slice",category:"Strings",signature:"slice(target: string|array, start: number, [end: number]): string|array",description:"Extracts a section of a string or array.",example:"part = slice([1, 2, 3, 4], 1, 3);"},{name:"char_at",category:"Strings",signature:"char_at(s: string, index: number): string",description:"Returns the character at the specified index.",example:'c = char_at("hello", 0);'},{name:"char_code",category:"Strings",signature:"char_code(s: string, [index: number = 0]): number",description:"Returns the UTF-16 code unit at index.",example:'code = char_code("A");'},{name:"from_char_code",category:"Strings",signature:"from_char_code(...codes: number): string",description:"Returns string from character codes.",example:"s = from_char_code(65, 66, 67);"},{name:"replace",category:"Strings",signature:"replace(s: string, search: string, replacement: string): string",description:"Replaces the first occurrence of search substring.",example:'s = replace("hello world", "world", "lmscript");'},{name:"replace_all",category:"Strings",signature:"replace_all(s: string, search: string, replacement: string): string",description:"Replaces all occurrences of search substring.",example:'s = replace_all("foo bar foo", "foo", "baz");'},{name:"repeat",category:"Strings",signature:"repeat(s: string, count: number): string",description:"Repeats a string count times.",example:'stars = repeat("*", 10);'},{name:"pad_start",category:"Strings",signature:'pad_start(s: string, targetLength: number, [padChar: string = " "]): string',description:"Left-pads string to target length.",example:'num_str = pad_start("5", 3, "0");'},{name:"pad_end",category:"Strings",signature:'pad_end(s: string, targetLength: number, [padChar: string = " "]): string',description:"Right-pads string to target length.",example:'row = pad_end("title", 20, ".");'},{name:"reverse_str",category:"Strings",signature:"reverse_str(s: string): string",description:"Reverses characters in a string.",example:'rev = reverse_str("abc");'},{name:"is_empty",category:"Strings",signature:"is_empty(val: any): boolean",description:"Literal emptiness: null, empty string, empty array or empty map; whitespace-only strings are not empty. Use is_blank for whitespace.",example:'if (is_empty(arr)) { print("empty"); }'},{name:"is_digit",category:"Strings",signature:"is_digit(s: string): boolean",description:"Checks if a string contains only digits.",example:'if (is_digit("123")) { print("all digits"); }'},{name:"is_alpha",category:"Strings",signature:"is_alpha(s: string): boolean",description:"Checks if a string contains only alphabetic characters.",example:'if (is_alpha("abc")) { ... }'},{name:"is_alnum",category:"Strings",signature:"is_alnum(s: string): boolean",description:"Checks if a string contains only letters and digits.",example:'if (is_alnum("item42")) { ... }'},{name:"format",category:"Strings",signature:"format(template: string, ...args: any): string",description:"Formats a template string replacing {{}} brace escapes, positional {0}, auto {}, and {key} map placeholders.",example:'msg = format("Hello, {}! You have {} tasks.", "User", 3);'},{name:"warning",category:"System & Process",signature:"warning(message: any): string",description:"Adds a located warning without failing execution or simulating an effect.",example:'warning("Review this input");'},{name:"which",category:"System & Process",signature:"which(name: string): string|null",description:"Returns the first executable absolute path from invocation PATH/cwd, or null, without spawning.",example:'tool = which("node");'},{name:"cmd_render",category:"System & Process",signature:"cmd_render(argv: array, [dialect: string]): string",description:"Renders string/number argv for posix, windows or powershell; default windows on win32, otherwise posix. Output only; never used for execution.",example:'text = cmd_render(["git", "status"], "posix");'},{name:"len",category:"Lists & Arrays",signature:"len(item: any): number",description:"Returns the length of a string, array, or number of object keys.",example:"n = len([10, 20, 30]);"},{name:"push",category:"Lists & Arrays",signature:"push(arr: array, ...items: any): array",description:"Appends an element to the end of an array and returns the array.",example:'push(items, "new_item");'},{name:"pop",category:"Lists & Arrays",signature:"pop(arr: array): any",description:"Removes and returns the last element of an array.",example:"last = pop(items);"},{name:"shift",category:"Lists & Arrays",signature:"shift(arr: array): any",description:"Removes and returns the first element of an array.",example:"first = shift(items);"},{name:"unshift",category:"Lists & Arrays",signature:"unshift(arr: array, ...items: any): array",description:"Prepends an element to the beginning of an array.",example:'unshift(items, "header");'},{name:"insert",category:"Lists & Arrays",signature:"insert(arr: array, index: number, item: any): array",description:"Inserts an element at the specified index in an array.",example:'insert(items, 1, "inserted");'},{name:"remove_at",category:"Lists & Arrays",signature:"remove_at(arr: array, index: number): any",description:"Removes and returns the element at the specified index.",example:"removed = remove_at(items, 0);"},{name:"concat",category:"Lists & Arrays",signature:"concat(first: array, ...more: array): array",description:"Concatenates two or more arrays into a new array.",example:"all = concat(arr1, arr2);"},{name:"reverse",category:"Lists & Arrays",signature:"reverse(arr: array): array",description:"Reverses elements of an array in place.",example:"reverse(items);"},{name:"sort",category:"Lists & Arrays",signature:"sort(arr: array, [key: string]): array",description:"Sorts array elements numerically, alphabetically, or by object key.",example:'sorted = sort(users, "age");'},{name:"unique",category:"Lists & Arrays",signature:"unique(arr: array): array",description:"Returns a new array with duplicate elements removed.",example:"deduped = unique([1, 2, 2, 3]);"},{name:"flatten",category:"Lists & Arrays",signature:"flatten(arr: array): array",description:"Flattens a nested array by one level.",example:"flat = flatten([[1, 2], [3, 4]]);"},{name:"first",category:"Lists & Arrays",signature:"first(arr: array): any",description:"Returns the first element of an array, or null if empty.",example:"top = first(items);"},{name:"last",category:"Lists & Arrays",signature:"last(arr: array): any",description:"Returns the last element of an array, or null if empty.",example:"tail = last(items);"},{name:"sum",category:"Lists & Arrays",signature:"sum(arr: array): number",description:"Computes the arithmetic sum of numeric elements in an array.",example:"total = sum([1, 2, 3, 4]);"},{name:"avg",category:"Lists & Arrays",signature:"avg(arr: array): number",description:"Computes the arithmetic mean of numeric elements in an array.",example:"mean = avg([10, 20, 30]);"},{name:"range",category:"Lists & Arrays",signature:"range(start: number, [end: number], [step: number = 1]): array",description:"Generates an array of numbers from start to end by step.",example:"nums = range(0, 5);"},{name:"keys",category:"Maps & Key-Value",signature:"keys(obj: object): array",description:"Returns an array of own property keys of an object.",example:"k = keys({ a: 1, b: 2 });"},{name:"values",category:"Maps & Key-Value",signature:"values(obj: object): array",description:"Returns an array of own property values of an object.",example:"v = values({ a: 1, b: 2 });"},{name:"entries",category:"Maps & Key-Value",signature:"entries(obj: object): array",description:"Returns an array of [key, value] pairs for an object.",example:"pairs = entries({ a: 1, b: 2 });"},{name:"from_entries",category:"Maps & Key-Value",signature:"from_entries(pairs: array): object",description:"Constructs an object from an array of [key, value] pairs.",example:'obj = from_entries([["name", "Bob"], ["age", 25]]);'},{name:"has_key",category:"Maps & Key-Value",signature:"has_key(obj: object, key: string): boolean",description:"Checks if an object has the specified own property key.",example:'if (has_key(config, "port")) { ... }'},{name:"get",category:"Maps & Key-Value",signature:"get(obj: any, path: string|array, [defaultVal: any]): any",description:"Retrieves a nested property safely using a dot or array path.",example:'val = get(config, "database.host", "localhost");'},{name:"set",category:"Maps & Key-Value",signature:"set(obj: object, path: string|array, value: any): object",description:"Sets a nested property on an object using a dot or array path.",example:'set(config, "server.port", 8080);'},{name:"delete_key",category:"Maps & Key-Value",signature:"delete_key(obj: object, key: string): object",description:"Deletes a key from an object.",example:'delete_key(data, "temp");'},{name:"merge",category:"Maps & Key-Value",signature:"merge(a: object, b: object): object",description:"Shallow merges two objects into a new object.",example:"combined = merge(defaults, overrides);"},{name:"clone",category:"Maps & Key-Value",signature:"clone(val: any): any",description:"Deep clones an object or array via JSON serialization.",example:"copy = clone(original);"},{name:"json_parse",category:"JSON & Data",signature:"json_parse(str: string): any",description:"Alias for json.",example:"data = json_parse(text);"},{name:"json_parse_safe",category:"JSON & Data",signature:"json_parse_safe(str: string, [fallback: any = null]): any",description:'Safely parses JSON with markdown fence and preamble tolerance, returning fallback on failure without throwing. Use a custom sentinel (e.g. "PARSE_FAILED") to distinguish parse failure from valid JSON null.',example:'data = json_parse_safe(llm_output, "PARSE_FAILED"); if (data == "PARSE_FAILED") { print("parse failed"); }'},{name:"json_stringify",category:"JSON & Data",signature:"json_stringify(val: any, [indent: number = 0]): string",description:"Serializes a value to compact JSON by default; optional indent formats the output.",example:"text = json_stringify(obj, 2);"},{name:"pluck",category:"JSON & Data",signature:"pluck(arr: array, key: string): array",description:"Extracts the specified key from each object in an array.",example:'names = pluck(users, "name");'},{name:"filter_by",category:"JSON & Data",signature:"filter_by(arr: array, key: string, value: any): array",description:"Filters an array of objects where item[key] == value.",example:'active = filter_by(users, "active", true);'},{name:"find_by",category:"JSON & Data",signature:"find_by(arr: array, key: string, value: any): any",description:"Finds the first object in an array where item[key] == value.",example:'user = find_by(users, "id", 42);'},{name:"num",category:"Math",signature:"num(val: any): number",description:"Converts a value to a numeric type.",example:'n = num("42.5");'},{name:"round",category:"Math",signature:"round(n: number): number",description:"Rounds a number to the nearest integer.",example:"r = round(3.7);"},{name:"floor",category:"Math",signature:"floor(n: number): number",description:"Returns the largest integer less than or equal to a number.",example:"f = floor(3.9);"},{name:"ceil",category:"Math",signature:"ceil(n: number): number",description:"Returns the smallest integer greater than or equal to a number.",example:"c = ceil(3.1);"},{name:"min",category:"Math",signature:"min(...nums: number|array): number",description:"Returns the minimum value from numbers or a number array.",example:"m = min(10, 5, 20);"},{name:"max",category:"Math",signature:"max(...nums: number|array): number",description:"Returns the maximum value from numbers or a number array.",example:"m = max([10, 5, 20]);"},{name:"abs",category:"Math",signature:"abs(n: number): number",description:"Returns the absolute value of a number.",example:"a = abs(-42);"},{name:"sqrt",category:"Math",signature:"sqrt(n: number): number",description:"Returns the square root of a number.",example:"s = sqrt(16);"},{name:"pow",category:"Math",signature:"pow(base: number, exp: number): number",description:"Calculates base raised to exponent.",example:"p = pow(2, 8);"},{name:"random",category:"Math",signature:"random(): number",description:"Returns a pseudo-random floating point number in [0, 1).",example:"r = random();"},{name:"system",category:"System & Process",signature:"system(argv: array, [timeoutMs: number = 60000 | options: map]): SystemResult",description:"Executes a non-empty string/number argv list directly with shell:false, returning a structured process execution record. The second argument is a timeout in milliseconds or an options map {cwd, timeoutMs, stdin}; a cwd that does not exist gives a result with code null and an error field instead of a failure.",parameters:[{name:"argv",type:"array",description:"Non-empty argv list of strings/numbers; NUL and an empty program are errors"},{name:"timeoutMs|options",type:"number|map",description:"(optional) Timeout in milliseconds (default: 60000), or options {cwd: string (relative to the invocation directory), timeoutMs: number (default 60000), stdin: string}; unknown keys are errors"}],returns:{type:"SystemResult",description:"{ stdout: string, stderr: string, code: number|null, signal: string|null, timed_out: bool, duration_ms: number, pid: number|null, error?: string }"},example:'res = system(["git", "log", "-n", "1"], {cwd: "."}); if (res.code == 0) { print(res.stdout); }'},{name:"prompt_human",category:"System & Process",signature:"prompt_human([question: string], [options: map]): string|null; prompt_human(session: map, [options: map]): map",description:"Pauses execution to prompt an operator on terminal stdin or dedicated directory, returning the entered input line or decision map, or null if stdin is closed/non-interactive.",example:'guidance = prompt_human("Enter instructions (or Enter to halt): "); if (guidance != null) { process(guidance); }'},{name:"prompt_human_config",category:"System & Process",signature:"prompt_human_config([config: map|string], [dir: string]): map",description:"Configures prompt_human mode ('interactive' or 'file' with dedicated directory, timeout_ms, poll_ms). Returns current configuration map.",example:'prompt_human_config({ dir: "/tmp/handoffs", timeout_ms: 60000 });'},{name:"error",category:"System & Process",signature:"error(value: any, ...args: any): string",description:"Formats and logs an error to stderr and records it for the execution error summary.",example:'error("Operation failed:", reason);'},{name:"exit",category:"System & Process",signature:"exit([code: number = 0]): never",description:"Terminates script execution immediately with exit code.",example:"exit(0);"},{name:"print",category:"System & Process",signature:"print(...args: any): string",description:"Formats values into an output-log entry rendered as a line by the CLI. Returns the formatted text without adding a newline.",example:'print("Result:", val);'},{name:"printf",category:"System & Process",signature:"printf(template: string, ...args: any): string",description:"Formats %s, %d, %f and %% with the sprintf width and precision rules and writes exactly that text to stdout: nothing is added, so end the format with \\n to finish the line.",example:'printf("%s scored %d\\n", "Alice", 95);'},{name:"println",category:"System & Process",signature:"println(...args: any): string",description:"Alias of print: both log formatted values rendered as a line by the CLI and return text without adding a newline.",example:'println("Done.");'},{name:"sleep_ms",category:"System & Process",signature:"sleep_ms(ms: number): void",description:"Pauses execution for specified milliseconds.",example:"sleep_ms(1000);"},{name:"now",category:"System & Process",signature:"now(): number",description:"Returns current epoch in milliseconds.",example:"t = now();"},{name:"timestamp",category:"System & Process",signature:"timestamp(): number",description:"Returns current Unix epoch in whole seconds.",example:"t = timestamp();"},{name:"date",category:"System & Process",signature:"date([epochMs: number]): string",description:"Returns an ISO 8601 date-time string for now or a supplied epoch-millisecond value.",example:"created = date(0);"},{name:"strftime",category:"System & Process",signature:"strftime(epochMs: number, fmt: string): string",description:"Takes epoch milliseconds first and format second, using local time. Supports %Y, %m, %d, %H, %M, %S and %% only; other tokens remain literal. Invalid dates or argument types are errors.",example:'s = strftime(now(), "%Y-%m-%d");'},{name:"coalesce",category:"System & Process",signature:"coalesce(...values: any): any",description:"Returns the first non-null/non-undefined argument, else null (including no arguments).",example:'v = coalesce(a, b, "default");'},{name:"if_null",category:"System & Process",signature:"if_null(val: any, fallback: any): any",description:"Returns fallback if val is null/undefined, else val.",example:'v = if_null(maybe_null, "default");'},{name:"if_else",category:"System & Process",signature:"if_else(cond: any, thenVal: any, elseVal: any): any",description:"Eager compatibility helper: returns thenVal if cond is truthy, else elseVal; all three arguments are evaluated. Use condition ? thenVal : elseVal for lazy selection.",example:'label = if_else(count > 0, "some", "none");'},{name:"str",category:"System & Process",signature:"str(val: any): string",description:"Converts lists and plain maps to compact JSON using the f-string collection rule; scalars retain normal text. Cyclic or lossy collections are errors. Does not change + coercion.",example:"s = str(123);"},{name:"is_array",category:"System & Process",signature:"is_array(val: any): boolean",description:"Checks if a value is an array (type-check alias over type()).",example:"if (is_array(val)) { ... }"},{name:"is_string",category:"System & Process",signature:"is_string(val: any): boolean",description:"Checks if a value is a string (type-check alias over type()).",example:"if (is_string(val)) { ... }"},{name:"is_number",category:"System & Process",signature:"is_number(val: any): boolean",description:"Checks if a value is a number (type-check alias over type()).",example:"if (is_number(val)) { ... }"},{name:"is_map",category:"System & Process",signature:"is_map(val: any): boolean",description:"Checks if a value is a map/object (type-check alias over type()).",example:"if (is_map(val)) { ... }"},{name:"is_function",category:"System & Process",signature:"is_function(val: any): boolean",description:"Checks if a value is a first-class function reference (type-check alias over type()).",example:"if (is_function(val)) { ... }"},{name:"type",category:"System & Process",signature:"type(val: any): string",description:"Returns the runtime type of a value ('string', 'number', 'boolean', 'array', 'object', 'null', 'function').",example:"t = type(data);"},{name:"assert",category:"System & Process",signature:"assert(condition: any, [message: string]): boolean",description:"Throws an error if condition is falsy.",example:'assert(len(items) > 0, "Items list must not be empty");'},{name:"http_get",category:"System & Process",signature:"http_get(url: string): string",description:"Performs HTTP(S) GET request and returns response body string.",example:'html = http_get("https://example.com");'}],rM=[{name:"is_blank",category:"Strings",signature:"is_blank(s: any): boolean",description:"Returns true if string is null, empty, or whitespace only.",example:'if (is_blank(user_input)) { println("input required"); }'},{name:"chunk",category:"Lists & Arrays",signature:"chunk(arr: array, size: number): array",description:"Splits an array into chunks of specified size.",example:"batches = chunk(items, 10);"},{name:"compact",category:"Lists & Arrays",signature:"compact(arr: array): array",description:"Returns a new array with all null elements removed.",example:"valid = compact([1, null, 2, null, 3]);"},{name:"zip",category:"Lists & Arrays",signature:"zip(arr1: array, arr2: array): array",description:"Combines two arrays into an array of pairs [[a1, b1], [a2, b2], ...].",example:'pairs = zip(["a", "b"], [1, 2]);'},{name:"take",category:"Lists & Arrays",signature:"take(arr: array, n: number): array",description:"Returns the first n elements of an array.",example:"first_three = take(items, 3);"},{name:"drop",category:"Lists & Arrays",signature:"drop(arr: array, n: number): array",description:"Returns a new array with the first n elements omitted.",example:"rest = drop(items, 3);"},{name:"clamp",category:"Math",signature:"clamp(val: number, low: number, high: number): number",description:"Restricts a numeric value to lie within [low, high] bounds.",example:"bounded = clamp(score, 0, 100);"}];Rr=class t{hostFunctions=new Map;functionDocs=new Map;registeredModules=new Map;functionOriginModule=new Map;currentRegisteringModule="core";outputLogs=[];isAsyncMode=!1;promptHumanConfig={mode:"interactive"};hostCatalog=new Map;nativeCatalog=new Map;builtinProviders=new Map;hostResolver;reservedFunctionPrefixes;builtinProviderNames;constructor(e={}){this.hostResolver=e.resolveHostModule,this.registeredModules.set("core",{name:"core",description:"LMScript core language built-ins and standard library"}),this.registerPredefinedFunctions();for(let[n,r]of[["get_property",{min:1,max:2}],["has_property",1],["get_properties",{min:0,max:1}],["set_property",2]])this.registerFunction(n,()=>{throw Error("Property store is not running")},r,"Read or overlay hierarchical run-local properties; no persistence");this.registerFunction("expand",()=>{throw Error("Template resolver is not running")},{min:1,max:2},"Expand simple references from explicit vars, PROPS paths and invocation ARGV; inserted text is opaque"),this.registerFunction("warning",n=>String(n),1,{description:"Adds a located non-failure warning",isDefault:!0,returnType:"string"}),this.registerFunction("which",n=>Um(n,process.cwd(),process.env),1,{description:"Finds the first executable path without spawning",isDefault:!0,returnType:"string|null"});for(let n of["print","println","printf"]){let r=this.hostFunctions.get(n),s=[{name:"dryrun",type:"boolean",optional:!0},...n==="printf"?[{name:"format",type:"string"}]:[],{name:"values",type:"any",rest:!0}],i=dn(n,{min:n==="printf"?2:0},s,"string",r.doc),o=r.fn;n==="printf"?r.fn=(a,...l)=>a?Ul(l[0],l.slice(1),"printf"):o(...l):r.fn=(a,...l)=>a?l.map(c=>typeof c=="object"?JSON.stringify(c):String(c)).join(" "):o(...l),Object.assign(r,{params:i.nativeParams,arity:i.nativeArity,signature:i,returnType:"string"})}for(let[n,r]of this.hostFunctions){let s=rp[n];s&&(r[Ge]=s)}this.registerDefaultDocs();for(let[n,r,s]of[["get_property","get_property(key, [default])","Returns a copied property value; absent keys are errors unless a default is supplied."],["has_property","has_property(key)","Tests property presence; missing/invalid profile errors remain loud."],["get_properties","get_properties([prefix])","Returns a detached nested property table copy."],["set_property","set_property(key, value)","Returns the previous value and changes only the run-local overlay; invocation facts are read-only."]])this.functionDocs.set(n,{name:n,signature:r,description:s,module:"core",category:"Properties"});this.functionDocs.set("expand",{name:"expand",signature:"expand(text, [vars])",description:"Resolve ${name} from an explicit vars map, ${PROPS.path}, and ${ARGV[n]}; $${ escapes, no caller-local capture or recursive expansion.",module:"core",category:"Strings"})}registerDefaultDocs(){for(let e of tM)this.functionDocs.set(e.name,{...e,module:e.module??"core"});for(let e of nM)this.registerFunctionDoc({...e,module:e.module??"core"});for(let e of rM)this.functionDocs.set(e.name,{...e,module:e.module??"core"})}registerFunctionDoc(e){let n=Wm({...e,module:e.module??this.currentRegisteringModule});this.functionDocs.set(e.name,n);let r=this.hostFunctions.get(e.name);return r&&this.hostFunctions.set(e.name,{...r,doc:n,signature:dn(e.name,r.arity,r.params,r.returnType,n)}),this}registerModule(e,n){if(this.registeredModules.has(e.name))throw new Error(`Module '${e.name}' is already registered`);this.registeredModules.set(e.name,e);let r=this.currentRegisteringModule;this.currentRegisteringModule=e.name;try{if(e.docs)for(let s of e.docs)this.registerFunctionDoc({...s,module:s.module??e.name});typeof e.register=="function"&&e.register(this,n)}finally{this.currentRegisteringModule=r}return this}getModules(){return Array.from(this.registeredModules.values())}getModule(e){return this.registeredModules.get(e)}getFunctionsByModule(e){return this.getFunctionDocs().filter(n=>(n.module??"core").toLowerCase()===e.toLowerCase())}getFunctionDocs(){return[...this.functionDocs.keys()].map(e=>this.getFunctionDoc(e))}getFunctionDoc(e){let n=this.functionDocs.get(e),r=this.hostFunctions.get(e)?.signature;return!n||!r?n:{...n,...r.returnType?{returns:{type:r.returnType,description:n.returns?.description??"Declared result type"}}:{},...r.dryrunIndex===void 0?{}:{signature:e+"("+r.publicParams.map(s=>s.rest?"..."+s.name:s.optional?"["+s.name+"]":s.name).join(", ")+")",parameters:n.parameters?.filter(s=>s.name!=="dryrun")}}}getFunctionCategories(){let e=new Set;for(let n of this.functionDocs.values())e.add(n.category);return Array.from(e)}getFunctionsByCategory(e){return Array.from(this.functionDocs.values()).filter(n=>n.category.toLowerCase()===e.toLowerCase())}registerPredefinedFunctions(){this.registerFunction("read_file",e=>j.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read",e=>j.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read_lines",e=>{let n=j.readFileSync(e,"utf-8"),r=n.length>0;return n.endsWith(`\r
432
432
  `)?n=n.slice(0,-2):n.endsWith(`
433
433
  `)&&(n=n.slice(0,-1)),r?n.length===0?[""]:n.split(/\r?\n/):[]},1,"Reads file as an array of string lines"),this.registerFunction("write_lines",(e,n)=>{if(!Array.isArray(n))throw new Error("write_lines: second argument must be an array of lines");let r=n.length===0?"":n.map(String).join(`
434
434
  `)+`
@@ -454,7 +454,7 @@ cmd_render(argv, dialect) outputs posix/windows/powershell text; never pass rend
454
454
  Precedence below || and above assignment; only the selected arm is evaluated.
455
455
  `;if(n==="graphql")return["Topic: GraphQL blocks (_graphql_)","q = _graphql_; then the GraphQL document lines, then a line exactly: end _graphql_ -> an ordinary string, linted before effects.",'Lowercase marker on a statement ending with ;, body on the following lines, closer at column 1; blank lines and whole-line # comments are dropped; no options; no decoding or dedent; a """ block string is plain body text; ${expr} anywhere in the body is plain text substitution: linted as an opaque placeholder at check time, inserted at run time (strings, numbers, booleans; null/list/map are run-time errors naming _graphql_) and the final text is linted again; prefer GraphQL variables for dynamic input.',"Executable October 2021 syntax is checked in run preflight, --check, --dry-run and --lint before effects; failures exit 2 with error:FILE:LINE:COLUMN: GraphQL: MESSAGE, every problem of a block reported.","Schema-free rules: Undefined fragment; Fragment cycle; Undefined variable; Unused variable; Unused fragment; Duplicate operation; Duplicate fragment; Duplicate variable; Duplicate argument; Anonymous operation must be alone.","Variable usage includes transitive fragments, directives and nested values; argument uniqueness is per field/directive list.","Fragment-only documents skip unused-fragment/operation-variable checks, retaining spread/cycle/duplicate checks. Plain/runtime-built strings and concatenation are unlinted; each constituent _graphql_ block is still checked independently.",'No field/argument/type/enum validation, subscription root cardinality, input-object field/directive uniqueness, schema selector or execution. Domain checks are a future library hook; parameter tags are deferred. graphql"""...""" literals were removed.',"Use GraphQL variables and a separate map; modules/gh.lms exposes gh.gh_graphql(query, vars) and owns tool/response failures.","Example:","q = _graphql_;","{ viewer { login } }","end _graphql_","println(q);"].join(`
456
456
  `)+`
457
- `;if(n==="dsl")return["Topic: DSL blocks (_dsl_) - EXPERIMENTAL proof of concept (poc/dsl-router), not an accepted design",'dsl = _dsl_ schema="FILE"; then DSL code lines, then a line exactly: end _dsl_ -> an opaque compiled program; savedsl(dsl, PATH) writes the bytecode file.',"schema= is a string literal resolved like an import (relative to the script) and read at check time; the body is compiled at check time, so every problem is error:FILE:LINE:COL: _dsl_: MESSAGE with exit 2 before effects, in untaken branches too.","The DSL is strongly typed and not lmscript: let x = expr; (type inferred), x = expr;, if (cond) { } else { }, calls; int (32-bit), string and bool literals, locals, the schema context objects, obj.method(args), fn(args), == != on int/string/bool, !, &&, ||, ( ). Mandatory ; and { } bodies. No loops, functions, arithmetic. ${expr} is a pre-process step: the value is substituted as a DSL literal (string, 32-bit int, bool; null/list/map refused) before compilation and typed; a computed value defers the compile to evaluation.","Schema (dsl.schema 1 JSON): types {Name: {methods: {m: {params: [...], returns: T}}}}, functions {f: {params, returns}}, context {name: Type}; primitives int, string, bool, void (returns only).",'Value: type(dsl) is "dsl"; printing, str, json_stringify, f-string fields, keys, indexes and methods are errors; savedsl is the only consumer (atomic temp file + rename; a dummy under --dry-run).','Bytecode v1: big-endian fixed widths: "DSLB", u16 version 1, SHA-256 of the schema bytes, string constants, locals, code; the native host (dslvm) refuses bad magic/version, a schema mismatch, truncation and unbound names before running.',"Example (schema/router.dsl.json as in poc/dsl-router):",'router = _dsl_ schema="schema/router.dsl.json";','if (req.method() == "GET") { res.status(200); res.body(now_date()); } else { res.status(405); }',"end _dsl_",'savedsl(router, "build/router.dslb");'].join(`
457
+ `;if(n==="dsl")return["Topic: DSL blocks (_dsl_) - EXPERIMENTAL proof of concept (repos lmctlhq/poc-web and lmctlhq/poc-numpy), not an accepted design",'dsl = _dsl_ schema="FILE"; then DSL code lines, then a line exactly: end _dsl_ -> an opaque compiled program; savedsl(dsl, PATH) writes the bytecode file.',"schema= is a string literal resolved like an import (relative to the script) and read at check time; the body is compiled at check time, so every problem is error:FILE:LINE:COL: _dsl_: MESSAGE with exit 2 before effects, in untaken branches too.","The DSL is strongly typed and not lmscript: let x = expr; (type inferred), x = expr;, if (cond) { } else { }, calls; int (32-bit), string and bool literals, locals, the schema context objects, obj.method(args), fn(args), == != on int/string/bool, !, &&, ||, ( ). Mandatory ; and { } bodies. No loops, functions, arithmetic. ${expr} is a pre-process step: the value is substituted as a DSL literal (string, 32-bit int, bool; null/list/map refused) before compilation and typed; a computed value defers the compile to evaluation.","Schema (dsl.schema 1 JSON): types {Name: {methods: {m: {params: [...], returns: T}}}}, functions {f: {params, returns}}, context {name: Type}; primitives int, string, bool, void (returns only).",'Value: type(dsl) is "dsl"; printing, str, json_stringify, f-string fields, keys, indexes and methods are errors; savedsl is the only consumer (atomic temp file + rename; a dummy under --dry-run).','Bytecode v1: big-endian fixed widths: "DSLB", u16 version 1, SHA-256 of the schema bytes, string constants, locals, code; the native host (dslvm) refuses bad magic/version, a schema mismatch, truncation and unbound names before running.',"Example (schema/router.dsl.json as in github.com/lmctlhq/poc-web):",'router = _dsl_ schema="schema/router.dsl.json";','if (req.method() == "GET") { res.status(200); res.body(now_date()); } else { res.status(405); }',"end _dsl_",'savedsl(router, "build/router.dslb");'].join(`
458
458
  `)+`
459
459
  `;if(n==="csv")return["Topic: Data-embedding blocks (_csv_)",'users = _csv_ heading=true delimiter=","; then the body lines, then a line exactly: end _csv_',"A marker _name_ is a reserved-shape expression whose body follows the statement: the statement ends with a mandatory ; on the marker line, the body starts on the next line and closes with end _csv_ at column 1 with nothing else on it. Several markers in one statement take bodies in order.",'Options are greedy name=value pairs (value is a primary); unknown keys and wrong types are check errors with hints; dynamic values are re-checked at run time. heading (boolean, default true): header row gives a list of maps, false gives a list of lists. delimiter (string, one character, default ",").',"Body: blank lines and whole-line # comments are dropped; # elsewhere is data; indentation is data. ${expr} is a checked expression substituted per value after parsing: alone in a cell it is the value itself (no coercion); beside text or inside quotes it inserts as text (strings, numbers, booleans only; null/list/map refused). A value can never change the structure.","CSV rules: RFC 4180 quoting, quoted cells may span lines, text cells typed like csv_parse, header cells trimmed/unique/non-empty, short rows filled with null; longer rows, misplaced quotes and a missing header are check errors at the body position: error:FILE:LINE:COLUMN: CSV: MESSAGE (exit 2 before effects, also through lmctl script).",'Closers are structural: end _csv_ outside a block "closes nothing"; a mismatched, indented or trailing-text closer and a missing closer are check errors naming expected/found. csv"""...""" literals were removed; csv_parse keeps its parameters. A marker inside an f-string or command field is not supported yet.',"Example:","rows = _csv_;","name,score","Ada,95","end _csv_","println(rows[0].score);"].join(`
460
460
  `)+`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmctl-ai/lmctl",
3
- "version": "0.2.325",
3
+ "version": "0.2.326",
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",