@lmctl-ai/lmctl 0.2.62 → 0.2.63

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/CHANGELOG.md CHANGED
@@ -4,6 +4,9 @@ All notable public-preview changes for `@lmctl-ai/lmctl` are recorded here.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ - **Breaking: explicit properties replace implicit profile globals.** init.toml keeps its name and stores lmctl properties. Provider1..3 become PROPS.Provider1..3.Provider; Model1/2/3 become PROPS.Provider1/2/3.Model1. Directory/NonInteractive remain invocation facts. PROPS is a strict read-only hierarchical map, with dotted-key indexing; get_property/has_property/get_properties/set_property use plain values and run-local copies/overlays. Checks are profile-free with known-key suggestions; reads load the profile lazily. Nested ARGV now contains only the child arguments, matching top-level ARGV (no filename). Bare variables, ARGV, PROPS and env() are separate access forms; f-string expressions stay general.
8
+
9
+
7
10
  - **Workspace interpreter containment.** Script routes use only the declared monorepo sibling and report a missing build instead of silently running a retired checkout. Fresh clones bootstrap with `npm ci --ignore-scripts && npm run build` at the root; the ordered build now smoke-tests the script route.
8
11
 
9
12
  - **Gate fixes: script ABI restored.** lm_members and lm_session_list return plain arrays; lm_member returns a map-or-null; prompt reads return arrays; batch open/close use managed handles/booleans. Seed/lint/turn results retain legacy projections and snake-case prompt IDs. Neutral API envelopes remain internal, and operational failures name the script call.
package/README.md CHANGED
@@ -131,3 +131,7 @@ LMCTL_DB="$test_root/state.db" MINIPLAYER_HOME="$test_root/miniplayer" \
131
131
  `LMCTL_DB` overrides lmctl's default SQLite database; an explicit `--db PATH`
132
132
  takes precedence. The integration tests also isolate `LMCTL_HOME` and native
133
133
  provider storage. Mock responses need no keys or network access.
134
+
135
+ ### lmctl properties (init.toml)
136
+
137
+ `~/.lmctl/init.toml` (or `$LMCTL_HOME/init.toml`) is lmctl's properties file, not the process environment. Managed TOML keys include `Provider1.provider` and `Provider1.model1`; top-level user keys such as `Env1` are supported. Scripts use `PROPS.Provider1.Provider`, `PROPS.Provider1.Model1` or `PROPS["Provider1.Model1"]`. The source repository documents the complete property contract. The six old bare provider/model globals are removed. `--check` uses declared keys without a profile or DB; a file-backed runtime read needs a valid profile and reports its path plus `lmctl init` guidance. `Directory` and `NonInteractive` remain core invocation facts.
package/build-info.json CHANGED
@@ -1 +1 @@
1
- {"sha": "6e03bfed77531f0ef364327eca2dc701299e0e0e", "dirty": true, "builtAt": "2026-10-05T05:09:05.000Z"}
1
+ {"sha": "73bf5b850295a40b8dd26f20f3488cc3e637c7a5", "dirty": true, "builtAt": "2026-10-05T06:39:45.000Z"}
package/dist/cli/index.js CHANGED
@@ -1755,13 +1755,14 @@ ${o}`,r),this.line=n,this.column=s,this.codeblock=o}static x(e,r,n){throw new t(
1755
1755
  `;)r++;continue}let s=r;if(n==='"'||n==="'"){let o=t.startsWith(n.repeat(3),r);r+=o?3:1;let i=!1;for(;r<t.length;){if(n==='"'&&t[r]==="\\"){r+=2;continue}if(t[r]===n){if(!o){r++,i=!0;break}if(t.startsWith(n.repeat(3),r)){for(;t[r]===n;)r++;i=!0;break}}r++}if(!i)throw new Error("cannot locate string boundary");e.push({start:s,end:r,text:t.slice(s,r),kind:"string",multiline:o});continue}if("[]=.{},".includes(n)){r++,e.push({start:s,end:r,text:n,kind:"symbol"});continue}for(;r<t.length&&!/\s/.test(t[r])&&!`"'#[]=.{},`.includes(t[r]);)r++;if(r===s)throw new Error("cannot locate token");e.push({start:s,end:r,text:t.slice(s,r),kind:"word"})}return e}function lC(t){let e=xn(t+" = 0"),r=[];for(;e&&typeof e=="object"&&!Array.isArray(e);){let n=Object.entries(e);if(n.length!==1)throw new Error("ambiguous key");r.push(n[0][0]),e=n[0][1]}return r}function cC(t){let e=xn(t+`
1756
1756
  __init_edit_marker__ = 0`),r=[];for(;e&&typeof e=="object"&&!Array.isArray(e);){let n=Object.entries(e);if(n.length!==1)return[];if(n[0][0]==="__init_edit_marker__")return r;r.push(n[0][0]),e=n[0][1]}return[]}function Nu(t){return'"'+Array.from(t).map(e=>{let r=e.codePointAt(0);if(r>=55296&&r<=57343)throw new Error("managed string contains an invalid Unicode scalar");return e==='"'?'\\"':e==="\\"?"\\\\":r<32||r===127?"\\u"+r.toString(16).padStart(4,"0"):e}).join("")+'"'}function $T(t,e,r=[]){if(r.length===2&&zs.includes(r[0])&&Qs.includes(r[1])||Object.is(t,e))return!0;if(t instanceof Date||e instanceof Date)return t instanceof Date&&e instanceof Date&&t.toISOString()===e.toISOString();if(!t||!e||typeof t!="object"||typeof e!="object"||Array.isArray(t)!==Array.isArray(e))return!1;let n=Object.keys(t),s=Object.keys(e);return n.length!==s.length||n.some(o=>!Object.hasOwn(e,o))?!1:n.every(o=>$T(t[o],e[o],[...r,o]))}function PT(t,e){try{let r=Xt(t),n=[];for(let u of zs)for(let m of Qs){let f=r.config[u.toLowerCase()][m],_=e[u.toLowerCase()][m];f!==_&&n.push({section:u,key:m,oldValue:f,newValue:_,line:1})}if(!n.length)return{ok:!0,text:t,changes:n};let s=new Map,o=aC(t),i=0,a=[];for(;i<o.length;){if(o[i].kind==="newline"){i++;continue}let u=i;if(o[i].text==="["){for(;i<o.length&&o[i].kind!=="newline";)i++;a=cC(t.slice(o[u].start,o[i-1].end));continue}for(;i<o.length&&o[i].text!=="=";)i++;if(i===o.length)throw new Error("cannot locate assignment");let m=lC(t.slice(o[u].start,o[i-1].end));i++;let f=i,_=0;for(;i<o.length;){let g=o[i];if(g.kind==="newline"&&_===0)break;g.kind==="symbol"&&((g.text==="["||g.text==="{")&&_++,(g.text==="]"||g.text==="}")&&_--),i++}if(a.length===1&&m.length===1&&i-f===1){let g=o[f];g.kind==="string"&&!g.multiline&&s.set(a[0]+"."+m[0],g)}}let l=n.map(u=>{let m=s.get(u.section+"."+u.key);if(!m)throw new Error("cannot edit "+u.section+"."+u.key+" in place (multiline, dotted or inline managed layout); edit by hand");return u.line=t.slice(0,m.start).split(/\r\n|\r|\n/).length,{start:m.start,end:m.end,text:Nu(u.newValue)}}).sort((u,m)=>m.start-u.start),c=t;for(let u of l)c=c.slice(0,u.start)+u.text+c.slice(u.end);let d=Xt(c);for(let u of zs)for(let m of Qs)if(d.config[u.toLowerCase()][m]!==e[u.toLowerCase()][m])throw new Error("managed-value verification failed");if(!$T(r.document,d.document))throw new Error("unmanaged semantic verification failed");return{ok:!0,text:c,changes:n}}catch(r){return{ok:!1,error:r.message,line:r.line}}}var FT=k(()=>{"use strict";Au();ya()});import{existsSync as dC,mkdirSync as IJ,readdirSync as uC,writeFileSync as bJ}from"node:fs";import{homedir as fC}from"node:os";import{dirname as NJ,join as Cn}from"node:path";function Ru(t){let e=UT[t]??UT.claude;return{provider:t,model1:e[0],model2:e[1],model3:e[2]}}function jT(t){let e=t.filter((i,a)=>t.indexOf(i)===a),r=e.length>0?e:["claude"],[n,s=n,o=n]=r;return{provider1:Ru(n),provider2:Ru(s),provider3:Ru(o)}}function eo(t){try{return dC(t)&&uC(t).length>0}catch{return!1}}function WT(){let t=fC(),e=process.env.KIMI_CODE_HOME??Cn(t,".kimi-code"),r=[];return eo(Cn(t,".claude","projects"))&&r.push("claude"),(eo(Cn(t,".codex","sessions"))||eo(Cn(t,".code","sessions")))&&r.push("codex"),eo(Cn(t,".gemini","antigravity-cli","conversations"))&&r.push("agy"),eo(Cn(e,"sessions"))&&r.push("kimi"),r}function wa(t){return Nu(t)}function to(t){let e=(r,n)=>[`[${r}]`,`provider = ${wa(n.provider)}`,`model1 = ${wa(n.model1)}`,`model2 = ${wa(n.model2)}`,`model3 = ${wa(n.model3)}`].join(`
1757
1757
  `);return`# Generated by \`lmctl init\`. This is a STARTING POINT, not a fixed answer --
1758
- # edit any value below to change what \`lmctl plan\`/\`lmctl quickrun\` resolve to.
1758
+ # lmctl properties: hierarchical keys such as Provider1.provider, Provider1.model1,
1759
+ # and user-defined top-level Env1. edit any value below to change what \`lmctl plan\`/\`lmctl quickrun\` resolve to.
1759
1760
  #
1760
1761
  # Provider1/Provider2/Provider3 are SLOTS, not a ranking: a .lmctl template
1761
1762
  # published on lmctl.com writes \${Provider1}/\${Model1}, so the same template
1762
1763
  # works whether you have one provider or three -- with only one, all three
1763
- # slots just point at it. lmscript scripts see them as the variables
1764
- # Provider1..3 and Model1..3.
1764
+ # slots just point at it. lmscript reads PROPS.Provider1.Provider and
1765
+ # PROPS.Provider1.Model1 (managed lowercase TOML fields projected as property paths).
1765
1766
  #
1766
1767
  # model1 is the slot's active/top-tier model; model2 and model3 are lighter
1767
1768
  # alternatives for the SAME provider. Promote one to model1 to make it the
@@ -2218,7 +2219,7 @@ ${Af}
2218
2219
  This is a starting point, not a fixed answer -- edit provider/model1/model2/model3 above before running lmctl plan or lmctl quickrun if it is not right.
2219
2220
  `),e.stdout.write(`${Af}
2220
2221
  `),l(),0}catch(i){return e.stderr.write("error: cannot update "+o+": "+(i instanceof Error?i.message:String(i))+`
2221
- `),1}}var Af,oM,Cw=k(()=>{"use strict";Lw();qr();Af="These are environment values: lmscript sees them as the variables Provider1..3 and Model1..3, and lmctl plan/quickrun templates use them as ${Provider1}/${Model1}.",oM=`usage: lmctl init [--force]
2222
+ `),1}}var Af,oM,Cw=k(()=>{"use strict";Lw();qr();Af="These are lmctl properties: lmscript reads PROPS.Provider1.Provider and PROPS.Provider1.Model1; legacy plan/quickrun templates use them as ${Provider1}/${Model1}.",oM=`usage: lmctl init [--force]
2222
2223
 
2223
2224
  Writes ~/.lmctl/init.toml if it does not exist: three provider slots
2224
2225
  (Provider1/2/3), each resolved to a provider and a starting model,
@@ -2235,8 +2236,9 @@ old -> new. If nothing would change, the file is not rewritten. A file
2235
2236
  whose whole document is invalid TOML or whose managed slot schema is invalid is reported with its line number and left
2236
2237
  byte-identical.
2237
2238
 
2238
- The values are ENVIRONMENT values: lmscript sees them as the variables
2239
- Provider1..3 and Model1..3, and lmctl plan and lmctl quickrun read this
2239
+ The file contains lmctl properties: hierarchical keys Provider1.provider,
2240
+ Provider1.model1, and user-defined top-level keys such as Env1. Scripts read
2241
+ PROPS.Provider1.Provider and PROPS.Provider1.Model1. Plan and quickrun read this
2240
2242
  file so a published .lmctl template's \${Provider1}/\${Model1}-style
2241
2243
  placeholders resolve without asking you provider/model questions
2242
2244
  directly.
@@ -2306,9 +2308,10 @@ it is expected.
2306
2308
  List current samples from lmctl.com/quickrun/index.txt, or fetch and execute
2307
2309
  one. Example: lmctl quickrun solo
2308
2310
 
2309
- The script engine reads ~/.lmctl/init.toml at startup (run lmctl init first),
2310
- defining Provider1..3, Model1..3, Directory and NonInteractive. Quickrun uses
2311
- the same runtime globals as lmctl script and --check. Samples can be added
2311
+ init.toml contains lmctl properties. Scripts lazily read PROPS.Provider1.Provider
2312
+ and PROPS.Provider1.Model1; checks use passive keys without opening the profile.
2313
+ Directory and NonInteractive are invocation facts, and ARGV holds script arguments.
2314
+ Samples can be added
2312
2315
  to the website without a CLI release.
2313
2316
  Bare names always select hosted samples; use ./paths for local scripts or directories.
2314
2317
  Explicit URLs are also accepted. Only run scripts you trust.