llmist 1.0.0 → 1.2.0

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.cjs CHANGED
@@ -1447,6 +1447,447 @@ var init_hook_validators = __esm({
1447
1447
  }
1448
1448
  });
1449
1449
 
1450
+ // src/gadgets/schema-introspector.ts
1451
+ function getDef(schema) {
1452
+ return schema._def;
1453
+ }
1454
+ function getTypeName(schema) {
1455
+ const def = getDef(schema);
1456
+ return def?.type ?? def?.typeName;
1457
+ }
1458
+ function getShape(schema) {
1459
+ const def = getDef(schema);
1460
+ if (typeof def?.shape === "function") {
1461
+ return def.shape();
1462
+ }
1463
+ return def?.shape;
1464
+ }
1465
+ var SchemaIntrospector;
1466
+ var init_schema_introspector = __esm({
1467
+ "src/gadgets/schema-introspector.ts"() {
1468
+ "use strict";
1469
+ SchemaIntrospector = class {
1470
+ schema;
1471
+ cache = /* @__PURE__ */ new Map();
1472
+ constructor(schema) {
1473
+ this.schema = schema;
1474
+ }
1475
+ /**
1476
+ * Get the expected type at a JSON pointer path.
1477
+ *
1478
+ * @param pointer - JSON pointer path without leading / (e.g., "config/timeout", "items/0")
1479
+ * @returns Type hint for coercion decision
1480
+ */
1481
+ getTypeAtPath(pointer) {
1482
+ const cached = this.cache.get(pointer);
1483
+ if (cached !== void 0) {
1484
+ return cached;
1485
+ }
1486
+ const result = this.resolveTypeAtPath(pointer);
1487
+ this.cache.set(pointer, result);
1488
+ return result;
1489
+ }
1490
+ /**
1491
+ * Internal method to resolve type at path without caching.
1492
+ */
1493
+ resolveTypeAtPath(pointer) {
1494
+ if (!pointer) {
1495
+ return this.getBaseType(this.schema);
1496
+ }
1497
+ const segments = pointer.split("/");
1498
+ let current = this.schema;
1499
+ for (const segment of segments) {
1500
+ current = this.unwrapSchema(current);
1501
+ const typeName = getTypeName(current);
1502
+ if (typeName === "object" || typeName === "ZodObject") {
1503
+ const shape = getShape(current);
1504
+ if (!shape || !(segment in shape)) {
1505
+ return "unknown";
1506
+ }
1507
+ current = shape[segment];
1508
+ } else if (typeName === "array" || typeName === "ZodArray") {
1509
+ if (!/^\d+$/.test(segment)) {
1510
+ return "unknown";
1511
+ }
1512
+ const def = getDef(current);
1513
+ const elementType = def?.element ?? def?.type;
1514
+ if (!elementType) {
1515
+ return "unknown";
1516
+ }
1517
+ current = elementType;
1518
+ } else if (typeName === "tuple" || typeName === "ZodTuple") {
1519
+ if (!/^\d+$/.test(segment)) {
1520
+ return "unknown";
1521
+ }
1522
+ const index = parseInt(segment, 10);
1523
+ const def = getDef(current);
1524
+ const items = def?.items;
1525
+ if (!items || index >= items.length) {
1526
+ return "unknown";
1527
+ }
1528
+ current = items[index];
1529
+ } else if (typeName === "record" || typeName === "ZodRecord") {
1530
+ const def = getDef(current);
1531
+ const valueType = def?.valueType;
1532
+ if (!valueType) {
1533
+ return "unknown";
1534
+ }
1535
+ current = valueType;
1536
+ } else {
1537
+ return "unknown";
1538
+ }
1539
+ }
1540
+ return this.getBaseType(current);
1541
+ }
1542
+ /**
1543
+ * Unwrap schema modifiers (optional, default, nullable, branded, etc.)
1544
+ * to get to the underlying type.
1545
+ */
1546
+ unwrapSchema(schema) {
1547
+ let current = schema;
1548
+ let iterations = 0;
1549
+ const maxIterations = 20;
1550
+ while (iterations < maxIterations) {
1551
+ const typeName = getTypeName(current);
1552
+ const wrapperTypes = [
1553
+ "optional",
1554
+ "nullable",
1555
+ "default",
1556
+ "catch",
1557
+ "branded",
1558
+ "readonly",
1559
+ "pipeline",
1560
+ "ZodOptional",
1561
+ "ZodNullable",
1562
+ "ZodDefault",
1563
+ "ZodCatch",
1564
+ "ZodBranded",
1565
+ "ZodReadonly",
1566
+ "ZodPipeline"
1567
+ ];
1568
+ if (typeName && wrapperTypes.includes(typeName)) {
1569
+ const def = getDef(current);
1570
+ const inner = def?.innerType ?? def?.in ?? def?.type;
1571
+ if (!inner || inner === current) break;
1572
+ current = inner;
1573
+ iterations++;
1574
+ continue;
1575
+ }
1576
+ break;
1577
+ }
1578
+ return current;
1579
+ }
1580
+ /**
1581
+ * Get the primitive type hint from an unwrapped schema.
1582
+ */
1583
+ getBaseType(schema) {
1584
+ const unwrapped = this.unwrapSchema(schema);
1585
+ const typeName = getTypeName(unwrapped);
1586
+ switch (typeName) {
1587
+ // Primitive types
1588
+ case "string":
1589
+ case "ZodString":
1590
+ return "string";
1591
+ case "number":
1592
+ case "ZodNumber":
1593
+ case "bigint":
1594
+ case "ZodBigInt":
1595
+ return "number";
1596
+ case "boolean":
1597
+ case "ZodBoolean":
1598
+ return "boolean";
1599
+ // Literal types - check the literal value type
1600
+ case "literal":
1601
+ case "ZodLiteral": {
1602
+ const def = getDef(unwrapped);
1603
+ const values = def?.values;
1604
+ const value = values?.[0] ?? def?.value;
1605
+ if (typeof value === "string") return "string";
1606
+ if (typeof value === "number" || typeof value === "bigint")
1607
+ return "number";
1608
+ if (typeof value === "boolean") return "boolean";
1609
+ return "unknown";
1610
+ }
1611
+ // Enum - always string keys
1612
+ case "enum":
1613
+ case "ZodEnum":
1614
+ case "nativeEnum":
1615
+ case "ZodNativeEnum":
1616
+ return "string";
1617
+ // Union - return 'unknown' to let auto-coercion decide
1618
+ // Since multiple types are valid, we can't definitively say what the LLM intended
1619
+ // Auto-coercion will handle common cases (numbers, booleans) appropriately
1620
+ case "union":
1621
+ case "ZodUnion":
1622
+ return "unknown";
1623
+ // Discriminated union - complex, return unknown
1624
+ case "discriminatedUnion":
1625
+ case "ZodDiscriminatedUnion":
1626
+ return "unknown";
1627
+ // Intersection - check both sides
1628
+ case "intersection":
1629
+ case "ZodIntersection": {
1630
+ const def = getDef(unwrapped);
1631
+ const left = def?.left;
1632
+ const right = def?.right;
1633
+ if (!left || !right) return "unknown";
1634
+ const leftType = this.getBaseType(left);
1635
+ const rightType = this.getBaseType(right);
1636
+ if (leftType === rightType) return leftType;
1637
+ if (leftType === "string" || rightType === "string") return "string";
1638
+ return "unknown";
1639
+ }
1640
+ // Effects/transforms - return unknown to let Zod handle it
1641
+ case "effects":
1642
+ case "ZodEffects":
1643
+ return "unknown";
1644
+ // Lazy - can't resolve without evaluating
1645
+ case "lazy":
1646
+ case "ZodLazy":
1647
+ return "unknown";
1648
+ // Complex types - return unknown
1649
+ case "object":
1650
+ case "ZodObject":
1651
+ case "array":
1652
+ case "ZodArray":
1653
+ case "tuple":
1654
+ case "ZodTuple":
1655
+ case "record":
1656
+ case "ZodRecord":
1657
+ case "map":
1658
+ case "ZodMap":
1659
+ case "set":
1660
+ case "ZodSet":
1661
+ case "function":
1662
+ case "ZodFunction":
1663
+ case "promise":
1664
+ case "ZodPromise":
1665
+ case "date":
1666
+ case "ZodDate":
1667
+ return "unknown";
1668
+ // Unknown/any/never/void/undefined/null
1669
+ case "unknown":
1670
+ case "ZodUnknown":
1671
+ case "any":
1672
+ case "ZodAny":
1673
+ case "never":
1674
+ case "ZodNever":
1675
+ case "void":
1676
+ case "ZodVoid":
1677
+ case "undefined":
1678
+ case "ZodUndefined":
1679
+ case "null":
1680
+ case "ZodNull":
1681
+ return "unknown";
1682
+ default:
1683
+ return "unknown";
1684
+ }
1685
+ }
1686
+ };
1687
+ }
1688
+ });
1689
+
1690
+ // src/gadgets/block-params.ts
1691
+ function parseBlockParams(content, options) {
1692
+ const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
1693
+ const result = {};
1694
+ const seenPointers = /* @__PURE__ */ new Set();
1695
+ const introspector = options?.schema ? new SchemaIntrospector(options.schema) : void 0;
1696
+ const parts = content.split(argPrefix);
1697
+ for (let i = 1; i < parts.length; i++) {
1698
+ const part = parts[i];
1699
+ const newlineIndex = part.indexOf("\n");
1700
+ if (newlineIndex === -1) {
1701
+ const pointer2 = part.trim();
1702
+ if (pointer2) {
1703
+ if (seenPointers.has(pointer2)) {
1704
+ throw new Error(`Duplicate pointer: ${pointer2}`);
1705
+ }
1706
+ seenPointers.add(pointer2);
1707
+ setByPointer(result, pointer2, "", introspector);
1708
+ }
1709
+ continue;
1710
+ }
1711
+ const pointer = part.substring(0, newlineIndex).trim();
1712
+ let value = part.substring(newlineIndex + 1);
1713
+ if (value.endsWith("\n")) {
1714
+ value = value.slice(0, -1);
1715
+ }
1716
+ if (!pointer) {
1717
+ continue;
1718
+ }
1719
+ if (seenPointers.has(pointer)) {
1720
+ throw new Error(`Duplicate pointer: ${pointer}`);
1721
+ }
1722
+ seenPointers.add(pointer);
1723
+ setByPointer(result, pointer, value, introspector);
1724
+ }
1725
+ return result;
1726
+ }
1727
+ function coerceValue(value, expectedType) {
1728
+ if (value.includes("\n")) {
1729
+ return value;
1730
+ }
1731
+ const trimmed = value.trim();
1732
+ if (expectedType === "string") {
1733
+ return value;
1734
+ }
1735
+ if (expectedType === "boolean") {
1736
+ if (trimmed === "true") return true;
1737
+ if (trimmed === "false") return false;
1738
+ return value;
1739
+ }
1740
+ if (expectedType === "number") {
1741
+ const num = Number(trimmed);
1742
+ if (!isNaN(num) && isFinite(num) && trimmed !== "") {
1743
+ return num;
1744
+ }
1745
+ return value;
1746
+ }
1747
+ if (trimmed === "true") return true;
1748
+ if (trimmed === "false") return false;
1749
+ if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
1750
+ const num = Number(trimmed);
1751
+ if (!isNaN(num) && isFinite(num)) {
1752
+ return num;
1753
+ }
1754
+ }
1755
+ return value;
1756
+ }
1757
+ function setByPointer(obj, pointer, value, introspector) {
1758
+ const segments = pointer.split("/");
1759
+ let current = obj;
1760
+ for (let i = 0; i < segments.length - 1; i++) {
1761
+ const segment = segments[i];
1762
+ const nextSegment = segments[i + 1];
1763
+ const nextIsArrayIndex = /^\d+$/.test(nextSegment);
1764
+ if (Array.isArray(current)) {
1765
+ const index = parseInt(segment, 10);
1766
+ if (isNaN(index) || index < 0) {
1767
+ throw new Error(`Invalid array index: ${segment}`);
1768
+ }
1769
+ if (index > current.length) {
1770
+ throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1771
+ }
1772
+ if (current[index] === void 0) {
1773
+ current[index] = nextIsArrayIndex ? [] : {};
1774
+ }
1775
+ current = current[index];
1776
+ } else {
1777
+ const rec = current;
1778
+ if (rec[segment] === void 0) {
1779
+ rec[segment] = nextIsArrayIndex ? [] : {};
1780
+ }
1781
+ current = rec[segment];
1782
+ }
1783
+ }
1784
+ const lastSegment = segments[segments.length - 1];
1785
+ const expectedType = introspector?.getTypeAtPath(pointer);
1786
+ const coercedValue = coerceValue(value, expectedType);
1787
+ if (Array.isArray(current)) {
1788
+ const index = parseInt(lastSegment, 10);
1789
+ if (isNaN(index) || index < 0) {
1790
+ throw new Error(`Invalid array index: ${lastSegment}`);
1791
+ }
1792
+ if (index > current.length) {
1793
+ throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1794
+ }
1795
+ current[index] = coercedValue;
1796
+ } else {
1797
+ current[lastSegment] = coercedValue;
1798
+ }
1799
+ }
1800
+ var init_block_params = __esm({
1801
+ "src/gadgets/block-params.ts"() {
1802
+ "use strict";
1803
+ init_constants();
1804
+ init_schema_introspector();
1805
+ }
1806
+ });
1807
+
1808
+ // src/gadgets/error-formatter.ts
1809
+ var GadgetErrorFormatter;
1810
+ var init_error_formatter = __esm({
1811
+ "src/gadgets/error-formatter.ts"() {
1812
+ "use strict";
1813
+ init_constants();
1814
+ GadgetErrorFormatter = class {
1815
+ argPrefix;
1816
+ startPrefix;
1817
+ endPrefix;
1818
+ constructor(options = {}) {
1819
+ this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
1820
+ this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
1821
+ this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
1822
+ }
1823
+ /**
1824
+ * Format a Zod validation error with full gadget instructions.
1825
+ *
1826
+ * @param gadgetName - Name of the gadget that was called
1827
+ * @param zodError - The Zod validation error
1828
+ * @param gadget - The gadget instance (for generating instructions)
1829
+ * @returns Formatted error message with usage instructions
1830
+ */
1831
+ formatValidationError(gadgetName, zodError, gadget) {
1832
+ const parts = [];
1833
+ parts.push(`Error: Invalid parameters for '${gadgetName}':`);
1834
+ for (const issue of zodError.issues) {
1835
+ const path2 = issue.path.join(".") || "root";
1836
+ parts.push(` - ${path2}: ${issue.message}`);
1837
+ }
1838
+ parts.push("");
1839
+ parts.push("Gadget Usage:");
1840
+ parts.push(gadget.getInstruction(this.argPrefix));
1841
+ return parts.join("\n");
1842
+ }
1843
+ /**
1844
+ * Format a parse error with block format reference.
1845
+ *
1846
+ * @param gadgetName - Name of the gadget that was called
1847
+ * @param parseError - The parse error message
1848
+ * @param gadget - The gadget instance if found (for generating instructions)
1849
+ * @returns Formatted error message with format reference
1850
+ */
1851
+ formatParseError(gadgetName, parseError, gadget) {
1852
+ const parts = [];
1853
+ parts.push(`Error: Failed to parse parameters for '${gadgetName}':`);
1854
+ parts.push(` ${parseError}`);
1855
+ if (gadget) {
1856
+ parts.push("");
1857
+ parts.push("Gadget Usage:");
1858
+ parts.push(gadget.getInstruction(this.argPrefix));
1859
+ }
1860
+ parts.push("");
1861
+ parts.push("Block Format Reference:");
1862
+ parts.push(` ${this.startPrefix}${gadgetName}`);
1863
+ parts.push(` ${this.argPrefix}parameterName`);
1864
+ parts.push(" parameter value here");
1865
+ parts.push(` ${this.endPrefix}`);
1866
+ return parts.join("\n");
1867
+ }
1868
+ /**
1869
+ * Format a registry error (gadget not found) with available gadgets list.
1870
+ *
1871
+ * @param gadgetName - Name of the gadget that was not found
1872
+ * @param availableGadgets - List of available gadget names
1873
+ * @returns Formatted error message with available gadgets
1874
+ */
1875
+ formatRegistryError(gadgetName, availableGadgets) {
1876
+ const parts = [];
1877
+ parts.push(`Error: Gadget '${gadgetName}' not found.`);
1878
+ if (availableGadgets.length > 0) {
1879
+ parts.push("");
1880
+ parts.push(`Available gadgets: ${availableGadgets.join(", ")}`);
1881
+ } else {
1882
+ parts.push("");
1883
+ parts.push("No gadgets are currently registered.");
1884
+ }
1885
+ return parts.join("\n");
1886
+ }
1887
+ };
1888
+ }
1889
+ });
1890
+
1450
1891
  // src/gadgets/exceptions.ts
1451
1892
  var BreakLoopException, HumanInputException, TimeoutException;
1452
1893
  var init_exceptions = __esm({
@@ -1479,21 +1920,206 @@ var init_exceptions = __esm({
1479
1920
  }
1480
1921
  });
1481
1922
 
1923
+ // src/gadgets/parser.ts
1924
+ function stripMarkdownFences(content) {
1925
+ let cleaned = content.trim();
1926
+ const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
1927
+ const closingFence = /\n?```\s*$/;
1928
+ cleaned = cleaned.replace(openingFence, "");
1929
+ cleaned = cleaned.replace(closingFence, "");
1930
+ return cleaned.trim();
1931
+ }
1932
+ var globalInvocationCounter, StreamParser;
1933
+ var init_parser = __esm({
1934
+ "src/gadgets/parser.ts"() {
1935
+ "use strict";
1936
+ init_constants();
1937
+ init_block_params();
1938
+ globalInvocationCounter = 0;
1939
+ StreamParser = class {
1940
+ buffer = "";
1941
+ lastReportedTextLength = 0;
1942
+ startPrefix;
1943
+ endPrefix;
1944
+ argPrefix;
1945
+ constructor(options = {}) {
1946
+ this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
1947
+ this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
1948
+ this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
1949
+ }
1950
+ takeTextUntil(index) {
1951
+ if (index <= this.lastReportedTextLength) {
1952
+ return void 0;
1953
+ }
1954
+ const segment = this.buffer.slice(this.lastReportedTextLength, index);
1955
+ this.lastReportedTextLength = index;
1956
+ return segment.trim().length > 0 ? segment : void 0;
1957
+ }
1958
+ /**
1959
+ * Parse gadget name, handling both old format (name:invocationId) and new format (just name).
1960
+ * For new format, generates a unique invocation ID.
1961
+ */
1962
+ parseGadgetName(gadgetName) {
1963
+ if (gadgetName.includes(":")) {
1964
+ const parts = gadgetName.split(":");
1965
+ return { actualName: parts[0], invocationId: parts[1] };
1966
+ }
1967
+ return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
1968
+ }
1969
+ /**
1970
+ * Extract the error message from a parse error.
1971
+ * Preserves full message since the error formatter adds contextual help
1972
+ * that benefits from precise, detailed error information.
1973
+ */
1974
+ extractParseError(error) {
1975
+ return error instanceof Error ? error.message : String(error);
1976
+ }
1977
+ /**
1978
+ * Parse parameter string using block format
1979
+ */
1980
+ parseParameters(raw) {
1981
+ const cleaned = stripMarkdownFences(raw);
1982
+ try {
1983
+ return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };
1984
+ } catch (error) {
1985
+ return { parseError: this.extractParseError(error) };
1986
+ }
1987
+ }
1988
+ // Feed a chunk of text and get parsed events
1989
+ *feed(chunk) {
1990
+ this.buffer += chunk;
1991
+ let startIndex = 0;
1992
+ while (true) {
1993
+ const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
1994
+ if (partStartIndex === -1) break;
1995
+ const textBefore = this.takeTextUntil(partStartIndex);
1996
+ if (textBefore !== void 0) {
1997
+ yield { type: "text", content: textBefore };
1998
+ }
1999
+ const metadataStartIndex = partStartIndex + this.startPrefix.length;
2000
+ const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
2001
+ if (metadataEndIndex === -1) break;
2002
+ const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
2003
+ const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
2004
+ const contentStartIndex = metadataEndIndex + 1;
2005
+ let partEndIndex;
2006
+ let endMarkerLength = 0;
2007
+ if (gadgetName.includes(":")) {
2008
+ const oldEndMarker = `${this.endPrefix + actualGadgetName}:${invocationId}`;
2009
+ partEndIndex = this.buffer.indexOf(oldEndMarker, contentStartIndex);
2010
+ if (partEndIndex === -1) break;
2011
+ endMarkerLength = oldEndMarker.length;
2012
+ } else {
2013
+ const nextStartPos = this.buffer.indexOf(this.startPrefix, contentStartIndex);
2014
+ let validEndPos = -1;
2015
+ let searchPos = contentStartIndex;
2016
+ while (true) {
2017
+ const endPos = this.buffer.indexOf(this.endPrefix, searchPos);
2018
+ if (endPos === -1) break;
2019
+ const afterEnd = this.buffer.substring(endPos + this.endPrefix.length);
2020
+ if (afterEnd.startsWith("\n") || afterEnd.startsWith("\r") || afterEnd.startsWith(this.startPrefix) || afterEnd.length === 0) {
2021
+ validEndPos = endPos;
2022
+ break;
2023
+ } else {
2024
+ searchPos = endPos + this.endPrefix.length;
2025
+ }
2026
+ }
2027
+ if (nextStartPos !== -1 && (validEndPos === -1 || nextStartPos < validEndPos)) {
2028
+ partEndIndex = nextStartPos;
2029
+ endMarkerLength = 0;
2030
+ } else if (validEndPos !== -1) {
2031
+ partEndIndex = validEndPos;
2032
+ endMarkerLength = this.endPrefix.length;
2033
+ } else {
2034
+ break;
2035
+ }
2036
+ }
2037
+ const parametersRaw = this.buffer.substring(contentStartIndex, partEndIndex).trim();
2038
+ const { parameters, parseError } = this.parseParameters(parametersRaw);
2039
+ yield {
2040
+ type: "gadget_call",
2041
+ call: {
2042
+ gadgetName: actualGadgetName,
2043
+ invocationId,
2044
+ parametersRaw,
2045
+ parameters,
2046
+ parseError
2047
+ }
2048
+ };
2049
+ startIndex = partEndIndex + endMarkerLength;
2050
+ this.lastReportedTextLength = startIndex;
2051
+ }
2052
+ if (startIndex > 0) {
2053
+ this.buffer = this.buffer.substring(startIndex);
2054
+ this.lastReportedTextLength = 0;
2055
+ }
2056
+ }
2057
+ // Finalize parsing and return remaining text or incomplete gadgets
2058
+ *finalize() {
2059
+ const startIndex = this.buffer.indexOf(this.startPrefix, this.lastReportedTextLength);
2060
+ if (startIndex !== -1) {
2061
+ const textBefore = this.takeTextUntil(startIndex);
2062
+ if (textBefore !== void 0) {
2063
+ yield { type: "text", content: textBefore };
2064
+ }
2065
+ const metadataStartIndex = startIndex + this.startPrefix.length;
2066
+ const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
2067
+ if (metadataEndIndex !== -1) {
2068
+ const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
2069
+ const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
2070
+ const contentStartIndex = metadataEndIndex + 1;
2071
+ const parametersRaw = this.buffer.substring(contentStartIndex).trim();
2072
+ const { parameters, parseError } = this.parseParameters(parametersRaw);
2073
+ yield {
2074
+ type: "gadget_call",
2075
+ call: {
2076
+ gadgetName: actualGadgetName,
2077
+ invocationId,
2078
+ parametersRaw,
2079
+ parameters,
2080
+ parseError
2081
+ }
2082
+ };
2083
+ return;
2084
+ }
2085
+ }
2086
+ const remainingText = this.takeTextUntil(this.buffer.length);
2087
+ if (remainingText !== void 0) {
2088
+ yield { type: "text", content: remainingText };
2089
+ }
2090
+ }
2091
+ // Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
2092
+ reset() {
2093
+ this.buffer = "";
2094
+ this.lastReportedTextLength = 0;
2095
+ }
2096
+ };
2097
+ }
2098
+ });
2099
+
1482
2100
  // src/gadgets/executor.ts
1483
2101
  var GadgetExecutor;
1484
2102
  var init_executor = __esm({
1485
2103
  "src/gadgets/executor.ts"() {
1486
2104
  "use strict";
2105
+ init_constants();
1487
2106
  init_logger();
2107
+ init_block_params();
2108
+ init_error_formatter();
1488
2109
  init_exceptions();
2110
+ init_parser();
1489
2111
  GadgetExecutor = class {
1490
- constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs) {
2112
+ constructor(registry, onHumanInputRequired, logger, defaultGadgetTimeoutMs, errorFormatterOptions) {
1491
2113
  this.registry = registry;
1492
2114
  this.onHumanInputRequired = onHumanInputRequired;
1493
2115
  this.defaultGadgetTimeoutMs = defaultGadgetTimeoutMs;
1494
2116
  this.logger = logger ?? createLogger({ name: "llmist:executor" });
2117
+ this.errorFormatter = new GadgetErrorFormatter(errorFormatterOptions);
2118
+ this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;
1495
2119
  }
1496
2120
  logger;
2121
+ errorFormatter;
2122
+ argPrefix;
1497
2123
  /**
1498
2124
  * Creates a promise that rejects with a TimeoutException after the specified timeout.
1499
2125
  */
@@ -1518,11 +2144,12 @@ var init_executor = __esm({
1518
2144
  const gadget = this.registry.get(call.gadgetName);
1519
2145
  if (!gadget) {
1520
2146
  this.logger.error("Gadget not found", { gadgetName: call.gadgetName });
2147
+ const availableGadgets = this.registry.getNames();
1521
2148
  return {
1522
2149
  gadgetName: call.gadgetName,
1523
2150
  invocationId: call.invocationId,
1524
2151
  parameters: call.parameters ?? {},
1525
- error: `Gadget '${call.gadgetName}' not found in registry`,
2152
+ error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),
1526
2153
  executionTimeMs: Date.now() - startTime
1527
2154
  };
1528
2155
  }
@@ -1532,35 +2159,69 @@ var init_executor = __esm({
1532
2159
  parseError: call.parseError,
1533
2160
  rawParameters: call.parametersRaw
1534
2161
  });
2162
+ const parseErrorMessage = call.parseError ?? "Failed to parse parameters";
1535
2163
  return {
1536
2164
  gadgetName: call.gadgetName,
1537
2165
  invocationId: call.invocationId,
1538
2166
  parameters: {},
1539
- error: call.parseError ?? "Failed to parse parameters",
2167
+ error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),
1540
2168
  executionTimeMs: Date.now() - startTime
1541
2169
  };
1542
2170
  }
2171
+ let schemaAwareParameters = rawParameters;
2172
+ const hasBlockFormat = call.parametersRaw?.includes(this.argPrefix);
2173
+ if (gadget.parameterSchema && hasBlockFormat) {
2174
+ try {
2175
+ const cleanedRaw = stripMarkdownFences(call.parametersRaw);
2176
+ const initialParse = parseBlockParams(cleanedRaw, { argPrefix: this.argPrefix });
2177
+ const parametersWereModified = !this.deepEquals(rawParameters, initialParse);
2178
+ if (parametersWereModified) {
2179
+ this.logger.debug("Parameters modified by interceptor, skipping re-parse", {
2180
+ gadgetName: call.gadgetName
2181
+ });
2182
+ schemaAwareParameters = rawParameters;
2183
+ } else {
2184
+ schemaAwareParameters = parseBlockParams(cleanedRaw, {
2185
+ argPrefix: this.argPrefix,
2186
+ schema: gadget.parameterSchema
2187
+ });
2188
+ this.logger.debug("Re-parsed parameters with schema", {
2189
+ gadgetName: call.gadgetName,
2190
+ original: rawParameters,
2191
+ schemaAware: schemaAwareParameters
2192
+ });
2193
+ }
2194
+ } catch (error) {
2195
+ this.logger.warn("Schema-aware re-parsing failed, using original parameters", {
2196
+ gadgetName: call.gadgetName,
2197
+ error: error instanceof Error ? error.message : String(error)
2198
+ });
2199
+ schemaAwareParameters = rawParameters;
2200
+ }
2201
+ }
1543
2202
  if (gadget.parameterSchema) {
1544
- const validationResult = gadget.parameterSchema.safeParse(rawParameters);
2203
+ const validationResult = gadget.parameterSchema.safeParse(schemaAwareParameters);
1545
2204
  if (!validationResult.success) {
1546
- const formattedIssues = validationResult.error.issues.map((issue) => {
1547
- const path2 = issue.path.join(".") || "root";
1548
- return `${path2}: ${issue.message}`;
1549
- }).join("; ");
1550
- const validationError = `Invalid parameters: ${formattedIssues}`;
2205
+ const validationError = this.errorFormatter.formatValidationError(
2206
+ call.gadgetName,
2207
+ validationResult.error,
2208
+ gadget
2209
+ );
1551
2210
  this.logger.error("Gadget parameter validation failed", {
1552
2211
  gadgetName: call.gadgetName,
1553
- error: validationError
2212
+ issueCount: validationResult.error.issues.length
1554
2213
  });
1555
2214
  return {
1556
2215
  gadgetName: call.gadgetName,
1557
2216
  invocationId: call.invocationId,
1558
- parameters: rawParameters,
2217
+ parameters: schemaAwareParameters,
1559
2218
  error: validationError,
1560
2219
  executionTimeMs: Date.now() - startTime
1561
2220
  };
1562
2221
  }
1563
2222
  validatedParameters = validationResult.data;
2223
+ } else {
2224
+ validatedParameters = schemaAwareParameters;
1564
2225
  }
1565
2226
  const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;
1566
2227
  let result;
@@ -1653,322 +2314,61 @@ var init_executor = __esm({
1653
2314
  gadgetName: call.gadgetName,
1654
2315
  invocationId: call.invocationId,
1655
2316
  parameters: validatedParameters,
1656
- error: inputError instanceof Error ? inputError.message : String(inputError),
1657
- executionTimeMs: Date.now() - startTime
1658
- };
1659
- }
1660
- }
1661
- this.logger.warn("Human input required but no callback provided", {
1662
- gadgetName: call.gadgetName
1663
- });
1664
- return {
1665
- gadgetName: call.gadgetName,
1666
- invocationId: call.invocationId,
1667
- parameters: validatedParameters,
1668
- error: "Human input required but not available (stdin is not interactive)",
1669
- executionTimeMs: Date.now() - startTime
1670
- };
1671
- }
1672
- const executionTimeMs = Date.now() - startTime;
1673
- this.logger.error("Gadget execution failed", {
1674
- gadgetName: call.gadgetName,
1675
- error: error instanceof Error ? error.message : String(error),
1676
- executionTimeMs
1677
- });
1678
- return {
1679
- gadgetName: call.gadgetName,
1680
- invocationId: call.invocationId,
1681
- parameters: validatedParameters,
1682
- error: error instanceof Error ? error.message : String(error),
1683
- executionTimeMs
1684
- };
1685
- }
1686
- }
1687
- // Execute multiple gadget calls in parallel
1688
- async executeAll(calls) {
1689
- return Promise.all(calls.map((call) => this.execute(call)));
1690
- }
1691
- };
1692
- }
1693
- });
1694
-
1695
- // src/gadgets/block-params.ts
1696
- function parseBlockParams(content, options) {
1697
- const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
1698
- const result = {};
1699
- const seenPointers = /* @__PURE__ */ new Set();
1700
- const parts = content.split(argPrefix);
1701
- for (let i = 1; i < parts.length; i++) {
1702
- const part = parts[i];
1703
- const newlineIndex = part.indexOf("\n");
1704
- if (newlineIndex === -1) {
1705
- const pointer2 = part.trim();
1706
- if (pointer2) {
1707
- if (seenPointers.has(pointer2)) {
1708
- throw new Error(`Duplicate pointer: ${pointer2}`);
1709
- }
1710
- seenPointers.add(pointer2);
1711
- setByPointer(result, pointer2, "");
1712
- }
1713
- continue;
1714
- }
1715
- const pointer = part.substring(0, newlineIndex).trim();
1716
- let value = part.substring(newlineIndex + 1);
1717
- if (value.endsWith("\n")) {
1718
- value = value.slice(0, -1);
1719
- }
1720
- if (!pointer) {
1721
- continue;
1722
- }
1723
- if (seenPointers.has(pointer)) {
1724
- throw new Error(`Duplicate pointer: ${pointer}`);
1725
- }
1726
- seenPointers.add(pointer);
1727
- setByPointer(result, pointer, value);
1728
- }
1729
- return result;
1730
- }
1731
- function coerceValue(value) {
1732
- if (value.includes("\n")) {
1733
- return value;
1734
- }
1735
- const trimmed = value.trim();
1736
- if (trimmed === "true") return true;
1737
- if (trimmed === "false") return false;
1738
- if (trimmed !== "" && /^-?\d+(\.\d+)?$/.test(trimmed)) {
1739
- const num = Number(trimmed);
1740
- if (!isNaN(num) && isFinite(num)) {
1741
- return num;
1742
- }
1743
- }
1744
- return value;
1745
- }
1746
- function setByPointer(obj, pointer, value) {
1747
- const segments = pointer.split("/");
1748
- let current = obj;
1749
- for (let i = 0; i < segments.length - 1; i++) {
1750
- const segment = segments[i];
1751
- const nextSegment = segments[i + 1];
1752
- const nextIsArrayIndex = /^\d+$/.test(nextSegment);
1753
- if (Array.isArray(current)) {
1754
- const index = parseInt(segment, 10);
1755
- if (isNaN(index) || index < 0) {
1756
- throw new Error(`Invalid array index: ${segment}`);
1757
- }
1758
- if (index > current.length) {
1759
- throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1760
- }
1761
- if (current[index] === void 0) {
1762
- current[index] = nextIsArrayIndex ? [] : {};
1763
- }
1764
- current = current[index];
1765
- } else {
1766
- const rec = current;
1767
- if (rec[segment] === void 0) {
1768
- rec[segment] = nextIsArrayIndex ? [] : {};
1769
- }
1770
- current = rec[segment];
1771
- }
1772
- }
1773
- const lastSegment = segments[segments.length - 1];
1774
- const coercedValue = coerceValue(value);
1775
- if (Array.isArray(current)) {
1776
- const index = parseInt(lastSegment, 10);
1777
- if (isNaN(index) || index < 0) {
1778
- throw new Error(`Invalid array index: ${lastSegment}`);
1779
- }
1780
- if (index > current.length) {
1781
- throw new Error(`Array index gap: expected ${current.length}, got ${index}`);
1782
- }
1783
- current[index] = coercedValue;
1784
- } else {
1785
- current[lastSegment] = coercedValue;
1786
- }
1787
- }
1788
- var init_block_params = __esm({
1789
- "src/gadgets/block-params.ts"() {
1790
- "use strict";
1791
- init_constants();
1792
- }
1793
- });
1794
-
1795
- // src/gadgets/parser.ts
1796
- function stripMarkdownFences(content) {
1797
- let cleaned = content.trim();
1798
- const openingFence = /^```(?:toml|yaml|json)?\s*\n/i;
1799
- const closingFence = /\n?```\s*$/;
1800
- cleaned = cleaned.replace(openingFence, "");
1801
- cleaned = cleaned.replace(closingFence, "");
1802
- return cleaned.trim();
1803
- }
1804
- var globalInvocationCounter, StreamParser;
1805
- var init_parser = __esm({
1806
- "src/gadgets/parser.ts"() {
1807
- "use strict";
1808
- init_constants();
1809
- init_block_params();
1810
- globalInvocationCounter = 0;
1811
- StreamParser = class {
1812
- buffer = "";
1813
- lastReportedTextLength = 0;
1814
- startPrefix;
1815
- endPrefix;
1816
- argPrefix;
1817
- constructor(options = {}) {
1818
- this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;
1819
- this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;
1820
- this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;
1821
- }
1822
- takeTextUntil(index) {
1823
- if (index <= this.lastReportedTextLength) {
1824
- return void 0;
1825
- }
1826
- const segment = this.buffer.slice(this.lastReportedTextLength, index);
1827
- this.lastReportedTextLength = index;
1828
- return segment.trim().length > 0 ? segment : void 0;
1829
- }
1830
- /**
1831
- * Parse gadget name, handling both old format (name:invocationId) and new format (just name).
1832
- * For new format, generates a unique invocation ID.
1833
- */
1834
- parseGadgetName(gadgetName) {
1835
- if (gadgetName.includes(":")) {
1836
- const parts = gadgetName.split(":");
1837
- return { actualName: parts[0], invocationId: parts[1] };
1838
- }
1839
- return { actualName: gadgetName, invocationId: `gadget_${++globalInvocationCounter}` };
1840
- }
1841
- /**
1842
- * Truncate verbose parse errors to avoid context overflow.
1843
- * Keeps first meaningful line and limits total length.
1844
- */
1845
- truncateParseError(error, format) {
1846
- const message = error instanceof Error ? error.message : String(error);
1847
- const firstLine = message.split("\n")[0];
1848
- const maxLen = 200;
1849
- if (firstLine.length <= maxLen) {
1850
- return firstLine;
1851
- }
1852
- return `${firstLine.slice(0, maxLen)}... (${message.length} chars total)`;
1853
- }
1854
- /**
1855
- * Parse parameter string using block format
1856
- */
1857
- parseParameters(raw) {
1858
- const cleaned = stripMarkdownFences(raw);
1859
- try {
1860
- return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };
1861
- } catch (error) {
1862
- return { parseError: this.truncateParseError(error, "block") };
1863
- }
1864
- }
1865
- // Feed a chunk of text and get parsed events
1866
- *feed(chunk) {
1867
- this.buffer += chunk;
1868
- let startIndex = 0;
1869
- while (true) {
1870
- const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);
1871
- if (partStartIndex === -1) break;
1872
- const textBefore = this.takeTextUntil(partStartIndex);
1873
- if (textBefore !== void 0) {
1874
- yield { type: "text", content: textBefore };
1875
- }
1876
- const metadataStartIndex = partStartIndex + this.startPrefix.length;
1877
- const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
1878
- if (metadataEndIndex === -1) break;
1879
- const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
1880
- const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
1881
- const contentStartIndex = metadataEndIndex + 1;
1882
- let partEndIndex;
1883
- let endMarkerLength = 0;
1884
- if (gadgetName.includes(":")) {
1885
- const oldEndMarker = `${this.endPrefix + actualGadgetName}:${invocationId}`;
1886
- partEndIndex = this.buffer.indexOf(oldEndMarker, contentStartIndex);
1887
- if (partEndIndex === -1) break;
1888
- endMarkerLength = oldEndMarker.length;
1889
- } else {
1890
- const nextStartPos = this.buffer.indexOf(this.startPrefix, contentStartIndex);
1891
- let validEndPos = -1;
1892
- let searchPos = contentStartIndex;
1893
- while (true) {
1894
- const endPos = this.buffer.indexOf(this.endPrefix, searchPos);
1895
- if (endPos === -1) break;
1896
- const afterEnd = this.buffer.substring(endPos + this.endPrefix.length);
1897
- if (afterEnd.startsWith("\n") || afterEnd.startsWith("\r") || afterEnd.startsWith(this.startPrefix) || afterEnd.length === 0) {
1898
- validEndPos = endPos;
1899
- break;
1900
- } else {
1901
- searchPos = endPos + this.endPrefix.length;
2317
+ error: inputError instanceof Error ? inputError.message : String(inputError),
2318
+ executionTimeMs: Date.now() - startTime
2319
+ };
1902
2320
  }
1903
2321
  }
1904
- if (nextStartPos !== -1 && (validEndPos === -1 || nextStartPos < validEndPos)) {
1905
- partEndIndex = nextStartPos;
1906
- endMarkerLength = 0;
1907
- } else if (validEndPos !== -1) {
1908
- partEndIndex = validEndPos;
1909
- endMarkerLength = this.endPrefix.length;
1910
- } else {
1911
- break;
1912
- }
2322
+ this.logger.warn("Human input required but no callback provided", {
2323
+ gadgetName: call.gadgetName
2324
+ });
2325
+ return {
2326
+ gadgetName: call.gadgetName,
2327
+ invocationId: call.invocationId,
2328
+ parameters: validatedParameters,
2329
+ error: "Human input required but not available (stdin is not interactive)",
2330
+ executionTimeMs: Date.now() - startTime
2331
+ };
1913
2332
  }
1914
- const parametersRaw = this.buffer.substring(contentStartIndex, partEndIndex).trim();
1915
- const { parameters, parseError } = this.parseParameters(parametersRaw);
1916
- yield {
1917
- type: "gadget_call",
1918
- call: {
1919
- gadgetName: actualGadgetName,
1920
- invocationId,
1921
- parametersRaw,
1922
- parameters,
1923
- parseError
1924
- }
2333
+ const executionTimeMs = Date.now() - startTime;
2334
+ this.logger.error("Gadget execution failed", {
2335
+ gadgetName: call.gadgetName,
2336
+ error: error instanceof Error ? error.message : String(error),
2337
+ executionTimeMs
2338
+ });
2339
+ return {
2340
+ gadgetName: call.gadgetName,
2341
+ invocationId: call.invocationId,
2342
+ parameters: validatedParameters,
2343
+ error: error instanceof Error ? error.message : String(error),
2344
+ executionTimeMs
1925
2345
  };
1926
- startIndex = partEndIndex + endMarkerLength;
1927
- this.lastReportedTextLength = startIndex;
1928
- }
1929
- if (startIndex > 0) {
1930
- this.buffer = this.buffer.substring(startIndex);
1931
- this.lastReportedTextLength = 0;
1932
2346
  }
1933
2347
  }
1934
- // Finalize parsing and return remaining text or incomplete gadgets
1935
- *finalize() {
1936
- const startIndex = this.buffer.indexOf(this.startPrefix, this.lastReportedTextLength);
1937
- if (startIndex !== -1) {
1938
- const textBefore = this.takeTextUntil(startIndex);
1939
- if (textBefore !== void 0) {
1940
- yield { type: "text", content: textBefore };
1941
- }
1942
- const metadataStartIndex = startIndex + this.startPrefix.length;
1943
- const metadataEndIndex = this.buffer.indexOf("\n", metadataStartIndex);
1944
- if (metadataEndIndex !== -1) {
1945
- const gadgetName = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();
1946
- const { actualName: actualGadgetName, invocationId } = this.parseGadgetName(gadgetName);
1947
- const contentStartIndex = metadataEndIndex + 1;
1948
- const parametersRaw = this.buffer.substring(contentStartIndex).trim();
1949
- const { parameters, parseError } = this.parseParameters(parametersRaw);
1950
- yield {
1951
- type: "gadget_call",
1952
- call: {
1953
- gadgetName: actualGadgetName,
1954
- invocationId,
1955
- parametersRaw,
1956
- parameters,
1957
- parseError
1958
- }
1959
- };
1960
- return;
1961
- }
1962
- }
1963
- const remainingText = this.takeTextUntil(this.buffer.length);
1964
- if (remainingText !== void 0) {
1965
- yield { type: "text", content: remainingText };
1966
- }
2348
+ // Execute multiple gadget calls in parallel
2349
+ async executeAll(calls) {
2350
+ return Promise.all(calls.map((call) => this.execute(call)));
1967
2351
  }
1968
- // Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)
1969
- reset() {
1970
- this.buffer = "";
1971
- this.lastReportedTextLength = 0;
2352
+ /**
2353
+ * Deep equality check for objects/arrays.
2354
+ * Used to detect if parameters were modified by an interceptor.
2355
+ */
2356
+ deepEquals(a, b) {
2357
+ if (a === b) return true;
2358
+ if (a === null || b === null) return a === b;
2359
+ if (typeof a !== typeof b) return false;
2360
+ if (typeof a !== "object") return a === b;
2361
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
2362
+ if (Array.isArray(a) && Array.isArray(b)) {
2363
+ if (a.length !== b.length) return false;
2364
+ return a.every((val, i) => this.deepEquals(val, b[i]));
2365
+ }
2366
+ const aObj = a;
2367
+ const bObj = b;
2368
+ const aKeys = Object.keys(aObj);
2369
+ const bKeys = Object.keys(bObj);
2370
+ if (aKeys.length !== bKeys.length) return false;
2371
+ return aKeys.every((key) => this.deepEquals(aObj[key], bObj[key]));
1972
2372
  }
1973
2373
  };
1974
2374
  }
@@ -2011,7 +2411,8 @@ var init_stream_processor = __esm({
2011
2411
  options.registry,
2012
2412
  options.onHumanInputRequired,
2013
2413
  this.logger.getSubLogger({ name: "executor" }),
2014
- options.defaultGadgetTimeoutMs
2414
+ options.defaultGadgetTimeoutMs,
2415
+ { argPrefix: options.gadgetArgPrefix }
2015
2416
  );
2016
2417
  }
2017
2418
  /**
@@ -5460,7 +5861,8 @@ var CLI_DESCRIPTION = "Command line utilities for llmist agents and direct LLM a
5460
5861
  var COMMANDS = {
5461
5862
  complete: "complete",
5462
5863
  agent: "agent",
5463
- models: "models"
5864
+ models: "models",
5865
+ gadget: "gadget"
5464
5866
  };
5465
5867
  var LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
5466
5868
  var DEFAULT_MODEL = "openai:gpt-5-nano";
@@ -5504,7 +5906,7 @@ var import_commander2 = require("commander");
5504
5906
  // package.json
5505
5907
  var package_default = {
5506
5908
  name: "llmist",
5507
- version: "0.8.0",
5909
+ version: "1.1.0",
5508
5910
  description: "Universal TypeScript LLM client with streaming-first agent framework. Works with any model - no structured outputs or native tool calling required. Implements its own flexible grammar for function calling.",
5509
5911
  type: "module",
5510
5912
  main: "dist/index.cjs",
@@ -7491,8 +7893,439 @@ function resolveInheritance(config, configPath) {
7491
7893
  return resolved;
7492
7894
  }
7493
7895
 
7494
- // src/cli/models-command.ts
7896
+ // src/cli/gadget-command.ts
7897
+ var import_chalk5 = __toESM(require("chalk"), 1);
7898
+ init_schema_to_json();
7899
+ init_schema_validator();
7900
+
7901
+ // src/cli/gadget-prompts.ts
7902
+ var import_promises3 = require("readline/promises");
7495
7903
  var import_chalk4 = __toESM(require("chalk"), 1);
7904
+ init_schema_to_json();
7905
+ async function promptForParameters(schema, ctx) {
7906
+ if (!schema) {
7907
+ return {};
7908
+ }
7909
+ const jsonSchema = schemaToJSONSchema(schema, { target: "draft-7" });
7910
+ if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {
7911
+ return {};
7912
+ }
7913
+ const rl = (0, import_promises3.createInterface)({ input: ctx.stdin, output: ctx.stdout });
7914
+ const params = {};
7915
+ try {
7916
+ for (const [key, prop] of Object.entries(jsonSchema.properties)) {
7917
+ const value = await promptForField(rl, key, prop, jsonSchema.required ?? []);
7918
+ if (value !== void 0) {
7919
+ params[key] = value;
7920
+ }
7921
+ }
7922
+ } finally {
7923
+ rl.close();
7924
+ }
7925
+ const result = schema.safeParse(params);
7926
+ if (!result.success) {
7927
+ const issues = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
7928
+ throw new Error(`Invalid parameters:
7929
+ ${issues}`);
7930
+ }
7931
+ return result.data;
7932
+ }
7933
+ async function promptForField(rl, key, prop, required) {
7934
+ const isRequired = required.includes(key);
7935
+ const typeHint = formatTypeHint(prop);
7936
+ const defaultHint = prop.default !== void 0 ? import_chalk4.default.dim(` [default: ${JSON.stringify(prop.default)}]`) : "";
7937
+ const requiredMarker = isRequired ? import_chalk4.default.red("*") : "";
7938
+ let prompt = `
7939
+ ${import_chalk4.default.cyan.bold(key)}${requiredMarker}`;
7940
+ if (prop.description) {
7941
+ prompt += import_chalk4.default.dim(` - ${prop.description}`);
7942
+ }
7943
+ prompt += `
7944
+ ${typeHint}${defaultHint}
7945
+ ${import_chalk4.default.green(">")} `;
7946
+ const answer = await rl.question(prompt);
7947
+ const trimmed = answer.trim();
7948
+ if (!trimmed) {
7949
+ if (prop.default !== void 0) {
7950
+ return void 0;
7951
+ }
7952
+ if (!isRequired) {
7953
+ return void 0;
7954
+ }
7955
+ throw new Error(`Parameter '${key}' is required.`);
7956
+ }
7957
+ return parseValue(trimmed, prop, key);
7958
+ }
7959
+ function formatTypeHint(prop) {
7960
+ if (prop.enum) {
7961
+ return import_chalk4.default.yellow(`(${prop.enum.join(" | ")})`);
7962
+ }
7963
+ if (prop.type === "array") {
7964
+ const items = prop.items;
7965
+ if (items?.enum) {
7966
+ return import_chalk4.default.yellow(`(${items.enum.join(" | ")})[] comma-separated`);
7967
+ }
7968
+ const itemType = items?.type ?? "any";
7969
+ return import_chalk4.default.yellow(`(${itemType}[]) comma-separated`);
7970
+ }
7971
+ if (prop.type === "object" && prop.properties) {
7972
+ return import_chalk4.default.yellow("(object) enter as JSON");
7973
+ }
7974
+ return import_chalk4.default.yellow(`(${prop.type ?? "any"})`);
7975
+ }
7976
+ function parseValue(input, prop, key) {
7977
+ const type = prop.type;
7978
+ if (type === "number" || type === "integer") {
7979
+ const num = Number(input);
7980
+ if (Number.isNaN(num)) {
7981
+ throw new Error(`Invalid number for '${key}': ${input}`);
7982
+ }
7983
+ if (type === "integer" && !Number.isInteger(num)) {
7984
+ throw new Error(`Expected integer for '${key}', got: ${input}`);
7985
+ }
7986
+ return num;
7987
+ }
7988
+ if (type === "boolean") {
7989
+ const lower = input.toLowerCase();
7990
+ if (["true", "yes", "1", "y"].includes(lower)) return true;
7991
+ if (["false", "no", "0", "n"].includes(lower)) return false;
7992
+ throw new Error(`Invalid boolean for '${key}': ${input} (use true/false, yes/no, 1/0)`);
7993
+ }
7994
+ if (type === "array") {
7995
+ const items = input.split(",").map((s) => s.trim()).filter(Boolean);
7996
+ const itemType = prop.items?.type;
7997
+ if (itemType === "number" || itemType === "integer") {
7998
+ return items.map((item) => {
7999
+ const num = Number(item);
8000
+ if (Number.isNaN(num)) throw new Error(`Invalid number in '${key}' array: ${item}`);
8001
+ return num;
8002
+ });
8003
+ }
8004
+ if (itemType === "boolean") {
8005
+ return items.map((item) => {
8006
+ const lower = item.toLowerCase();
8007
+ if (["true", "yes", "1", "y"].includes(lower)) return true;
8008
+ if (["false", "no", "0", "n"].includes(lower)) return false;
8009
+ throw new Error(`Invalid boolean in '${key}' array: ${item}`);
8010
+ });
8011
+ }
8012
+ return items;
8013
+ }
8014
+ if (type === "object") {
8015
+ try {
8016
+ return JSON.parse(input);
8017
+ } catch {
8018
+ throw new Error(`Invalid JSON for '${key}': ${input}`);
8019
+ }
8020
+ }
8021
+ return input;
8022
+ }
8023
+ async function readStdinJson(stdin) {
8024
+ const chunks = [];
8025
+ for await (const chunk of stdin) {
8026
+ if (typeof chunk === "string") {
8027
+ chunks.push(chunk);
8028
+ } else {
8029
+ chunks.push(chunk.toString("utf8"));
8030
+ }
8031
+ }
8032
+ const content = chunks.join("").trim();
8033
+ if (!content) {
8034
+ return {};
8035
+ }
8036
+ try {
8037
+ const parsed = JSON.parse(content);
8038
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
8039
+ throw new Error("Stdin must contain a JSON object, not an array or primitive.");
8040
+ }
8041
+ return parsed;
8042
+ } catch (error) {
8043
+ if (error instanceof SyntaxError) {
8044
+ throw new Error(`Invalid JSON from stdin: ${error.message}`);
8045
+ }
8046
+ throw error;
8047
+ }
8048
+ }
8049
+
8050
+ // src/cli/gadget-command.ts
8051
+ async function selectGadget(file, nameOption, cwd) {
8052
+ const gadgets = await loadGadgets([file], cwd);
8053
+ if (gadgets.length === 0) {
8054
+ throw new Error(
8055
+ `No gadgets found in '${file}'.
8056
+ Ensure the file exports a Gadget class or instance.`
8057
+ );
8058
+ }
8059
+ if (gadgets.length === 1) {
8060
+ const gadget = gadgets[0];
8061
+ const name = gadget.name ?? gadget.constructor.name;
8062
+ return { gadget, name };
8063
+ }
8064
+ const names = gadgets.map((g) => g.name ?? g.constructor.name);
8065
+ if (!nameOption) {
8066
+ throw new Error(
8067
+ `File '${file}' exports ${gadgets.length} gadgets.
8068
+ Use --name to select one:
8069
+ ` + names.map((n) => ` - ${n}`).join("\n")
8070
+ );
8071
+ }
8072
+ const found = gadgets.find((g) => (g.name ?? g.constructor.name) === nameOption);
8073
+ if (!found) {
8074
+ throw new Error(
8075
+ `Gadget '${nameOption}' not found in '${file}'.
8076
+ Available gadgets:
8077
+ ` + names.map((n) => ` - ${n}`).join("\n")
8078
+ );
8079
+ }
8080
+ return { gadget: found, name: nameOption };
8081
+ }
8082
+ async function executeGadgetRun(file, options, env) {
8083
+ const cwd = process.cwd();
8084
+ const { gadget, name } = await selectGadget(file, options.name, cwd);
8085
+ env.stderr.write(import_chalk5.default.cyan.bold(`
8086
+ \u{1F527} Running gadget: ${name}
8087
+ `));
8088
+ let params;
8089
+ if (env.isTTY) {
8090
+ params = await promptForParameters(gadget.parameterSchema, {
8091
+ stdin: env.stdin,
8092
+ stdout: env.stderr
8093
+ // Prompts go to stderr to keep stdout clean
8094
+ });
8095
+ } else {
8096
+ env.stderr.write(import_chalk5.default.dim("Reading parameters from stdin...\n"));
8097
+ const stdinParams = await readStdinJson(env.stdin);
8098
+ if (gadget.parameterSchema) {
8099
+ const result2 = gadget.parameterSchema.safeParse(stdinParams);
8100
+ if (!result2.success) {
8101
+ const issues = result2.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
8102
+ throw new Error(`Invalid parameters:
8103
+ ${issues}`);
8104
+ }
8105
+ params = result2.data;
8106
+ } else {
8107
+ params = stdinParams;
8108
+ }
8109
+ }
8110
+ env.stderr.write(import_chalk5.default.dim("\nExecuting...\n"));
8111
+ const startTime = Date.now();
8112
+ let result;
8113
+ try {
8114
+ if (gadget.timeoutMs && gadget.timeoutMs > 0) {
8115
+ result = await Promise.race([
8116
+ Promise.resolve(gadget.execute(params)),
8117
+ new Promise(
8118
+ (_, reject) => setTimeout(
8119
+ () => reject(new Error(`Gadget timed out after ${gadget.timeoutMs}ms`)),
8120
+ gadget.timeoutMs
8121
+ )
8122
+ )
8123
+ ]);
8124
+ } else {
8125
+ result = await Promise.resolve(gadget.execute(params));
8126
+ }
8127
+ } catch (error) {
8128
+ const message = error instanceof Error ? error.message : String(error);
8129
+ throw new Error(`Execution failed: ${message}`);
8130
+ }
8131
+ const elapsed = Date.now() - startTime;
8132
+ env.stderr.write(import_chalk5.default.green(`
8133
+ \u2713 Completed in ${elapsed}ms
8134
+
8135
+ `));
8136
+ formatOutput(result, options, env.stdout);
8137
+ }
8138
+ function formatOutput(result, options, stdout) {
8139
+ if (options.raw) {
8140
+ stdout.write(result);
8141
+ if (!result.endsWith("\n")) stdout.write("\n");
8142
+ return;
8143
+ }
8144
+ if (options.json || looksLikeJson(result)) {
8145
+ try {
8146
+ const parsed = JSON.parse(result);
8147
+ stdout.write(JSON.stringify(parsed, null, 2) + "\n");
8148
+ return;
8149
+ } catch {
8150
+ }
8151
+ }
8152
+ stdout.write(result);
8153
+ if (!result.endsWith("\n")) stdout.write("\n");
8154
+ }
8155
+ function looksLikeJson(str) {
8156
+ const trimmed = str.trim();
8157
+ return trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
8158
+ }
8159
+ async function executeGadgetInfo(file, options, env) {
8160
+ const cwd = process.cwd();
8161
+ const { gadget, name } = await selectGadget(file, options.name, cwd);
8162
+ if (options.json) {
8163
+ const info = buildGadgetInfo(gadget, name);
8164
+ env.stdout.write(JSON.stringify(info, null, 2) + "\n");
8165
+ return;
8166
+ }
8167
+ env.stdout.write("\n");
8168
+ env.stdout.write(import_chalk5.default.cyan.bold(`${name}
8169
+ `));
8170
+ env.stdout.write(import_chalk5.default.cyan("\u2550".repeat(name.length)) + "\n\n");
8171
+ env.stdout.write(import_chalk5.default.bold("Description:\n"));
8172
+ env.stdout.write(` ${gadget.description}
8173
+
8174
+ `);
8175
+ if (gadget.parameterSchema) {
8176
+ env.stdout.write(import_chalk5.default.bold("Parameters:\n"));
8177
+ const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
8178
+ env.stdout.write(formatSchemaAsText(jsonSchema, " ") + "\n\n");
8179
+ } else {
8180
+ env.stdout.write(import_chalk5.default.dim("No parameters required.\n\n"));
8181
+ }
8182
+ if (gadget.timeoutMs) {
8183
+ env.stdout.write(import_chalk5.default.bold("Timeout:\n"));
8184
+ env.stdout.write(` ${gadget.timeoutMs}ms
8185
+
8186
+ `);
8187
+ }
8188
+ if (gadget.examples && gadget.examples.length > 0) {
8189
+ env.stdout.write(import_chalk5.default.bold("Examples:\n"));
8190
+ for (const example of gadget.examples) {
8191
+ if (example.comment) {
8192
+ env.stdout.write(import_chalk5.default.dim(` # ${example.comment}
8193
+ `));
8194
+ }
8195
+ env.stdout.write(` Input: ${import_chalk5.default.cyan(JSON.stringify(example.params))}
8196
+ `);
8197
+ if (example.output !== void 0) {
8198
+ env.stdout.write(` Output: ${import_chalk5.default.green(example.output)}
8199
+ `);
8200
+ }
8201
+ env.stdout.write("\n");
8202
+ }
8203
+ }
8204
+ }
8205
+ function buildGadgetInfo(gadget, name) {
8206
+ const info = {
8207
+ name,
8208
+ description: gadget.description
8209
+ };
8210
+ if (gadget.parameterSchema) {
8211
+ info.schema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
8212
+ }
8213
+ if (gadget.timeoutMs) {
8214
+ info.timeoutMs = gadget.timeoutMs;
8215
+ }
8216
+ if (gadget.examples && gadget.examples.length > 0) {
8217
+ info.examples = gadget.examples;
8218
+ }
8219
+ return info;
8220
+ }
8221
+ function formatSchemaAsText(schema, indent = "") {
8222
+ const lines = [];
8223
+ const properties = schema.properties || {};
8224
+ const required = schema.required || [];
8225
+ for (const [key, prop] of Object.entries(properties)) {
8226
+ const type = prop.type;
8227
+ const description = prop.description;
8228
+ const isRequired = required.includes(key);
8229
+ const enumValues = prop.enum;
8230
+ const defaultValue = prop.default;
8231
+ let line = `${indent}${import_chalk5.default.cyan(key)}`;
8232
+ if (isRequired) {
8233
+ line += import_chalk5.default.red("*");
8234
+ }
8235
+ if (type === "array") {
8236
+ const items = prop.items;
8237
+ const itemType = items?.type || "any";
8238
+ line += import_chalk5.default.dim(` (${itemType}[])`);
8239
+ } else if (type === "object" && prop.properties) {
8240
+ line += import_chalk5.default.dim(" (object)");
8241
+ } else {
8242
+ line += import_chalk5.default.dim(` (${type})`);
8243
+ }
8244
+ if (defaultValue !== void 0) {
8245
+ line += import_chalk5.default.dim(` [default: ${JSON.stringify(defaultValue)}]`);
8246
+ }
8247
+ if (description) {
8248
+ line += `: ${description}`;
8249
+ }
8250
+ if (enumValues) {
8251
+ line += import_chalk5.default.yellow(` - one of: ${enumValues.join(", ")}`);
8252
+ }
8253
+ lines.push(line);
8254
+ if (type === "object" && prop.properties) {
8255
+ lines.push(formatSchemaAsText(prop, indent + " "));
8256
+ }
8257
+ }
8258
+ return lines.join("\n");
8259
+ }
8260
+ async function executeGadgetValidate(file, env) {
8261
+ const cwd = process.cwd();
8262
+ try {
8263
+ const gadgets = await loadGadgets([file], cwd);
8264
+ if (gadgets.length === 0) {
8265
+ throw new Error(
8266
+ "No gadgets exported from file.\nA valid gadget must have:\n - execute() method\n - description property\n - parameterSchema (optional)"
8267
+ );
8268
+ }
8269
+ const issues = [];
8270
+ for (const gadget of gadgets) {
8271
+ const name = gadget.name ?? gadget.constructor.name;
8272
+ if (!gadget.description) {
8273
+ issues.push(`${name}: Missing 'description' property.`);
8274
+ }
8275
+ if (gadget.parameterSchema) {
8276
+ try {
8277
+ validateGadgetSchema(gadget.parameterSchema, name);
8278
+ } catch (schemaError) {
8279
+ const message = schemaError instanceof Error ? schemaError.message : String(schemaError);
8280
+ issues.push(`${name}: ${message}`);
8281
+ }
8282
+ }
8283
+ if (typeof gadget.execute !== "function") {
8284
+ issues.push(`${name}: Missing 'execute()' method.`);
8285
+ }
8286
+ }
8287
+ if (issues.length > 0) {
8288
+ throw new Error(`Validation issues:
8289
+ ${issues.map((i) => ` - ${i}`).join("\n")}`);
8290
+ }
8291
+ env.stdout.write(import_chalk5.default.green.bold("\n\u2713 Valid\n\n"));
8292
+ env.stdout.write(import_chalk5.default.bold("Gadgets found:\n"));
8293
+ for (const gadget of gadgets) {
8294
+ const name = gadget.name ?? gadget.constructor.name;
8295
+ const schemaInfo = gadget.parameterSchema ? import_chalk5.default.cyan("(with schema)") : import_chalk5.default.dim("(no schema)");
8296
+ env.stdout.write(` ${import_chalk5.default.bold(name)} ${schemaInfo}
8297
+ `);
8298
+ env.stdout.write(import_chalk5.default.dim(` ${gadget.description}
8299
+ `));
8300
+ }
8301
+ env.stdout.write("\n");
8302
+ } catch (error) {
8303
+ const message = error instanceof Error ? error.message : String(error);
8304
+ env.stdout.write(import_chalk5.default.red.bold(`
8305
+ \u2717 Invalid
8306
+
8307
+ `));
8308
+ env.stdout.write(`${message}
8309
+
8310
+ `);
8311
+ env.setExitCode(1);
8312
+ }
8313
+ }
8314
+ function registerGadgetCommand(program, env) {
8315
+ const gadgetCmd = program.command("gadget").description("Test and inspect gadgets outside the agent loop.");
8316
+ gadgetCmd.command("run <file>").description("Execute a gadget with interactive prompts or stdin JSON.").option("--name <gadget>", "Select gadget by name (required if file exports multiple)").option("--json", "Format output as pretty-printed JSON").option("--raw", "Output result as raw string without formatting").action(
8317
+ (file, options) => executeAction(() => executeGadgetRun(file, options, env), env)
8318
+ );
8319
+ gadgetCmd.command("info <file>").description("Display gadget description, schema, and examples.").option("--name <gadget>", "Select gadget by name (required if file exports multiple)").option("--json", "Output as JSON instead of formatted text").action(
8320
+ (file, options) => executeAction(() => executeGadgetInfo(file, options, env), env)
8321
+ );
8322
+ gadgetCmd.command("validate <file>").description("Check if file exports valid gadget(s).").action(
8323
+ (file) => executeAction(() => executeGadgetValidate(file, env), env)
8324
+ );
8325
+ }
8326
+
8327
+ // src/cli/models-command.ts
8328
+ var import_chalk6 = __toESM(require("chalk"), 1);
7496
8329
  init_model_shortcuts();
7497
8330
  async function handleModelsCommand(options, env) {
7498
8331
  const client = env.createClient();
@@ -7512,13 +8345,13 @@ function renderTable(models, verbose, stream2) {
7512
8345
  }
7513
8346
  grouped.get(provider).push(model);
7514
8347
  }
7515
- stream2.write(import_chalk4.default.bold.cyan("\nAvailable Models\n"));
7516
- stream2.write(import_chalk4.default.cyan("=".repeat(80)) + "\n\n");
8348
+ stream2.write(import_chalk6.default.bold.cyan("\nAvailable Models\n"));
8349
+ stream2.write(import_chalk6.default.cyan("=".repeat(80)) + "\n\n");
7517
8350
  const providers = Array.from(grouped.keys()).sort();
7518
8351
  for (const provider of providers) {
7519
8352
  const providerModels = grouped.get(provider);
7520
8353
  const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
7521
- stream2.write(import_chalk4.default.bold.yellow(`${providerName} Models
8354
+ stream2.write(import_chalk6.default.bold.yellow(`${providerName} Models
7522
8355
  `));
7523
8356
  if (verbose) {
7524
8357
  renderVerboseTable(providerModels, stream2);
@@ -7527,11 +8360,11 @@ function renderTable(models, verbose, stream2) {
7527
8360
  }
7528
8361
  stream2.write("\n");
7529
8362
  }
7530
- stream2.write(import_chalk4.default.bold.magenta("Model Shortcuts\n"));
7531
- stream2.write(import_chalk4.default.dim("\u2500".repeat(80)) + "\n");
8363
+ stream2.write(import_chalk6.default.bold.magenta("Model Shortcuts\n"));
8364
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(80)) + "\n");
7532
8365
  const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));
7533
8366
  for (const [shortcut, fullName] of shortcuts) {
7534
- stream2.write(import_chalk4.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk4.default.dim(" \u2192 ") + import_chalk4.default.white(fullName) + "\n");
8367
+ stream2.write(import_chalk6.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk6.default.dim(" \u2192 ") + import_chalk6.default.white(fullName) + "\n");
7535
8368
  }
7536
8369
  stream2.write("\n");
7537
8370
  }
@@ -7541,45 +8374,45 @@ function renderCompactTable(models, stream2) {
7541
8374
  const contextWidth = 13;
7542
8375
  const inputWidth = 10;
7543
8376
  const outputWidth = 10;
7544
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8377
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7545
8378
  stream2.write(
7546
- import_chalk4.default.bold(
8379
+ import_chalk6.default.bold(
7547
8380
  "Model ID".padEnd(idWidth) + " " + "Display Name".padEnd(nameWidth) + " " + "Context".padEnd(contextWidth) + " " + "Input".padEnd(inputWidth) + " " + "Output".padEnd(outputWidth)
7548
8381
  ) + "\n"
7549
8382
  );
7550
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8383
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7551
8384
  for (const model of models) {
7552
8385
  const contextFormatted = formatTokens2(model.contextWindow);
7553
8386
  const inputPrice = `$${model.pricing.input.toFixed(2)}`;
7554
8387
  const outputPrice = `$${model.pricing.output.toFixed(2)}`;
7555
8388
  stream2.write(
7556
- import_chalk4.default.green(model.modelId.padEnd(idWidth)) + " " + import_chalk4.default.white(model.displayName.padEnd(nameWidth)) + " " + import_chalk4.default.yellow(contextFormatted.padEnd(contextWidth)) + " " + import_chalk4.default.cyan(inputPrice.padEnd(inputWidth)) + " " + import_chalk4.default.cyan(outputPrice.padEnd(outputWidth)) + "\n"
8389
+ import_chalk6.default.green(model.modelId.padEnd(idWidth)) + " " + import_chalk6.default.white(model.displayName.padEnd(nameWidth)) + " " + import_chalk6.default.yellow(contextFormatted.padEnd(contextWidth)) + " " + import_chalk6.default.cyan(inputPrice.padEnd(inputWidth)) + " " + import_chalk6.default.cyan(outputPrice.padEnd(outputWidth)) + "\n"
7557
8390
  );
7558
8391
  }
7559
- stream2.write(import_chalk4.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
7560
- stream2.write(import_chalk4.default.dim(` * Prices are per 1M tokens
8392
+ stream2.write(import_chalk6.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
8393
+ stream2.write(import_chalk6.default.dim(` * Prices are per 1M tokens
7561
8394
  `));
7562
8395
  }
7563
8396
  function renderVerboseTable(models, stream2) {
7564
8397
  for (const model of models) {
7565
- stream2.write(import_chalk4.default.bold.green(`
8398
+ stream2.write(import_chalk6.default.bold.green(`
7566
8399
  ${model.modelId}
7567
8400
  `));
7568
- stream2.write(import_chalk4.default.dim(" " + "\u2500".repeat(60)) + "\n");
7569
- stream2.write(` ${import_chalk4.default.dim("Name:")} ${import_chalk4.default.white(model.displayName)}
8401
+ stream2.write(import_chalk6.default.dim(" " + "\u2500".repeat(60)) + "\n");
8402
+ stream2.write(` ${import_chalk6.default.dim("Name:")} ${import_chalk6.default.white(model.displayName)}
7570
8403
  `);
7571
- stream2.write(` ${import_chalk4.default.dim("Context:")} ${import_chalk4.default.yellow(formatTokens2(model.contextWindow))}
8404
+ stream2.write(` ${import_chalk6.default.dim("Context:")} ${import_chalk6.default.yellow(formatTokens2(model.contextWindow))}
7572
8405
  `);
7573
- stream2.write(` ${import_chalk4.default.dim("Max Output:")} ${import_chalk4.default.yellow(formatTokens2(model.maxOutputTokens))}
8406
+ stream2.write(` ${import_chalk6.default.dim("Max Output:")} ${import_chalk6.default.yellow(formatTokens2(model.maxOutputTokens))}
7574
8407
  `);
7575
- stream2.write(` ${import_chalk4.default.dim("Pricing:")} ${import_chalk4.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk4.default.dim("/")} ${import_chalk4.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk4.default.dim("(per 1M tokens)")}
8408
+ stream2.write(` ${import_chalk6.default.dim("Pricing:")} ${import_chalk6.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk6.default.dim("/")} ${import_chalk6.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk6.default.dim("(per 1M tokens)")}
7576
8409
  `);
7577
8410
  if (model.pricing.cachedInput !== void 0) {
7578
- stream2.write(` ${import_chalk4.default.dim("Cached Input:")} ${import_chalk4.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
8411
+ stream2.write(` ${import_chalk6.default.dim("Cached Input:")} ${import_chalk6.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
7579
8412
  `);
7580
8413
  }
7581
8414
  if (model.knowledgeCutoff) {
7582
- stream2.write(` ${import_chalk4.default.dim("Knowledge:")} ${model.knowledgeCutoff}
8415
+ stream2.write(` ${import_chalk6.default.dim("Knowledge:")} ${model.knowledgeCutoff}
7583
8416
  `);
7584
8417
  }
7585
8418
  const features = [];
@@ -7590,20 +8423,20 @@ function renderVerboseTable(models, stream2) {
7590
8423
  if (model.features.structuredOutputs) features.push("structured-outputs");
7591
8424
  if (model.features.fineTuning) features.push("fine-tuning");
7592
8425
  if (features.length > 0) {
7593
- stream2.write(` ${import_chalk4.default.dim("Features:")} ${import_chalk4.default.blue(features.join(", "))}
8426
+ stream2.write(` ${import_chalk6.default.dim("Features:")} ${import_chalk6.default.blue(features.join(", "))}
7594
8427
  `);
7595
8428
  }
7596
8429
  if (model.metadata) {
7597
8430
  if (model.metadata.family) {
7598
- stream2.write(` ${import_chalk4.default.dim("Family:")} ${model.metadata.family}
8431
+ stream2.write(` ${import_chalk6.default.dim("Family:")} ${model.metadata.family}
7599
8432
  `);
7600
8433
  }
7601
8434
  if (model.metadata.releaseDate) {
7602
- stream2.write(` ${import_chalk4.default.dim("Released:")} ${model.metadata.releaseDate}
8435
+ stream2.write(` ${import_chalk6.default.dim("Released:")} ${model.metadata.releaseDate}
7603
8436
  `);
7604
8437
  }
7605
8438
  if (model.metadata.notes) {
7606
- stream2.write(` ${import_chalk4.default.dim("Notes:")} ${import_chalk4.default.italic(model.metadata.notes)}
8439
+ stream2.write(` ${import_chalk6.default.dim("Notes:")} ${import_chalk6.default.italic(model.metadata.notes)}
7607
8440
  `);
7608
8441
  }
7609
8442
  }
@@ -7653,7 +8486,7 @@ function registerModelsCommand(program, env) {
7653
8486
 
7654
8487
  // src/cli/environment.ts
7655
8488
  var import_node_readline = __toESM(require("readline"), 1);
7656
- var import_chalk5 = __toESM(require("chalk"), 1);
8489
+ var import_chalk7 = __toESM(require("chalk"), 1);
7657
8490
  init_client();
7658
8491
  init_logger();
7659
8492
  var LOG_LEVEL_MAP = {
@@ -7702,14 +8535,14 @@ function createPromptFunction(stdin, stdout) {
7702
8535
  output: stdout
7703
8536
  });
7704
8537
  stdout.write("\n");
7705
- stdout.write(`${import_chalk5.default.cyan("\u2500".repeat(60))}
8538
+ stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
7706
8539
  `);
7707
- stdout.write(import_chalk5.default.cyan.bold("\u{1F916} Agent asks:\n"));
8540
+ stdout.write(import_chalk7.default.cyan.bold("\u{1F916} Agent asks:\n"));
7708
8541
  stdout.write(`${question}
7709
8542
  `);
7710
- stdout.write(`${import_chalk5.default.cyan("\u2500".repeat(60))}
8543
+ stdout.write(`${import_chalk7.default.cyan("\u2500".repeat(60))}
7711
8544
  `);
7712
- rl.question(import_chalk5.default.green.bold("You: "), (answer) => {
8545
+ rl.question(import_chalk7.default.green.bold("You: "), (answer) => {
7713
8546
  rl.close();
7714
8547
  resolve(answer);
7715
8548
  });
@@ -7799,6 +8632,7 @@ function createProgram(env, config) {
7799
8632
  registerCompleteCommand(program, env, config?.complete);
7800
8633
  registerAgentCommand(program, env, config?.agent);
7801
8634
  registerModelsCommand(program, env);
8635
+ registerGadgetCommand(program, env);
7802
8636
  if (config) {
7803
8637
  const customNames = getCustomCommandNames(config);
7804
8638
  for (const name of customNames) {