@lmctl-ai/lmctl 0.2.48 → 0.2.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lmscript.js DELETED
@@ -1,388 +0,0 @@
1
- import{spawn as ie,spawnSync as X}from"node:child_process";import{randomUUID as be}from"node:crypto";import{tmpdir as Se}from"node:os";import*as d from"node:fs";import*as k from"node:path";import*as ue from"node:readline";import{fileURLToPath as re}from"node:url";var p=class extends Error{message;line;column;stage;file;constructor(e,t,n,r,i){let s=i&&i!=="<main>"?`${i}:${t}:${n}`:`${t}:${n}`;super(`[${r} Error at ${s}] ${e}`),this.name="LMScriptError",this.message=e,this.line=t,this.column=n,this.stage=r,this.file=i}},P=class extends Error{isControlFlow=!0;exitCode;constructor(e=0){super(`LMScript exited with code ${e}`),this.name="LMScriptExit",this.exitCode=e}};function pe(a,e){let t=a.file&&a.file!=="<main>"?`${a.file}:${a.line}:${a.column}`:`${a.line}:${a.column}`,n=e;if(a.file&&(!n||n&&a.file!=="<main>"&&a.file!=="<std>"))try{d.existsSync(a.file)&&d.statSync(a.file).isFile()&&(n=d.readFileSync(a.file,"utf-8"))}catch{}if(!n)return`[${a.severity.toUpperCase()} at ${t}] ${a.message}`;let r=n.split(`
2
- `),i=String(a.line),s=a.line-1,o=r[s]??"",l=" | ",c=` ${i.padStart(4," ")} | `,m=" ".repeat(Math.max(0,a.column-1));return`[${a.severity.toUpperCase()} at ${t}] ${a.message}
3
- `+l+`
4
- ${c}${o}
5
- ${l}${m}^`}function de(a){if(typeof a!="string"||a.length!==1||/["\r\n]/.test(a))throw new Error("CSV delimiter must be one character other than a quote or newline")}function I(a,e){return a!=null&&Object.hasOwn(a,e)?a[e]:void 0}function M(a,e,t){String(e)==="__proto__"?Object.defineProperty(a,e,{value:t,writable:!0,enumerable:!0,configurable:!0}):a[e]=t}var Q=10*1024*1024;function he(a){if(typeof a!="string"||!a.trim())throw new Error("urlget() requires a non-empty URL string");let e;try{e=new URL(a)}catch{throw new Error("urlget() requires a valid HTTP(S) URL")}if(e.protocol!=="http:"&&e.protocol!=="https:"||e.username||e.password)throw new Error("urlget() only permits HTTP(S) URLs without embedded credentials");let t=`
6
- const target = process.argv[1];
7
- const maxBytes = ${Q};
8
- const controller = new AbortController();
9
- const timer = setTimeout(() => controller.abort(), 30000);
10
- try {
11
- const response = await fetch(target, { method: "GET", redirect: "follow", signal: controller.signal });
12
- if (!response.ok) throw new Error("HTTP " + response.status + " " + response.statusText);
13
- const reader = response.body?.getReader();
14
- const chunks = [];
15
- let total = 0;
16
- if (reader) {
17
- while (true) {
18
- const part = await reader.read();
19
- if (part.done) break;
20
- total += part.value.byteLength;
21
- if (total > maxBytes) throw new Error("response exceeds 10 MiB limit");
22
- chunks.push(Buffer.from(part.value));
23
- }
24
- }
25
- process.stdout.write(Buffer.concat(chunks));
26
- } catch (error) {
27
- controller.abort();
28
- process.stderr.write(error?.message || String(error));
29
- process.exitCode = 1;
30
- } finally {
31
- clearTimeout(timer);
32
- }
33
- `,n=X(process.execPath,["--input-type=module","-e",t,a],{encoding:"utf8",shell:!1,timeout:35e3,maxBuffer:Q+4096,windowsHide:!0});if(n.error)throw n.error.code==="ETIMEDOUT"?new Error("urlget() request timed out"):new Error(`urlget() failed: ${n.error.message}`);if(n.status!==0)throw new Error(`urlget() failed: ${String(n.stderr||"child process exited")}`.trim());return String(n.stdout||"")}async function we(a){if(typeof a!="string"||!a.trim())throw new Error("urlget() requires a non-empty URL string");let e;try{e=new URL(a)}catch{throw new Error("urlget() requires a valid HTTP(S) URL")}if(e.protocol!=="http:"&&e.protocol!=="https:"||e.username||e.password)throw new Error("urlget() only permits HTTP(S) URLs without embedded credentials");let t=new AbortController,n=setTimeout(()=>t.abort(),3e4),r;try{let i=await fetch(e.toString(),{method:"GET",redirect:"follow",signal:t.signal});if(!i.ok)throw t.abort(),new Error("HTTP "+i.status+" "+i.statusText);r=i.body?.getReader();let s=[],o=0;if(r)for(;;){let l=await r.read();if(l.done)break;if(o+=l.value.byteLength,o>Q)throw await r.cancel().catch(()=>{}),t.abort(),new Error("response exceeds 10 MiB limit");s.push(l.value)}return Buffer.concat(s).toString("utf-8")}catch(i){if(t.abort(),r)try{await r.cancel().catch(()=>{})}catch{}throw i.name==="AbortError"?new Error("urlget() request timed out"):new Error(`urlget() failed: ${i?.message||String(i)}`)}finally{clearTimeout(n)}}var G=new Set,$=1e3;process.on("exit",()=>{for(let a of G)try{process.platform!=="win32"&&a.pid?process.kill(-a.pid,"SIGKILL"):a.kill("SIGKILL")}catch{}G.clear()});function z(a,e,t,n=null,r=!1,i=0,s=null){return{stdout:a,stderr:e,code:t,signal:n,timed_out:r,duration_ms:i,pid:s}}function fe(a){let e=String(a);return e.length>0&&/^[a-zA-Z0-9_./@=-]+$/.test(e)?e:"'"+e.replace(/'/g,"'\\''")+"'"}function me(a,e=6e4){if(!Number.isSafeInteger(e)||e<0)throw new Error("system() timeout must be a non-negative safe integer in milliseconds");let t=performance.now(),n;if(Array.isArray(a)){if(a.length===0)throw new Error("system() argv array must not be empty");let m=String(a[0]),u=a.slice(1).map(String);n=X(m,u,{shell:!1,encoding:"utf-8",timeout:e>0?e:void 0,maxBuffer:10*1024*1024,killSignal:"SIGKILL"})}else n=X(a,{shell:!0,encoding:"utf-8",timeout:e>0?e:void 0,maxBuffer:10*1024*1024,killSignal:"SIGKILL"});let r=Math.max(0,Math.round(performance.now()-t)),i=typeof n.pid=="number"?n.pid:null;if(n.error){if(n.error.code==="ETIMEDOUT"){let m=n.stdout!=null?String(n.stdout):"",u=n.stderr!=null?String(n.stderr):"";return z(m,u,null,n.signal||"SIGKILL",!0,r,i)}throw n.error}let s=n.stdout!=null?String(n.stdout):"",o=n.stderr!=null?String(n.stderr):"",l=n.status!==null?n.status:null,c=n.signal!==null?String(n.signal):null;return z(s,o,l,c,!1,r,i)}function ge(a,e=6e4){return new Promise((t,n)=>{if(!Number.isSafeInteger(e)||e<0){n(new Error("system() timeout must be a non-negative safe integer in milliseconds"));return}let r=performance.now();try{let i=process.platform!=="win32",s;if(Array.isArray(a)){if(a.length===0){n(new Error("system() argv array must not be empty"));return}let g=String(a[0]),b=a.slice(1).map(String);s=ie(g,b,{shell:!1,detached:i,stdio:["ignore","pipe","pipe"]})}else s=ie(a,{shell:!0,detached:i,stdio:["ignore","pipe","pipe"]});G.add(s);let o="",l="",c=null,m=null,u=0,y=!1,E=!1,x,w=!1,_,h=()=>{if(w)return;w=!0,G.delete(s),_&&clearTimeout(_);try{s.stdout?.destroy(),s.stderr?.destroy()}catch{}let g=Math.max(0,Math.round(performance.now()-r)),b=typeof s.pid=="number"?s.pid:null;if(x){n(x);return}if(E){t(z(o,l,null,m||"SIGKILL",!0,g,b));return}t(z(o,l,c,m,!1,g,b))};e>0&&(_=setTimeout(()=>{E=!0,m="SIGKILL";try{if(i&&s.pid)try{process.kill(-s.pid,"SIGKILL")}catch{s.kill("SIGKILL")}else s.kill("SIGKILL")}catch{}h()},e));let f=10*1024*1024;s.stdout?.setEncoding("utf-8"),s.stderr?.setEncoding("utf-8"),s.stdout?.on("data",g=>{let b=Buffer.byteLength(g,"utf-8");if(u+b>f){if(!y){y=!0;try{if(i&&s.pid)try{process.kill(-s.pid,"SIGKILL")}catch{s.kill("SIGKILL")}else s.kill("SIGKILL")}catch{}l+=(l&&!l.endsWith(`
34
- `)?`
35
- `:"")+"system() output exceeds 10 MiB limit",x=new Error("system() output exceeds 10 MiB limit"),h()}return}u+=b,o+=g}),s.stderr?.on("data",g=>{let b=Buffer.byteLength(g,"utf-8");if(u+b>f){if(!y){y=!0;try{if(i&&s.pid)try{process.kill(-s.pid,"SIGKILL")}catch{s.kill("SIGKILL")}else s.kill("SIGKILL")}catch{}l+=(l&&!l.endsWith(`
36
- `)?`
37
- `:"")+"system() output exceeds 10 MiB limit",x=new Error("system() output exceeds 10 MiB limit"),h()}return}u+=b,l+=g}),s.on("error",g=>{x||(x=g)}),s.on("close",(g,b)=>{g!==null?(c=g,m=null):(c=null,m=b?String(b):null),h()})}catch(i){n(i instanceof Error?i:new Error(String(i)))}})}function ve(a,e=null){if(typeof a!="string")return a??e;let t=a.trim();if(t.length===0)return e;try{return JSON.parse(t)}catch{}let n=t.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);if(n&&n[1])try{return JSON.parse(n[1].trim())}catch{}let r=t.indexOf("{"),i=t.lastIndexOf("}");if(r!==-1&&i>r)try{return JSON.parse(t.slice(r,i+1))}catch{}let s=t.indexOf("["),o=t.lastIndexOf("]");if(s!==-1&&o>s)try{return JSON.parse(t.slice(s,o+1))}catch{}return e}function ye(a){if(typeof process>"u"||!process.stdin||!process.stdin.isTTY)return null;a!=null&&process.stdout&&typeof process.stdout.write=="function"&&process.stdout.write(String(a));try{let e=Buffer.alloc(1024),t="";for(;;){let n=0;try{n=d.readSync(0,e,0,1,null)}catch{return t.length>0?t:null}if(n===0)return t.length>0?t:null;let r=e.toString("utf-8",0,n);if(r===`
38
- `)return t.endsWith("\r")&&(t=t.slice(0,-1)),t;t+=r}}catch{return null}}function Ee(a,e=typeof process<"u"?process.stdin:null,t=typeof process<"u"?process.stdout:null){return new Promise(n=>{if(!e||typeof e.on!="function"){n(null);return}if(e.destroyed||e.readableEnded){n(null);return}if(e.isTTY===!1||typeof process<"u"&&e===process.stdin&&!process.stdin.isTTY){n(null);return}a!=null&&t&&typeof t.write=="function"&&t.write(String(a));let r=ue.createInterface({input:e,output:t,terminal:!!e.isTTY}),i=!1,s=()=>{r.close()};r.question("",o=>{i||(i=!0,s(),n(o))}),r.on("close",()=>{i||(i=!0,n(null))}),r.on("error",()=>{i||(i=!0,s(),n(null))})})}async function xe(a,e){let t=k.resolve(String(e.dir));d.mkdirSync(t,{recursive:!0});let n=e.sessionId??`prompt_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,r=n.replace(/[/\\?%*:|"<>]/g,"_"),i=k.join(t,`${r}.out`),s=k.join(t,`${r}.out_state`),o=k.join(t,`${r}.in`),l=k.join(t,`${r}.in_state`);try{d.existsSync(l)&&d.unlinkSync(l)}catch{}try{d.existsSync(o)&&d.unlinkSync(o)}catch{}d.writeFileSync(i,a!=null?String(a):"","utf-8"),d.writeFileSync(s,JSON.stringify({sessionId:n,status:"waiting",timestamp:Date.now()})+`
39
- `,"utf-8");let c=typeof e.timeoutMs=="number"&&Number.isFinite(e.timeoutMs)&&e.timeoutMs>0?e.timeoutMs:0,m=typeof e.pollIntervalMs=="number"&&Number.isFinite(e.pollIntervalMs)&&e.pollIntervalMs>0?e.pollIntervalMs:200,u=`[prompt_human] Waiting for marker: ${l} (session: ${n})${c>0?` [timeout: ${c}ms]`:""}
40
- `;e.onWaiting?e.onWaiting(u):typeof process<"u"&&process.stderr&&process.stderr.write(u);let y=Date.now(),E=y;for(;!d.existsSync(l);){if(c>0&&Date.now()-y>=c){try{d.existsSync(s)&&d.unlinkSync(s)}catch{}return null}if(Date.now()-E>=3e4){E=Date.now();let w=`[prompt_human] Still waiting for ${l} (session: ${n})...
41
- `;e.onWaiting?e.onWaiting(w):typeof process<"u"&&process.stderr&&process.stderr.write(w)}await new Promise(w=>setTimeout(w,m))}let x="";if(d.existsSync(o))try{x=d.readFileSync(o,"utf-8")}catch{}if(!x.trim()&&d.existsSync(l))try{x=d.readFileSync(l,"utf-8")}catch{}try{d.existsSync(l)&&d.unlinkSync(l)}catch{}try{d.existsSync(o)&&d.unlinkSync(o)}catch{}try{d.existsSync(s)&&d.unlinkSync(s)}catch{}try{d.existsSync(i)&&d.unlinkSync(i)}catch{}return x.replace(/\r?\n$/u,"")}function se(a,e=!0,t=","){de(t);let n=[],r=[],i="",s=!1,o=!1,l=!1;for(let u=0;u<a.length;u++){let y=a[u],E=a[u+1];if(l=!0,s)y==='"'?E==='"'?(i+='"',u++):(s=!1,o=!0):i+=y;else{if(o&&y!==t&&y!=="\r"&&y!==`
42
- `)throw new Error("Invalid CSV: unexpected character after closing quote");if(y==='"'){if(i.length>0)throw new Error("Invalid CSV: quote inside unquoted field");s=!0}else y===t?(o=!1,r.push(i),i=""):y==="\r"?(E===`
43
- `&&u++,r.push(i),n.push(r),r=[],i="",o=!1,l=!1):y===`
44
- `?(r.push(i),n.push(r),r=[],i="",o=!1,l=!1):i+=y}}if(s)throw new Error("Invalid CSV: unterminated quoted field");if(l&&(r.push(i),n.push(r)),!e)return n.map(u=>u.map(ae));if(n.length===0)return[];let c=n[0].map(u=>u.trim()),m=[];for(let u=1;u<n.length;u++){let y=n[u],E={};for(let x=0;x<c.length;x++)M(E,c[x],x<y.length?ae(y[x]):null);m.push(E)}return m}function ae(a){let e=a.trim();if(e==="")return"";if(/^-?\d+$/.test(e)){let t=Number(e);if(!Number.isNaN(t))return t}if(/^-?\d+\.\d+$/.test(e)){let t=Number(e);if(!Number.isNaN(t))return t}return e.toLowerCase()==="true"?!0:e.toLowerCase()==="false"?!1:e.toLowerCase()==="null"?null:a}function oe(a,e=","){if(de(e),!Array.isArray(a)||a.length===0)return"";let t=a[0];if(Array.isArray(t))return a.map(n=>n.map(r=>H(r,e)).join(e)).join(`
45
- `);if(typeof t=="object"&&t!==null){let n=Object.keys(t),r=n.map(s=>H(s,e)).join(e),i=a.map(s=>n.map(o=>H(I(s,o)??"",e)).join(e));return[r,...i].join(`
46
- `)}return a.map(n=>H(n,e)).join(`
47
- `)}function H(a,e){let t=a==null?"":String(a);return t===""||t.includes(e)||t.includes('"')||t.includes(`
48
- `)||t.includes("\r")?`"${t.replaceAll('"','""')}"`:t}var le={fn:"FN",function:"FN",let:"LET",if:"IF",else:"ELSE",while:"WHILE",for:"FOR",return:"RETURN",break:"BREAK",continue:"CONTINUE",true:"TRUE",false:"FALSE",null:"NULL",parallel:"PARALLEL",sync:"SYNC",import:"IMPORT"},D=class{diagnostics=[];formattedDepth=0;modes=[];source;length;file;pos=0;line=1;column=1;constructor(e,t){this.source=e,this.length=e.length,this.file=t}tokenize(){let e=[];return this.scanTokens(e),e.push({type:"EOF",value:"",line:this.line,column:this.column}),e}position(){return{offset:this.pos,line:this.line,column:this.column}}spannedToken(e,t,n){return{type:e,value:t,line:n.line,column:n.column,offset:n.offset,endOffset:this.pos,endLine:this.line,endColumn:this.column}}scanTokens(e,t){for(;this.pos<this.length&&(this.skipWhitespaceAndComments(),!(this.pos>=this.length));){let n=this.position(),r=this.peek();if(t&&t.delimiters.length===0){if(r==="}"){if(t.lastToken===void 0)throw new p("Empty formatted-string field",n.line,n.column,"LEXER",this.file);this.advance(),e.push(this.spannedToken("FSTRING_FIELD_END","}",n));return}if(r==="?"&&t.pendingQuestions++,r===":")if(t.pendingQuestions>0)t.pendingQuestions--;else throw new p("Format specifications are not supported in formatted strings",n.line,n.column,"LEXER",this.file);if(t.lastToken&&["IDENTIFIER","NUMBER","STRING","TRUE","FALSE","NULL","RPAREN","RBRACKET","RBRACE","FSTRING_END"].includes(t.lastToken)&&r==="!"&&/[rsa]/.test(this.peekNext())&&this.peekNext()!=="")throw new p("Conversion suffixes (!r, !s, !a) are not supported in formatted strings",n.line,n.column,"LEXER",this.file);if(r==="="&&this.peekNext()!=="=")throw new p("Assignment/debug fields ({x=}) are not supported in formatted strings",n.line,n.column,"LEXER",this.file)}let i=e.length;this.readNextToken(e);for(let s of e.slice(i))s.offset===void 0&&(s.offset=n.offset,s.endOffset=this.pos,s.endLine=this.line,s.endColumn=this.column);if(t){let s=e[i],o={RPAREN:"LPAREN",RBRACKET:"LBRACKET",RBRACE:"LBRACE"};if(["LPAREN","LBRACKET","LBRACE"].includes(s.type))t.delimiters.push(s.type);else if(o[s.type]&&t.delimiters.pop()!==o[s.type])throw new p("Mismatched delimiter in formatted-string field",s.line,s.column,"LEXER",this.file);t.lastToken=e[e.length-1].type}}if(t)throw new p("Unterminated formatted-string field; expected '}'",t.opener.line,t.opener.column,"LEXER",this.file)}readNextToken(e){let t=this.line,n=this.column,r=this.peek();if(this.isDigit(r)||r==="."&&this.isDigit(this.peekNext())){e.push(this.readNumber(t,n));return}if(r==='"'||r==="'"){e.push(this.source.startsWith(r.repeat(3),this.pos)?this.readModernString("",t,n,e):this.readString(r,t,n));return}if(r==="<"&&this.peekNext()==="<"&&/^<<[A-Za-z_][A-Za-z0-9_]*(?:\r\n|\r|\n)/.test(this.source.slice(this.pos)))throw new p('Heredocs are not supported; use raw triple-quoted strings (r"""...""")',t,n,"LEXER",this.file);if(this.isAlpha(r)){let i=this.pos+1;for(;i<this.length&&this.isAlphaNumeric(this.source[i]);)i++;if(this.source[i]==='"'||this.source[i]==="'"){let s=this.source.slice(this.pos,i);if(!/^(r|f|rf|fr)$/i.test(s)){let o=this.modes.at(-1);throw o?.kind==="field"&&o.delimiters.length===0?new p("Unterminated formatted-string field; expected '}' before enclosing quote",o.opener.line,o.opener.column,"LEXER",this.file):new p("Unsupported string prefix '"+s+"'; separate an identifier or keyword from its string with whitespace",t,n,"LEXER",this.file)}e.push(this.readModernString(s,t,n,e));return}e.push(this.readIdentifier(t,n));return}switch(this.advance(),r){case".":e.push({type:"DOT",value:".",line:t,column:n});break;case"?":e.push({type:"QUESTION",value:"?",line:t,column:n});break;case":":e.push({type:"COLON",value:":",line:t,column:n});break;case"(":e.push({type:"LPAREN",value:"(",line:t,column:n});break;case")":e.push({type:"RPAREN",value:")",line:t,column:n});break;case"{":e.push({type:"LBRACE",value:"{",line:t,column:n});break;case"}":e.push({type:"RBRACE",value:"}",line:t,column:n});break;case"[":e.push({type:"LBRACKET",value:"[",line:t,column:n});break;case"]":e.push({type:"RBRACKET",value:"]",line:t,column:n});break;case",":e.push({type:"COMMA",value:",",line:t,column:n});break;case";":e.push({type:"SEMICOLON",value:";",line:t,column:n});break;case"+":e.push({type:"PLUS",value:"+",line:t,column:n});break;case"-":e.push({type:"MINUS",value:"-",line:t,column:n});break;case"*":e.push({type:"STAR",value:"*",line:t,column:n});break;case"/":e.push({type:"SLASH",value:"/",line:t,column:n});break;case"%":e.push({type:"PERCENT",value:"%",line:t,column:n});break;case"=":this.match("=")?e.push({type:"EQUAL",value:"==",line:t,column:n}):e.push({type:"ASSIGN",value:"=",line:t,column:n});break;case"!":this.match("=")?e.push({type:"NOT_EQUAL",value:"!=",line:t,column:n}):e.push({type:"NOT",value:"!",line:t,column:n});break;case"<":this.match("=")?e.push({type:"LESS_EQUAL",value:"<=",line:t,column:n}):e.push({type:"LESS",value:"<",line:t,column:n});break;case">":this.match("=")?e.push({type:"GREATER_EQUAL",value:">=",line:t,column:n}):e.push({type:"GREATER",value:">",line:t,column:n});break;case"&":if(this.match("&"))e.push({type:"AND",value:"&&",line:t,column:n});else throw new p("Unexpected character '&'. Did you mean '&&'?",t,n,"LEXER",this.file);break;case"|":if(this.match("|"))e.push({type:"OR",value:"||",line:t,column:n});else throw new p("Unexpected character '|'. Did you mean '||'?",t,n,"LEXER",this.file);break;default:throw new p(`Unexpected character: '${r}'`,t,n,"LEXER",this.file)}}peek(){return this.source[this.pos]||""}peekNext(){return this.source[this.pos+1]||""}advance(){let e=this.source[this.pos++];return e==="\r"||e===`
49
- `?((e!==`
50
- `||this.source[this.pos-2]!=="\r")&&this.line++,this.column=1):this.column++,e}match(e){return this.pos>=this.length||this.source[this.pos]!==e?!1:(this.advance(),!0)}isDigit(e){return e>="0"&&e<="9"}isAlpha(e){return e>="a"&&e<="z"||e>="A"&&e<="Z"||e==="_"}isAlphaNumeric(e){return this.isAlpha(e)||this.isDigit(e)}skipWhitespaceAndComments(){for(;this.pos<this.length;){let e=this.peek();if(e===" "||e===" "||e==="\r"||e===`
51
- `)this.advance();else if(e==="/"&&this.peekNext()==="/"||e==="#")for(;this.pos<this.length&&this.peek()!==`
52
- `&&(this.modes.length===0||this.peek()!=="\r");)this.advance();else if(e==="/"&&this.peekNext()==="*"){let t=this.line,n=this.column;this.advance(),this.advance();let r=!1;for(;this.pos<this.length;){if(this.peek()==="*"&&this.peekNext()==="/"){this.advance(),this.advance(),r=!0;break}this.advance()}if(!r)throw new p("Unterminated block comment",t,n,"LEXER",this.file)}else break}}readNumber(e,t){let n="";for(;this.pos<this.length&&this.isDigit(this.peek());)n+=this.advance();if(this.peek()==="."&&this.isDigit(this.peekNext()))for(n+=this.advance();this.pos<this.length&&this.isDigit(this.peek());)n+=this.advance();return{type:"NUMBER",value:n,literal:parseFloat(n),line:e,column:t}}readString(e,t,n){this.advance();let r="";for(;this.pos<this.length&&this.peek()!==e;){if(this.peek()===`
53
- `)throw new p("Unterminated string literal across newline",t,n,"LEXER",this.file);if(this.peek()==="\\"){this.advance();let i=this.advance();switch(i){case"n":r+=`
54
- `;break;case"t":r+=" ";break;case"r":r+="\r";break;case"\\":r+="\\";break;case'"':r+='"';break;case"'":r+="'";break;default:r+=i;break}}else r+=this.advance()}if(this.pos>=this.length)throw new p("Unterminated string literal at end of file",t,n,"LEXER",this.file);return this.advance(),{type:"STRING",value:r,literal:r,line:t,column:n}}consumeStringNewline(){return this.advance()==="\r"&&this.peek()===`
55
- `&&this.advance(),`
56
- `}readModernEscape(e){let t=this.line,n=this.column;if(this.advance(),this.pos>=this.length)throw new p("Unterminated escape in string literal",t,n,"LEXER",this.file);let r=this.peek();if(r==="\r"||r===`
57
- `)return this.consumeStringNewline(),"";let i={"\\":"\\",'"':'"',"'":"'",a:"\x07",b:"\b",f:"\f",n:`
58
- `,r:"\r",t:" ",v:"\v"};if(Object.hasOwn(i,r))return this.advance(),i[r];if(r==="N")throw new p("Named Unicode escapes (\\N) are not supported",t,n,"LEXER",this.file);if(r==="x"||r==="u"||r==="U"){this.advance();let s=r==="x"?2:r==="u"?4:8,o=this.source.slice(this.pos,this.pos+s);if(o.length!==s||!/^[0-9a-fA-F]+$/.test(o))throw new p("Invalid \\"+r+" escape; expected "+s+" hexadecimal digits",t,n,"LEXER",this.file);let l=Number.parseInt(o,16);if(l>1114111||l>=55296&&l<=57343)throw new p("Invalid Unicode scalar in string escape",t,n,"LEXER",this.file);for(let c=0;c<s;c++)this.advance();return String.fromCodePoint(l)}if(/[0-7]/.test(r)){let s=this.advance();for(;s.length<3&&this.peek()!==""&&/[0-7]/.test(this.peek());)s+=this.advance();return String.fromCodePoint(Number.parseInt(s,8))}return this.diagnostics.push({message:"Unknown escape '\\"+r+"'; backslash preserved",severity:"warning",line:t,column:n,file:this.file}),e&&(r==="{"||r==="}")?"\\":"\\"+this.advance()}readModernString(e,t,n,r){let i=this.pos;for(let E=0;E<e.length;E++)this.advance();let s=this.peek(),o=this.source.startsWith(s.repeat(3),this.pos),l=s.repeat(o?3:1),c={prefix:e.toLowerCase(),raw:/r/i.test(e),triple:o,formatted:/f/i.test(e)};if(c.formatted&&this.formattedDepth>=64)throw new p("Formatted-string nesting exceeds limit 64",t,n,"LEXER",this.file);c.formatted&&this.formattedDepth++;for(let E=0;E<l.length;E++)this.advance();if(this.modes.push({kind:"string",delimiter:l}),c.formatted){let E=this.spannedToken("FSTRING_START",e+l,{offset:i,line:t,column:n});E.stringLiteral=c,r.push(E)}let m=this.position(),u="",y=()=>{if(this.pos>m.offset){let E=this.spannedToken("FSTRING_TEXT",u,m);E.literal=u,r.push(E)}u=""};try{for(;this.pos<this.length;){if(this.source.startsWith(l,this.pos)){c.formatted&&y();let x=this.position();for(let w=0;w<l.length;w++)this.advance();return c.formatted?this.spannedToken("FSTRING_END",l,x):{type:"STRING",value:u,literal:u,line:t,column:n,offset:i,endOffset:this.pos,endLine:this.line,endColumn:this.column,stringLiteral:c}}let E=this.peek();if(c.formatted&&(E==="{"||E==="}"))if(this.peekNext()===E)this.advance(),this.advance(),u+=E;else{if(E==="}")throw new p("Unmatched '}' in formatted-string text; use '}}' for a literal brace",this.line,this.column,"LEXER",this.file);{y();let x=this.position();this.advance();let w=this.spannedToken("FSTRING_FIELD_START","{",x);r.push(w);let _={kind:"field",opener:w,delimiters:[],pendingQuestions:0};this.modes.push(_);try{this.scanTokens(r,_)}finally{this.modes.pop()}m=this.position()}}else if(E==="\r"||E===`
59
- `){if(!o)throw new p("Unterminated short string across newline",t,n,"LEXER",this.file);u+=this.consumeStringNewline()}else E==="\\"?c.raw?(u+=this.advance(),this.pos<this.length&&!(c.formatted&&(this.peek()==="{"||this.peek()==="}"))&&(u+=this.peek()==="\r"||this.peek()===`
60
- `?this.consumeStringNewline():this.advance())):u+=this.readModernEscape(c.formatted):u+=this.advance()}throw new p("Unterminated string literal; expected "+l,t,n,"LEXER",this.file)}finally{this.modes.pop(),c.formatted&&this.formattedDepth--}}readIdentifier(e,t){let n="";for(;this.pos<this.length&&this.isAlphaNumeric(this.peek());)n+=this.advance();let r=Object.hasOwn(le,n)?le[n]:void 0;if(r){let i;return r==="TRUE"&&(i=!0),r==="FALSE"&&(i=!1),r==="NULL"&&(i=null),{type:r,value:n,literal:i,line:e,column:t}}return{type:"IDENTIFIER",value:n,line:e,column:t}}};function ce(a,e){try{if(Array.isArray(a))return Array.from({length:a.length},(n,r)=>a[r]);if(typeof a=="string")return Array.from(a);if(a!==null&&typeof a=="object"&&(Object.getPrototypeOf(a)===Object.prototype||Object.getPrototypeOf(a)===null))return Object.keys(a);let t=a===null?"null":a instanceof Date?"Date":typeof a;throw new p(`Cannot iterate value of type ${t}; expected list, map or string`,e.line,e.column,"RUNTIME",e.file)}catch(t){throw t instanceof p?t:new p(`Cannot snapshot iterable: ${t instanceof Error?t.message:String(t)}`,e.line,e.column,"RUNTIME",e.file)}}function Y(a,e){if(!(!a||typeof a!="object")){"line"in a&&"column"in a&&!a.file&&(a.file=e);for(let t of Object.keys(a)){let n=a[t];if(Array.isArray(n))for(let r of n)Y(r,e);else n&&typeof n=="object"&&Y(n,e)}}}var Z=Object.freeze({startsWith:"starts_with",endsWith:"ends_with",indexOf:"index_of",lastIndexOf:"last_index_of",toUpperCase:"upper",toLowerCase:"lower",parseInt:"num",parseFloat:"num",trimStart:"trim_start",trimLeft:"trim_start",trimEnd:"trim_end",trimRight:"trim_end",strip:"trim",lstrip:"trim_start",rstrip:"trim_end",length:"len",append:"push",prepend:"unshift",push_back:"push",push_front:"unshift","JSON.parse":"json_parse","JSON.stringify":"json_stringify"});function J(a,e="Call to undefined function"){let t=`${e} '${a}'`;return Object.hasOwn(Z,a)?t+`; did you mean '${Z[a]}'?`:t}var B=class{tokens;current=0;file;constructor(e,t){this.tokens=e,this.file=t}parse(){let e=[],t=this.peek();for(;!this.isAtEnd();)e.push(this.parseDeclaration(!0));let n={kind:"Program",statements:e,line:t.line,column:t.column,file:this.file};return this.file&&Y(n,this.file),n}parseDeclaration(e=!1){try{if(this.match("FN"))return this.parseFunctionDecl();if(this.match("LET"))return this.parseVarDecl();if(this.match("IMPORT")){if(!e)throw new p("'import' statement is only allowed at the top level of a file",this.previous().line,this.previous().column,"PARSER",this.file);return this.parseImportStmt()}return this.parseStatement()}catch(t){throw t instanceof p?t:new p(t instanceof Error?t.message:String(t),this.peek().line,this.peek().column,"PARSER",this.file)}}parseImportStmt(){let e=this.previous();if(this.check("FSTRING_START")){let n=this.peek();throw new p("Import paths require an unprefixed short string",n.line,n.column,"PARSER",this.file)}let t=this.consume("STRING","Expected file path string after 'import'");if(t.stringLiteral?.prefix||t.stringLiteral?.triple)throw new p("Import paths require an unprefixed short string",t.line,t.column,"PARSER",this.file);return this.consumeOptionalSemicolon(),{kind:"ImportStmt",path:t.value,line:e.line,column:e.column,file:this.file}}parseFunctionDecl(){let e=this.previous(),t=this.consume("IDENTIFIER","Expected function name after 'fn'");this.consume("LPAREN","Expected '(' after function name");let n=[];if(!this.check("RPAREN"))do{let i=this.consume("IDENTIFIER","Expected parameter name");n.push(i.value)}while(this.match("COMMA"));this.consume("RPAREN","Expected ')' after parameters"),this.consume("LBRACE","Expected '{' before function body");let r=this.parseBlockBody(this.previous());return{kind:"FunctionDeclStmt",name:t.value,params:n,body:r,line:e.line,column:e.column}}parseVarDecl(){let e=this.previous();if(this.match("LPAREN","LBRACKET")){let r=this.previous().type==="LPAREN"?"RPAREN":"RBRACKET",i=[];if(!this.check(r))do{let o=this.consume("IDENTIFIER","Expected variable name in destructuring");i.push(o.value)}while(this.match("COMMA"));this.consume(r,`Expected '${r==="RPAREN"?")":"]"}' after variable list`),this.consume("ASSIGN","Expected '=' after destructuring variable list");let s=this.parseExpression();return this.consumeOptionalSemicolon(),{kind:"TupleVarDeclStmt",names:i,initializer:s,line:e.line,column:e.column}}let t=this.consume("IDENTIFIER","Expected variable name after 'let'"),n;return this.match("ASSIGN")&&(n=this.parseExpression()),this.consumeOptionalSemicolon(),{kind:"VarDeclStmt",name:t.value,initializer:n,line:e.line,column:e.column}}parseStatement(){if(this.match("IMPORT"))throw new p("'import' statement is only allowed at the top level of a file",this.previous().line,this.previous().column,"PARSER",this.file);return this.match("SYNC")?this.parseSyncStatement():this.match("IF")?this.parseIfStatement():this.match("WHILE")?this.parseWhileStatement():this.match("FOR")?this.parseForStatement():this.match("RETURN")?this.parseReturnStatement():this.match("BREAK")?this.parseBreakStatement():this.match("CONTINUE")?this.parseContinueStatement():this.match("LBRACE")?this.parseBlockBody(this.previous()):this.parseExpressionStatement()}parseSyncStatement(){let e=this.previous(),t=this.parseExpression();if(this.consumeOptionalSemicolon(),t.kind==="AssignExpr")return{kind:"SyncAssignStmt",target:t.target,value:t.value,line:e.line,column:e.column};if(t.kind==="IndexAssignExpr")return{kind:"SyncIndexAssignStmt",target:t.target,index:t.index,value:t.value,line:e.line,column:e.column};if(t.kind==="CallExpr")return{kind:"SyncCallStmt",call:t,line:e.line,column:e.column};throw new p("Invalid 'sync' statement target; expected variable assignment ('sync a = ...'), member/index assignment ('sync obj.k = ...'), or container mutation call ('sync push(arr, ...)').",e.line,e.column,"PARSER",this.file)}parseIfStatement(){let e=this.previous();this.consume("LPAREN","Expected '(' after 'if'");let t=this.parseExpression();this.consume("RPAREN","Expected ')' after if condition");let n=this.parseStatement(),r;return this.match("ELSE")&&(r=this.parseStatement()),{kind:"IfStmt",condition:t,thenBranch:n,elseBranch:r,line:e.line,column:e.column}}parseWhileStatement(){let e=this.previous();this.consume("LPAREN","Expected '(' after 'while'");let t=this.parseExpression();this.consume("RPAREN","Expected ')' after while condition");let n=this.parseStatement();return{kind:"WhileStmt",condition:t,body:n,line:e.line,column:e.column}}parseForStatement(){let e=this.previous();if(this.consume("LPAREN","Expected '(' after 'for'"),this.check("IDENTIFIER")&&this.tokens[this.current+1]?.type==="COMMA")throw new p("For-in requires one binding; use 'for (x in expr)'",this.peek().line,this.peek().column,"PARSER",this.file);if(this.check("IDENTIFIER")&&this.tokens[this.current+1]?.type==="IDENTIFIER"&&this.tokens[this.current+1].value==="in"){let s=this.advance().value;if(this.advance(),this.check("RPAREN"))throw new p("Expected expression after 'in' in for-loop",this.peek().line,this.peek().column,"PARSER",this.file);let o=this.parseExpression();this.consume("RPAREN","Expected ')' after for-in expression");let l=this.parseStatement();return{kind:"ForInStmt",name:s,iterable:o,body:l,line:e.line,column:e.column}}let t;if(this.match("SEMICOLON"))t=void 0;else if(this.match("LET"))t=this.parseVarDecl();else{let s=this.parseExpression();this.consume("SEMICOLON","Expected ';' after for-loop initializer"),t={kind:"ExprStmt",expr:s,line:s.line,column:s.column}}let n;this.check("SEMICOLON")||(n=this.parseExpression()),this.consume("SEMICOLON","Expected ';' after for-loop condition");let r;this.check("RPAREN")||(r=this.parseExpression()),this.consume("RPAREN","Expected ')' after for clauses");let i=this.parseStatement();return{kind:"ForStmt",init:t,condition:n,update:r,body:i,line:e.line,column:e.column}}parseReturnStatement(){let e=this.previous(),t;return!this.check("SEMICOLON")&&!this.check("RBRACE")&&!this.isAtEnd()&&(t=this.parseExpression()),this.consumeOptionalSemicolon(),{kind:"ReturnStmt",value:t,line:e.line,column:e.column}}parseBreakStatement(){let e=this.previous();return this.consumeOptionalSemicolon(),{kind:"BreakStmt",line:e.line,column:e.column}}parseContinueStatement(){let e=this.previous();return this.consumeOptionalSemicolon(),{kind:"ContinueStmt",line:e.line,column:e.column}}parseBlockBody(e){let t=[];for(;!this.check("RBRACE")&&!this.isAtEnd();)t.push(this.parseDeclaration());return this.consume("RBRACE","Expected '}' after block"),{kind:"BlockStmt",statements:t,line:e.line,column:e.column}}parseExpressionStatement(){let e=this.parseExpression();return this.consumeOptionalSemicolon(),{kind:"ExprStmt",expr:e,line:e.line,column:e.column}}parseExpression(){return this.parseAssignment()}parseAssignment(){let e=this.parseConditional();if(this.match("ASSIGN")){let t=this.previous(),n=this.parseAssignment();if(e.kind==="IdentifierExpr")return{kind:"AssignExpr",target:e.name,value:n,line:t.line,column:t.column};if(e.kind==="IndexExpr")return{kind:"IndexAssignExpr",target:e.target,index:e.index,value:n,line:t.line,column:t.column};if(e.kind==="TupleExpr"||e.kind==="ArrayExpr"){let r=[];for(let i of e.elements){if(i.kind!=="IdentifierExpr")throw new p("Destructuring assignment target must be an identifier",i.line,i.column,"PARSER",this.file);r.push(i.name)}return{kind:"TupleAssignExpr",targets:r,value:n,line:t.line,column:t.column}}throw new p("Invalid assignment target",e.line,e.column,"PARSER",this.file)}return e}parseConditional(){let e=this.parseLogicalOr();if(!this.match("QUESTION"))return e;let t=this.previous(),n=()=>["COLON","SEMICOLON","RPAREN","RBRACKET","RBRACE","FSTRING_FIELD_END","EOF","COMMA"].includes(this.peek().type);if(n())throw new p("Expected true arm after '?'",this.peek().line,this.peek().column,"PARSER",this.file);let r=this.parseAssignment();if(this.consume("COLON","Expected ':' after conditional true arm"),n())throw new p("Expected false arm after ':'",this.peek().line,this.peek().column,"PARSER",this.file);let i=this.parseAssignment();return{kind:"ConditionalExpr",condition:e,trueArm:r,falseArm:i,line:t.line,column:t.column}}parseLogicalOr(){let e=this.parseLogicalAnd();for(;this.match("OR");){let t=this.previous(),n=this.parseLogicalAnd();e={kind:"BinaryExpr",operator:"||",left:e,right:n,line:t.line,column:t.column}}return e}parseLogicalAnd(){let e=this.parseEquality();for(;this.match("AND");){let t=this.previous(),n=this.parseEquality();e={kind:"BinaryExpr",operator:"&&",left:e,right:n,line:t.line,column:t.column}}return e}parseEquality(){let e=this.parseRelational();for(;this.match("EQUAL","NOT_EQUAL");){let t=this.previous(),n=t.type==="EQUAL"?"==":"!=",r=this.parseRelational();e={kind:"BinaryExpr",operator:n,left:e,right:r,line:t.line,column:t.column}}return e}parseRelational(){let e=this.parseAdditive();for(;this.match("LESS","LESS_EQUAL","GREATER","GREATER_EQUAL");){let t=this.previous(),n=t.type==="LESS"?"<":t.type==="LESS_EQUAL"?"<=":t.type==="GREATER"?">":">=",r=this.parseAdditive();e={kind:"BinaryExpr",operator:n,left:e,right:r,line:t.line,column:t.column}}return e}parseAdditive(){let e=this.parseMultiplicative();for(;this.match("PLUS","MINUS");){let t=this.previous(),n=t.type==="PLUS"?"+":"-",r=this.parseMultiplicative();e={kind:"BinaryExpr",operator:n,left:e,right:r,line:t.line,column:t.column}}return e}parseMultiplicative(){let e=this.parseUnary();for(;this.match("STAR","SLASH","PERCENT");){let t=this.previous(),n=t.type==="STAR"?"*":t.type==="SLASH"?"/":"%",r=this.parseUnary();e={kind:"BinaryExpr",operator:n,left:e,right:r,line:t.line,column:t.column}}return e}parseUnary(){if(this.match("NOT","MINUS")){let e=this.previous(),t=e.type==="NOT"?"!":"-",n=this.parseUnary();return{kind:"UnaryExpr",operator:t,operand:n,line:e.line,column:e.column}}return this.parseCallAndIndex()}parseCallAndIndex(){let e=this.parsePrimary();for(;;)if(this.match("LPAREN")){if(e.kind!=="IdentifierExpr"){if(e.kind==="IndexExpr"&&e.target.kind==="IdentifierExpr"&&e.index.kind==="LiteralExpr"){let n=e.target.name+"."+e.index.value;if(Object.hasOwn(Z,n))throw new p(J(n),e.line,e.column,"PARSER",this.file)}throw new p("Only identifiers can be called directly as functions",e.line,e.column,"PARSER",this.file)}let t=[];if(!this.check("RPAREN"))do t.push(this.parseExpression());while(this.match("COMMA"));this.consume("RPAREN","Expected ')' after function arguments"),e={kind:"CallExpr",callee:e.name,args:t,line:e.line,column:e.column}}else if(this.match("LBRACKET")){let t=this.parseExpression();this.consume("RBRACKET","Expected ']' after index expression"),e={kind:"IndexExpr",target:e,index:t,line:e.line,column:e.column}}else if(this.match("DOT")){let t=this.consume("IDENTIFIER","Expected property name after '.'");e={kind:"IndexExpr",target:e,index:{kind:"LiteralExpr",value:t.value,line:t.line,column:t.column},line:t.line,column:t.column}}else break;return e}parsePrimary(){let e=this.peek();if(this.check("FSTRING_START"))return this.parseFormattedString();if(this.match("NUMBER","STRING","TRUE","FALSE","NULL"))return{kind:"LiteralExpr",value:this.previous().literal,line:e.line,column:e.column};if(this.match("PARALLEL")){let t=this.previous();this.consume("LPAREN","Expected '(' after 'parallel'"),this.consume("LBRACKET","Expected '[' starting array of function calls in 'parallel([ ... ])'");let n=[];if(!this.check("RBRACKET"))do{let r=this.parseExpression();if(r.kind!=="CallExpr")throw new p("Each task in parallel([...]) must be a direct function call expression",r.line,r.column,"PARSER",this.file);n.push(r)}while(this.match("COMMA"));return this.consume("RBRACKET","Expected ']' closing array in 'parallel([ ... ])'"),this.consume("RPAREN","Expected ')' closing 'parallel(...)'"),{kind:"ParallelExpr",tasks:n,line:t.line,column:t.column}}if(this.match("IDENTIFIER"))return{kind:"IdentifierExpr",name:this.previous().value,line:e.line,column:e.column};if(this.match("LPAREN")){let t=this.previous(),n=[],r=!1;if(!this.check("RPAREN"))do if(n.push(this.parseExpression()),this.match("COMMA"))r=!0;else break;while(!this.check("RPAREN")&&!this.isAtEnd());return this.consume("RPAREN","Expected ')' after expression"),n.length===1&&!r?{kind:"GroupingExpr",expression:n[0],line:t.line,column:t.column}:{kind:"TupleExpr",elements:n,line:t.line,column:t.column}}if(this.match("LBRACKET")){let t=[];if(!this.check("RBRACKET"))do t.push(this.parseExpression());while(this.match("COMMA"));return this.consume("RBRACKET","Expected ']' after array elements"),{kind:"ArrayExpr",elements:t,line:e.line,column:e.column}}if(this.match("LBRACE")){let t=this.previous(),n=[];if(!this.check("RBRACE"))do{let r="";if(this.match("IDENTIFIER","STRING"))r=this.previous().value;else throw new p("Expected object key (identifier or string)",this.peek().line,this.peek().column,"PARSER",this.file);this.consume("COLON","Expected ':' after object key");let i=this.parseExpression();n.push({key:r,value:i})}while(this.match("COMMA"));return this.consume("RBRACE","Expected '}' after object literal"),{kind:"ObjectExpr",properties:n,line:t.line,column:t.column}}throw new p(`Unexpected token '${e.value||e.type}' in expression`,e.line,e.column,"PARSER",this.file)}parseFormattedString(){let e=this.advance(),t=[];for(;!this.check("FSTRING_END")&&!this.isAtEnd();){if(this.match("FSTRING_TEXT")){t.push(this.previous().value);continue}let n=this.consume("FSTRING_FIELD_START","Expected formatted-string text or field"),r=this.parseExpression();this.validateFieldExpression(r);let i=this.consume("FSTRING_FIELD_END","Expected '}' after one formatted-string expression");t.push({expression:r,line:n.line,column:n.column,file:this.file,offset:n.offset,endOffset:i.endOffset})}return this.consume("FSTRING_END","Unterminated formatted string"),{kind:"InterpolatedStringExpr",parts:t,line:e.line,column:e.column,file:this.file}}validateFieldExpression(e){let t=[];switch(e.kind){case"AssignExpr":case"IndexAssignExpr":case"TupleAssignExpr":case"ParallelExpr":throw new p("Assignment and parallel expressions are not permitted in formatted-string fields",e.line,e.column,"PARSER",this.file);case"UnaryExpr":t=[e.operand];break;case"BinaryExpr":t=[e.left,e.right];break;case"ConditionalExpr":t=[e.condition,e.trueArm,e.falseArm];break;case"GroupingExpr":t=[e.expression];break;case"CallExpr":t=e.args;break;case"ArrayExpr":case"TupleExpr":t=e.elements;break;case"ObjectExpr":t=e.properties.map(n=>n.value);break;case"IndexExpr":t=[e.target,e.index];break;case"InterpolatedStringExpr":t=e.parts.flatMap(n=>typeof n=="string"?[]:[n.expression]);break;case"LiteralExpr":case"IdentifierExpr":break}for(let n of t)this.validateFieldExpression(n)}match(...e){for(let t of e)if(this.check(t))return this.advance(),!0;return!1}check(e){return this.isAtEnd()?!1:this.peek().type===e}advance(){return this.isAtEnd()||this.current++,this.previous()}isAtEnd(){return this.peek().type==="EOF"}peek(){return this.tokens[this.current]}previous(){return this.tokens[this.current-1]}consume(e,t){if(this.check(e))return this.advance();let n=this.peek();throw new p(t,n.line,n.column,"PARSER",this.file)}consumeOptionalSemicolon(){this.check("SEMICOLON")&&this.advance()}},ke=`# LMScript Standard Library (std.lms)
61
-
62
- # String Utilities
63
- fn is_blank(s) {
64
- if (s == null) {
65
- return true;
66
- }
67
- return len(trim(s)) == 0;
68
- }
69
-
70
- # Array Utilities
71
- fn chunk(arr, size) {
72
- if (size <= 0) {
73
- return [];
74
- }
75
- res = [];
76
- current = [];
77
- for (i = 0; i < len(arr); i = i + 1) {
78
- push(current, arr[i]);
79
- if (len(current) == size) {
80
- push(res, current);
81
- current = [];
82
- }
83
- }
84
- if (len(current) > 0) {
85
- push(res, current);
86
- }
87
- return res;
88
- }
89
-
90
- fn compact(arr) {
91
- res = [];
92
- for (i = 0; i < len(arr); i = i + 1) {
93
- item = arr[i];
94
- if (item != null) {
95
- push(res, item);
96
- }
97
- }
98
- return res;
99
- }
100
-
101
- fn zip(arr1, arr2) {
102
- res = [];
103
- limit = len(arr1);
104
- if (len(arr2) < limit) {
105
- limit = len(arr2);
106
- }
107
- for (i = 0; i < limit; i = i + 1) {
108
- push(res, [arr1[i], arr2[i]]);
109
- }
110
- return res;
111
- }
112
-
113
- fn take(arr, n) {
114
- res = [];
115
- limit = n;
116
- if (limit > len(arr)) {
117
- limit = len(arr);
118
- }
119
- for (i = 0; i < limit; i = i + 1) {
120
- push(res, arr[i]);
121
- }
122
- return res;
123
- }
124
-
125
- fn drop(arr, n) {
126
- res = [];
127
- start = n;
128
- if (start < 0) {
129
- start = 0;
130
- }
131
- for (i = start; i < len(arr); i = i + 1) {
132
- push(res, arr[i]);
133
- }
134
- return res;
135
- }
136
-
137
- # Math Utilities
138
- fn clamp(val, low, high) {
139
- if (val < low) {
140
- return low;
141
- }
142
- if (val > high) {
143
- return high;
144
- }
145
- return val;
146
- }
147
- `,q=null;function Ae(){if(!q){let e=new D(ke,"<std>").tokenize(),n=new B(e,"<std>").parse();for(let r of n.statements)r.kind==="FunctionDeclStmt"&&(r.isStdlib=!0);q=n}return{kind:"Program",statements:[...q.statements],line:1,column:1,file:"<std>"}}function Re(a,e={}){let t=[],n=e.file||"<main>",r=e.baseDir||(e.file?k.dirname(k.resolve(e.file)):process.cwd()),i=new Map,s=new Set;function o(h,f){if(e.moduleResolver)return e.moduleResolver(h,f).path;let g=r;f&&f!=="<main>"&&f!=="<std>"&&(g=k.dirname(f));let b=k.resolve(g,h);try{return d.realpathSync(b)}catch{return b}}function l(h,f){let g,b;if(e.moduleResolver){let v=e.moduleResolver(h,f);g=v.path,b=v.source}else{if(g=o(h,f),i.has(g))return i.get(g);if(s.has(g))return{kind:"Program",statements:[],line:1,column:1,file:g};try{b=d.readFileSync(g,"utf-8")}catch(v){throw new p(`Cannot resolve import '${h}': ${v?.message||String(v)}`,1,1,"PARSER",f)}}if(i.has(g))return i.get(g);if(s.has(g))return{kind:"Program",statements:[],line:1,column:1,file:g};s.add(g);let R=new D(b,g),F=R.tokenize();t.push(...R.diagnostics);let A=new B(F,g).parse();for(let v of A.statements)if(v.kind!=="FunctionDeclStmt"&&v.kind!=="ImportStmt")throw new p(`Library '${g}' cannot contain top-level executable statements; libraries must only declare functions. Found '${v.kind}'.`,v.line,v.column,"CHECKER",g);for(let v of A.statements)v.kind==="ImportStmt"&&l(v.path,g);return s.delete(g),i.set(g,A),A}let c=new D(a,n),m=c.tokenize();t.push(...c.diagnostics);let y=new B(m,n).parse(),E=n!=="<main>"?o(n):"<main>";i.set(E,y);for(let h of y.statements)h.kind==="ImportStmt"&&l(h.path,n);let x=[];if(!e.noStdlib){let h=Ae();for(let f of h.statements)f.kind==="FunctionDeclStmt"&&x.push(f)}for(let[h,f]of i.entries())if(h!==E)for(let g of f.statements)g.kind==="FunctionDeclStmt"&&x.push(g);for(let h of y.statements)h.kind!=="ImportStmt"&&x.push(h);let w={kind:"Program",statements:x,line:y.line,column:y.column,file:n},_=Array.from(i.keys());return{program:w,loadedFiles:_,diagnostics:t}}var L=class{variables=new Set;parent;isFunctionScope;constructor(e,t=!1){this.parent=e,this.isFunctionScope=t}define(e){this.variables.add(e)}hasInCurrent(e){return this.variables.has(e)}resolve(e){return this.variables.has(e)?!0:this.parent?this.parent.resolve(e):!1}resolveInScope(e){return this.variables.has(e)?!0:this.isFunctionScope?!1:this.parent?this.parent.resolveInScope(e):!1}},ee=class{diagnostics=[];hostFunctions=new Map;options;functions=new Map;currentScope=new L;loopDepth=0;inFunction=!1;hasConcurrency=!1;constructor(e,t={}){this.options=t;for(let[n,r]of e.entries())this.hostFunctions.set(n,r),this.functions.set(n,{name:n,paramCount:typeof r.arity=="number"?r.arity:-1,params:[],isHost:!0,line:0,column:0})}check(e){if(this.diagnostics=[],this.hasConcurrency=!1,this.loopDepth=0,this.inFunction=!1,this.currentScope=new L,this.options.globals)for(let t of this.options.globals)this.currentScope.define(t);this.functions.clear();for(let[t,n]of this.hostFunctions.entries())this.functions.set(t,{name:t,paramCount:typeof n.arity=="number"?n.arity:-1,params:[],isHost:!0,line:0,column:0});for(let t of e.statements)t.kind==="FunctionDeclStmt"&&this.collectFunction(t);for(let t of e.statements)this.checkStmt(t);return this.diagnostics}addError(e,t,n,r){this.diagnostics.push({message:e,line:t,column:n,severity:"error",file:r})}collectFunction(e){if(this.functions.has(e.name)){let n=this.functions.get(e.name);if(n.isHost){this.addError(`Cannot redefine host function '${e.name}'`,e.line,e.column,e.file);return}if(n.isStdlib){this.functions.set(e.name,{name:e.name,paramCount:e.params.length,params:e.params,isHost:!1,isStdlib:!1,file:e.file,line:e.line,column:e.column});return}let r=n.file?`${n.file}:${n.line}`:`line ${n.line}`;this.addError(`Duplicate function declaration '${e.name}' (already defined at ${r})`,e.line,e.column,e.file);return}let t=new Set;for(let n of e.params)t.has(n)&&this.addError(`Duplicate parameter name '${n}' in function '${e.name}'`,e.line,e.column,e.file),t.add(n);this.functions.set(e.name,{name:e.name,paramCount:e.params.length,params:e.params,isHost:!1,isStdlib:e.isStdlib||!1,file:e.file,line:e.line,column:e.column})}checkStmt(e){switch(e.kind){case"ImportStmt":break;case"FunctionDeclStmt":{if(this.inFunction||this.currentScope.parent){this.addError("Function declarations are only allowed at top level",e.line,e.column,e.file);break}let t=this.currentScope,n=this.inFunction;this.inFunction=!0,this.currentScope=new L(t,!0);for(let r of e.params)this.currentScope.define(r);for(let r of e.body.statements)this.checkStmt(r);this.inFunction=n,this.currentScope=t;break}case"VarDeclStmt":{this.currentScope.hasInCurrent(e.name)&&this.addError(`Variable '${e.name}' is already declared in this scope`,e.line,e.column,e.file),e.initializer&&this.checkExpr(e.initializer),this.currentScope.define(e.name);break}case"TupleVarDeclStmt":{this.checkExpr(e.initializer);for(let t of e.names)this.currentScope.hasInCurrent(t)&&this.addError(`Variable '${t}' is already declared in this scope`,e.line,e.column,e.file),this.currentScope.define(t);break}case"IfStmt":{this.checkExpr(e.condition),this.checkStmt(e.thenBranch),e.elseBranch&&this.checkStmt(e.elseBranch);break}case"WhileStmt":{this.checkExpr(e.condition),this.loopDepth++,this.checkStmt(e.body),this.loopDepth--;break}case"ForInStmt":{this.checkExpr(e.iterable);let t=this.currentScope;if(this.currentScope=new L(t),this.currentScope.define(e.name),this.loopDepth++,e.body.kind==="BlockStmt")for(let n of e.body.statements)this.checkStmt(n);else this.checkStmt(e.body);this.loopDepth--,this.currentScope=t;break}case"ForStmt":{let t=this.currentScope;this.currentScope=new L(t),e.init&&this.checkStmt(e.init),e.condition&&this.checkExpr(e.condition),e.update&&this.checkExpr(e.update),this.loopDepth++,this.checkStmt(e.body),this.loopDepth--,this.currentScope=t;break}case"ReturnStmt":{this.inFunction||this.addError("'return' statement is only allowed inside a function",e.line,e.column,e.file),e.value&&this.checkExpr(e.value);break}case"BreakStmt":{this.loopDepth===0&&this.addError("'break' statement is only allowed inside a loop",e.line,e.column,e.file);break}case"ContinueStmt":{this.loopDepth===0&&this.addError("'continue' statement is only allowed inside a loop",e.line,e.column,e.file);break}case"BlockStmt":{let t=this.currentScope;this.currentScope=new L(t);for(let n of e.statements)this.checkStmt(n);this.currentScope=t;break}case"SyncAssignStmt":{this.hasConcurrency=!0,this.currentScope.resolve(e.target)||this.addError(`Synchronized assignment target '${e.target}' must be declared beforehand`,e.line,e.column,e.file),this.checkExpr(e.value);break}case"SyncIndexAssignStmt":{this.hasConcurrency=!0,this.checkExpr(e.target),this.checkExpr(e.index),this.checkExpr(e.value);break}case"SyncCallStmt":{this.hasConcurrency=!0;let t=e.call;t.args.length===0&&this.addError(`Synchronized call '${t.callee}' requires at least one argument (the target container)`,e.line,e.column,e.file);let n=this.hostFunctions.get(t.callee);(!n||!n.isContainerMutation)&&this.addError(`Synchronized call '${t.callee}' is not an authorized container mutation operation`,e.line,e.column,e.file),this.checkExpr(e.call);break}case"ExprStmt":{this.checkExpr(e.expr);break}}}checkReadPath(e){let t=e.args[0];for(;t.kind==="GroupingExpr";)t=t.expression;if(t.kind!=="LiteralExpr"){this.diagnostics.push({message:`Cannot preflight dynamic file path in '${e.callee}'; check it at runtime with file_exists(path)`,line:e.line,column:e.column,severity:"warning",file:e.file});return}if(typeof t.value!="string"){this.addError(`File path in '${e.callee}' must be a string`,e.line,e.column,e.file);return}try{if(!d.statSync(t.value).isFile())throw new Error("path is not a regular file");d.accessSync(t.value,d.constants.R_OK)}catch(n){this.addError(`Cannot read file ${JSON.stringify(t.value)}: ${n instanceof Error?n.message:String(n)}`,e.line,e.column,e.file)}}checkExpr(e){switch(e.kind){case"InterpolatedStringExpr":for(let t of e.parts)typeof t!="string"&&this.checkExpr(t.expression);break;case"LiteralExpr":break;case"IdentifierExpr":{this.currentScope.resolve(e.name)||this.addError(`Undeclared variable '${e.name}'`,e.line,e.column,e.file);break}case"AssignExpr":{this.checkExpr(e.value),this.currentScope.resolveInScope(e.target)||this.currentScope.define(e.target);break}case"TupleAssignExpr":{this.checkExpr(e.value);for(let t of e.targets)this.currentScope.resolveInScope(t)||this.currentScope.define(t);break}case"IndexAssignExpr":{this.checkExpr(e.target),this.checkExpr(e.index),this.checkExpr(e.value);break}case"UnaryExpr":{this.checkExpr(e.operand);break}case"ConditionalExpr":{this.checkExpr(e.condition),this.checkExpr(e.trueArm),this.checkExpr(e.falseArm);break}case"BinaryExpr":{this.checkExpr(e.left),this.checkExpr(e.right);break}case"GroupingExpr":{this.checkExpr(e.expression);break}case"TupleExpr":{for(let t of e.elements)this.checkExpr(t);break}case"ArrayExpr":{for(let t of e.elements)this.checkExpr(t);break}case"ObjectExpr":{for(let t of e.properties)this.checkExpr(t.value);break}case"IndexExpr":{this.checkExpr(e.target),this.checkExpr(e.index);break}case"ParallelExpr":{this.hasConcurrency=!0;for(let t of e.tasks)this.checkExpr(t);break}case"CallExpr":{let t=this.functions.get(e.callee);t?t.paramCount>=0&&e.args.length!==t.paramCount&&this.addError(`Function '${e.callee}' expects ${t.paramCount} argument(s), but received ${e.args.length}`,e.line,e.column,e.file):this.addError(J(e.callee),e.line,e.column,e.file);let n=this.hostFunctions.get(e.callee),r=n?.arity;typeof r=="object"&&(e.args.length<r.min||e.args.length>(r.max??1/0))&&this.addError(`Function '${e.callee}' expects ${r.min}..${r.max??"unlimited"} argument(s), but received ${e.args.length}`,e.line,e.column,e.file),this.options.checkFiles&&n?.readsFile&&e.args.length>0&&this.checkReadPath(e);for(let i of e.args)this.checkExpr(i);break}}}};function te(a,e){let t,n=s=>{throw t=e?new p("Cannot interpolate value: "+s,e.line,e.column,"RUNTIME",e.file):new Error("Cannot convert value to text: "+s),t},r=new Set,i=s=>{if(s===null)return"null";if(typeof s=="string")return JSON.stringify(s);if(typeof s=="boolean")return String(s);if(typeof s=="number")return Number.isFinite(s)?String(s):n("nonfinite number");if(typeof s!="object")return n(s===void 0?"undefined":"unsupported "+typeof s);let o=Array.isArray(s),l=Object.getPrototypeOf(s);if(!o&&l!==Object.prototype&&l!==null)return n("unsupported host object");if(r.has(s))return n("cyclic collection");r.add(s);try{if(Reflect.ownKeys(s).some(y=>typeof y=="symbol"))return n("symbol-keyed collection");let c=o?Array.from({length:s.length},(y,E)=>String(E)):Object.keys(s);if(o&&c.some(y=>!Object.hasOwn(s,y)))return n("sparse array");let m=Object.getOwnPropertyNames(s).filter(y=>!o||y!=="length");if(m.length!==c.length||m.some(y=>!c.includes(y)))return n("extra or non-enumerable collection property");let u=[];for(let y of c){let E=Object.getOwnPropertyDescriptor(s,y);if(!E)return n("sparse array");if(!Object.hasOwn(E,"value"))return n("accessor property");let x=i(E.value);u.push(o?x:JSON.stringify(y)+":"+x)}return o?"["+u.join(",")+"]":"{"+u.join(",")+"}"}finally{r.delete(s)}};try{return typeof a=="string"?a:i(a)}catch(s){if(s===t)throw s;return n("serialization failed: "+(s instanceof Error?s.message:String(s)))}}var O=class{value;constructor(e){this.value=e}},T=class{},N=class{},C=class a{static nextId=1;id=a.nextId++;values=new Map;parent;isFunctionScope;constructor(e,t=!1){this.parent=e,this.isFunctionScope=t}resolveBinding(e){if(this.values.has(e))return{env:this,name:e};if(this.parent)return this.parent.resolveBinding(e)}define(e,t){this.values.set(e,t)}get(e){if(this.values.has(e))return this.values.get(e);if(this.parent)return this.parent.get(e)}has(e){return this.values.has(e)||(this.parent?.has(e)??!1)}hasInScope(e){return this.values.has(e)?!0:this.isFunctionScope?!1:this.parent?this.parent.hasInScope(e):!1}set(e,t){if(this.values.has(e)){this.values.set(e,t);return}if(!this.isFunctionScope&&this.parent&&this.parent.hasInScope(e)){this.parent.set(e,t);return}this.values.set(e,t)}},V=class{holderTaskId;depth=0;waiters=[];acquire(e=0,t=1e4){return this.depth===0?(this.holderTaskId=e,this.depth=1,Promise.resolve()):this.holderTaskId===e?(this.depth++,Promise.resolve()):new Promise((n,r)=>{let i;t>0&&(i=setTimeout(()=>{let o=this.waiters.findIndex(l=>l.resolve===s);o!==-1&&(this.waiters.splice(o,1),r(new Error(`Lock acquisition timed out after ${t}ms (possible deadlock)`)))},t));let s=()=>{i&&clearTimeout(i),this.holderTaskId=e,this.depth=1,n()};this.waiters.push({taskId:e,resolve:s})})}release(){this.depth<=0||(this.depth--,this.depth===0&&(this.holderTaskId=void 0,this.waiters.length>0&&this.waiters.shift().resolve()))}async withLock(e,t=0,n=1e4){await this.acquire(t,n);try{return await e()}finally{this.release()}}},ne=class{bindingLocks=new Map;objectLocks=new WeakMap;getBindingLock(e){let t=this.bindingLocks.get(e);return t||(t=new V,this.bindingLocks.set(e,t)),t}getObjectLock(e){let t=this.objectLocks.get(e);return t||(t=new V,this.objectLocks.set(e,t)),t}},K=class{globalEnv;userFunctions=new Map;hostFunctions;stdout;stderr;lockManager=new ne;isAsync;nextTaskId=1;initialGlobals;callDepth=0;asyncCallDepth=new Map;recordedErrors=[];promptHumanConfig;constructor(e,t=o=>console.log(o),n=!1,r,i,s){this.stdout=t,this.stderr=i,this.isAsync=n,this.initialGlobals=r,this.globalEnv=new C,this.hostFunctions=new Map(e),this.promptHumanConfig=s??{mode:"interactive"};let o=e.get("print");(!o||o.isDefault)&&this.hostFunctions.set("print",{fn:(...h)=>{let f=h.map(g=>typeof g=="object"?JSON.stringify(g):String(g)).join(" ");return this.stdout(f),f},description:"Prints formatted values to output log",isDefault:!0});let l=e.get("println");(!l||l.isDefault)&&this.hostFunctions.set("println",{fn:(...h)=>{let f=h.map(g=>typeof g=="object"?JSON.stringify(g):String(g)).join(" ");return this.stdout(f),f},description:"Prints line to output log",isDefault:!0});let c=e.get("error");(!c||c.isDefault)&&this.hostFunctions.set("error",{fn:(...h)=>{let f=h.map(g=>typeof g=="object"?JSON.stringify(g):String(g)).join(" ");return this.stderr?this.stderr(`error: ${f}`):typeof process<"u"&&process.stderr?process.stderr.write(`error: ${f}
148
- `):console.error(`error: ${f}`),this.recordedErrors.push(f),f},description:"Prints error message to stderr and records it for execution error summary",isDefault:!0});let m=e.get("system");(!m||m.isDefault)&&this.hostFunctions.set("system",{fn:(h,f=6e4)=>{if(!Number.isSafeInteger(f)||f<0)throw new Error("system() timeout must be a non-negative safe integer in milliseconds");return this.isAsync?ge(h,f):me(h,f)},arity:{min:1,max:2},description:"Executes shell command or argv array directly with shell:false and optional timeoutMs (default 60000), returning {stdout, stderr, code, signal, timed_out, duration_ms, pid}",isDefault:!0});let u=e.get("prompt_human_config");(!u||u.isDefault)&&this.hostFunctions.set("prompt_human_config",{fn:(h,f)=>{if(h===void 0)return{mode:this.promptHumanConfig.mode??"interactive",dir:this.promptHumanConfig.dir??null,timeout_ms:this.promptHumanConfig.timeoutMs??null,poll_interval_ms:this.promptHumanConfig.pollIntervalMs??200};if(typeof h=="string")h==="interactive"?this.promptHumanConfig.mode="interactive":h==="file"?(this.promptHumanConfig.mode="file",f&&(this.promptHumanConfig.dir=String(f))):(this.promptHumanConfig.mode="file",this.promptHumanConfig.dir=h);else if(h&&typeof h=="object"){let g=h.mode?String(h.mode):h.dir?"file":this.promptHumanConfig.mode??"interactive",b=h.dir!==void 0?String(h.dir):this.promptHumanConfig.dir,R=h.timeout_ms!==void 0?Number(h.timeout_ms):h.timeoutMs!==void 0?Number(h.timeoutMs):this.promptHumanConfig.timeoutMs,F=h.poll_ms!==void 0?Number(h.poll_ms):h.pollIntervalMs!==void 0?Number(h.pollIntervalMs):this.promptHumanConfig.pollIntervalMs;this.promptHumanConfig.mode=g==="file"?"file":"interactive",this.promptHumanConfig.dir=b,this.promptHumanConfig.timeoutMs=typeof R=="number"&&Number.isFinite(R)?R:void 0,this.promptHumanConfig.pollIntervalMs=typeof F=="number"&&Number.isFinite(F)&&F>0?F:200}return{mode:this.promptHumanConfig.mode,dir:this.promptHumanConfig.dir??null,timeout_ms:this.promptHumanConfig.timeoutMs??null,poll_interval_ms:this.promptHumanConfig.pollIntervalMs??200}},arity:{min:0,max:2},description:"Configures prompt_human mode ('interactive' or 'file' with dedicated directory, timeout_ms, poll_ms)",isDefault:!0});let y=e.get("prompt_human");(!y||y.isDefault)&&this.hostFunctions.set("prompt_human",{fn:(h,f)=>{if((f?.mode??(f?.dir?"file":this.promptHumanConfig.mode??"interactive"))==="file"){let b=f?.dir??this.promptHumanConfig.dir;if(!b)throw new Error("prompt_human: file mode requires a directory (configure via prompt_human_config({ dir }) or pass { dir })");if(!this.isAsync)throw new Error("prompt_human: file mode requires asynchronous execution (runAsync)");return xe(h,{dir:b,sessionId:f?.sessionId??f?.sessionid??f?.id,timeoutMs:f?.timeout_ms??f?.timeoutMs??this.promptHumanConfig.timeoutMs,pollIntervalMs:f?.poll_ms??f?.pollIntervalMs??this.promptHumanConfig.pollIntervalMs,onWaiting:R=>this.stderr?this.stderr(R):typeof process<"u"&&process.stderr?process.stderr.write(R):void 0})}return this.isAsync?Ee(h):ye(h)},arity:{min:0,max:2},description:"Prompts operator on stdin/terminal or dedicated directory, returning input string or null if closed/non-interactive",isDefault:!0});let E=e.get("shell_quote");(!E||E.isDefault)&&this.hostFunctions.set("shell_quote",{fn:h=>fe(h),arity:1,description:"Quotes string safely for POSIX shell command execution",isDefault:!0});let x=e.get("run_script");(!x||x.isDefault)&&this.hostFunctions.set("run_script",{fn:(h,f=[])=>{let g=k.resolve(String(h));if(!d.existsSync(g))throw new Error(`run_script: file not found: '${g}'`);let b=d.readFileSync(g,"utf-8"),R=Array.isArray(f)?f.map(String):[],F=new U;for(let[S,A]of this.hostFunctions)F.hasFunction(S)?A.isDefault||F.registerFunction(S,A.fn,A.arity,{description:A.description,allowOverwrite:!0},!1,A.isContainerMutation):F.registerFunction(S,A.fn,A.arity,A.description,A.isDefault,A.isContainerMutation);if(F.setGlobal("args",[...R]),F.setGlobal("ARGV",[g,...R]),this.isAsync)return(async()=>{let S=await F.runAsync(b,{file:g}),A=S.output.join(`
149
- `)+(S.output.length>0?`
150
- `:""),v=S.exitCode!==void 0?S.exitCode:S.success?0:1,j={success:S.success&&v===0,stdout:A,output:[...S.output],value:S.value,exit_code:v,code:v,errors:S.errors??[]};return j.toString=()=>A,j})();{let S=F.run(b,{file:g}),A=S.output.join(`
151
- `)+(S.output.length>0?`
152
- `:""),v=S.exitCode!==void 0?S.exitCode:S.success?0:1,j={success:S.success&&v===0,stdout:A,output:[...S.output],value:S.value,exit_code:v,code:v,errors:S.errors??[]};return j.toString=()=>A,j}},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 w=e.get("urlget");(!w||w.isDefault)&&this.hostFunctions.set("urlget",{fn:h=>this.isAsync?we(h):he(h),arity:1,description:"Downloads UTF-8 text from a public HTTP(S) URL",isDefault:!0});let _=e.get("sleep");(!_||_.isDefault)&&this.hostFunctions.set("sleep",{fn:h=>{if(typeof h!="number"||!Number.isFinite(h)||h<0)throw new Error("sleep() duration must be a non-negative finite number");if(h>2147483647)throw new Error("sleep() duration exceeds maximum supported timeout (2147483647 ms)");if(this.isAsync)return new Promise(g=>setTimeout(g,h));let f=Date.now()+h;for(;Date.now()<f;);return null},arity:1,description:"Sleeps for the specified milliseconds",isDefault:!0})}evaluateProgram(e){if(this.globalEnv=new C,this.initialGlobals)for(let[n,r]of this.initialGlobals.entries())this.globalEnv.define(n,r);this.userFunctions.clear(),this.callDepth=0;for(let n of e.statements)n.kind==="FunctionDeclStmt"&&this.userFunctions.set(n.name,n);let t;for(let n of e.statements)n.kind!=="FunctionDeclStmt"&&(t=this.execStmt(n,this.globalEnv));return t}execStmt(e,t){switch(e.kind){case"ImportStmt":return;case"BlockStmt":{let n=new C(t);for(let r of e.statements)this.execStmt(r,n);return}case"VarDeclStmt":{let n=null;return e.initializer&&(n=this.evalExpr(e.initializer,t)),t.define(e.name,n),n}case"TupleVarDeclStmt":{let n=this.evalExpr(e.initializer,t);if(!Array.isArray(n))throw new p(`Cannot destructure non-array value (got ${typeof n})`,e.line,e.column,"RUNTIME",e.file);for(let r=0;r<e.names.length;r++){let i=r<n.length?n[r]:null;t.define(e.names[r],i)}return n}case"IfStmt":{let n=this.evalExpr(e.condition,t);return this.isTruthy(n)?this.execStmt(e.thenBranch,t):e.elseBranch?this.execStmt(e.elseBranch,t):void 0}case"WhileStmt":{let n=0;for(;this.isTruthy(this.evalExpr(e.condition,t));){if(++n>1e6)throw new p("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");try{this.execStmt(e.body,t)}catch(r){if(r instanceof T)break;if(r instanceof N)continue;throw r}}return}case"ForInStmt":{let n=ce(this.evalExpr(e.iterable,t),e),r=0;for(let i of n){if(++r>1e6)throw new p("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let s=new C(t);s.define(e.name,i);try{if(e.body.kind==="BlockStmt")for(let o of e.body.statements)this.execStmt(o,s);else this.execStmt(e.body,s)}catch(o){if(o instanceof T)break;if(o instanceof N)continue;throw o}}return}case"ForStmt":{let n=new C(t);e.init&&this.execStmt(e.init,n);let r=0;for(;;){if(e.condition){let i=this.evalExpr(e.condition,n);if(!this.isTruthy(i))break}if(++r>1e6)throw new p("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");try{this.execStmt(e.body,n)}catch(i){if(i instanceof T)break;if(!(i instanceof N))throw i}e.update&&this.evalExpr(e.update,n)}return}case"ReturnStmt":{let n=e.value?this.evalExpr(e.value,t):null;throw new O(n)}case"BreakStmt":throw new T;case"ContinueStmt":throw new N;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":return this.evalExpr(e.expr,t);default:return}}evalExpr(e,t){switch(e.kind){case"InterpolatedStringExpr":{let n="";for(let r of e.parts)n+=typeof r=="string"?r:te(this.evalExpr(r.expression,t),r);return n}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"IdentifierExpr":return t.get(e.name);case"AssignExpr":{let n=this.evalExpr(e.value,t);return t.set(e.target,n),n}case"TupleAssignExpr":{let n=this.evalExpr(e.value,t);if(!Array.isArray(n))throw new p(`Cannot destructure non-array value (got ${typeof n})`,e.line,e.column,"RUNTIME",e.file);for(let r=0;r<e.targets.length;r++){let i=r<n.length?n[r]:null;t.set(e.targets[r],i)}return n}case"IndexAssignExpr":{let n=this.evalExpr(e.target,t),r=this.evalExpr(e.index,t),i=this.evalExpr(e.value,t);if(Array.isArray(n)||typeof n=="object"&&n!==null)return Array.isArray(n)&&typeof r=="number"&&r<0&&(r=n.length+r),M(n,r,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,t);case"TupleExpr":return e.elements.map(n=>this.evalExpr(n,t));case"ArrayExpr":return e.elements.map(n=>this.evalExpr(n,t));case"ObjectExpr":{let n={};for(let r of e.properties)M(n,r.key,this.evalExpr(r.value,t));return n}case"IndexExpr":{let n=this.evalExpr(e.target,t),r=this.evalExpr(e.index,t);if(n==null)throw new p("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Array.isArray(n)&&typeof r=="number"&&r<0?n[n.length+r]:I(n,r)}case"UnaryExpr":{let n=this.evalExpr(e.operand,t),r=e.operator;if(r==="!")return!this.isTruthy(n);if(r==="-")return-n;throw new p(`Unknown unary operator: ${r}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let n=this.evalExpr(e.condition,t);return this.isTruthy(n)?this.evalExpr(e.trueArm,t):this.evalExpr(e.falseArm,t)}case"BinaryExpr":{if(e.operator==="&&"){let s=this.evalExpr(e.left,t);return this.isTruthy(s)?this.evalExpr(e.right,t):s}if(e.operator==="||"){let s=this.evalExpr(e.left,t);return this.isTruthy(s)?s:this.evalExpr(e.right,t)}let n=this.evalExpr(e.left,t),r=this.evalExpr(e.right,t),i=e.operator;switch(i){case"+":return typeof n=="string"||typeof r=="string"?String(n)+String(r):n+r;case"-":return n-r;case"*":return n*r;case"/":if(r===0)throw new p("Division by zero",e.line,e.column,"RUNTIME",e.file);return n/r;case"%":return n%r;case"==":return n===r;case"!=":return n!==r;case"<":return n<r;case"<=":return n<=r;case">":return n>r;case">=":return n>=r;default:throw new p(`Unknown binary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let n=e.args.map(r=>this.evalExpr(r,t));if(this.userFunctions.has(e.callee)){let r=this.userFunctions.get(e.callee);if(this.callDepth++,this.callDepth>$)throw this.callDepth--,new p(`Execution fuel exhausted: maximum function call depth exceeded (${$})`,e.line,e.column,"RUNTIME",e.file);let i=new C(this.globalEnv,!0);for(let s=0;s<r.params.length;s++)i.define(r.params[s],n[s]);try{for(let s of r.body.statements)this.execStmt(s,i)}catch(s){if(s instanceof O)return s.value;throw s}finally{this.callDepth--}return null}if(this.hostFunctions.has(e.callee)){let r=this.hostFunctions.get(e.callee);try{return r.fn(...n)}catch(i){throw i instanceof P||i?.name==="LMScriptExit"||i?.isControlFlow?i:new p(`Error in host function '${e.callee}': ${i?.message||String(i)}`,e.line,e.column,"RUNTIME",e.file)}}throw new p(J(e.callee,"Undefined function"),e.line,e.column,"RUNTIME",e.file)}}}isTruthy(e){return!(e==null||e===!1||e===0||e==="")}async evaluateProgramAsync(e){if(this.globalEnv=new C,this.initialGlobals)for(let[r,i]of this.initialGlobals.entries())this.globalEnv.define(r,i);this.userFunctions.clear(),this.asyncCallDepth.clear();for(let r of e.statements)r.kind==="FunctionDeclStmt"&&this.userFunctions.set(r.name,r);let t=this.nextTaskId++,n;for(let r of e.statements)r.kind!=="FunctionDeclStmt"&&(n=await this.execStmtAsync(r,this.globalEnv,t));return n}async execStmtAsync(e,t,n){switch(e.kind){case"ImportStmt":return;case"BlockStmt":{let r=new C(t);for(let i of e.statements)await this.execStmtAsync(i,r,n);return}case"VarDeclStmt":{let r=null;return e.initializer&&(r=await this.evalExprAsync(e.initializer,t,n)),t.define(e.name,r),r}case"TupleVarDeclStmt":{let r=await this.evalExprAsync(e.initializer,t,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 i=0;i<e.names.length;i++){let s=i<r.length?r[i]:null;t.define(e.names[i],s)}return r}case"IfStmt":{let r=await this.evalExprAsync(e.condition,t,n);return this.isTruthy(r)?await this.execStmtAsync(e.thenBranch,t,n):e.elseBranch?await this.execStmtAsync(e.elseBranch,t,n):void 0}case"WhileStmt":{let r=0;for(;this.isTruthy(await this.evalExprAsync(e.condition,t,n));){if(++r>1e6)throw new p("Execution fuel exhausted: while loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");try{await this.execStmtAsync(e.body,t,n)}catch(i){if(i instanceof T)break;if(i instanceof N)continue;throw i}}return}case"ForInStmt":{let r=ce(await this.evalExprAsync(e.iterable,t,n),e),i=0;for(let s of r){if(++i>1e6)throw new p("Execution fuel exhausted: for-in loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME",e.file);let o=new C(t);o.define(e.name,s);try{if(e.body.kind==="BlockStmt")for(let l of e.body.statements)await this.execStmtAsync(l,o,n);else await this.execStmtAsync(e.body,o,n)}catch(l){if(l instanceof T)break;if(l instanceof N)continue;throw l}}return}case"ForStmt":{let r=new C(t);e.init&&await this.execStmtAsync(e.init,r,n);let i=0;for(;;){if(e.condition){let s=await this.evalExprAsync(e.condition,r,n);if(!this.isTruthy(s))break}if(++i>1e6)throw new p("Execution fuel exhausted: for loop exceeded maximum iterations limit (1000000)",e.line,e.column,"RUNTIME");try{await this.execStmtAsync(e.body,r,n)}catch(s){if(s instanceof T)break;if(!(s instanceof N))throw s}e.update&&await this.evalExprAsync(e.update,r,n)}return}case"ReturnStmt":{let r=e.value?await this.evalExprAsync(e.value,t,n):null;throw new O(r)}case"BreakStmt":throw new T;case"ContinueStmt":throw new N;case"SyncAssignStmt":{let r=t.resolveBinding(e.target);if(!r)throw new p(`Synchronized assignment target '${e.target}' is not defined`,e.line,e.column,"RUNTIME",e.file);let i=`bind:${r.env.id}:${r.name}`;await this.lockManager.getBindingLock(i).withLock(async()=>{let o=await this.evalExprAsync(e.value,t,n);r.env.set(r.name,o)},n);return}case"SyncIndexAssignStmt":{let r=await this.evalExprAsync(e.target,t,n);if(r==null||typeof r!="object"&&typeof r!="function")throw new p("Cannot perform synchronized assignment on non-object",e.line,e.column,"RUNTIME",e.file);await this.lockManager.getObjectLock(r).withLock(async()=>{let s=await this.evalExprAsync(e.index,t,n),o=await this.evalExprAsync(e.value,t,n);Array.isArray(r)&&typeof s=="number"&&s<0&&(s=r.length+s),M(r,s,o)},n);return}case"SyncCallStmt":{let r=e.call;if(r.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(r.callee);if(!i||!i.isContainerMutation)throw new p(`Function '${r.callee}' is not an authorized container mutation operation`,e.line,e.column,"RUNTIME",e.file);let s=await this.evalExprAsync(r.args[0],t,n);if(s==null||typeof s!="object"&&typeof s!="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(s).withLock(async()=>{let l=[];for(let c=1;c<r.args.length;c++)l.push(await this.evalExprAsync(r.args[c],t,n));await this.invokeCallAsync(r.callee,[s,...l],t,e.line,e.column,n,e.file)},n);return}case"ExprStmt":return await this.evalExprAsync(e.expr,t,n);default:return}}async evalExprAsync(e,t,n){switch(e.kind){case"InterpolatedStringExpr":{let r="";for(let i of e.parts)r+=typeof i=="string"?i:te(await this.evalExprAsync(i.expression,t,n),i);return r}case"LiteralExpr":return e.value;case"IdentifierExpr":return t.get(e.name);case"AssignExpr":{let r=await this.evalExprAsync(e.value,t,n);return t.set(e.target,r),r}case"TupleAssignExpr":{let r=await this.evalExprAsync(e.value,t,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 i=0;i<e.targets.length;i++){let s=i<r.length?r[i]:null;t.set(e.targets[i],s)}return r}case"IndexAssignExpr":{let r=await this.evalExprAsync(e.target,t,n),i=await this.evalExprAsync(e.index,t,n),s=await this.evalExprAsync(e.value,t,n);if(Array.isArray(r)||typeof r=="object"&&r!==null)return Array.isArray(r)&&typeof i=="number"&&i<0&&(i=r.length+i),M(r,i,s),s;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,t,n);case"TupleExpr":{let r=[];for(let i of e.elements)r.push(await this.evalExprAsync(i,t,n));return r}case"ArrayExpr":{let r=[];for(let i of e.elements)r.push(await this.evalExprAsync(i,t,n));return r}case"ObjectExpr":{let r={};for(let i of e.properties)M(r,i.key,await this.evalExprAsync(i.value,t,n));return r}case"ParallelExpr":{if(e.tasks.length===0)return[];let r=this.asyncCallDepth.get(n)??0,i=e.tasks.map(async c=>{let m=this.nextTaskId++;return this.asyncCallDepth.set(m,r),await this.evalExprAsync(c,t,m)}),s=await Promise.allSettled(i),o=[],l;for(let c of s)c.status==="fulfilled"?o.push(c.value):l||(l=c.reason);if(l)throw l;return o}case"IndexExpr":{let r=await this.evalExprAsync(e.target,t,n),i=await this.evalExprAsync(e.index,t,n);if(r==null)throw new p("Cannot read property of null or undefined",e.line,e.column,"RUNTIME",e.file);return Array.isArray(r)&&typeof i=="number"&&i<0?r[r.length+i]:I(r,i)}case"UnaryExpr":{let r=await this.evalExprAsync(e.operand,t,n),i=e.operator;if(i==="!")return!this.isTruthy(r);if(i==="-")return-r;throw new p(`Unknown unary operator: ${i}`,e.line,e.column,"RUNTIME",e.file)}case"ConditionalExpr":{let r=await this.evalExprAsync(e.condition,t,n);return this.isTruthy(r)?await this.evalExprAsync(e.trueArm,t,n):await this.evalExprAsync(e.falseArm,t,n)}case"BinaryExpr":{if(e.operator==="&&"){let o=await this.evalExprAsync(e.left,t,n);return this.isTruthy(o)?await this.evalExprAsync(e.right,t,n):o}if(e.operator==="||"){let o=await this.evalExprAsync(e.left,t,n);return this.isTruthy(o)?o:await this.evalExprAsync(e.right,t,n)}let r=await this.evalExprAsync(e.left,t,n),i=await this.evalExprAsync(e.right,t,n),s=e.operator;switch(s){case"+":return typeof r=="string"||typeof i=="string"?String(r)+String(i):r+i;case"-":return r-i;case"*":return r*i;case"/":if(i===0)throw new p("Division by zero",e.line,e.column,"RUNTIME",e.file);return r/i;case"%":return r%i;case"==":return r===i;case"!=":return r!==i;case"<":return r<i;case"<=":return r<=i;case">":return r>i;case">=":return r>=i;default:throw new p(`Unknown binary operator: ${s}`,e.line,e.column,"RUNTIME",e.file)}}case"CallExpr":{let r=[];for(let i of e.args)r.push(await this.evalExprAsync(i,t,n));return await this.invokeCallAsync(e.callee,r,t,e.line,e.column,n,e.file)}}}async invokeCallAsync(e,t,n,r,i,s,o){if(this.userFunctions.has(e)){let l=this.userFunctions.get(e),c=(this.asyncCallDepth.get(s)??0)+1;if(this.asyncCallDepth.set(s,c),c>$)throw this.asyncCallDepth.set(s,c-1),new p(`Execution fuel exhausted: maximum function call depth exceeded (${$})`,r,i,"RUNTIME",o);let m=new C(this.globalEnv,!0);for(let u=0;u<l.params.length;u++)m.define(l.params[u],t[u]);try{for(let u of l.body.statements)await this.execStmtAsync(u,m,s)}catch(u){if(u instanceof O)return u.value;throw u}finally{this.asyncCallDepth.set(s,c-1)}return null}if(this.hostFunctions.has(e)){let l=this.hostFunctions.get(e);try{let c=l.fn(...t);return c instanceof Promise?await c:c}catch(c){throw c instanceof P||c?.name==="LMScriptExit"||c?.isControlFlow?c:new p(`Error in host function '${e}': ${c?.message||String(c)}`,r,i,"RUNTIME",o)}}throw new p(J(e,"Undefined function"),r,i,"RUNTIME",o)}getRecordedErrors(){return[...this.recordedErrors]}},Fe=[{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;"}],Ce=[{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:"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:"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:"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 last non-blank line of a string if it is a valid state word (DONE, NOTHING_TO_DO, BLOCKED, OTHER), otherwise returns null.",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:"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:"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:"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:"capitalize",category:"Strings",signature:"capitalize(s: string): string",description:"Capitalizes the first character of a string.",example:'c = capitalize("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:"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:"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 Unicode code point 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:"Checks if a string, array, or object is empty or null.",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:"shell_quote",category:"Strings",signature:"shell_quote(val: any): string",description:"Quotes string safely for POSIX shell command execution.",example:'escaped = shell_quote("arg with spaces");'},{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, item: 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, item: 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(a: array, b: array): array",description:"Concatenates two 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:"has",category:"Maps & Key-Value",signature:"has(obj: object, key: string): boolean",description:"Checks if an object has the specified key (alias for has_key).",example:'if (has(user, "email")) { ... }'},{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",category:"JSON & Data",signature:"json(str: string): any",description:"Parses a JSON string into an object or array.",example:'data = json("{\\"key\\": \\"value\\"}");'},{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 = 2]): string",description:"Serializes a value to formatted JSON string.",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(command: string|array, [timeoutMs: number = 60000]): SystemResult",description:"Executes a shell command string or argv array directly with shell:false, returning a structured process execution record.",parameters:[{name:"command",type:"string|array",description:"Shell command string or argv array to execute"},{name:"timeoutMs",type:"number",description:"(optional) Execution timeout in milliseconds (default: 60000)"}],returns:{type:"SystemResult",description:"{ stdout: string, stderr: string, code: number|null, signal: string|null, timed_out: bool, duration_ms: number, pid: number|null }"},example:'res = system(["git", "log", "-n", "1"]); 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(...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:"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",category:"System & Process",signature:"sleep(ms: number): void",description:"Pauses execution for specified milliseconds.",example:"sleep(1000);"},{name:"clock",category:"System & Process",signature:"clock(): number",description:"Returns current epoch timestamp in milliseconds.",example:"start = clock();"},{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(clock(), "%Y-%m-%d");'},{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:"type",category:"System & Process",signature:"type(val: any): string",description:"Returns the runtime type of a value ('string', 'number', 'boolean', 'array', 'object', 'null').",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:"urlget",category:"System & Process",signature:"urlget(url: string): string",description:"Performs HTTP(S) GET request and returns response body string.",example:'html = urlget("https://example.com");'}],_e=[{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);"}];function Te(a,e){let t=0;return String(a).replace(/%(-?0?)(\d+)?(?:\.(\d+))?([sdf%])|%/g,(n,r,i,s,o)=>{if(n==="%%")return"%";if(!o||o==="%")throw new Error("sprintf: unsupported or malformed directive");if(t>=e.length)throw new Error("sprintf: missing value for "+n);let l=i===void 0?0:Number(i),c=s===void 0?void 0:Number(s);if(l>1e4||c!==void 0&&c>(o==="f"?100:1e4))throw new Error("sprintf: width or precision exceeds supported limit");let m=e[t++],u;if(o==="s")u=m!==null&&typeof m=="object"?JSON.stringify(m):String(m),c!==void 0&&(u=u.slice(0,c));else{let y=Number(m);if(!Number.isFinite(y))throw new Error("sprintf: numeric directive needs a finite number");if(o==="f")u=c===void 0?String(y):y.toFixed(c);else{let E=Math.trunc(y);u=BigInt(Math.abs(E)).toString().padStart(c??0,"0"),E<0&&(u="-"+u)}}return r.includes("-")?u.padEnd(l," "):o!=="s"&&r.includes("0")&&!(o==="d"&&c!==void 0)?u.startsWith("-")?"-"+u.slice(1).padStart(Math.max(0,l-1),"0"):u.padStart(l,"0"):u.padStart(l," ")})}var U=class a{hostFunctions=new Map;functionDocs=new Map;registeredModules=new Map;functionOriginModule=new Map;currentRegisteringModule="core";outputLogs=[];isAsyncMode=!1;promptHumanConfig={mode:"interactive"};constructor(){this.registeredModules.set("core",{name:"core",description:"LMScript core language built-ins and standard library"}),this.registerPredefinedFunctions(),this.registerDefaultDocs()}registerDefaultDocs(){for(let e of Fe)this.functionDocs.set(e.name,{...e,module:e.module??"core"});for(let e of Ce)this.functionDocs.set(e.name,{...e,module:e.module??"core"});for(let e of _e)this.functionDocs.set(e.name,{...e,module:e.module??"core"})}registerFunctionDoc(e){return this.functionDocs.set(e.name,{...e,module:e.module??this.currentRegisteringModule}),this}registerModule(e,t){if(this.registeredModules.has(e.name))throw new Error(`Module '${e.name}' is already registered`);this.registeredModules.set(e.name,e);let n=this.currentRegisteringModule;this.currentRegisteringModule=e.name;try{if(e.docs)for(let r of e.docs)this.registerFunctionDoc({...r,module:r.module??e.name});typeof e.register=="function"&&e.register(this,t)}finally{this.currentRegisteringModule=n}return this}getModules(){return Array.from(this.registeredModules.values())}getModule(e){return this.registeredModules.get(e)}getFunctionsByModule(e){return Array.from(this.functionDocs.values()).filter(t=>(t.module??"core").toLowerCase()===e.toLowerCase())}getFunctionDocs(){return Array.from(this.functionDocs.values())}getFunctionDoc(e){return this.functionDocs.get(e)}getFunctionCategories(){let e=new Set;for(let t of this.functionDocs.values())e.add(t.category);return Array.from(e)}getFunctionsByCategory(e){return Array.from(this.functionDocs.values()).filter(t=>t.category.toLowerCase()===e.toLowerCase())}registerPredefinedFunctions(){this.registerFunction("read_file",e=>d.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read",e=>d.readFileSync(e,"utf-8"),1,"Reads entire file as UTF-8 string"),this.registerFunction("read_lines",e=>{let t=d.readFileSync(e,"utf-8"),n=t.length>0;return t.endsWith(`\r
153
- `)?t=t.slice(0,-2):t.endsWith(`
154
- `)&&(t=t.slice(0,-1)),n?t.length===0?[""]:t.split(/\r?\n/):[]},1,"Reads file as an array of string lines"),this.registerFunction("write_lines",(e,t)=>{if(!Array.isArray(t))throw new Error("write_lines: second argument must be an array of lines");let n=t.length===0?"":t.map(String).join(`
155
- `)+`
156
- `;return d.writeFileSync(e,n,"utf-8"),!0},2,"Writes an array of lines to a file with trailing newline"),this.registerFunction("glob",e=>{try{return Array.from(d.globSync(e))}catch{return[]}},1,"Finds files matching a glob pattern and returns an array of matching paths"),this.registerFunction("list_dir",e=>{try{return d.readdirSync(k.resolve(String(e)))}catch{return[]}},1,"Lists filenames in a directory"),this.registerFunction("write_file",(e,t)=>(d.writeFileSync(e,String(t),"utf-8"),!0),2,"Writes string content to file"),this.registerFunction("write",(e,t)=>(d.writeFileSync(e,String(t),"utf-8"),!0),2,"Writes string content to file"),this.registerFunction("append_file",(e,t)=>(d.appendFileSync(e,String(t),"utf-8"),!0),2,"Appends string content to file"),this.registerFunction("read_json",e=>{let t=d.readFileSync(e,"utf-8");return JSON.parse(t)},1,"Reads file and parses JSON content"),this.registerFunction("write_json",(e,t,n=2)=>(d.writeFileSync(e,JSON.stringify(t,null,n),"utf-8"),!0),{min:2,max:3},"Serializes data and writes formatted JSON to file"),this.registerFunction("read_csv",(e,t=!0,n=",")=>{let r=d.readFileSync(e,"utf-8");return se(r,t,n)},{min:1,max:3},"Reads CSV file and parses into array of objects or rows"),this.registerFunction("write_csv",(e,t,n=",")=>(d.writeFileSync(e,oe(t,n),"utf-8"),!0),{min:2,max:3},"Writes array of objects or rows to CSV file"),this.registerFunction("csv_parse",se,{min:1,max:3},"Parses inline CSV text into records or rows"),this.registerFunction("csv_stringify",oe,{min:1,max:2},"Serializes records or rows to CSV text");for(let e of["read","read_file","read_lines","read_json","read_csv","glob","list_dir"])this.hostFunctions.get(e).readsFile=!0;this.registerFunction("temp_file",()=>{let e=k.resolve(Se(),`lmscript-${be()}`),t=d.openSync(e,"wx",384);return d.closeSync(t),e},0,"Creates an empty temporary file and returns its absolute path; caller deletes it"),this.registerFunction("file_exists",e=>d.existsSync(e),1,"Checks if file exists"),this.registerFunction("exit",(e=0)=>{throw new P(Number(e))},{min:0,max:1},"Terminates script execution with an optional exit code (default: 0)"),this.registerFunction("delete_file",e=>d.existsSync(e)?(d.unlinkSync(e),!0):!1,1,"Deletes file if it exists"),this.registerFunction("remove_file",e=>d.existsSync(e)?(d.unlinkSync(e),!0):!1,1,"Deletes file if it exists"),this.registerFunction("list",(...e)=>e,void 0,"Creates a new list/array"),this.registerFunction("array",(...e)=>e,void 0,"Creates a new list/array"),this.registerFunction("push",(e,...t)=>(e.push(...t),e.length),void 0,"Pushes item(s) to end of array",!0,!0),this.registerFunction("pop",e=>e.pop(),1,"Pops item from end of array",!0,!0),this.registerFunction("shift",e=>e.shift(),1,"Removes and returns first element",!0,!0),this.registerFunction("unshift",(e,...t)=>(e.unshift(...t),e.length),void 0,"Adds item(s) to front of array",!0,!0),this.registerFunction("insert",(e,t,n)=>{let r=t<0?e.length+t:t;return e.splice(r,0,n),e.length},3,"Inserts item at index",!0,!0),this.registerFunction("remove_at",(e,t)=>{let n=t<0?e.length+t:t,r=e.splice(n,1);return r.length>0?r[0]:null},2,"Removes element at index",!0,!0),this.registerFunction("concat",(e,...t)=>e.concat(...t),void 0,"Concatenates arrays"),this.registerFunction("reverse",e=>Array.isArray(e)?[...e].reverse():e,1,"Returns reversed array"),this.registerFunction("sort",(e,t)=>{if(!Array.isArray(e))return e;let n=[...e];return t?n.sort((r,i)=>{let s=r?r[t]:void 0,o=i?i[t]:void 0;return s<o?-1:s>o?1:0}):n.sort((r,i)=>typeof r=="number"&&typeof i=="number"?r-i:String(r).localeCompare(String(i)))},void 0,"Sorts array numerically, alphabetically, or by object key"),this.registerFunction("unique",e=>Array.isArray(e)?Array.from(new Set(e)):[],1,"Removes duplicate elements"),this.registerFunction("flatten",e=>Array.isArray(e)?e.flat():[],1,"Flattens array one level"),this.registerFunction("first",e=>Array.isArray(e)&&e.length>0?e[0]:null,1,"Returns first element"),this.registerFunction("last",e=>Array.isArray(e)&&e.length>0?e[e.length-1]:null,1,"Returns last element"),this.registerFunction("sum",e=>Array.isArray(e)?e.reduce((t,n)=>t+(typeof n=="number"?n:Number(n)||0),0):0,1,"Calculates sum of array"),this.registerFunction("avg",e=>!Array.isArray(e)||e.length===0?0:e.reduce((n,r)=>n+(typeof r=="number"?r:Number(r)||0),0)/e.length,1,"Calculates average of array"),this.registerFunction("map",()=>({}),0,"Creates a new empty map/hash"),this.registerFunction("hash",()=>({}),0,"Creates a new empty map/hash"),this.registerFunction("from_entries",e=>Array.isArray(e)?Object.fromEntries(e):{},1,"Creates map from [key, value] pairs"),this.registerFunction("clear",e=>{if(Array.isArray(e))return e.length=0,e;if(e&&typeof e=="object"){for(let t of Object.keys(e))delete e[t];return e}return e},1,"Clears array or map",!0,!0),this.registerFunction("size",e=>Array.isArray(e)||typeof e=="string"?e.length:e&&typeof e=="object"?Object.keys(e).length:0,1,"Returns number of elements in array, string, or map"),this.registerFunction("system",(e,t=6e4)=>{if(!Number.isSafeInteger(t)||t<0)throw new Error("system() timeout must be a non-negative safe integer in milliseconds");return this.isAsyncMode?ge(e,t):me(e,t)},{min:1,max:2},"Executes shell command or argv array directly with shell:false and optional timeoutMs (default 60000), returning {stdout, stderr, code, signal, timed_out, duration_ms, pid}",!0),this.registerFunction("run_script",(e,t=[])=>{let n=k.resolve(String(e));if(!d.existsSync(n))throw new Error(`run_script: file not found: '${n}'`);let r=d.readFileSync(n,"utf-8"),i=Array.isArray(t)?t.map(String):[],s=new a;for(let[o,l]of this.hostFunctions)s.hasFunction(o)?l.isDefault||s.registerFunction(o,l.fn,l.arity,{description:l.description,allowOverwrite:!0},!1,l.isContainerMutation):s.registerFunction(o,l.fn,l.arity,l.description,l.isDefault,l.isContainerMutation);if(s.setGlobal("args",[...i]),s.setGlobal("ARGV",[n,...i]),this.isAsyncMode)return(async()=>{let o=await s.runAsync(r,{file:n}),l=o.output.join(`
157
- `)+(o.output.length>0?`
158
- `:""),c=o.exitCode!==void 0?o.exitCode:o.success?0:1,m={success:o.success&&c===0,stdout:l,output:[...o.output],value:o.value,exit_code:c,code:c,errors:o.errors??[]};return m.toString=()=>l,m})();{let o=s.run(r,{file:n}),l=o.output.join(`
159
- `)+(o.output.length>0?`
160
- `:""),c=o.exitCode!==void 0?o.exitCode:o.success?0:1,m={success:o.success&&c===0,stdout:l,output:[...o.output],value:o.value,exit_code:c,code:c,errors:o.errors??[]};return m.toString=()=>l,m}},{min:1,max:2},"Executes another LMScript file in-process and returns execution result with .stdout, .output, .success, .exit_code",!0),this.registerFunction("error",(...e)=>{let t=e.map(n=>typeof n=="object"?JSON.stringify(n):String(n)).join(" ");return typeof process<"u"&&process.stderr?process.stderr.write(`error: ${t}
161
- `):console.error(`error: ${t}`),t},void 0,"Formats and logs an error to stderr and records it for the execution error summary",!0),this.registerFunction("urlget",e=>he(e),1,"Downloads UTF-8 text from a public HTTP(S) URL",!0),this.registerFunction("sleep",e=>{if(typeof e!="number"||!Number.isFinite(e)||e<0)throw new Error("sleep() duration must be a non-negative finite number");if(e>2147483647)throw new Error("sleep() duration exceeds maximum supported timeout (2147483647 ms)");let t=Date.now()+e;for(;Date.now()<t;);return null},1,"Sleeps for the specified milliseconds",!0),this.registerFunction("prompt_human_config",(e,t)=>{if(e===void 0)return{mode:this.promptHumanConfig.mode??"interactive",dir:this.promptHumanConfig.dir??null,timeout_ms:this.promptHumanConfig.timeoutMs??null,poll_interval_ms:this.promptHumanConfig.pollIntervalMs??200};if(typeof e=="string")e==="interactive"?this.promptHumanConfig.mode="interactive":e==="file"?(this.promptHumanConfig.mode="file",t&&(this.promptHumanConfig.dir=String(t))):(this.promptHumanConfig.mode="file",this.promptHumanConfig.dir=e);else if(e&&typeof e=="object"){let n=e.mode?String(e.mode):e.dir?"file":this.promptHumanConfig.mode??"interactive",r=e.dir!==void 0?String(e.dir):this.promptHumanConfig.dir,i=e.timeout_ms!==void 0?Number(e.timeout_ms):e.timeoutMs!==void 0?Number(e.timeoutMs):this.promptHumanConfig.timeoutMs,s=e.poll_ms!==void 0?Number(e.poll_ms):e.pollIntervalMs!==void 0?Number(e.pollIntervalMs):this.promptHumanConfig.pollIntervalMs;this.promptHumanConfig.mode=n==="file"?"file":"interactive",this.promptHumanConfig.dir=r,this.promptHumanConfig.timeoutMs=typeof i=="number"&&Number.isFinite(i)?i:void 0,this.promptHumanConfig.pollIntervalMs=typeof s=="number"&&Number.isFinite(s)&&s>0?s:200}return{mode:this.promptHumanConfig.mode,dir:this.promptHumanConfig.dir??null,timeout_ms:this.promptHumanConfig.timeoutMs??null,poll_interval_ms:this.promptHumanConfig.pollIntervalMs??200}},{min:0,max:2},"Configures prompt_human mode ('interactive' or 'file' with dedicated directory, timeout_ms, poll_ms)",!0),this.registerFunction("prompt_human",(e,t)=>{if((t?.mode??(t?.dir?"file":this.promptHumanConfig.mode??"interactive"))==="file"){let r=t?.dir??this.promptHumanConfig.dir;if(!r)throw new Error("prompt_human: file mode requires a directory (configure via prompt_human_config({ dir }) or pass { dir })");if(!this.isAsyncMode)throw new Error("prompt_human: file mode requires asynchronous execution (runAsync)");return xe(e,{dir:r,sessionId:t?.sessionId??t?.sessionid??t?.id,timeoutMs:t?.timeout_ms??t?.timeoutMs??this.promptHumanConfig.timeoutMs,pollIntervalMs:t?.poll_ms??t?.pollIntervalMs??this.promptHumanConfig.pollIntervalMs})}return this.isAsyncMode?Ee(e):ye(e)},{min:0,max:2},"Prompts operator on stdin/terminal or dedicated directory, returning input string or null if closed/non-interactive",!0),this.registerFunction("json",(e,t)=>{if(typeof e=="string")try{return JSON.parse(e)}catch(n){throw new Error(`Invalid JSON string: ${n.message}`)}return JSON.stringify(e,null,t)},{min:1,max:2},"Parses JSON string into object/array, or stringifies data to JSON string"),this.registerFunction("json_parse",e=>{try{return JSON.parse(String(e))}catch(t){throw new Error(`JSON parse error: ${t.message}`)}},1,"Parses JSON string into object/array"),this.registerFunction("json_parse_safe",(e,t=null)=>ve(e,t),{min:1,max:2},"Safely parses JSON string with preamble/fence recovery, returning fallback (default null) on failure without throwing",!0),this.registerFunction("json_stringify",(e,t)=>JSON.stringify(e,null,t),{min:1,max:2},"Serializes value into JSON string"),this.registerFunction("keys",e=>e&&typeof e=="object"?Object.keys(e):[],1,"Returns array of object keys"),this.registerFunction("values",e=>e&&typeof e=="object"?Object.values(e):[],1,"Returns array of object values"),this.registerFunction("entries",e=>e&&typeof e=="object"?Object.entries(e):[],1,"Returns array of [key, value] pairs"),this.registerFunction("has_key",(e,t)=>e&&typeof e=="object"?Object.hasOwn(e,t):!1,2,"Checks if object has key"),this.registerFunction("has",(e,t)=>e&&typeof e=="object"?Object.hasOwn(e,t):!1,2,"Checks if object has key"),this.registerFunction("get",(e,t,n=null)=>{if(e==null)return n;let r=Array.isArray(t)?t:String(t).replace(/\[(\w+)\]/g,".$1").split(".").filter(Boolean),i=e;for(let s of r){if(i==null||typeof i!="object")return n;i=I(i,s)}return i!==void 0?i:n},void 0,"Safely extracts nested property by path (e.g. 'user.address.city')"),this.registerFunction("set",(e,t,n)=>{if(e==null||typeof e!="object")return e;let r=Array.isArray(t)?t:String(t).replace(/\[(\w+)\]/g,".$1").split(".").filter(Boolean),i=e;for(let s=0;s<r.length-1;s++){let o=r[s];(I(i,o)==null||typeof I(i,o)!="object")&&M(i,o,{}),i=I(i,o)}return r.length>0&&M(i,r[r.length-1],n),e},3,"Sets nested property by path",!0,!0),this.registerFunction("pluck",(e,t)=>Array.isArray(e)?e.map(n=>I(n,t)):[],2,"Extracts key from array of objects"),this.registerFunction("filter_by",(e,t,n)=>Array.isArray(e)?e.filter(r=>r!=null&&I(r,t)===n):[],3,"Filters array of objects where item[key] == value"),this.registerFunction("find_by",(e,t,n)=>{if(!Array.isArray(e))return null;let r=e.find(i=>i!=null&&I(i,t)===n);return r!==void 0?r:null},3,"Finds first object in array where item[key] == value"),this.registerFunction("merge",(e,t)=>({...e,...t}),2,"Shallow merges two objects"),this.registerFunction("clone",e=>e==null||typeof e!="object"?e:JSON.parse(JSON.stringify(e)),1,"Deep clones an object or array"),this.registerFunction("delete_key",(e,t)=>(e&&typeof e=="object"&&delete e[t],e),2,"Deletes key from object",!0,!0),this.registerFunction("print",(...e)=>{let t=e.map(n=>typeof n=="object"?JSON.stringify(n):String(n)).join(" ");return this.outputLogs.push(t),t},void 0,"Prints formatted values to output log",!0),this.registerFunction("println",(...e)=>{let t=e.map(n=>typeof n=="object"?JSON.stringify(n):String(n)).join(" ");return this.outputLogs.push(t),t},void 0,"Prints line to output log",!0),this.registerFunction("split",(e,t)=>String(e).split(t),2,"Splits string by required delimiter; use explicit empty delimiter for characters"),this.registerFunction("lines",e=>String(e).split(/\r?\n/),1,"Splits string into array of lines"),this.registerFunction("last_line_as_status",e=>{if(typeof e!="string")return null;let t=e.split(/\r?\n/);for(let n=t.length-1;n>=0;n--){let r=t[n].trim();if(r.length>0)return r==="DONE"||r==="NOTHING_TO_DO"||r==="BLOCKED"||r==="OTHER"?r:null}return null},1,"Returns the last non-blank line of a string if it is a valid state word (DONE, NOTHING_TO_DO, BLOCKED, OTHER), else null"),this.registerFunction("words",e=>String(e).trim().split(/\s+/).filter(Boolean),1,"Splits string into words"),this.registerFunction("join",(e,t=", ")=>Array.isArray(e)?e.join(t):String(e),void 0,"Joins array into string"),this.registerFunction("trim",e=>String(e).trim(),1,"Trims whitespace from both ends"),this.registerFunction("trim_start",e=>String(e).trimStart(),1,"Trims leading whitespace"),this.registerFunction("trim_end",e=>String(e).trimEnd(),1,"Trims trailing whitespace"),this.registerFunction("to_upper",e=>String(e).toUpperCase(),1,"Converts string to uppercase"),this.registerFunction("upper",e=>String(e).toUpperCase(),1,"Converts string to uppercase"),this.registerFunction("to_lower",e=>String(e).toLowerCase(),1,"Converts string to lowercase"),this.registerFunction("lower",e=>String(e).toLowerCase(),1,"Converts string to lowercase"),this.registerFunction("capitalize",e=>{let t=String(e);return t.length===0?"":t.charAt(0).toUpperCase()+t.slice(1)},1,"Capitalizes first letter"),this.registerFunction("title_case",e=>String(e).replace(/\b\w/g,t=>t.toUpperCase()),1,"Converts string to Title Case"),this.registerFunction("contains",(e,t)=>Array.isArray(e)?e.includes(t):String(e).includes(String(t)),2,"Checks if string or array contains item"),this.registerFunction("includes",(e,t)=>Array.isArray(e)?e.includes(t):String(e).includes(String(t)),2,"Checks if string or array contains item"),this.registerFunction("starts_with",(e,t)=>String(e).startsWith(t),2,"Checks if string starts with prefix"),this.registerFunction("ends_with",(e,t)=>String(e).endsWith(t),2,"Checks if string ends with suffix"),this.registerFunction("index_of",(e,t,n)=>Array.isArray(e)?e.indexOf(t,n):String(e).indexOf(t,n),{min:2,max:3},"Finds substring or strictly equal array element index; -1 if absent"),this.registerFunction("last_index_of",(e,t)=>Array.isArray(e)?e.lastIndexOf(t):String(e).lastIndexOf(t),2,"Finds last substring or strictly equal array element index; -1 if absent"),this.registerFunction("count_matches",(e,t)=>t?String(e).split(t).length-1:0,2,"Counts occurrences of substring"),this.registerFunction("substr",(e,t,n)=>{let r=String(e),i=Math.trunc(Number(t))||0,s=i<0?Math.max(0,r.length+i):Math.min(r.length,i);if(n===void 0)return r.slice(s);let o=Math.max(0,Math.trunc(Number(n))||0);return r.slice(s,s+o)},{min:2,max:3},"Returns substring by end-relative start and optional length"),this.registerFunction("substring",(e,t,n)=>String(e).substring(t,n),void 0,"Returns substring between indices"),this.registerFunction("slice",(e,t,n)=>e!=null?e.slice(t,n):"",void 0,"Slices string or array"),this.registerFunction("char_at",(e,t)=>String(e).charAt(t),2,"Returns character at index"),this.registerFunction("char_code",(e,t=0)=>String(e).charCodeAt(t),void 0,"Returns character code at index"),this.registerFunction("from_char_code",(...e)=>String.fromCharCode(...e),void 0,"Returns string from character codes"),this.registerFunction("replace",(e,t,n)=>String(e).replace(t,n),3,"Replaces first occurrence"),this.registerFunction("replace_all",(e,t,n)=>String(e).replaceAll(t,n),3,"Replaces all occurrences"),this.registerFunction("repeat",(e,t)=>String(e).repeat(t),2,"Repeats string count times"),this.registerFunction("pad_start",(e,t,n=" ")=>String(e).padStart(t,n),void 0,"Left-pads string"),this.registerFunction("pad_end",(e,t,n=" ")=>String(e).padEnd(t,n),void 0,"Right-pads string"),this.registerFunction("reverse_str",e=>String(e).split("").reverse().join(""),1,"Reverses string"),this.registerFunction("is_empty",e=>e==null?!0:typeof e=="string"?e.trim().length===0:Array.isArray(e)?e.length===0:typeof e=="object"?Object.keys(e).length===0:!1,1,"Checks if string, array, or map is empty"),this.registerFunction("is_digit",e=>/^\d+$/.test(String(e)),1,"Checks if string contains only digits"),this.registerFunction("is_alpha",e=>/^[a-zA-Z]+$/.test(String(e)),1,"Checks if string contains only letters"),this.registerFunction("is_alnum",e=>/^[a-zA-Z0-9]+$/.test(String(e)),1,"Checks if string contains only letters and digits"),this.registerFunction("shell_quote",e=>fe(e),1,"Quotes string safely for POSIX shell command execution",!0),this.registerFunction("sprintf",(e,...t)=>Te(e,t),{min:1},"Formats %s/%d/%f/%% with width and precision"),this.registerFunction("format",(e,...t)=>{let n=String(e),r=t.length===1&&typeof t[0]=="object"&&t[0]!==null&&!Array.isArray(t[0])?t[0]:void 0,i=0,s="",o=l=>typeof l=="object"&&l!==null?JSON.stringify(l):String(l);for(let l=0;l<n.length;){let c=n[l];if(c==="{"&&n[l+1]==="{"){s+="{",l+=2;continue}if(c==="}"&&n[l+1]==="}"){s+="}",l+=2;continue}if(c!=="{"){s+=c,l+=1;continue}let m=n.indexOf("}",l+1);if(m<0){s+=c,l+=1;continue}let u=n.slice(l+1,m);if(u==="")s+=i<t.length?o(t[i++]):"{}";else if(/^\d+$/.test(u)){let y=Number(u);s+=y<t.length?o(t[y]):`{${u}}`}else r&&/^[a-zA-Z0-9_]+$/.test(u)&&Object.hasOwn(r,u)?s+=o(r[u]):s+=`{${u}}`;l=m+1}return s},void 0,"Formats string with arguments, supporting {{ and }} brace escapes, positional {0}, auto {}, and {key} map substitution"),this.registerFunction("len",e=>typeof e=="string"||Array.isArray(e)?e.length:e&&typeof e=="object"?Object.keys(e).length:0,1,"Returns length of string, array, or object"),this.registerFunction("range",(e,t,n=1)=>{let r=t===void 0?0:e,i=t===void 0?e:t,s=[];if(n>0)for(let o=r;o<i;o+=n)s.push(o);else if(n<0)for(let o=r;o>i;o+=n)s.push(o);return s},void 0,"Generates an array of numbers"),this.registerFunction("abs",e=>Math.abs(e),1,"Absolute value"),this.registerFunction("min",(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e;return Math.min(...t)},void 0,"Minimum value"),this.registerFunction("max",(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e;return Math.max(...t)},void 0,"Maximum value"),this.registerFunction("floor",e=>Math.floor(e),1,"Floor value"),this.registerFunction("ceil",e=>Math.ceil(e),1,"Ceil value"),this.registerFunction("round",e=>Math.round(e),1,"Round value"),this.registerFunction("sqrt",e=>Math.sqrt(e),1,"Square root"),this.registerFunction("pow",(e,t)=>Math.pow(e,t),2,"Power calculation"),this.registerFunction("random",()=>Math.random(),0,"Random float between 0 and 1"),this.registerFunction("clock",()=>Date.now(),0,"Returns current epoch in ms"),this.registerFunction("strftime",(e,t)=>{if(typeof e!="number"||!Number.isFinite(e)||typeof t!="string")throw new Error("strftime: expected epoch milliseconds first and format string second");let n=new Date(e);if(!Number.isFinite(n.getTime()))throw new Error("strftime: invalid epoch milliseconds");let r=s=>String(s).padStart(2,"0"),i={"%Y":String(n.getFullYear()),"%m":r(n.getMonth()+1),"%d":r(n.getDate()),"%H":r(n.getHours()),"%M":r(n.getMinutes()),"%S":r(n.getSeconds()),"%%":"%"};return t.replace(/%[YmdHMS%]/g,s=>i[s])},2,"Formats local time: epoch milliseconds first, format string second"),this.registerFunction("str",e=>{if(e!==null&&typeof e=="object"){let t=Object.getPrototypeOf(e);if(Array.isArray(e)||t===Object.prototype||t===null)return te(e)}return e===null?"null":String(e)},1,"Converts lists and maps to compact JSON; scalars to normal text"),this.registerFunction("num",e=>Number(e),1,"Converts value to number"),this.registerFunction("type",e=>e===null?"null":Array.isArray(e)?"array":typeof e,1,"Returns runtime type of value"),this.registerFunction("assert",(e,t="Assertion failed")=>{if(!e)throw new Error(t);return!0},void 0,"Throws error if condition is falsy")}registerFunction(e,t,n,r,i=!1,s=!1){let o=typeof r=="string"?r:r?.description,l=typeof r=="object"?!!r.isDefault:i,c=typeof r=="object"?!!r.isContainerMutation:s,m=typeof r=="object"?r.doc:void 0,u=typeof r=="object"?!!r.allowOverwrite:!1,y=typeof r=="object"&&r.module?r.module:this.currentRegisteringModule,E=this.functionOriginModule.get(e);if(E&&E!==y&&!u)throw new Error(`Cannot register function '${e}' from module '${y}': already registered by module '${E}'`);return this.functionOriginModule.set(e,y),this.hostFunctions.set(e,{fn:t,arity:n,description:o,isDefault:l,isContainerMutation:c,doc:m}),m&&this.functionDocs.set(e,{...m,module:m.module??y}),this}getFunctionOriginModule(e){return this.functionOriginModule.get(e)}initialGlobals=new Map;setGlobal(e,t){return this.initialGlobals.set(e,t),this}getGlobal(e){return this.initialGlobals.get(e)}scanAndCheck(e,t={}){try{let{program:n,diagnostics:r}=Re(e,t),i=[...this.initialGlobals.keys(),...t.globals||[]],s=new ee(this.hostFunctions,{...t,globals:i}),o=[...r,...s.check(n)];return{ast:n,diagnostics:o,hasConcurrency:s.hasConcurrency}}catch(n){return n instanceof p?{ast:null,diagnostics:[{message:n.message,line:n.line,column:n.column,severity:"error",file:n.file||t.file}],hasConcurrency:!1}:{ast:null,diagnostics:[{message:n instanceof Error?n.message:String(n),line:1,column:1,severity:"error",file:t.file}],hasConcurrency:!1}}}run(e,t={}){let n=[],{ast:r,diagnostics:i,hasConcurrency:s}=this.scanAndCheck(e,t);if(i.filter(c=>c.severity==="error").length>0||!r)return this.outputLogs=n,{success:!1,diagnostics:i,output:n};if(s)return this.outputLogs=n,{success:!1,diagnostics:[...i,{message:"Concurrency constructs ('parallel', 'sync') require asynchronous execution via engine.runAsync()",line:1,column:1,severity:"error",file:t.file}],output:n};let l;try{l=new K(this.hostFunctions,u=>n.push(u),!1,this.initialGlobals,t.stderr,this.promptHumanConfig);let c=l.evaluateProgram(r);this.outputLogs=[...n];let m=l.getRecordedErrors();return this.lastRecordedErrors=m,{success:!0,value:c,diagnostics:i,output:n,errors:m}}catch(c){let m=l?l.getRecordedErrors():[];if(this.lastRecordedErrors=m,c instanceof P||c?.name==="LMScriptExit"||c?.isControlFlow){this.outputLogs=[...n];let x=typeof c.exitCode=="number"?c.exitCode:0;return{success:x===0,value:x,exitCode:x,diagnostics:i,output:n,errors:m}}let u=c instanceof p?c.line:1,y=c instanceof p?c.column:1,E=c instanceof p&&c.file||t.file;return this.outputLogs=[...n],{success:!1,diagnostics:[...i,{message:c?.message||String(c),line:u,column:y,severity:"error",file:E}],output:n,errors:m}}}async runAsync(e,t={}){let n=[],{ast:r,diagnostics:i}=this.scanAndCheck(e,t);if(i.filter(l=>l.severity==="error").length>0||!r)return this.outputLogs=n,this.lastRecordedErrors=[],{success:!1,diagnostics:i,output:n,errors:[]};let o;try{o=new K(this.hostFunctions,m=>n.push(m),!0,this.initialGlobals,t.stderr,this.promptHumanConfig);let l=await o.evaluateProgramAsync(r);this.outputLogs=[...n];let c=o.getRecordedErrors();return this.lastRecordedErrors=c,{success:!0,value:l,diagnostics:i,output:n,errors:c}}catch(l){let c=o?o.getRecordedErrors():[];if(this.lastRecordedErrors=c,l instanceof P||l?.name==="LMScriptExit"||l?.isControlFlow){this.outputLogs=[...n];let E=typeof l.exitCode=="number"?l.exitCode:0;return{success:E===0,value:E,exitCode:E,diagnostics:i,output:n,errors:c}}let m=l instanceof p?l.line:1,u=l instanceof p?l.column:1,y=l instanceof p&&l.file||t.file;return this.outputLogs=[...n],{success:!1,diagnostics:[...i,{message:l?.message||String(l),line:m,column:u,severity:"error",file:y}],output:n,errors:c}}}lastRecordedErrors=[];getRecordedErrors(){return[...this.lastRecordedErrors]}hasFunction(e){return this.hostFunctions.has(e)}getRegisteredFunctions(){return Array.from(this.hostFunctions.keys())}};async function Ne(){console.log("================================================="),console.log(" LMScript Verification & Full Feature Test Suite "),console.log(`=================================================
162
- `);let a=new U,e=!0;console.log("Test Suite 1: Functions, Recursion, and Control Flow");let n=a.run(`
163
- fn factorial(n) {
164
- if (n <= 1) {
165
- return 1;
166
- }
167
- return n * factorial(n - 1);
168
- }
169
-
170
- let fact5 = factorial(5);
171
- print("factorial(5) =", fact5);
172
- assert(fact5 == 120, "factorial(5) must be 120");
173
-
174
- let sumVal = 0;
175
- for (let i = 1; i <= 5; i = i + 1) {
176
- if (i == 3) {
177
- continue;
178
- }
179
- sumVal = sumVal + i;
180
- }
181
- print("sum skipping 3 =", sumVal);
182
- assert(sumVal == 12, "sum must be 12");
183
- `);n.success?(console.log(n.output.map(f=>" [out] "+f).join(`
184
- `)),console.log(` -> Passed!
185
- `)):(console.error(" -> Failed:",n.diagnostics),e=!1),console.log("Test Suite 2: TS Predefined Builtins & Host Registration"),a.registerFunction("base64Encode",f=>Buffer.from(f).toString("base64"),1,"Base64 encodes a string"),a.registerFunction("addVectors",(f,g)=>f.map((b,R)=>b+(g[R]||0)),2,"Adds two numeric arrays element-wise");let i=a.run(`
186
- let text = "TypeScript Engine";
187
- let encoded = base64Encode(text);
188
- print("Encoded base64:", encoded);
189
-
190
- let v1 = [10, 20, 30];
191
- let v2 = [1, 2, 3];
192
- let vSum = addVectors(v1, v2);
193
- print("Vector sum:", vSum);
194
-
195
- push(vSum, 99);
196
- print("vSum after push:", vSum, "length:", len(vSum));
197
-
198
- print("sqrt(16) =", sqrt(16));
199
- print("min(5, 2, 9) =", min(5, 2, 9));
200
- `);i.success?(console.log(i.output.map(f=>" [out] "+f).join(`
201
- `)),console.log(` -> Passed!
202
- `)):(console.error(" -> Failed:",i.diagnostics),e=!1),console.log("Test Suite 3: Static Analysis Validation (Zero Execution on Error)");let s=`
203
- let x = 10;
204
- let x = 20; // ERROR 1: Duplicate variable declaration
205
-
206
- fn testReturn() {
207
- // ok
208
- }
209
- return 42; // ERROR 2: return outside function
210
-
211
- while (x > 0) {
212
- // ok
213
- }
214
- continue; // ERROR 3: continue outside loop
215
-
216
- undefinedFunctionCall(); // ERROR 4: undefined function
217
- base64Encode("hello", "extra_arg"); // ERROR 5: arity mismatch
218
- `,o=a.run(s);console.log(" Executed successfully?",o.success),console.log(" Formatted visual diagnostics caught BEFORE execution:");for(let f of o.diagnostics)console.log(" "+pe(f,s).split(`
219
- `).join(`
220
- `));!o.success&&o.diagnostics.length===5?console.log(` -> Passed! (All 5 static errors caught upfront with visual carets)
221
- `):(console.error(" -> Failed! Expected 5 diagnostics, got",o.diagnostics.length),e=!1),console.log("Test Suite 4: Forward Function Declarations & Mutual Recursion");let c=a.run(`
222
- print("even(6):", even(6));
223
- print("odd(6):", odd(6));
224
-
225
- fn even(n) {
226
- if (n == 0) { return true; }
227
- return odd(n - 1);
228
- }
229
-
230
- fn odd(n) {
231
- if (n == 0) { return false; }
232
- return even(n - 1);
233
- }
234
- `);c.success?(console.log(c.output.map(f=>" [out] "+f).join(`
235
- `)),console.log(` -> Passed!
236
- `)):(console.error(" -> Failed:",c.diagnostics),e=!1),console.log("Test Suite 5: Perl-style system() & String Operations");let u=a.run(`
237
- res = system("ls -ltr");
238
- out = res.stdout;
239
- err = res.stderr;
240
- print("Command executed. stdout length:", len(out), "stderr length:", len(err));
241
-
242
- let outLines = lines(out);
243
- print("STDOUT lines count:", len(outLines));
244
- print("First line:", outLines[0]);
245
-
246
- let sample = " apple, banana, cherry, date ";
247
- let cleaned = trim(sample);
248
- print("Trimmed:", cleaned);
249
- print("Upper:", to_upper(cleaned));
250
- print("Contains 'banana':", contains(cleaned, "banana"));
251
-
252
- let fruits = split(cleaned, ", ");
253
- print("Split fruits array:", fruits);
254
- print("Joined fruits:", join(fruits, " | "));
255
- print("Title Case:", title_case("hello world of scripts"));
256
- `);u.success?(console.log(u.output.map(f=>" [out] "+f).join(`
257
- `)),console.log(` -> Passed!
258
- `)):(console.error(" -> Failed:",u.diagnostics),e=!1),console.log("Test Suite 6: JSON Parsing & Object Primitive Methods");let E=a.run(`
259
- res = system("echo '{\\"status\\": \\"ok\\", \\"code\\": 200, \\"users\\": [{\\"id\\": 1, \\"name\\": \\"Alice\\", \\"active\\": true}, {\\"id\\": 2, \\"name\\": \\"Bob\\", \\"active\\": false}], \\"server\\": {\\"host\\": \\"localhost\\", \\"port\\": 8080}}'");
260
-
261
- data = json(res.stdout);
262
-
263
- print("Extracted status:", data.status);
264
- print("Extracted code:", data.code);
265
- print("Extracted server.host:", data.server.host);
266
- print("Extracted server.port:", data.server.port);
267
- print("First user name:", data.users[0].name);
268
-
269
- print("Object keys(data):", keys(data));
270
- print("Object keys(data.server):", keys(data.server));
271
- print("Object values(data.server):", values(data.server));
272
- print("has_key(data, 'server'):", has_key(data, "server"));
273
- print("has_key(data, 'database'):", has_key(data, "database"));
274
-
275
- print("Deep get host:", get(data, "server.host"));
276
- print("Deep get fallback:", get(data, "server.ssl", false));
277
-
278
- let userNames = pluck(data.users, "name");
279
- print("Plucked names:", userNames);
280
-
281
- let activeUsers = filter_by(data.users, "active", true);
282
- print("Active users count:", len(activeUsers), "Name:", activeUsers[0].name);
283
-
284
- let bob = find_by(data.users, "name", "Bob");
285
- print("Found Bob ID:", bob.id);
286
-
287
- data.server.port = 9000;
288
- let serialized = json(data);
289
- print("Re-serialized JSON length:", len(serialized));
290
-
291
- let localConfig = {
292
- app: "LMScript",
293
- version: 1.0,
294
- tags: ["json", "compiler"]
295
- };
296
- print("Local config dot access:", localConfig.app, "tags:", localConfig.tags[0]);
297
- `);E.success?(console.log(E.output.map(f=>" [out] "+f).join(`
298
- `)),console.log(` -> Passed!
299
- `)):(console.error(" -> Failed:",E.diagnostics),e=!1),console.log("Test Suite 7: File I/O & Advanced Data Structures");let w=a.run(`
300
- // 1. Raw file write and read
301
- let tmpFile = "scratch_test.txt";
302
- write_file(tmpFile, "line 1\\nline 2\\nline 3");
303
- print("File exists?", file_exists(tmpFile));
304
- print("Read content:\\n" + read_file(tmpFile));
305
- let fileLines = read_lines(tmpFile);
306
- print("Read lines count:", len(fileLines));
307
- assert(fileLines[1] == "line 2", "Second line must be 'line 2'");
308
-
309
- // 2. JSON file write and read
310
- let jsonFile = "scratch_test.json";
311
- let originalData = { title: "Report", count: 42, tags: ["ts", "script"] };
312
- write_json(jsonFile, originalData);
313
- let loadedJson = read_json(jsonFile);
314
- print("Loaded JSON title:", loadedJson.title, "count:", loadedJson.count);
315
- assert(loadedJson.count == 42, "JSON count must match 42");
316
-
317
- // 3. CSV file write and read
318
- let csvFile = "scratch_test.csv";
319
- let usersList = [
320
- { name: "Alice", age: 30, city: "New York" },
321
- { name: "Bob", age: 25, city: "San Francisco" },
322
- { name: "Charlie", age: 35, city: "Chicago" }
323
- ];
324
- write_csv(csvFile, usersList);
325
- let parsedCsv = read_csv(csvFile);
326
- print("Parsed CSV rows count:", len(parsedCsv));
327
- print("Parsed CSV row 0:", parsedCsv[0].name, "age:", parsedCsv[0].age, "city:", parsedCsv[0].city);
328
- assert(parsedCsv[0].age == 30, "Alice age must be coerced to numeric 30");
329
-
330
- // Clean up temporary files
331
- delete_file(tmpFile);
332
- delete_file(jsonFile);
333
- delete_file(csvFile);
334
-
335
- // 4. List / Array data structures
336
- let numbers = [5, 2, 8, 1, 9];
337
- push(numbers, 3);
338
- print("After push:", numbers);
339
- let popped = pop(numbers);
340
- print("Popped:", popped);
341
- shift(numbers); // removes 5
342
- unshift(numbers, 10); // adds 10 to front
343
- print("After shift/unshift:", numbers);
344
- print("Sorted numbers:", sort(numbers));
345
- print("Reversed numbers:", reverse(numbers));
346
- print("First:", first(numbers), "Last:", last(numbers), "Negative index [-1]:", numbers[-1]);
347
- print("Sum:", sum(numbers), "Avg:", avg(numbers));
348
- print("Unique [1,1,2,3,3]:", unique([1, 1, 2, 3, 3]));
349
-
350
- // 5. Hash / Map data structures
351
- let userMap = map();
352
- userMap.name = "Diana";
353
- userMap["department"] = "Engineering";
354
- set(userMap, "contact.email", "diana@example.com");
355
- print("User map name:", userMap.name);
356
- print("User map contact email:", get(userMap, "contact.email"));
357
- print("User map keys:", keys(userMap));
358
- print("Has department?", has_key(userMap, "department"));
359
- delete_key(userMap, "department");
360
- print("After delete_key has department?", has_key(userMap, "department"));
361
- `);w.success?(console.log(w.output.map(f=>" [out] "+f).join(`
362
- `)),console.log(` -> Passed!
363
- `)):(console.error(" -> Failed:",w.diagnostics),e=!1),console.log("Test Suite 8: Concurrency & Synchronized State Access");let h=await a.runAsync(`
364
- let counter = 0;
365
- let list = [];
366
- let state = map();
367
-
368
- fn worker(id, val) {
369
- sleep(10);
370
- sync counter = counter + 1;
371
- sync push(list, val);
372
- sync state[id] = val;
373
- return id;
374
- }
375
-
376
- (res1, res2, res3) = parallel([worker("a", 100), worker("b", 200), worker("c", 300)]);
377
- print("Parallel results:", res1, res2, res3);
378
- print("Final counter:", counter);
379
- print("List size:", len(list));
380
- print("State keys:", keys(state));
381
-
382
- assert(counter == 3, "counter must be 3");
383
- assert(len(list) == 3, "list length must be 3");
384
- assert(state.a == 100, "state.a must be 100");
385
- assert(res1 == "a" && res2 == "b" && res3 == "c", "parallel results must match return values");
386
- `);return h.success?(console.log(h.output.map(f=>" [out] "+f).join(`
387
- `)),console.log(` -> Passed!
388
- `)):(console.error(" -> Failed:",h.diagnostics),e=!1),e}function Ie(){try{let a=k.dirname(re(import.meta.url));for(let e of["package.json","../package.json"]){let t=k.resolve(a,e);if(d.existsSync(t))return JSON.parse(d.readFileSync(t,"utf8")).version??"unknown"}}catch{}return"unknown"}async function Le(){let a=process.argv.slice(2);if(a.length===0||a.length===1&&a[0]==="--test"){await Ne()||(process.exitCode=1);return}let e="Usage: lmscript [--check|--dry-run|--lint] [--check-files] <file> | [check options] -e <source> | --test | --help | --version";if(a.length===1&&(a[0]==="--help"||a[0]==="-h")){console.log(e);return}if(a.length===1&&(a[0]==="--version"||a[0]==="-v")){console.log(`lmscript ${Ie()}`);return}let t=!1,n=!1;for(;["--check","--dry-run","--lint","--check-files"].includes(a[0]);)t=!0,a.shift()==="--check-files"&&(n=!0);let r=a[0]==="-e";if(r?a.length<2:a.length===0||a[0].startsWith("-")){console.error(e),process.exitCode=1;return}try{let i=a.shift(),s=r?void 0:k.resolve(i),o=r?a.shift():d.readFileSync(s,"utf-8");a[0]==="--"&&a.shift();let l=[...a],c=new U;c.setGlobal("args",l),c.setGlobal("ARGV",[i,...l]);let m=t?c.scanAndCheck(o,{checkFiles:n,file:s}):await c.runAsync(o,{file:s});if("output"in m)for(let u of m.output)console.log(u);for(let u of m.diagnostics)console.error(pe(u,o));m.diagnostics.some(u=>u.severity==="error")&&(process.exitCode=1)}catch(i){console.error(`Execution failed: ${i instanceof Error?i.message:String(i)}`),process.exitCode=1}}var W=k.basename(re(import.meta.url));(W==="lmscript.ts"||W==="lmscript.js"||W==="lmscript")&&process.argv[1]&&d.existsSync(process.argv[1])&&d.realpathSync(re(import.meta.url))===d.realpathSync(k.resolve(process.argv[1]))&&Le();export{V as AsyncLock,ne as AsyncLockManager,Ce as BUILTIN_FUNCTION_DOCS,T as BreakSignal,N as ContinueSignal,C as Environment,K as Interpreter,Fe as LANGUAGE_DOCS,U as LMScript,p as LMScriptError,P as LMScriptExit,D as Lexer,B as Parser,O as ReturnSignal,_e as STDLIB_FUNCTION_DOCS,ke as STDLIB_SOURCE,ee as StaticChecker,Y as attachSourceFile,Re as compileProgram,z as createSystemResult,pe as formatDiagnostic,Ae as getStdlibProgram,Le as main,se as parseCsv,Ee as promptHumanAsync,xe as promptHumanFileAsync,ye as promptHumanSync,Ne as runDemoSuite,ve as safeParseJson,fe as shellQuote,oe as stringifyCsv,me as systemSync};