llmist 2.6.0 → 3.1.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/README.md +10 -1
- package/dist/{chunk-364PEMVT.js → chunk-JCFPJMRQ.js} +754 -218
- package/dist/chunk-JCFPJMRQ.js.map +1 -0
- package/dist/{chunk-4IHLIYW5.js → chunk-LFI4WQVV.js} +6 -6
- package/dist/chunk-LFI4WQVV.js.map +1 -0
- package/dist/cli.cjs +1458 -279
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +702 -58
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +763 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +139 -54
- package/dist/index.d.ts +139 -54
- package/dist/index.js +20 -18
- package/dist/{mock-stream-Jgg5u6Uf.d.cts → mock-stream-CTLm00_q.d.cts} +344 -56
- package/dist/{mock-stream-Jgg5u6Uf.d.ts → mock-stream-CTLm00_q.d.ts} +344 -56
- package/dist/testing/index.cjs +745 -210
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +6 -6
- package/dist/testing/index.d.ts +6 -6
- package/dist/testing/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-364PEMVT.js.map +0 -1
- package/dist/chunk-4IHLIYW5.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-LFI4WQVV.js";
|
|
3
3
|
import {
|
|
4
|
+
AbstractGadget,
|
|
4
5
|
AgentBuilder,
|
|
5
|
-
BaseGadget,
|
|
6
|
-
BreakLoopException,
|
|
7
6
|
FALLBACK_CHARS_PER_TOKEN,
|
|
8
7
|
GadgetRegistry,
|
|
9
|
-
|
|
8
|
+
HumanInputRequiredException,
|
|
10
9
|
LLMMessageBuilder,
|
|
11
10
|
LLMist,
|
|
12
11
|
MODEL_ALIASES,
|
|
12
|
+
TaskCompletionSignal,
|
|
13
13
|
audioFromBuffer,
|
|
14
14
|
createGadget,
|
|
15
15
|
createLogger,
|
|
16
16
|
detectAudioMimeType,
|
|
17
17
|
detectImageMimeType,
|
|
18
|
-
|
|
18
|
+
extractMessageText,
|
|
19
19
|
imageFromBuffer,
|
|
20
20
|
init_builder,
|
|
21
21
|
init_client,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
schemaToJSONSchema,
|
|
35
35
|
text,
|
|
36
36
|
validateGadgetSchema
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-JCFPJMRQ.js";
|
|
38
38
|
|
|
39
39
|
// src/cli/constants.ts
|
|
40
40
|
var CLI_NAME = "llmist";
|
|
@@ -46,7 +46,8 @@ var COMMANDS = {
|
|
|
46
46
|
gadget: "gadget",
|
|
47
47
|
image: "image",
|
|
48
48
|
speech: "speech",
|
|
49
|
-
vision: "vision"
|
|
49
|
+
vision: "vision",
|
|
50
|
+
init: "init"
|
|
50
51
|
};
|
|
51
52
|
var LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
52
53
|
var DEFAULT_MODEL = "openai:gpt-5-nano";
|
|
@@ -122,7 +123,7 @@ import { Command, InvalidArgumentError as InvalidArgumentError2 } from "commande
|
|
|
122
123
|
// package.json
|
|
123
124
|
var package_default = {
|
|
124
125
|
name: "llmist",
|
|
125
|
-
version: "
|
|
126
|
+
version: "3.0.0",
|
|
126
127
|
description: "TypeScript LLM client with streaming tool execution. Tools fire mid-stream. Built-in function calling works with any model\u2014no structured outputs or native tool support required.",
|
|
127
128
|
type: "module",
|
|
128
129
|
main: "dist/index.cjs",
|
|
@@ -530,7 +531,7 @@ var askUser = createGadget({
|
|
|
530
531
|
}
|
|
531
532
|
],
|
|
532
533
|
execute: ({ question }) => {
|
|
533
|
-
throw new
|
|
534
|
+
throw new HumanInputRequiredException(question);
|
|
534
535
|
}
|
|
535
536
|
});
|
|
536
537
|
var tellUser = createGadget({
|
|
@@ -580,11 +581,59 @@ var finish = createGadget({
|
|
|
580
581
|
}
|
|
581
582
|
],
|
|
582
583
|
execute: () => {
|
|
583
|
-
throw new
|
|
584
|
+
throw new TaskCompletionSignal("Task completed");
|
|
584
585
|
}
|
|
585
586
|
});
|
|
586
587
|
var builtinGadgets = [askUser, tellUser, finish];
|
|
587
588
|
|
|
589
|
+
// src/cli/subagent-config.ts
|
|
590
|
+
var INHERIT_MODEL = "inherit";
|
|
591
|
+
function resolveSubagentConfig(subagentName, parentModel, profileConfig, globalConfig) {
|
|
592
|
+
const resolved = {};
|
|
593
|
+
const globalDefaultModel = globalConfig?.["default-model"];
|
|
594
|
+
const globalSubagent = extractSubagentConfig(globalConfig, subagentName);
|
|
595
|
+
const profileSubagent = profileConfig?.[subagentName] ?? {};
|
|
596
|
+
const merged = { ...globalSubagent, ...profileSubagent };
|
|
597
|
+
const configModel = merged.model ?? globalDefaultModel ?? INHERIT_MODEL;
|
|
598
|
+
resolved.model = configModel === INHERIT_MODEL ? parentModel : configModel;
|
|
599
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
600
|
+
if (key !== "model") {
|
|
601
|
+
resolved[key] = value;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return resolved;
|
|
605
|
+
}
|
|
606
|
+
function buildSubagentConfigMap(parentModel, profileConfig, globalConfig) {
|
|
607
|
+
const subagentNames = /* @__PURE__ */ new Set();
|
|
608
|
+
if (globalConfig) {
|
|
609
|
+
for (const key of Object.keys(globalConfig)) {
|
|
610
|
+
if (key !== "default-model" && typeof globalConfig[key] === "object") {
|
|
611
|
+
subagentNames.add(key);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (profileConfig) {
|
|
616
|
+
for (const key of Object.keys(profileConfig)) {
|
|
617
|
+
subagentNames.add(key);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
const result = {};
|
|
621
|
+
for (const name of subagentNames) {
|
|
622
|
+
result[name] = resolveSubagentConfig(name, parentModel, profileConfig, globalConfig);
|
|
623
|
+
}
|
|
624
|
+
return result;
|
|
625
|
+
}
|
|
626
|
+
function extractSubagentConfig(globalConfig, subagentName) {
|
|
627
|
+
if (!globalConfig) {
|
|
628
|
+
return {};
|
|
629
|
+
}
|
|
630
|
+
const value = globalConfig[subagentName];
|
|
631
|
+
if (typeof value === "object" && value !== null) {
|
|
632
|
+
return value;
|
|
633
|
+
}
|
|
634
|
+
return {};
|
|
635
|
+
}
|
|
636
|
+
|
|
588
637
|
// src/cli/config.ts
|
|
589
638
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
590
639
|
import { homedir } from "node:os";
|
|
@@ -673,7 +722,7 @@ function hasTemplateSyntax(str) {
|
|
|
673
722
|
}
|
|
674
723
|
|
|
675
724
|
// src/cli/config.ts
|
|
676
|
-
var
|
|
725
|
+
var VALID_PERMISSION_LEVELS = ["allowed", "denied", "approval-required"];
|
|
677
726
|
var GLOBAL_CONFIG_KEYS = /* @__PURE__ */ new Set(["log-level", "log-file", "log-reset"]);
|
|
678
727
|
var VALID_LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
679
728
|
var COMPLETE_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -713,6 +762,8 @@ var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
713
762
|
"gadget-end-prefix",
|
|
714
763
|
"gadget-arg-prefix",
|
|
715
764
|
"gadget-approval",
|
|
765
|
+
"subagents",
|
|
766
|
+
// Per-subagent configuration overrides
|
|
716
767
|
"quiet",
|
|
717
768
|
"inherits",
|
|
718
769
|
"log-level",
|
|
@@ -738,9 +789,9 @@ function getConfigPath() {
|
|
|
738
789
|
return join(homedir(), ".llmist", "cli.toml");
|
|
739
790
|
}
|
|
740
791
|
var ConfigError = class extends Error {
|
|
741
|
-
constructor(message,
|
|
742
|
-
super(
|
|
743
|
-
this.path =
|
|
792
|
+
constructor(message, path6) {
|
|
793
|
+
super(path6 ? `${path6}: ${message}` : message);
|
|
794
|
+
this.path = path6;
|
|
744
795
|
this.name = "ConfigError";
|
|
745
796
|
}
|
|
746
797
|
};
|
|
@@ -796,6 +847,63 @@ function validateInherits(value, section) {
|
|
|
796
847
|
}
|
|
797
848
|
throw new ConfigError(`[${section}].inherits must be a string or array of strings`);
|
|
798
849
|
}
|
|
850
|
+
function validateSingleSubagentConfig(value, subagentName, section) {
|
|
851
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
852
|
+
throw new ConfigError(
|
|
853
|
+
`[${section}].${subagentName} must be a table (e.g., { model = "inherit", maxIterations = 20 })`
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
const result = {};
|
|
857
|
+
const rawObj = value;
|
|
858
|
+
for (const [key, val] of Object.entries(rawObj)) {
|
|
859
|
+
if (key === "model") {
|
|
860
|
+
if (typeof val !== "string") {
|
|
861
|
+
throw new ConfigError(`[${section}].${subagentName}.model must be a string`);
|
|
862
|
+
}
|
|
863
|
+
result.model = val;
|
|
864
|
+
} else if (key === "maxIterations") {
|
|
865
|
+
if (typeof val !== "number" || !Number.isInteger(val) || val < 1) {
|
|
866
|
+
throw new ConfigError(
|
|
867
|
+
`[${section}].${subagentName}.maxIterations must be a positive integer`
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
result.maxIterations = val;
|
|
871
|
+
} else {
|
|
872
|
+
result[key] = val;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return result;
|
|
876
|
+
}
|
|
877
|
+
function validateSubagentConfigMap(value, section) {
|
|
878
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
879
|
+
throw new ConfigError(
|
|
880
|
+
`[${section}].subagents must be a table (e.g., { BrowseWeb = { model = "inherit" } })`
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
const result = {};
|
|
884
|
+
for (const [subagentName, config] of Object.entries(value)) {
|
|
885
|
+
result[subagentName] = validateSingleSubagentConfig(config, subagentName, `${section}.subagents`);
|
|
886
|
+
}
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
function validateGlobalSubagentConfig(value, section) {
|
|
890
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
891
|
+
throw new ConfigError(`[${section}] must be a table`);
|
|
892
|
+
}
|
|
893
|
+
const result = {};
|
|
894
|
+
const rawObj = value;
|
|
895
|
+
for (const [key, val] of Object.entries(rawObj)) {
|
|
896
|
+
if (key === "default-model") {
|
|
897
|
+
if (typeof val !== "string") {
|
|
898
|
+
throw new ConfigError(`[${section}].default-model must be a string`);
|
|
899
|
+
}
|
|
900
|
+
result["default-model"] = val;
|
|
901
|
+
} else {
|
|
902
|
+
result[key] = validateSingleSubagentConfig(val, key, section);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return result;
|
|
906
|
+
}
|
|
799
907
|
function validateGadgetApproval(value, section) {
|
|
800
908
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
801
909
|
throw new ConfigError(
|
|
@@ -807,9 +915,9 @@ function validateGadgetApproval(value, section) {
|
|
|
807
915
|
if (typeof mode !== "string") {
|
|
808
916
|
throw new ConfigError(`[${section}].gadget-approval.${gadgetName} must be a string`);
|
|
809
917
|
}
|
|
810
|
-
if (!
|
|
918
|
+
if (!VALID_PERMISSION_LEVELS.includes(mode)) {
|
|
811
919
|
throw new ConfigError(
|
|
812
|
-
`[${section}].gadget-approval.${gadgetName} must be one of: ${
|
|
920
|
+
`[${section}].gadget-approval.${gadgetName} must be one of: ${VALID_PERMISSION_LEVELS.join(", ")}`
|
|
813
921
|
);
|
|
814
922
|
}
|
|
815
923
|
result[gadgetName] = mode;
|
|
@@ -978,6 +1086,9 @@ function validateAgentConfig(raw, section) {
|
|
|
978
1086
|
if ("gadget-approval" in rawObj) {
|
|
979
1087
|
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
980
1088
|
}
|
|
1089
|
+
if ("subagents" in rawObj) {
|
|
1090
|
+
result.subagents = validateSubagentConfigMap(rawObj.subagents, section);
|
|
1091
|
+
}
|
|
981
1092
|
if ("quiet" in rawObj) {
|
|
982
1093
|
result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
|
|
983
1094
|
}
|
|
@@ -1146,6 +1257,9 @@ function validateCustomConfig(raw, section) {
|
|
|
1146
1257
|
if ("gadget-approval" in rawObj) {
|
|
1147
1258
|
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
1148
1259
|
}
|
|
1260
|
+
if ("subagents" in rawObj) {
|
|
1261
|
+
result.subagents = validateSubagentConfigMap(rawObj.subagents, section);
|
|
1262
|
+
}
|
|
1149
1263
|
if ("max-tokens" in rawObj) {
|
|
1150
1264
|
result["max-tokens"] = validateNumber(rawObj["max-tokens"], "max-tokens", section, {
|
|
1151
1265
|
integer: true,
|
|
@@ -1193,6 +1307,8 @@ function validateConfig(raw, configPath) {
|
|
|
1193
1307
|
result.prompts = validatePromptsConfig(value, key);
|
|
1194
1308
|
} else if (key === "docker") {
|
|
1195
1309
|
result.docker = validateDockerConfig(value, key);
|
|
1310
|
+
} else if (key === "subagents") {
|
|
1311
|
+
result.subagents = validateGlobalSubagentConfig(value, key);
|
|
1196
1312
|
} else {
|
|
1197
1313
|
result[key] = validateCustomConfig(value, key);
|
|
1198
1314
|
}
|
|
@@ -1233,7 +1349,16 @@ function loadConfig() {
|
|
|
1233
1349
|
return resolveTemplatesInConfig(inherited, configPath);
|
|
1234
1350
|
}
|
|
1235
1351
|
function getCustomCommandNames(config) {
|
|
1236
|
-
const reserved = /* @__PURE__ */ new Set([
|
|
1352
|
+
const reserved = /* @__PURE__ */ new Set([
|
|
1353
|
+
"global",
|
|
1354
|
+
"complete",
|
|
1355
|
+
"agent",
|
|
1356
|
+
"image",
|
|
1357
|
+
"speech",
|
|
1358
|
+
"prompts",
|
|
1359
|
+
"docker",
|
|
1360
|
+
"subagents"
|
|
1361
|
+
]);
|
|
1237
1362
|
return Object.keys(config).filter((key) => !reserved.has(key));
|
|
1238
1363
|
}
|
|
1239
1364
|
function resolveTemplatesInConfig(config, configPath) {
|
|
@@ -1767,11 +1892,11 @@ function resolveDevMode(config, cliDevMode) {
|
|
|
1767
1892
|
}
|
|
1768
1893
|
return { enabled: true, sourcePath };
|
|
1769
1894
|
}
|
|
1770
|
-
function expandHome(
|
|
1771
|
-
if (
|
|
1772
|
-
return
|
|
1895
|
+
function expandHome(path6) {
|
|
1896
|
+
if (path6.startsWith("~")) {
|
|
1897
|
+
return path6.replace(/^~/, homedir3());
|
|
1773
1898
|
}
|
|
1774
|
-
return
|
|
1899
|
+
return path6;
|
|
1775
1900
|
}
|
|
1776
1901
|
function buildDockerRunArgs(ctx, imageName, devMode) {
|
|
1777
1902
|
const args = ["run", "--rm"];
|
|
@@ -1949,9 +2074,9 @@ async function readFileBuffer(filePath, options = {}) {
|
|
|
1949
2074
|
|
|
1950
2075
|
// src/cli/gadgets.ts
|
|
1951
2076
|
init_gadget();
|
|
1952
|
-
import
|
|
1953
|
-
import
|
|
1954
|
-
import { pathToFileURL } from "node:url";
|
|
2077
|
+
import fs6 from "node:fs";
|
|
2078
|
+
import path5 from "node:path";
|
|
2079
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
1955
2080
|
|
|
1956
2081
|
// src/cli/builtins/filesystem/edit-file.ts
|
|
1957
2082
|
import { z as z2 } from "zod";
|
|
@@ -2404,6 +2529,208 @@ function isBuiltinGadgetName(name) {
|
|
|
2404
2529
|
return name in builtinGadgetRegistry;
|
|
2405
2530
|
}
|
|
2406
2531
|
|
|
2532
|
+
// src/cli/external-gadgets.ts
|
|
2533
|
+
import { execSync } from "node:child_process";
|
|
2534
|
+
import fs5 from "node:fs";
|
|
2535
|
+
import path4 from "node:path";
|
|
2536
|
+
import os from "node:os";
|
|
2537
|
+
import { pathToFileURL } from "node:url";
|
|
2538
|
+
var CACHE_DIR2 = path4.join(os.homedir(), ".llmist", "gadget-cache");
|
|
2539
|
+
function isExternalPackageSpecifier(specifier) {
|
|
2540
|
+
if (/^@?[a-z0-9][\w.-]*(?:@[\w.-]+)?(?::[a-z]+)?(?:\/\w+)?$/i.test(specifier)) {
|
|
2541
|
+
return true;
|
|
2542
|
+
}
|
|
2543
|
+
if (specifier.startsWith("git+")) {
|
|
2544
|
+
return true;
|
|
2545
|
+
}
|
|
2546
|
+
return false;
|
|
2547
|
+
}
|
|
2548
|
+
function parseGadgetSpecifier(specifier) {
|
|
2549
|
+
if (specifier.startsWith("git+")) {
|
|
2550
|
+
const url = specifier.slice(4);
|
|
2551
|
+
const [baseUrl, ref] = url.split("#");
|
|
2552
|
+
return {
|
|
2553
|
+
type: "git",
|
|
2554
|
+
package: baseUrl,
|
|
2555
|
+
version: ref
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
const npmMatch = specifier.match(
|
|
2559
|
+
/^(@?[a-z0-9][\w.-]*)(?:@([\w.-]+))?(?::([a-z]+))?(?:\/(\w+))?$/i
|
|
2560
|
+
);
|
|
2561
|
+
if (npmMatch) {
|
|
2562
|
+
const [, pkg, version, preset, gadgetName] = npmMatch;
|
|
2563
|
+
return {
|
|
2564
|
+
type: "npm",
|
|
2565
|
+
package: pkg,
|
|
2566
|
+
version,
|
|
2567
|
+
preset,
|
|
2568
|
+
gadgetName
|
|
2569
|
+
};
|
|
2570
|
+
}
|
|
2571
|
+
return null;
|
|
2572
|
+
}
|
|
2573
|
+
function getCacheDir(spec) {
|
|
2574
|
+
const versionSuffix = spec.version ? `@${spec.version}` : "@latest";
|
|
2575
|
+
if (spec.type === "npm") {
|
|
2576
|
+
return path4.join(CACHE_DIR2, "npm", `${spec.package}${versionSuffix}`);
|
|
2577
|
+
}
|
|
2578
|
+
const sanitizedUrl = spec.package.replace(/[/:]/g, "-").replace(/^-+|-+$/g, "");
|
|
2579
|
+
return path4.join(CACHE_DIR2, "git", `${sanitizedUrl}${versionSuffix}`);
|
|
2580
|
+
}
|
|
2581
|
+
function isCached(cacheDir) {
|
|
2582
|
+
const packageJsonPath = path4.join(cacheDir, "package.json");
|
|
2583
|
+
return fs5.existsSync(packageJsonPath);
|
|
2584
|
+
}
|
|
2585
|
+
async function installNpmPackage(spec, cacheDir) {
|
|
2586
|
+
fs5.mkdirSync(cacheDir, { recursive: true });
|
|
2587
|
+
const packageJson = {
|
|
2588
|
+
name: "llmist-gadget-cache",
|
|
2589
|
+
private: true,
|
|
2590
|
+
type: "module"
|
|
2591
|
+
};
|
|
2592
|
+
fs5.writeFileSync(path4.join(cacheDir, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
2593
|
+
const packageSpec = spec.version ? `${spec.package}@${spec.version}` : spec.package;
|
|
2594
|
+
try {
|
|
2595
|
+
execSync(`npm install --prefix "${cacheDir}" "${packageSpec}" --save`, {
|
|
2596
|
+
stdio: "pipe",
|
|
2597
|
+
cwd: cacheDir
|
|
2598
|
+
});
|
|
2599
|
+
} catch (error) {
|
|
2600
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2601
|
+
throw new Error(`Failed to install npm package '${packageSpec}': ${message}`);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
async function installGitPackage(spec, cacheDir) {
|
|
2605
|
+
fs5.mkdirSync(path4.dirname(cacheDir), { recursive: true });
|
|
2606
|
+
if (fs5.existsSync(cacheDir)) {
|
|
2607
|
+
try {
|
|
2608
|
+
execSync("git fetch", { cwd: cacheDir, stdio: "pipe" });
|
|
2609
|
+
if (spec.version) {
|
|
2610
|
+
execSync(`git checkout ${spec.version}`, { cwd: cacheDir, stdio: "pipe" });
|
|
2611
|
+
}
|
|
2612
|
+
} catch (error) {
|
|
2613
|
+
fs5.rmSync(cacheDir, { recursive: true, force: true });
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
if (!fs5.existsSync(cacheDir)) {
|
|
2617
|
+
try {
|
|
2618
|
+
const cloneCmd = spec.version ? `git clone --branch ${spec.version} "${spec.package}" "${cacheDir}"` : `git clone "${spec.package}" "${cacheDir}"`;
|
|
2619
|
+
execSync(cloneCmd, { stdio: "pipe" });
|
|
2620
|
+
} catch (error) {
|
|
2621
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2622
|
+
throw new Error(`Failed to clone git repository '${spec.package}': ${message}`);
|
|
2623
|
+
}
|
|
2624
|
+
if (fs5.existsSync(path4.join(cacheDir, "package.json"))) {
|
|
2625
|
+
try {
|
|
2626
|
+
execSync("npm install", { cwd: cacheDir, stdio: "pipe" });
|
|
2627
|
+
} catch (error) {
|
|
2628
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2629
|
+
throw new Error(`Failed to install dependencies for '${spec.package}': ${message}`);
|
|
2630
|
+
}
|
|
2631
|
+
try {
|
|
2632
|
+
const packageJson = JSON.parse(fs5.readFileSync(path4.join(cacheDir, "package.json"), "utf-8"));
|
|
2633
|
+
if (packageJson.scripts?.build) {
|
|
2634
|
+
execSync("npm run build", { cwd: cacheDir, stdio: "pipe" });
|
|
2635
|
+
}
|
|
2636
|
+
} catch (error) {
|
|
2637
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2638
|
+
throw new Error(`Failed to build package '${spec.package}': ${message}`);
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
function readManifest(packageDir) {
|
|
2644
|
+
const packageJsonPath = path4.join(packageDir, "package.json");
|
|
2645
|
+
if (!fs5.existsSync(packageJsonPath)) {
|
|
2646
|
+
return null;
|
|
2647
|
+
}
|
|
2648
|
+
try {
|
|
2649
|
+
const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
|
|
2650
|
+
return packageJson.llmist || null;
|
|
2651
|
+
} catch {
|
|
2652
|
+
return null;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
function getPackagePath(cacheDir, packageName) {
|
|
2656
|
+
const nodeModulesPath = path4.join(cacheDir, "node_modules", packageName);
|
|
2657
|
+
if (fs5.existsSync(nodeModulesPath)) {
|
|
2658
|
+
return nodeModulesPath;
|
|
2659
|
+
}
|
|
2660
|
+
return cacheDir;
|
|
2661
|
+
}
|
|
2662
|
+
async function loadExternalGadgets(specifier, forceInstall = false) {
|
|
2663
|
+
const spec = parseGadgetSpecifier(specifier);
|
|
2664
|
+
if (!spec) {
|
|
2665
|
+
throw new Error(`Invalid external package specifier: ${specifier}`);
|
|
2666
|
+
}
|
|
2667
|
+
const cacheDir = getCacheDir(spec);
|
|
2668
|
+
if (!isCached(cacheDir) || forceInstall) {
|
|
2669
|
+
if (spec.type === "npm") {
|
|
2670
|
+
await installNpmPackage(spec, cacheDir);
|
|
2671
|
+
} else {
|
|
2672
|
+
await installGitPackage(spec, cacheDir);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
const packagePath = getPackagePath(cacheDir, spec.package);
|
|
2676
|
+
const manifest = readManifest(packagePath);
|
|
2677
|
+
let entryPoint;
|
|
2678
|
+
let gadgetNames = null;
|
|
2679
|
+
if (spec.gadgetName) {
|
|
2680
|
+
gadgetNames = [spec.gadgetName];
|
|
2681
|
+
if (manifest?.subagents?.[spec.gadgetName]) {
|
|
2682
|
+
entryPoint = manifest.subagents[spec.gadgetName].entryPoint;
|
|
2683
|
+
} else {
|
|
2684
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
2685
|
+
}
|
|
2686
|
+
} else if (spec.preset) {
|
|
2687
|
+
if (!manifest?.presets?.[spec.preset]) {
|
|
2688
|
+
throw new Error(`Unknown preset '${spec.preset}' in package '${spec.package}'`);
|
|
2689
|
+
}
|
|
2690
|
+
const preset = manifest.presets[spec.preset];
|
|
2691
|
+
if (preset === "*") {
|
|
2692
|
+
gadgetNames = null;
|
|
2693
|
+
} else {
|
|
2694
|
+
gadgetNames = preset;
|
|
2695
|
+
}
|
|
2696
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
2697
|
+
} else {
|
|
2698
|
+
entryPoint = manifest?.gadgets || "./dist/index.js";
|
|
2699
|
+
}
|
|
2700
|
+
const resolvedEntryPoint = path4.resolve(packagePath, entryPoint);
|
|
2701
|
+
if (!fs5.existsSync(resolvedEntryPoint)) {
|
|
2702
|
+
throw new Error(
|
|
2703
|
+
`Entry point not found: ${resolvedEntryPoint}. Make sure the package is built (run 'npm run build' in the package directory).`
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2706
|
+
const moduleUrl = pathToFileURL(resolvedEntryPoint).href;
|
|
2707
|
+
let exports;
|
|
2708
|
+
try {
|
|
2709
|
+
exports = await import(moduleUrl);
|
|
2710
|
+
} catch (error) {
|
|
2711
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2712
|
+
throw new Error(`Failed to import '${specifier}': ${message}`);
|
|
2713
|
+
}
|
|
2714
|
+
let gadgets = extractGadgetsFromModule(exports);
|
|
2715
|
+
if (gadgetNames) {
|
|
2716
|
+
const gadgetSet = new Set(gadgetNames.map((n) => n.toLowerCase()));
|
|
2717
|
+
gadgets = gadgets.filter((g) => {
|
|
2718
|
+
const name = g.name?.toLowerCase() || "";
|
|
2719
|
+
return gadgetSet.has(name);
|
|
2720
|
+
});
|
|
2721
|
+
const foundNames = new Set(gadgets.map((g) => g.name?.toLowerCase() || ""));
|
|
2722
|
+
for (const requested of gadgetNames) {
|
|
2723
|
+
if (!foundNames.has(requested.toLowerCase())) {
|
|
2724
|
+
throw new Error(`Gadget '${requested}' not found in package '${spec.package}'`);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
if (gadgets.length === 0) {
|
|
2729
|
+
throw new Error(`No gadgets found in package '${spec.package}'`);
|
|
2730
|
+
}
|
|
2731
|
+
return gadgets;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2407
2734
|
// src/cli/gadgets.ts
|
|
2408
2735
|
var PATH_PREFIXES = [".", "/", "~"];
|
|
2409
2736
|
var BUILTIN_PREFIX = "builtin:";
|
|
@@ -2419,7 +2746,17 @@ function isGadgetConstructor(value) {
|
|
|
2419
2746
|
return false;
|
|
2420
2747
|
}
|
|
2421
2748
|
const prototype = value.prototype;
|
|
2422
|
-
|
|
2749
|
+
if (!prototype) {
|
|
2750
|
+
return false;
|
|
2751
|
+
}
|
|
2752
|
+
if (prototype instanceof AbstractGadget) {
|
|
2753
|
+
return true;
|
|
2754
|
+
}
|
|
2755
|
+
const proto = prototype;
|
|
2756
|
+
if (typeof proto.execute === "function") {
|
|
2757
|
+
return true;
|
|
2758
|
+
}
|
|
2759
|
+
return isGadgetLike(prototype);
|
|
2423
2760
|
}
|
|
2424
2761
|
function expandHomePath(input) {
|
|
2425
2762
|
if (!input.startsWith("~")) {
|
|
@@ -2429,10 +2766,10 @@ function expandHomePath(input) {
|
|
|
2429
2766
|
if (!home) {
|
|
2430
2767
|
return input;
|
|
2431
2768
|
}
|
|
2432
|
-
return
|
|
2769
|
+
return path5.join(home, input.slice(1));
|
|
2433
2770
|
}
|
|
2434
2771
|
function isFileLikeSpecifier(specifier) {
|
|
2435
|
-
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(
|
|
2772
|
+
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(path5.sep);
|
|
2436
2773
|
}
|
|
2437
2774
|
function tryResolveBuiltin(specifier) {
|
|
2438
2775
|
if (specifier.startsWith(BUILTIN_PREFIX)) {
|
|
@@ -2455,11 +2792,11 @@ function resolveGadgetSpecifier(specifier, cwd) {
|
|
|
2455
2792
|
return specifier;
|
|
2456
2793
|
}
|
|
2457
2794
|
const expanded = expandHomePath(specifier);
|
|
2458
|
-
const resolvedPath =
|
|
2459
|
-
if (!
|
|
2795
|
+
const resolvedPath = path5.resolve(cwd, expanded);
|
|
2796
|
+
if (!fs6.existsSync(resolvedPath)) {
|
|
2460
2797
|
throw new Error(`Gadget module not found at ${resolvedPath}`);
|
|
2461
2798
|
}
|
|
2462
|
-
return
|
|
2799
|
+
return pathToFileURL2(resolvedPath).href;
|
|
2463
2800
|
}
|
|
2464
2801
|
function extractGadgetsFromModule(moduleExports) {
|
|
2465
2802
|
const results = [];
|
|
@@ -2472,7 +2809,7 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
2472
2809
|
return;
|
|
2473
2810
|
}
|
|
2474
2811
|
visited.add(value);
|
|
2475
|
-
if (value instanceof
|
|
2812
|
+
if (value instanceof AbstractGadget || isGadgetLike(value)) {
|
|
2476
2813
|
results.push(value);
|
|
2477
2814
|
return;
|
|
2478
2815
|
}
|
|
@@ -2497,12 +2834,23 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
2497
2834
|
}
|
|
2498
2835
|
async function loadGadgets(specifiers, cwd, importer = (specifier) => import(specifier)) {
|
|
2499
2836
|
const gadgets = [];
|
|
2837
|
+
const usingDefaultImporter = importer.toString().includes("import(specifier)");
|
|
2500
2838
|
for (const specifier of specifiers) {
|
|
2501
2839
|
const builtin = tryResolveBuiltin(specifier);
|
|
2502
2840
|
if (builtin) {
|
|
2503
2841
|
gadgets.push(builtin);
|
|
2504
2842
|
continue;
|
|
2505
2843
|
}
|
|
2844
|
+
if (usingDefaultImporter && isExternalPackageSpecifier(specifier)) {
|
|
2845
|
+
try {
|
|
2846
|
+
const externalGadgets = await loadExternalGadgets(specifier);
|
|
2847
|
+
gadgets.push(...externalGadgets);
|
|
2848
|
+
continue;
|
|
2849
|
+
} catch (error) {
|
|
2850
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2851
|
+
throw new Error(`Failed to load external package '${specifier}': ${message}`);
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2506
2854
|
const resolved = resolveGadgetSpecifier(specifier, cwd);
|
|
2507
2855
|
let exports;
|
|
2508
2856
|
try {
|
|
@@ -2545,7 +2893,7 @@ function formatLlmRequest(messages) {
|
|
|
2545
2893
|
const lines = [];
|
|
2546
2894
|
for (const msg of messages) {
|
|
2547
2895
|
lines.push(`=== ${msg.role.toUpperCase()} ===`);
|
|
2548
|
-
lines.push(msg.content ?
|
|
2896
|
+
lines.push(msg.content ? extractMessageText(msg.content) : "");
|
|
2549
2897
|
lines.push("");
|
|
2550
2898
|
}
|
|
2551
2899
|
return lines.join("\n");
|
|
@@ -2760,12 +3108,14 @@ function formatMediaLine(media) {
|
|
|
2760
3108
|
const id = chalk3.cyan(media.id);
|
|
2761
3109
|
const mimeType = chalk3.dim(media.mimeType);
|
|
2762
3110
|
const size = chalk3.yellow(formatBytes(media.sizeBytes));
|
|
2763
|
-
const
|
|
2764
|
-
return `${chalk3.dim("[")}${icon} ${id} ${mimeType} ${size}${chalk3.dim("]")} ${chalk3.dim("\u2192")} ${
|
|
3111
|
+
const path6 = chalk3.dim(media.path);
|
|
3112
|
+
return `${chalk3.dim("[")}${icon} ${id} ${mimeType} ${size}${chalk3.dim("]")} ${chalk3.dim("\u2192")} ${path6}`;
|
|
2765
3113
|
}
|
|
2766
3114
|
function formatGadgetSummary2(result) {
|
|
2767
3115
|
const gadgetLabel = chalk3.magenta.bold(result.gadgetName);
|
|
2768
|
-
const timeLabel = chalk3.dim(
|
|
3116
|
+
const timeLabel = chalk3.dim(
|
|
3117
|
+
result.executionTimeMs >= 1e3 ? `${(result.executionTimeMs / 1e3).toFixed(1)}s` : `${Math.round(result.executionTimeMs)}ms`
|
|
3118
|
+
);
|
|
2769
3119
|
const paramsStr = formatParametersInline(result.parameters);
|
|
2770
3120
|
const paramsLabel = paramsStr ? `${chalk3.dim("(")}${paramsStr}${chalk3.dim(")")}` : "";
|
|
2771
3121
|
if (result.error) {
|
|
@@ -2933,6 +3283,8 @@ var StreamProgress = class {
|
|
|
2933
3283
|
delayTimeout = null;
|
|
2934
3284
|
isRunning = false;
|
|
2935
3285
|
hasRendered = false;
|
|
3286
|
+
lastRenderLineCount = 0;
|
|
3287
|
+
// Track lines rendered for multi-line clearing
|
|
2936
3288
|
// Current call stats (streaming mode)
|
|
2937
3289
|
mode = "cumulative";
|
|
2938
3290
|
model = "";
|
|
@@ -2952,6 +3304,99 @@ var StreamProgress = class {
|
|
|
2952
3304
|
totalCost = 0;
|
|
2953
3305
|
iterations = 0;
|
|
2954
3306
|
currentIteration = 0;
|
|
3307
|
+
// In-flight gadget tracking for concurrent status display
|
|
3308
|
+
inFlightGadgets = /* @__PURE__ */ new Map();
|
|
3309
|
+
// Nested agent tracking for hierarchical subagent display
|
|
3310
|
+
nestedAgents = /* @__PURE__ */ new Map();
|
|
3311
|
+
// Nested gadget tracking for hierarchical subagent display
|
|
3312
|
+
nestedGadgets = /* @__PURE__ */ new Map();
|
|
3313
|
+
/**
|
|
3314
|
+
* Add a gadget to the in-flight tracking (called when gadget_call event received).
|
|
3315
|
+
* Triggers re-render to show the gadget in the status display.
|
|
3316
|
+
*/
|
|
3317
|
+
addGadget(invocationId, name, params) {
|
|
3318
|
+
this.inFlightGadgets.set(invocationId, { name, params, startTime: Date.now() });
|
|
3319
|
+
if (this.isRunning && this.isTTY) {
|
|
3320
|
+
this.render();
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Remove a gadget from in-flight tracking (called when gadget_result event received).
|
|
3325
|
+
* Triggers re-render to update the status display.
|
|
3326
|
+
*/
|
|
3327
|
+
removeGadget(invocationId) {
|
|
3328
|
+
this.inFlightGadgets.delete(invocationId);
|
|
3329
|
+
if (this.isRunning && this.isTTY) {
|
|
3330
|
+
this.render();
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
/**
|
|
3334
|
+
* Check if there are any gadgets currently in flight.
|
|
3335
|
+
*/
|
|
3336
|
+
hasInFlightGadgets() {
|
|
3337
|
+
return this.inFlightGadgets.size > 0;
|
|
3338
|
+
}
|
|
3339
|
+
/**
|
|
3340
|
+
* Add a nested agent LLM call (called when nested llm_call_start event received).
|
|
3341
|
+
* Used to display hierarchical progress for subagent gadgets.
|
|
3342
|
+
*/
|
|
3343
|
+
addNestedAgent(id, parentInvocationId, depth, model, iteration, inputTokens) {
|
|
3344
|
+
this.nestedAgents.set(id, {
|
|
3345
|
+
parentInvocationId,
|
|
3346
|
+
depth,
|
|
3347
|
+
model,
|
|
3348
|
+
iteration,
|
|
3349
|
+
startTime: Date.now(),
|
|
3350
|
+
inputTokens
|
|
3351
|
+
});
|
|
3352
|
+
if (this.isRunning && this.isTTY) {
|
|
3353
|
+
this.render();
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Update a nested agent with completion info (called when nested llm_call_end event received).
|
|
3358
|
+
*/
|
|
3359
|
+
updateNestedAgent(id, outputTokens) {
|
|
3360
|
+
const agent = this.nestedAgents.get(id);
|
|
3361
|
+
if (agent) {
|
|
3362
|
+
agent.outputTokens = outputTokens;
|
|
3363
|
+
if (this.isRunning && this.isTTY) {
|
|
3364
|
+
this.render();
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
/**
|
|
3369
|
+
* Remove a nested agent (called when the nested LLM call completes).
|
|
3370
|
+
*/
|
|
3371
|
+
removeNestedAgent(id) {
|
|
3372
|
+
this.nestedAgents.delete(id);
|
|
3373
|
+
if (this.isRunning && this.isTTY) {
|
|
3374
|
+
this.render();
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Add a nested gadget call (called when nested gadget_call event received).
|
|
3379
|
+
*/
|
|
3380
|
+
addNestedGadget(id, depth, parentInvocationId, name) {
|
|
3381
|
+
this.nestedGadgets.set(id, {
|
|
3382
|
+
depth,
|
|
3383
|
+
parentInvocationId,
|
|
3384
|
+
name,
|
|
3385
|
+
startTime: Date.now()
|
|
3386
|
+
});
|
|
3387
|
+
if (this.isRunning && this.isTTY) {
|
|
3388
|
+
this.render();
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
/**
|
|
3392
|
+
* Remove a nested gadget (called when nested gadget_result event received).
|
|
3393
|
+
*/
|
|
3394
|
+
removeNestedGadget(id) {
|
|
3395
|
+
this.nestedGadgets.delete(id);
|
|
3396
|
+
if (this.isRunning && this.isTTY) {
|
|
3397
|
+
this.render();
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
2955
3400
|
/**
|
|
2956
3401
|
* Starts a new LLM call. Switches to streaming mode.
|
|
2957
3402
|
* @param model - Model name being used
|
|
@@ -3078,15 +3523,57 @@ var StreamProgress = class {
|
|
|
3078
3523
|
this.isStreaming = true;
|
|
3079
3524
|
}
|
|
3080
3525
|
render() {
|
|
3526
|
+
this.clearRenderedLines();
|
|
3081
3527
|
const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];
|
|
3528
|
+
const lines = [];
|
|
3082
3529
|
if (this.mode === "streaming") {
|
|
3083
|
-
this.
|
|
3530
|
+
lines.push(this.formatStreamingLine(spinner));
|
|
3084
3531
|
} else {
|
|
3085
|
-
this.
|
|
3532
|
+
lines.push(this.formatCumulativeLine(spinner));
|
|
3533
|
+
}
|
|
3534
|
+
if (this.isTTY) {
|
|
3535
|
+
for (const [gadgetId, gadget] of this.inFlightGadgets) {
|
|
3536
|
+
const elapsed = ((Date.now() - gadget.startTime) / 1e3).toFixed(1);
|
|
3537
|
+
const gadgetLine = ` ${chalk4.blue("\u23F5")} ${chalk4.magenta.bold(gadget.name)}${chalk4.dim("(...)")} ${chalk4.dim(elapsed + "s")}`;
|
|
3538
|
+
lines.push(gadgetLine);
|
|
3539
|
+
for (const [_agentId, nested] of this.nestedAgents) {
|
|
3540
|
+
if (nested.parentInvocationId !== gadgetId) continue;
|
|
3541
|
+
const indent = " ".repeat(nested.depth + 1);
|
|
3542
|
+
const nestedElapsed = ((Date.now() - nested.startTime) / 1e3).toFixed(1);
|
|
3543
|
+
const tokens = nested.inputTokens ? ` ${chalk4.dim("\u2191")}${chalk4.yellow(formatTokens(nested.inputTokens))}` : "";
|
|
3544
|
+
const outTokens = nested.outputTokens ? ` ${chalk4.dim("\u2193")}${chalk4.green(formatTokens(nested.outputTokens))}` : "";
|
|
3545
|
+
const nestedLine = `${indent}${chalk4.cyan(`#${nested.iteration}`)} ${chalk4.dim(nested.model)}${tokens}${outTokens} ${chalk4.dim(nestedElapsed + "s")} ${chalk4.cyan(spinner)}`;
|
|
3546
|
+
lines.push(nestedLine);
|
|
3547
|
+
}
|
|
3548
|
+
for (const [_nestedId, nestedGadget] of this.nestedGadgets) {
|
|
3549
|
+
if (nestedGadget.parentInvocationId === gadgetId) {
|
|
3550
|
+
const indent = " ".repeat(nestedGadget.depth + 1);
|
|
3551
|
+
const nestedElapsed = ((Date.now() - nestedGadget.startTime) / 1e3).toFixed(1);
|
|
3552
|
+
const nestedGadgetLine = `${indent}${chalk4.blue("\u23F5")} ${chalk4.dim(nestedGadget.name + "(...)")} ${chalk4.dim(nestedElapsed + "s")}`;
|
|
3553
|
+
lines.push(nestedGadgetLine);
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3086
3557
|
}
|
|
3558
|
+
this.lastRenderLineCount = lines.length;
|
|
3559
|
+
this.target.write("\r" + lines.join("\n"));
|
|
3087
3560
|
this.hasRendered = true;
|
|
3088
3561
|
}
|
|
3089
|
-
|
|
3562
|
+
/**
|
|
3563
|
+
* Clears the previously rendered lines (for multi-line status display).
|
|
3564
|
+
*/
|
|
3565
|
+
clearRenderedLines() {
|
|
3566
|
+
if (!this.hasRendered || this.lastRenderLineCount === 0) return;
|
|
3567
|
+
this.target.write("\r\x1B[K");
|
|
3568
|
+
for (let i = 1; i < this.lastRenderLineCount; i++) {
|
|
3569
|
+
this.target.write("\x1B[1A\x1B[K");
|
|
3570
|
+
}
|
|
3571
|
+
this.target.write("\r");
|
|
3572
|
+
}
|
|
3573
|
+
/**
|
|
3574
|
+
* Format the streaming mode progress line (returns string, doesn't write).
|
|
3575
|
+
*/
|
|
3576
|
+
formatStreamingLine(spinner) {
|
|
3090
3577
|
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
3091
3578
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
3092
3579
|
const parts = [];
|
|
@@ -3120,7 +3607,7 @@ var StreamProgress = class {
|
|
|
3120
3607
|
if (callCost > 0) {
|
|
3121
3608
|
parts.push(chalk4.cyan(`$${formatCost(callCost)}`));
|
|
3122
3609
|
}
|
|
3123
|
-
|
|
3610
|
+
return `${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`;
|
|
3124
3611
|
}
|
|
3125
3612
|
/**
|
|
3126
3613
|
* Calculates live cost estimate for the current streaming call.
|
|
@@ -3157,7 +3644,10 @@ var StreamProgress = class {
|
|
|
3157
3644
|
}
|
|
3158
3645
|
return this.callInputTokens / limits.contextWindow * 100;
|
|
3159
3646
|
}
|
|
3160
|
-
|
|
3647
|
+
/**
|
|
3648
|
+
* Format the cumulative mode progress line (returns string, doesn't write).
|
|
3649
|
+
*/
|
|
3650
|
+
formatCumulativeLine(spinner) {
|
|
3161
3651
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
3162
3652
|
const parts = [];
|
|
3163
3653
|
if (this.model) {
|
|
@@ -3173,10 +3663,10 @@ var StreamProgress = class {
|
|
|
3173
3663
|
parts.push(chalk4.dim("cost:") + chalk4.cyan(` $${formatCost(this.totalCost)}`));
|
|
3174
3664
|
}
|
|
3175
3665
|
parts.push(chalk4.dim(`${elapsed}s`));
|
|
3176
|
-
|
|
3666
|
+
return `${parts.join(chalk4.dim(" | "))} ${chalk4.cyan(spinner)}`;
|
|
3177
3667
|
}
|
|
3178
3668
|
/**
|
|
3179
|
-
* Pauses the progress indicator and clears
|
|
3669
|
+
* Pauses the progress indicator and clears all rendered lines.
|
|
3180
3670
|
* Can be resumed with start().
|
|
3181
3671
|
*/
|
|
3182
3672
|
pause() {
|
|
@@ -3190,10 +3680,9 @@ var StreamProgress = class {
|
|
|
3190
3680
|
this.interval = null;
|
|
3191
3681
|
}
|
|
3192
3682
|
this.isRunning = false;
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
}
|
|
3683
|
+
this.clearRenderedLines();
|
|
3684
|
+
this.hasRendered = false;
|
|
3685
|
+
this.lastRenderLineCount = 0;
|
|
3197
3686
|
}
|
|
3198
3687
|
/**
|
|
3199
3688
|
* Completes the progress indicator and clears the line.
|
|
@@ -3381,6 +3870,7 @@ function configToAgentOptions(config) {
|
|
|
3381
3870
|
if (config.docker !== void 0) result.docker = config.docker;
|
|
3382
3871
|
if (config["docker-cwd-permission"] !== void 0)
|
|
3383
3872
|
result.dockerCwdPermission = config["docker-cwd-permission"];
|
|
3873
|
+
if (config.subagents !== void 0) result.subagents = config.subagents;
|
|
3384
3874
|
return result;
|
|
3385
3875
|
}
|
|
3386
3876
|
|
|
@@ -3568,7 +4058,12 @@ async function executeAgent(promptArg, options, env) {
|
|
|
3568
4058
|
return void 0;
|
|
3569
4059
|
}
|
|
3570
4060
|
};
|
|
3571
|
-
const
|
|
4061
|
+
const resolvedSubagentConfig = buildSubagentConfigMap(
|
|
4062
|
+
options.model,
|
|
4063
|
+
options.subagents,
|
|
4064
|
+
options.globalSubagents
|
|
4065
|
+
);
|
|
4066
|
+
const builder = new AgentBuilder(client).withModel(options.model).withSubagentConfig(resolvedSubagentConfig).withLogger(env.createLogger("llmist:cli:agent")).withHooks({
|
|
3572
4067
|
observers: {
|
|
3573
4068
|
// onLLMCallStart: Start progress indicator for each LLM call
|
|
3574
4069
|
// This showcases how to react to agent lifecycle events
|
|
@@ -3764,6 +4259,38 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
3764
4259
|
"Maximize efficiency by batching independent operations in a single response."
|
|
3765
4260
|
].join(" ")
|
|
3766
4261
|
);
|
|
4262
|
+
if (!options.quiet) {
|
|
4263
|
+
builder.withNestedEventCallback((event) => {
|
|
4264
|
+
if (event.type === "llm_call_start") {
|
|
4265
|
+
const info = event.event;
|
|
4266
|
+
const nestedId = `${event.gadgetInvocationId}:${info.iteration}`;
|
|
4267
|
+
progress.addNestedAgent(
|
|
4268
|
+
nestedId,
|
|
4269
|
+
event.gadgetInvocationId,
|
|
4270
|
+
event.depth,
|
|
4271
|
+
info.model,
|
|
4272
|
+
info.iteration,
|
|
4273
|
+
info.inputTokens
|
|
4274
|
+
);
|
|
4275
|
+
} else if (event.type === "llm_call_end") {
|
|
4276
|
+
const info = event.event;
|
|
4277
|
+
const nestedId = `${event.gadgetInvocationId}:${info.iteration}`;
|
|
4278
|
+
progress.updateNestedAgent(nestedId, info.outputTokens);
|
|
4279
|
+
setTimeout(() => progress.removeNestedAgent(nestedId), 100);
|
|
4280
|
+
} else if (event.type === "gadget_call") {
|
|
4281
|
+
const gadgetEvent = event.event;
|
|
4282
|
+
progress.addNestedGadget(
|
|
4283
|
+
gadgetEvent.call.invocationId,
|
|
4284
|
+
event.depth,
|
|
4285
|
+
event.gadgetInvocationId,
|
|
4286
|
+
gadgetEvent.call.gadgetName
|
|
4287
|
+
);
|
|
4288
|
+
} else if (event.type === "gadget_result") {
|
|
4289
|
+
const resultEvent = event.event;
|
|
4290
|
+
progress.removeNestedGadget(resultEvent.result.invocationId);
|
|
4291
|
+
}
|
|
4292
|
+
});
|
|
4293
|
+
}
|
|
3767
4294
|
let agent;
|
|
3768
4295
|
if (options.image || options.audio) {
|
|
3769
4296
|
const parts = [text(prompt)];
|
|
@@ -3788,10 +4315,22 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
3788
4315
|
try {
|
|
3789
4316
|
for await (const event of agent.run()) {
|
|
3790
4317
|
if (event.type === "text") {
|
|
3791
|
-
progress.pause();
|
|
3792
4318
|
textBuffer += event.content;
|
|
4319
|
+
} else if (event.type === "gadget_call") {
|
|
4320
|
+
flushTextBuffer();
|
|
4321
|
+
if (!options.quiet) {
|
|
4322
|
+
progress.addGadget(
|
|
4323
|
+
event.call.invocationId,
|
|
4324
|
+
event.call.gadgetName,
|
|
4325
|
+
event.call.parameters
|
|
4326
|
+
);
|
|
4327
|
+
progress.start();
|
|
4328
|
+
}
|
|
3793
4329
|
} else if (event.type === "gadget_result") {
|
|
3794
4330
|
flushTextBuffer();
|
|
4331
|
+
if (!options.quiet) {
|
|
4332
|
+
progress.removeGadget(event.result.invocationId);
|
|
4333
|
+
}
|
|
3795
4334
|
progress.pause();
|
|
3796
4335
|
if (options.quiet) {
|
|
3797
4336
|
if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
|
|
@@ -3806,6 +4345,9 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
3806
4345
|
`
|
|
3807
4346
|
);
|
|
3808
4347
|
}
|
|
4348
|
+
if (progress.hasInFlightGadgets()) {
|
|
4349
|
+
progress.start();
|
|
4350
|
+
}
|
|
3809
4351
|
}
|
|
3810
4352
|
}
|
|
3811
4353
|
} catch (error) {
|
|
@@ -3838,14 +4380,16 @@ Denied: ${result.reason ?? "by user"}`
|
|
|
3838
4380
|
}
|
|
3839
4381
|
}
|
|
3840
4382
|
}
|
|
3841
|
-
function registerAgentCommand(program, env, config) {
|
|
4383
|
+
function registerAgentCommand(program, env, config, globalSubagents) {
|
|
3842
4384
|
const cmd = program.command(COMMANDS.agent).description("Run the llmist agent loop with optional gadgets.").argument("[prompt]", "Prompt for the agent loop. Falls back to stdin when available.");
|
|
3843
4385
|
addAgentOptions(cmd, config);
|
|
3844
4386
|
cmd.action(
|
|
3845
4387
|
(prompt, options) => executeAction(() => {
|
|
3846
4388
|
const mergedOptions = {
|
|
3847
4389
|
...options,
|
|
3848
|
-
gadgetApproval: config?.["gadget-approval"]
|
|
4390
|
+
gadgetApproval: config?.["gadget-approval"],
|
|
4391
|
+
subagents: config?.subagents,
|
|
4392
|
+
globalSubagents
|
|
3849
4393
|
};
|
|
3850
4394
|
return executeAgent(prompt, mergedOptions, env);
|
|
3851
4395
|
}, env)
|
|
@@ -3945,6 +4489,104 @@ function registerCompleteCommand(program, env, config) {
|
|
|
3945
4489
|
);
|
|
3946
4490
|
}
|
|
3947
4491
|
|
|
4492
|
+
// src/cli/init-command.ts
|
|
4493
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4494
|
+
import { dirname as dirname2 } from "node:path";
|
|
4495
|
+
var STARTER_CONFIG = `# ~/.llmist/cli.toml
|
|
4496
|
+
# llmist CLI configuration file
|
|
4497
|
+
#
|
|
4498
|
+
# This is a minimal starter config. For a comprehensive example with all options:
|
|
4499
|
+
# https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml
|
|
4500
|
+
#
|
|
4501
|
+
# Key concepts:
|
|
4502
|
+
# - Any section can inherit from others using: inherits = "section-name"
|
|
4503
|
+
# - Prompts can use templates with Eta syntax: <%~ include("@prompt-name") %>
|
|
4504
|
+
# - Custom sections become CLI commands: [my-command] -> llmist my-command
|
|
4505
|
+
|
|
4506
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4507
|
+
# GLOBAL OPTIONS
|
|
4508
|
+
# These apply to all commands. CLI flags override these settings.
|
|
4509
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4510
|
+
[global]
|
|
4511
|
+
# log-level = "info" # silly, trace, debug, info, warn, error, fatal
|
|
4512
|
+
# log-file = "/tmp/llmist.log" # Enable file logging (JSON format)
|
|
4513
|
+
|
|
4514
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4515
|
+
# COMPLETE COMMAND DEFAULTS
|
|
4516
|
+
# For single LLM responses: llmist complete "prompt"
|
|
4517
|
+
# Model format: provider:model (e.g., openai:gpt-4o, anthropic:claude-sonnet-4-5)
|
|
4518
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4519
|
+
[complete]
|
|
4520
|
+
# model = "openai:gpt-4o"
|
|
4521
|
+
# temperature = 0.7 # 0-2, higher = more creative
|
|
4522
|
+
# max-tokens = 4096 # Maximum response length
|
|
4523
|
+
|
|
4524
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4525
|
+
# AGENT COMMAND DEFAULTS
|
|
4526
|
+
# For tool-using agents: llmist agent "prompt"
|
|
4527
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4528
|
+
[agent]
|
|
4529
|
+
# model = "anthropic:claude-sonnet-4-5"
|
|
4530
|
+
# max-iterations = 15 # Max tool-use loops before stopping
|
|
4531
|
+
# gadgets = [ # Tools the agent can use
|
|
4532
|
+
# "ListDirectory",
|
|
4533
|
+
# "ReadFile",
|
|
4534
|
+
# "WriteFile",
|
|
4535
|
+
# ]
|
|
4536
|
+
|
|
4537
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4538
|
+
# CUSTOM COMMANDS
|
|
4539
|
+
# Any other section becomes a new CLI command!
|
|
4540
|
+
# Uncomment below to create: llmist summarize "your text"
|
|
4541
|
+
#\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4542
|
+
# [summarize]
|
|
4543
|
+
# type = "complete" # "complete" or "agent"
|
|
4544
|
+
# description = "Summarize text concisely."
|
|
4545
|
+
# system = "Summarize the following text in 2-3 bullet points."
|
|
4546
|
+
# temperature = 0.3
|
|
4547
|
+
`;
|
|
4548
|
+
async function executeInit(_options, env) {
|
|
4549
|
+
const configPath = getConfigPath();
|
|
4550
|
+
const configDir = dirname2(configPath);
|
|
4551
|
+
if (existsSync5(configPath)) {
|
|
4552
|
+
env.stderr.write(`Configuration already exists at ${configPath}
|
|
4553
|
+
`);
|
|
4554
|
+
env.stderr.write("\n");
|
|
4555
|
+
env.stderr.write(`To view it: cat ${configPath}
|
|
4556
|
+
`);
|
|
4557
|
+
env.stderr.write(`To reset: rm ${configPath} && llmist init
|
|
4558
|
+
`);
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
if (!existsSync5(configDir)) {
|
|
4562
|
+
mkdirSync2(configDir, { recursive: true });
|
|
4563
|
+
}
|
|
4564
|
+
writeFileSync2(configPath, STARTER_CONFIG, "utf-8");
|
|
4565
|
+
env.stderr.write(`Created ${configPath}
|
|
4566
|
+
`);
|
|
4567
|
+
env.stderr.write("\n");
|
|
4568
|
+
env.stderr.write("Next steps:\n");
|
|
4569
|
+
env.stderr.write(" 1. Set your API key:\n");
|
|
4570
|
+
env.stderr.write(" export OPENAI_API_KEY=sk-...\n");
|
|
4571
|
+
env.stderr.write(" export ANTHROPIC_API_KEY=sk-...\n");
|
|
4572
|
+
env.stderr.write(" export GEMINI_API_KEY=...\n");
|
|
4573
|
+
env.stderr.write("\n");
|
|
4574
|
+
env.stderr.write(` 2. Customize your config:
|
|
4575
|
+
`);
|
|
4576
|
+
env.stderr.write(` $EDITOR ${configPath}
|
|
4577
|
+
`);
|
|
4578
|
+
env.stderr.write("\n");
|
|
4579
|
+
env.stderr.write(" 3. See all options:\n");
|
|
4580
|
+
env.stderr.write(
|
|
4581
|
+
" https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml\n"
|
|
4582
|
+
);
|
|
4583
|
+
env.stderr.write("\n");
|
|
4584
|
+
env.stderr.write('Try it: llmist complete "Hello, world!"\n');
|
|
4585
|
+
}
|
|
4586
|
+
function registerInitCommand(program, env) {
|
|
4587
|
+
program.command(COMMANDS.init).description("Initialize llmist configuration at ~/.llmist/cli.toml").action((options) => executeAction(() => executeInit(options, env), env));
|
|
4588
|
+
}
|
|
4589
|
+
|
|
3948
4590
|
// src/cli/environment.ts
|
|
3949
4591
|
init_client();
|
|
3950
4592
|
init_logger();
|
|
@@ -4047,7 +4689,7 @@ function createCommandEnvironment(baseEnv, config) {
|
|
|
4047
4689
|
createLogger: createLoggerFactory(loggerConfig)
|
|
4048
4690
|
};
|
|
4049
4691
|
}
|
|
4050
|
-
function registerCustomCommand(program, name, config, env) {
|
|
4692
|
+
function registerCustomCommand(program, name, config, env, globalSubagents) {
|
|
4051
4693
|
const type = config.type ?? "agent";
|
|
4052
4694
|
const description = config.description ?? `Custom ${type} command`;
|
|
4053
4695
|
const cmd = program.command(name).description(description).argument("[prompt]", "Prompt for the command. Falls back to stdin when available.");
|
|
@@ -4072,7 +4714,8 @@ function registerCustomCommand(program, name, config, env) {
|
|
|
4072
4714
|
const configDefaults = configToAgentOptions(config);
|
|
4073
4715
|
const options = {
|
|
4074
4716
|
...configDefaults,
|
|
4075
|
-
...cliOptions
|
|
4717
|
+
...cliOptions,
|
|
4718
|
+
globalSubagents
|
|
4076
4719
|
};
|
|
4077
4720
|
await executeAgent(prompt, options, cmdEnv);
|
|
4078
4721
|
}, cmdEnv);
|
|
@@ -4515,7 +5158,7 @@ function registerGadgetCommand(program, env) {
|
|
|
4515
5158
|
}
|
|
4516
5159
|
|
|
4517
5160
|
// src/cli/image-command.ts
|
|
4518
|
-
import { writeFileSync as
|
|
5161
|
+
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
4519
5162
|
var DEFAULT_IMAGE_MODEL = "dall-e-3";
|
|
4520
5163
|
async function executeImage(promptArg, options, env) {
|
|
4521
5164
|
const prompt = await resolvePrompt(promptArg, env);
|
|
@@ -4539,7 +5182,7 @@ async function executeImage(promptArg, options, env) {
|
|
|
4539
5182
|
const imageData = result.images[0];
|
|
4540
5183
|
if (imageData.b64Json) {
|
|
4541
5184
|
const buffer = Buffer.from(imageData.b64Json, "base64");
|
|
4542
|
-
|
|
5185
|
+
writeFileSync3(options.output, buffer);
|
|
4543
5186
|
if (!options.quiet) {
|
|
4544
5187
|
env.stderr.write(`${SUMMARY_PREFIX} Image saved to ${options.output}
|
|
4545
5188
|
`);
|
|
@@ -4980,7 +5623,7 @@ function registerModelsCommand(program, env) {
|
|
|
4980
5623
|
}
|
|
4981
5624
|
|
|
4982
5625
|
// src/cli/speech-command.ts
|
|
4983
|
-
import { writeFileSync as
|
|
5626
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
4984
5627
|
var DEFAULT_SPEECH_MODEL = "tts-1";
|
|
4985
5628
|
var DEFAULT_VOICE = "nova";
|
|
4986
5629
|
async function executeSpeech(textArg, options, env) {
|
|
@@ -5003,7 +5646,7 @@ async function executeSpeech(textArg, options, env) {
|
|
|
5003
5646
|
});
|
|
5004
5647
|
const audioBuffer = Buffer.from(result.audio);
|
|
5005
5648
|
if (options.output) {
|
|
5006
|
-
|
|
5649
|
+
writeFileSync4(options.output, audioBuffer);
|
|
5007
5650
|
if (!options.quiet) {
|
|
5008
5651
|
env.stderr.write(`${SUMMARY_PREFIX} Audio saved to ${options.output}
|
|
5009
5652
|
`);
|
|
@@ -5077,17 +5720,18 @@ function createProgram(env, config) {
|
|
|
5077
5720
|
writeErr: (str) => env.stderr.write(str)
|
|
5078
5721
|
});
|
|
5079
5722
|
registerCompleteCommand(program, env, config?.complete);
|
|
5080
|
-
registerAgentCommand(program, env, config?.agent);
|
|
5723
|
+
registerAgentCommand(program, env, config?.agent, config?.subagents);
|
|
5081
5724
|
registerImageCommand(program, env, config?.image);
|
|
5082
5725
|
registerSpeechCommand(program, env, config?.speech);
|
|
5083
5726
|
registerVisionCommand(program, env);
|
|
5084
5727
|
registerModelsCommand(program, env);
|
|
5085
5728
|
registerGadgetCommand(program, env);
|
|
5729
|
+
registerInitCommand(program, env);
|
|
5086
5730
|
if (config) {
|
|
5087
5731
|
const customNames = getCustomCommandNames(config);
|
|
5088
5732
|
for (const name of customNames) {
|
|
5089
5733
|
const cmdConfig = config[name];
|
|
5090
|
-
registerCustomCommand(program, name, cmdConfig, env);
|
|
5734
|
+
registerCustomCommand(program, name, cmdConfig, env, config.subagents);
|
|
5091
5735
|
}
|
|
5092
5736
|
}
|
|
5093
5737
|
return program;
|