@lmctl-ai/lmctl 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +389 -371
- package/dist/cli/script.js +329 -320
- package/dist/script/lmscript.d.ts +47 -3
- package/package.json +1 -1
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
* 2. Scan all and check before execution: In-memory AST validation upfront. Zero intermediate files generated.
|
|
7
7
|
* 3. Language features: Top-level functions, flow control (if/else, while, for, break, continue, return), tuple & destructuring assignment: (a, b) = [1, 2], dot notation (data.key), object literals { key: val }, and negative indexing arr[-1].
|
|
8
8
|
* 4. Predefined functions implemented in TypeScript:
|
|
9
|
-
* - File I/O: read_file, write_file, append_file, read_lines, read_json, write_json, read_csv, write_csv, file_exists, delete_file.
|
|
9
|
+
* - File I/O: read_file, write_file, append_file, read_lines, read_json, write_json, read_csv, write_csv, file_exists, delete_file, mkdir, rmdir, copy_file, move_file, basename, dirname, path_join, abs_path.
|
|
10
10
|
* - Data structures:
|
|
11
11
|
* * List/Array: list, len, push, pop, shift, unshift, insert, remove_at, slice, concat, reverse, sort, contains, index_of, join, unique, flatten, first, last, is_empty, sum, avg.
|
|
12
|
-
* * Hash/Map:
|
|
12
|
+
* * Hash/Map: hash, keys, values, entries, from_entries, has_key, get, set, delete_key, merge, clone, clear, size. ("map" is deliberately unimplemented, not an empty-hash constructor -- reserved for a future higher-order array-transform function.)
|
|
13
13
|
* - JSON processing: data = json(out), json_parse, json_parse_safe, json_stringify, pluck, filter_by, find_by.
|
|
14
|
+
* - Regex: regex_test/test, regex_match/match/search, regex_find_all/findall, regex_replace, split_regex -- patterns are plain strings compiled via the host RegExp engine.
|
|
15
|
+
* - Environment & time: env, getenv, set_env, now, timestamp, date, strftime, date_format.
|
|
16
|
+
* - Null handling: coalesce, if_null, default_to, if_else (expression-level ternary).
|
|
14
17
|
* - System & Process: system() returning SystemResult, prompt_human() for attended terminal pause/handoff.
|
|
15
18
|
* - Comprehensive string operations (split, lines, words, join, trim, upper, lower, contains, replace, slice, etc.).
|
|
19
|
+
* - First-class function values: a bare reference to an already-declared function name (user or host) is a
|
|
20
|
+
* callable FunctionRef, assignable to a variable (`g = dbl; g(4);`) -- a NAMED reference, not a lexical
|
|
21
|
+
* closure; calling through a non-identifier expression (e.g. `arr[0](x)`) is not supported.
|
|
16
22
|
* 5. Register new functions: API allowing host TypeScript functions to be registered and checked statically.
|
|
17
23
|
*
|
|
18
24
|
* Security & Authority Model:
|
|
@@ -315,7 +321,7 @@ export declare class Parser {
|
|
|
315
321
|
private consume;
|
|
316
322
|
private consumeOptionalSemicolon;
|
|
317
323
|
}
|
|
318
|
-
export declare const STDLIB_SOURCE = "# LMScript Standard Library (std.lms)\n\n# String Utilities\nfn is_blank(s) {\n if (s == null) {\n return true;\n }\n return len(trim(s)) == 0;\n}\n\n# Array Utilities\nfn chunk(arr, size) {\n if (size <= 0) {\n return [];\n }\n res = [];\n current = [];\n for (i = 0; i < len(arr); i = i + 1) {\n push(current, arr[i]);\n if (len(current) == size) {\n push(res, current);\n current = [];\n }\n }\n if (len(current) > 0) {\n push(res, current);\n }\n return res;\n}\n\nfn compact(arr) {\n res = [];\n for (i = 0; i < len(arr); i = i + 1) {\n item = arr[i];\n if (item != null) {\n push(res, item);\n }\n }\n return res;\n}\n\nfn zip(arr1, arr2) {\n res = [];\n limit = len(arr1);\n if (len(arr2) < limit) {\n limit = len(arr2);\n }\n for (i = 0; i < limit; i = i + 1) {\n push(res, [arr1[i], arr2[i]]);\n }\n return res;\n}\n\nfn take(arr, n) {\n res = [];\n limit = n;\n if (limit > len(arr)) {\n limit = len(arr);\n }\n for (i = 0; i < limit; i = i + 1) {\n push(res, arr[i]);\n }\n return res;\n}\n\nfn drop(arr, n) {\n res = [];\n start = n;\n if (start < 0) {\n start = 0;\n }\n for (i = start; i < len(arr); i = i + 1) {\n push(res, arr[i]);\n }\n return res;\n}\n\n# Math Utilities\nfn clamp(val, low, high) {\n if (val < low) {\n return low;\n }\n if (val > high) {\n return high;\n }\n return val;\n}\n";
|
|
324
|
+
export declare const STDLIB_SOURCE = "# LMScript Standard Library (std.lms)\n\n# String Utilities\nfn is_blank(s) {\n if (s == null) {\n return true;\n }\n return len(trim(s)) == 0;\n}\n\n# Array Utilities\nfn chunk(arr, size) {\n if (size <= 0) {\n return [];\n }\n res = [];\n current = [];\n for (i = 0; i < len(arr); i = i + 1) {\n push(current, arr[i]);\n if (len(current) == size) {\n push(res, current);\n current = [];\n }\n }\n if (len(current) > 0) {\n push(res, current);\n }\n return res;\n}\n\nfn compact(arr) {\n res = [];\n for (i = 0; i < len(arr); i = i + 1) {\n item = arr[i];\n if (item != null) {\n push(res, item);\n }\n }\n return res;\n}\n\nfn zip(arr1, arr2) {\n res = [];\n limit = len(arr1);\n if (len(arr2) < limit) {\n limit = len(arr2);\n }\n for (i = 0; i < limit; i = i + 1) {\n push(res, [arr1[i], arr2[i]]);\n }\n return res;\n}\n\nfn enumerate(arr) {\n res = [];\n for (i = 0; i < len(arr); i = i + 1) {\n push(res, [i, arr[i]]);\n }\n return res;\n}\n\nfn take(arr, n) {\n res = [];\n limit = n;\n if (limit > len(arr)) {\n limit = len(arr);\n }\n for (i = 0; i < limit; i = i + 1) {\n push(res, arr[i]);\n }\n return res;\n}\n\nfn drop(arr, n) {\n res = [];\n start = n;\n if (start < 0) {\n start = 0;\n }\n for (i = start; i < len(arr); i = i + 1) {\n push(res, arr[i]);\n }\n return res;\n}\n\n# Math Utilities\nfn clamp(val, low, high) {\n if (val < low) {\n return low;\n }\n if (val > high) {\n return high;\n }\n return val;\n}\n";
|
|
319
325
|
export declare function getStdlibProgram(): Program;
|
|
320
326
|
export interface CheckOptions {
|
|
321
327
|
/** Inspect literal built-in read paths against the current filesystem. No script evaluation. */
|
|
@@ -385,6 +391,23 @@ export declare class BreakSignal {
|
|
|
385
391
|
}
|
|
386
392
|
export declare class ContinueSignal {
|
|
387
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* First-class function value (operator ruling, 2026-09-29, Rule 2 -- "if it
|
|
396
|
+
* is just how it came out, it is worth fixing": no stated design rationale
|
|
397
|
+
* anywhere separated function names from the variable namespace; it was an
|
|
398
|
+
* omission of scope, not a deliberate tradeoff). A bare reference to an
|
|
399
|
+
* already-declared function name (user `fn` or host) evaluates to one of
|
|
400
|
+
* these, which can be assigned, stored, and called through a variable --
|
|
401
|
+
* `g = dbl; g(4);` now works. Deliberately a NAMED reference, not a true
|
|
402
|
+
* lexical closure over an enclosing scope: nothing in the reported gaps
|
|
403
|
+
* (map/filter/reduce/etc. over top-level named functions) needs closures,
|
|
404
|
+
* and adding them is a materially bigger, separate change.
|
|
405
|
+
*/
|
|
406
|
+
export declare class FunctionRef {
|
|
407
|
+
readonly name: string;
|
|
408
|
+
constructor(name: string);
|
|
409
|
+
toString(): string;
|
|
410
|
+
}
|
|
388
411
|
export declare class Environment {
|
|
389
412
|
private static nextId;
|
|
390
413
|
readonly id: number;
|
|
@@ -464,6 +487,13 @@ export declare class Interpreter {
|
|
|
464
487
|
evaluateProgram(program: Program): any;
|
|
465
488
|
private execStmt;
|
|
466
489
|
private evalExpr;
|
|
490
|
+
/** A call's callee name is normally used directly -- but if it names
|
|
491
|
+
* neither a declared user function nor a host function, it may be a
|
|
492
|
+
* variable holding a first-class FunctionRef (`g = dbl; g(4);`), in which
|
|
493
|
+
* case the actual function to invoke is the ref's name instead. */
|
|
494
|
+
private resolveCallTarget;
|
|
495
|
+
private invokeNamed;
|
|
496
|
+
private resolveIdentifier;
|
|
467
497
|
private isTruthy;
|
|
468
498
|
evaluateProgramAsync(program: Program): Promise<any>;
|
|
469
499
|
private execStmtAsync;
|
|
@@ -482,6 +512,20 @@ export interface ExecutionResult {
|
|
|
482
512
|
export declare const LANGUAGE_DOCS: FunctionDoc[];
|
|
483
513
|
export declare const BUILTIN_FUNCTION_DOCS: FunctionDoc[];
|
|
484
514
|
export declare const STDLIB_FUNCTION_DOCS: FunctionDoc[];
|
|
515
|
+
/**
|
|
516
|
+
* Real C/Perl/Python printf-style substitution for sprintf()/printf()
|
|
517
|
+
* (math.lmctl, 2026-09-29, defect B: sprintf/printf were aliased onto
|
|
518
|
+
* format(), which is Python str.format brace syntax -- `sprintf("%s=%s",
|
|
519
|
+
* a, b)` silently returned the literal template unsubstituted, because "%s"
|
|
520
|
+
* is not a brace placeholder. "%s is the ONLY reason anyone reaches for the
|
|
521
|
+
* name sprintf" -- so these two entry points get their OWN real % syntax,
|
|
522
|
+
* format() keeps braces. Deliberately minimal: %s/%d/%f/%%, no width/
|
|
523
|
+
* precision/padding modifiers -- add more only against a concrete need.
|
|
524
|
+
* Extra args with no corresponding %-directive are silently unused,
|
|
525
|
+
* matching real printf (not folded into a "no directives -> space-join"
|
|
526
|
+
* fallback, which would just be a second silently-wrong behavior).
|
|
527
|
+
*/
|
|
528
|
+
export declare function printfFormat(template: any, args: any[]): string;
|
|
485
529
|
export declare class LMScript {
|
|
486
530
|
private readonly hostFunctions;
|
|
487
531
|
private readonly functionDocs;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmctl-ai/lmctl",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "A provider-agnostic control plane for teams of AI coding agents — across providers, with independent review and durable memory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://lmctl.com",
|