@llmist/cli 16.1.0 → 16.2.1
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.js +288 -44
- package/dist/cli.js.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -110,7 +110,7 @@ import { Command, InvalidArgumentError as InvalidArgumentError2 } from "commande
|
|
|
110
110
|
// package.json
|
|
111
111
|
var package_default = {
|
|
112
112
|
name: "@llmist/cli",
|
|
113
|
-
version: "16.1
|
|
113
|
+
version: "16.2.1",
|
|
114
114
|
description: "CLI for llmist - run LLM agents from the command line",
|
|
115
115
|
type: "module",
|
|
116
116
|
main: "dist/cli.js",
|
|
@@ -167,7 +167,7 @@ var package_default = {
|
|
|
167
167
|
node: ">=22.0.0"
|
|
168
168
|
},
|
|
169
169
|
dependencies: {
|
|
170
|
-
llmist: "^16.1
|
|
170
|
+
llmist: "^16.2.1",
|
|
171
171
|
"@unblessed/node": "^1.0.0-alpha.23",
|
|
172
172
|
"diff-match-patch": "^1.0.5",
|
|
173
173
|
chalk: "^5.6.2",
|
|
@@ -182,7 +182,7 @@ var package_default = {
|
|
|
182
182
|
zod: "^4.1.12"
|
|
183
183
|
},
|
|
184
184
|
devDependencies: {
|
|
185
|
-
"@llmist/testing": "^16.1
|
|
185
|
+
"@llmist/testing": "^16.2.1",
|
|
186
186
|
"@types/diff": "^8.0.0",
|
|
187
187
|
"@types/diff-match-patch": "^1.0.36",
|
|
188
188
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -211,15 +211,15 @@ var CONVERSION_TIMEOUT_MS = 3e4;
|
|
|
211
211
|
var ffmpegCheckPromise = null;
|
|
212
212
|
async function isFFmpegAvailable() {
|
|
213
213
|
if (ffmpegCheckPromise !== null) return ffmpegCheckPromise;
|
|
214
|
-
ffmpegCheckPromise = new Promise((
|
|
214
|
+
ffmpegCheckPromise = new Promise((resolve4) => {
|
|
215
215
|
const proc = spawn("ffmpeg", ["-version"], { stdio: "ignore" });
|
|
216
|
-
proc.on("error", () =>
|
|
217
|
-
proc.on("close", (code) =>
|
|
216
|
+
proc.on("error", () => resolve4(false));
|
|
217
|
+
proc.on("close", (code) => resolve4(code === 0));
|
|
218
218
|
});
|
|
219
219
|
return ffmpegCheckPromise;
|
|
220
220
|
}
|
|
221
221
|
async function convertToMp3(input, inputFormat, timeout = CONVERSION_TIMEOUT_MS) {
|
|
222
|
-
return new Promise((
|
|
222
|
+
return new Promise((resolve4) => {
|
|
223
223
|
let timeoutId;
|
|
224
224
|
const inputArgs = inputFormat === "pcm16" ? ["-f", "s16le", "-ar", "24000", "-ac", "1"] : ["-f", inputFormat];
|
|
225
225
|
const proc = spawn(
|
|
@@ -244,15 +244,15 @@ async function convertToMp3(input, inputFormat, timeout = CONVERSION_TIMEOUT_MS)
|
|
|
244
244
|
proc.stdout.on("data", (chunk) => chunks.push(chunk));
|
|
245
245
|
proc.on("error", () => {
|
|
246
246
|
clearTimeout(timeoutId);
|
|
247
|
-
|
|
247
|
+
resolve4(null);
|
|
248
248
|
});
|
|
249
249
|
proc.on("close", (code) => {
|
|
250
250
|
clearTimeout(timeoutId);
|
|
251
|
-
|
|
251
|
+
resolve4(code === 0 ? Buffer.concat(chunks) : null);
|
|
252
252
|
});
|
|
253
253
|
timeoutId = setTimeout(() => {
|
|
254
254
|
proc.kill();
|
|
255
|
-
|
|
255
|
+
resolve4(null);
|
|
256
256
|
}, timeout);
|
|
257
257
|
proc.stdin.on("error", () => {
|
|
258
258
|
});
|
|
@@ -1413,6 +1413,48 @@ function resolveTemplatesInConfig(config, configPath) {
|
|
|
1413
1413
|
return result;
|
|
1414
1414
|
}
|
|
1415
1415
|
|
|
1416
|
+
// src/skills/config-types.ts
|
|
1417
|
+
var SKILLS_CONFIG_KEYS = /* @__PURE__ */ new Set(["sources", "overrides"]);
|
|
1418
|
+
var SKILL_OVERRIDE_KEYS = /* @__PURE__ */ new Set(["model", "enabled"]);
|
|
1419
|
+
function validateSkillsConfig(value, sectionName) {
|
|
1420
|
+
if (typeof value !== "object" || value === null) {
|
|
1421
|
+
throw new Error(`[${sectionName}] must be a table`);
|
|
1422
|
+
}
|
|
1423
|
+
const raw = value;
|
|
1424
|
+
const result = {};
|
|
1425
|
+
for (const [key, val] of Object.entries(raw)) {
|
|
1426
|
+
if (key === "sources") {
|
|
1427
|
+
if (!Array.isArray(val)) {
|
|
1428
|
+
throw new Error(`[${sectionName}].sources must be an array`);
|
|
1429
|
+
}
|
|
1430
|
+
result.sources = val.map(String);
|
|
1431
|
+
} else if (key === "overrides") {
|
|
1432
|
+
if (typeof val !== "object" || val === null) {
|
|
1433
|
+
throw new Error(`[${sectionName}].overrides must be a table`);
|
|
1434
|
+
}
|
|
1435
|
+
result.overrides = {};
|
|
1436
|
+
for (const [skillName, override] of Object.entries(val)) {
|
|
1437
|
+
if (typeof override !== "object" || override === null) {
|
|
1438
|
+
throw new Error(`[${sectionName}].overrides.${skillName} must be a table`);
|
|
1439
|
+
}
|
|
1440
|
+
const overrideObj = override;
|
|
1441
|
+
const skillOverride = {};
|
|
1442
|
+
for (const [oKey, oVal] of Object.entries(overrideObj)) {
|
|
1443
|
+
if (!SKILL_OVERRIDE_KEYS.has(oKey)) {
|
|
1444
|
+
throw new Error(`[${sectionName}].overrides.${skillName}: unknown key "${oKey}"`);
|
|
1445
|
+
}
|
|
1446
|
+
if (oKey === "model") skillOverride.model = String(oVal);
|
|
1447
|
+
if (oKey === "enabled") skillOverride.enabled = Boolean(oVal);
|
|
1448
|
+
}
|
|
1449
|
+
result.overrides[skillName] = skillOverride;
|
|
1450
|
+
}
|
|
1451
|
+
} else if (!SKILLS_CONFIG_KEYS.has(key)) {
|
|
1452
|
+
throw new Error(`[${sectionName}]: unknown key "${key}"`);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
return result;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1416
1458
|
// src/config.ts
|
|
1417
1459
|
function getConfigPath() {
|
|
1418
1460
|
return join(homedir2(), ".llmist", "cli.toml");
|
|
@@ -1443,6 +1485,8 @@ function validateConfig(raw, configPath) {
|
|
|
1443
1485
|
result["rate-limits"] = validateRateLimitsConfig(value, key);
|
|
1444
1486
|
} else if (key === "retry") {
|
|
1445
1487
|
result.retry = validateRetryConfig(value, key);
|
|
1488
|
+
} else if (key === "skills") {
|
|
1489
|
+
result.skills = validateSkillsConfig(value, key);
|
|
1446
1490
|
} else {
|
|
1447
1491
|
result[key] = validateCustomConfig(value, key);
|
|
1448
1492
|
}
|
|
@@ -1607,6 +1651,12 @@ var PathSandboxException = class extends Error {
|
|
|
1607
1651
|
function validatePathIsWithinCwd(inputPath) {
|
|
1608
1652
|
const cwd = process.cwd();
|
|
1609
1653
|
const resolvedPath = path.resolve(cwd, inputPath);
|
|
1654
|
+
let realCwd;
|
|
1655
|
+
try {
|
|
1656
|
+
realCwd = fs.realpathSync(cwd);
|
|
1657
|
+
} catch {
|
|
1658
|
+
realCwd = cwd;
|
|
1659
|
+
}
|
|
1610
1660
|
let finalPath;
|
|
1611
1661
|
try {
|
|
1612
1662
|
finalPath = fs.realpathSync(resolvedPath);
|
|
@@ -1618,8 +1668,8 @@ function validatePathIsWithinCwd(inputPath) {
|
|
|
1618
1668
|
throw error;
|
|
1619
1669
|
}
|
|
1620
1670
|
}
|
|
1621
|
-
const cwdWithSep =
|
|
1622
|
-
if (!finalPath.startsWith(cwdWithSep) && finalPath !==
|
|
1671
|
+
const cwdWithSep = realCwd + path.sep;
|
|
1672
|
+
if (!finalPath.startsWith(cwdWithSep) && finalPath !== realCwd) {
|
|
1623
1673
|
throw new PathSandboxException(inputPath, "Path is outside the current working directory");
|
|
1624
1674
|
}
|
|
1625
1675
|
return finalPath;
|
|
@@ -2670,9 +2720,9 @@ function spawn2(argv, options = {}) {
|
|
|
2670
2720
|
options.stderr === "pipe" ? "pipe" : options.stderr ?? "ignore"
|
|
2671
2721
|
]
|
|
2672
2722
|
});
|
|
2673
|
-
const exited = new Promise((
|
|
2723
|
+
const exited = new Promise((resolve4, reject) => {
|
|
2674
2724
|
proc.on("exit", (code) => {
|
|
2675
|
-
|
|
2725
|
+
resolve4(code ?? 1);
|
|
2676
2726
|
});
|
|
2677
2727
|
proc.on("error", (err) => {
|
|
2678
2728
|
reject(err);
|
|
@@ -4858,14 +4908,14 @@ function configToCompleteOptions(config) {
|
|
|
4858
4908
|
if (rl["tokens-per-minute"] !== void 0) result.rateLimitTpm = rl["tokens-per-minute"];
|
|
4859
4909
|
if (rl["tokens-per-day"] !== void 0) result.rateLimitDaily = rl["tokens-per-day"];
|
|
4860
4910
|
if (rl["safety-margin"] !== void 0) result.rateLimitSafetyMargin = rl["safety-margin"];
|
|
4861
|
-
if (rl.enabled === false) result.
|
|
4911
|
+
if (rl.enabled === false) result.rateLimit = false;
|
|
4862
4912
|
}
|
|
4863
4913
|
if (config.retry) {
|
|
4864
4914
|
const r = config.retry;
|
|
4865
4915
|
if (r.retries !== void 0) result.maxRetries = r.retries;
|
|
4866
4916
|
if (r["min-timeout"] !== void 0) result.retryMinTimeout = r["min-timeout"];
|
|
4867
4917
|
if (r["max-timeout"] !== void 0) result.retryMaxTimeout = r["max-timeout"];
|
|
4868
|
-
if (r.enabled === false) result.
|
|
4918
|
+
if (r.enabled === false) result.retry = false;
|
|
4869
4919
|
}
|
|
4870
4920
|
if (config.reasoning) {
|
|
4871
4921
|
result.profileReasoning = config.reasoning;
|
|
@@ -4900,14 +4950,14 @@ function configToAgentOptions(config) {
|
|
|
4900
4950
|
if (rl["tokens-per-minute"] !== void 0) result.rateLimitTpm = rl["tokens-per-minute"];
|
|
4901
4951
|
if (rl["tokens-per-day"] !== void 0) result.rateLimitDaily = rl["tokens-per-day"];
|
|
4902
4952
|
if (rl["safety-margin"] !== void 0) result.rateLimitSafetyMargin = rl["safety-margin"];
|
|
4903
|
-
if (rl.enabled === false) result.
|
|
4953
|
+
if (rl.enabled === false) result.rateLimit = false;
|
|
4904
4954
|
}
|
|
4905
4955
|
if (config.retry) {
|
|
4906
4956
|
const r = config.retry;
|
|
4907
4957
|
if (r.retries !== void 0) result.maxRetries = r.retries;
|
|
4908
4958
|
if (r["min-timeout"] !== void 0) result.retryMinTimeout = r["min-timeout"];
|
|
4909
4959
|
if (r["max-timeout"] !== void 0) result.retryMaxTimeout = r["max-timeout"];
|
|
4910
|
-
if (r.enabled === false) result.
|
|
4960
|
+
if (r.enabled === false) result.retry = false;
|
|
4911
4961
|
}
|
|
4912
4962
|
if (config.reasoning) {
|
|
4913
4963
|
result.profileReasoning = config.reasoning;
|
|
@@ -4951,7 +5001,7 @@ function detectProvider(model) {
|
|
|
4951
5001
|
}
|
|
4952
5002
|
}
|
|
4953
5003
|
function resolveRateLimitConfig(options, globalConfig, profileConfig, model) {
|
|
4954
|
-
if (options.
|
|
5004
|
+
if (options.rateLimit === false) {
|
|
4955
5005
|
return { enabled: false, safetyMargin: 0.8 };
|
|
4956
5006
|
}
|
|
4957
5007
|
let resolved;
|
|
@@ -5076,12 +5126,82 @@ function resolveRetryConfig(options, globalConfig, profileConfig) {
|
|
|
5076
5126
|
if (options.retryMaxTimeout !== void 0) {
|
|
5077
5127
|
resolved.maxTimeout = options.retryMaxTimeout;
|
|
5078
5128
|
}
|
|
5079
|
-
if (options.
|
|
5129
|
+
if (options.retry === false) {
|
|
5080
5130
|
resolved.enabled = false;
|
|
5081
5131
|
}
|
|
5082
5132
|
return resolved;
|
|
5083
5133
|
}
|
|
5084
5134
|
|
|
5135
|
+
// src/skills/skill-manager.ts
|
|
5136
|
+
import { homedir as homedir3 } from "os";
|
|
5137
|
+
import { join as join2, resolve as resolve3 } from "path";
|
|
5138
|
+
import { discoverSkills, loadSkillsFromDirectory } from "llmist";
|
|
5139
|
+
var CLISkillManager = class {
|
|
5140
|
+
/**
|
|
5141
|
+
* Load all skills from standard locations and configured sources.
|
|
5142
|
+
*
|
|
5143
|
+
* @param config - Skills configuration from cli.toml [skills] section
|
|
5144
|
+
* @param projectDir - Project directory (cwd)
|
|
5145
|
+
*/
|
|
5146
|
+
async loadAll(config, projectDir) {
|
|
5147
|
+
const registry = discoverSkills({
|
|
5148
|
+
projectDir: projectDir ?? process.cwd()
|
|
5149
|
+
});
|
|
5150
|
+
if (config?.sources) {
|
|
5151
|
+
for (const source of config.sources) {
|
|
5152
|
+
const resolvedSource = this.resolveSource(source);
|
|
5153
|
+
const skills = loadSkillsFromDirectory(resolvedSource, {
|
|
5154
|
+
type: "directory",
|
|
5155
|
+
path: resolvedSource
|
|
5156
|
+
});
|
|
5157
|
+
registry.registerMany(skills);
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
if (config?.overrides) {
|
|
5161
|
+
for (const [skillName, override] of Object.entries(config.overrides)) {
|
|
5162
|
+
if (override.enabled === false) {
|
|
5163
|
+
registry.remove(skillName);
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5166
|
+
}
|
|
5167
|
+
return registry;
|
|
5168
|
+
}
|
|
5169
|
+
/**
|
|
5170
|
+
* Resolve a source string to an absolute directory path.
|
|
5171
|
+
*/
|
|
5172
|
+
resolveSource(source) {
|
|
5173
|
+
if (source.startsWith("~")) {
|
|
5174
|
+
return join2(homedir3(), source.slice(1));
|
|
5175
|
+
}
|
|
5176
|
+
return resolve3(source);
|
|
5177
|
+
}
|
|
5178
|
+
};
|
|
5179
|
+
|
|
5180
|
+
// src/skills/slash-handler.ts
|
|
5181
|
+
function parseSlashCommand(input, registry) {
|
|
5182
|
+
const trimmed = input.trim();
|
|
5183
|
+
if (!trimmed.startsWith("/")) {
|
|
5184
|
+
return { isSkillInvocation: false };
|
|
5185
|
+
}
|
|
5186
|
+
const match = trimmed.match(/^\/(\S+)(?:\s+(.*))?$/);
|
|
5187
|
+
if (!match) {
|
|
5188
|
+
return { isSkillInvocation: false };
|
|
5189
|
+
}
|
|
5190
|
+
const [, commandName, args] = match;
|
|
5191
|
+
if (commandName === "skills") {
|
|
5192
|
+
return { isSkillInvocation: true, isListCommand: true };
|
|
5193
|
+
}
|
|
5194
|
+
const skill = registry.get(commandName);
|
|
5195
|
+
if (!skill || !skill.isUserInvocable) {
|
|
5196
|
+
return { isSkillInvocation: false };
|
|
5197
|
+
}
|
|
5198
|
+
return {
|
|
5199
|
+
isSkillInvocation: true,
|
|
5200
|
+
skillName: commandName,
|
|
5201
|
+
arguments: args?.trim()
|
|
5202
|
+
};
|
|
5203
|
+
}
|
|
5204
|
+
|
|
5085
5205
|
// src/subagent-config.ts
|
|
5086
5206
|
var INHERIT_MODEL = "inherit";
|
|
5087
5207
|
function resolveSubagentConfig(subagentName, parentModel, profileConfig, globalConfig) {
|
|
@@ -7448,10 +7568,10 @@ var HintsBar = class {
|
|
|
7448
7568
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7449
7569
|
import { readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
7450
7570
|
import { tmpdir } from "os";
|
|
7451
|
-
import { join as
|
|
7571
|
+
import { join as join3 } from "path";
|
|
7452
7572
|
function openEditorSync(initialContent = "") {
|
|
7453
7573
|
const editor = process.env.VISUAL || process.env.EDITOR || "vi";
|
|
7454
|
-
const tmpFile =
|
|
7574
|
+
const tmpFile = join3(tmpdir(), `llmist-input-${Date.now()}.txt`);
|
|
7455
7575
|
writeFileSync2(tmpFile, initialContent, "utf-8");
|
|
7456
7576
|
try {
|
|
7457
7577
|
const parts = editor.split(/\s+/);
|
|
@@ -7686,11 +7806,11 @@ var InputHandler = class {
|
|
|
7686
7806
|
* @returns Promise that resolves with user's response
|
|
7687
7807
|
*/
|
|
7688
7808
|
async waitForInput(question, gadgetName) {
|
|
7689
|
-
return new Promise((
|
|
7809
|
+
return new Promise((resolve4, reject) => {
|
|
7690
7810
|
this.pendingInput = {
|
|
7691
7811
|
question,
|
|
7692
7812
|
gadgetName,
|
|
7693
|
-
resolve:
|
|
7813
|
+
resolve: resolve4,
|
|
7694
7814
|
reject
|
|
7695
7815
|
};
|
|
7696
7816
|
this.setActive();
|
|
@@ -7705,11 +7825,11 @@ var InputHandler = class {
|
|
|
7705
7825
|
* @returns Promise that resolves with user's prompt
|
|
7706
7826
|
*/
|
|
7707
7827
|
async waitForPrompt() {
|
|
7708
|
-
return new Promise((
|
|
7828
|
+
return new Promise((resolve4, reject) => {
|
|
7709
7829
|
this.pendingInput = {
|
|
7710
7830
|
question: "",
|
|
7711
7831
|
gadgetName: "prompt",
|
|
7712
|
-
resolve:
|
|
7832
|
+
resolve: resolve4,
|
|
7713
7833
|
reject
|
|
7714
7834
|
};
|
|
7715
7835
|
this.setPendingPrompt();
|
|
@@ -7805,10 +7925,10 @@ var InputHandler = class {
|
|
|
7805
7925
|
return;
|
|
7806
7926
|
}
|
|
7807
7927
|
if (this.pendingInput) {
|
|
7808
|
-
const { resolve:
|
|
7928
|
+
const { resolve: resolve4 } = this.pendingInput;
|
|
7809
7929
|
this.pendingInput = null;
|
|
7810
7930
|
this.setIdle();
|
|
7811
|
-
|
|
7931
|
+
resolve4(value);
|
|
7812
7932
|
} else if (this.midSessionHandler) {
|
|
7813
7933
|
this.midSessionHandler(value);
|
|
7814
7934
|
this.setIdle();
|
|
@@ -8266,7 +8386,7 @@ import { Box as Box3 } from "@unblessed/node";
|
|
|
8266
8386
|
var MAX_PREVIEW_LINES = 10;
|
|
8267
8387
|
var MAX_PARAM_VALUE_LENGTH = 60;
|
|
8268
8388
|
function showApprovalDialog(screen, context) {
|
|
8269
|
-
return new Promise((
|
|
8389
|
+
return new Promise((resolve4) => {
|
|
8270
8390
|
const content = buildDialogContent(context);
|
|
8271
8391
|
const dialog = new Box3({
|
|
8272
8392
|
parent: screen,
|
|
@@ -8321,7 +8441,7 @@ function showApprovalDialog(screen, context) {
|
|
|
8321
8441
|
if (response) {
|
|
8322
8442
|
dialog.destroy();
|
|
8323
8443
|
screen.render();
|
|
8324
|
-
|
|
8444
|
+
resolve4(response);
|
|
8325
8445
|
}
|
|
8326
8446
|
};
|
|
8327
8447
|
dialog.on("keypress", handleKey);
|
|
@@ -8391,7 +8511,7 @@ var WHITE = "\x1B[37m";
|
|
|
8391
8511
|
function showRawViewer(options) {
|
|
8392
8512
|
let closeCallback = () => {
|
|
8393
8513
|
};
|
|
8394
|
-
const closed = new Promise((
|
|
8514
|
+
const closed = new Promise((resolve4) => {
|
|
8395
8515
|
const {
|
|
8396
8516
|
screen,
|
|
8397
8517
|
mode,
|
|
@@ -8487,7 +8607,7 @@ ${error}`;
|
|
|
8487
8607
|
helpBar.destroy();
|
|
8488
8608
|
viewer.destroy();
|
|
8489
8609
|
screen.render();
|
|
8490
|
-
|
|
8610
|
+
resolve4();
|
|
8491
8611
|
};
|
|
8492
8612
|
closeCallback = close;
|
|
8493
8613
|
viewer.key(["escape", "q"], close);
|
|
@@ -9888,6 +10008,14 @@ async function executeAgent(promptArg, options, env, commandName) {
|
|
|
9888
10008
|
registry.registerByClass(gadget);
|
|
9889
10009
|
}
|
|
9890
10010
|
}
|
|
10011
|
+
let skillsConfig;
|
|
10012
|
+
try {
|
|
10013
|
+
const fullConfig = loadConfig();
|
|
10014
|
+
skillsConfig = fullConfig.skills;
|
|
10015
|
+
} catch {
|
|
10016
|
+
}
|
|
10017
|
+
const skillManager = new CLISkillManager();
|
|
10018
|
+
const skillRegistry = await skillManager.loadAll(skillsConfig);
|
|
9891
10019
|
let tui = null;
|
|
9892
10020
|
if (useTUI) {
|
|
9893
10021
|
tui = await TUIApp.create({
|
|
@@ -10121,6 +10249,9 @@ ${ctx.gadgetName} requires interactive approval. Enable TUI mode or adjust 'gadg
|
|
|
10121
10249
|
if (options.temperature !== void 0) {
|
|
10122
10250
|
builder.withTemperature(options.temperature);
|
|
10123
10251
|
}
|
|
10252
|
+
if (skillRegistry.size > 0) {
|
|
10253
|
+
builder.withSkills(skillRegistry);
|
|
10254
|
+
}
|
|
10124
10255
|
if (options.reasoning === false) {
|
|
10125
10256
|
builder.withoutReasoning();
|
|
10126
10257
|
} else if (options.reasoning !== void 0 || options.reasoningBudget !== void 0) {
|
|
@@ -10197,6 +10328,29 @@ ${ctx.gadgetName} requires interactive approval. Enable TUI mode or adjust 'gadg
|
|
|
10197
10328
|
);
|
|
10198
10329
|
let currentAgent = null;
|
|
10199
10330
|
const runAgentWithPrompt = async (userPrompt) => {
|
|
10331
|
+
builder.clearPreActivatedSkills();
|
|
10332
|
+
if (skillRegistry.size > 0 && userPrompt.startsWith("/")) {
|
|
10333
|
+
const slashResult = parseSlashCommand(userPrompt, skillRegistry);
|
|
10334
|
+
if (slashResult.isSkillInvocation) {
|
|
10335
|
+
if (slashResult.isListCommand) {
|
|
10336
|
+
const skills = skillRegistry.getUserInvocable();
|
|
10337
|
+
const lines = skills.map((s) => ` /${s.name} \u2014 ${s.description}`);
|
|
10338
|
+
const msg = skills.length > 0 ? `Available skills:
|
|
10339
|
+
${lines.join("\n")}` : "No skills available.";
|
|
10340
|
+
if (tui) {
|
|
10341
|
+
tui.showUserMessage(`/skills`);
|
|
10342
|
+
tui.showUserMessage(msg);
|
|
10343
|
+
} else {
|
|
10344
|
+
env.stdout.write(`${msg}
|
|
10345
|
+
`);
|
|
10346
|
+
}
|
|
10347
|
+
return;
|
|
10348
|
+
}
|
|
10349
|
+
if (slashResult.skillName) {
|
|
10350
|
+
builder.withSkill(slashResult.skillName, slashResult.arguments);
|
|
10351
|
+
}
|
|
10352
|
+
}
|
|
10353
|
+
}
|
|
10200
10354
|
if (tui) {
|
|
10201
10355
|
tui.resetAbort();
|
|
10202
10356
|
tui.startNewSession();
|
|
@@ -10321,11 +10475,11 @@ import {
|
|
|
10321
10475
|
|
|
10322
10476
|
// src/llm-logging.ts
|
|
10323
10477
|
import { mkdir, writeFile as writeFile2 } from "fs/promises";
|
|
10324
|
-
import { join as
|
|
10478
|
+
import { join as join4 } from "path";
|
|
10325
10479
|
import { formatCallNumber as formatCallNumber2, formatLlmRequest } from "llmist";
|
|
10326
10480
|
async function writeLogFile(dir, filename, content) {
|
|
10327
10481
|
await mkdir(dir, { recursive: true });
|
|
10328
|
-
await writeFile2(
|
|
10482
|
+
await writeFile2(join4(dir, filename), content, "utf-8");
|
|
10329
10483
|
}
|
|
10330
10484
|
|
|
10331
10485
|
// src/complete-command.ts
|
|
@@ -10603,7 +10757,7 @@ System Prompt (${chars.toLocaleString()} chars, ${lines} lines):
|
|
|
10603
10757
|
}
|
|
10604
10758
|
|
|
10605
10759
|
// src/environment.ts
|
|
10606
|
-
import { join as
|
|
10760
|
+
import { join as join5 } from "path";
|
|
10607
10761
|
import readline from "readline";
|
|
10608
10762
|
import chalk7 from "chalk";
|
|
10609
10763
|
import { createLogger, LLMist } from "llmist";
|
|
@@ -10626,7 +10780,7 @@ function createLoggerFactory(config, sessionLogDir) {
|
|
|
10626
10780
|
}
|
|
10627
10781
|
}
|
|
10628
10782
|
if (sessionLogDir) {
|
|
10629
|
-
const logFile =
|
|
10783
|
+
const logFile = join5(sessionLogDir, "session.log.jsonl");
|
|
10630
10784
|
const originalLogFile = process.env.LLMIST_LOG_FILE;
|
|
10631
10785
|
process.env.LLMIST_LOG_FILE = logFile;
|
|
10632
10786
|
const logger = createLogger(options);
|
|
@@ -10645,7 +10799,7 @@ function createLoggerFactory(config, sessionLogDir) {
|
|
|
10645
10799
|
}
|
|
10646
10800
|
function createPromptFunction(stdin, stdout) {
|
|
10647
10801
|
return (question) => {
|
|
10648
|
-
return new Promise((
|
|
10802
|
+
return new Promise((resolve4) => {
|
|
10649
10803
|
const rl = readline.createInterface({
|
|
10650
10804
|
input: stdin,
|
|
10651
10805
|
output: stdout
|
|
@@ -10660,7 +10814,7 @@ function createPromptFunction(stdin, stdout) {
|
|
|
10660
10814
|
`);
|
|
10661
10815
|
rl.question(chalk7.green.bold("You: "), (answer) => {
|
|
10662
10816
|
rl.close();
|
|
10663
|
-
|
|
10817
|
+
resolve4(answer);
|
|
10664
10818
|
});
|
|
10665
10819
|
});
|
|
10666
10820
|
};
|
|
@@ -11729,8 +11883,8 @@ function registerModelsCommand(program, env) {
|
|
|
11729
11883
|
// src/session.ts
|
|
11730
11884
|
import { existsSync as existsSync4 } from "fs";
|
|
11731
11885
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
11732
|
-
import { homedir as
|
|
11733
|
-
import { join as
|
|
11886
|
+
import { homedir as homedir4 } from "os";
|
|
11887
|
+
import { join as join6 } from "path";
|
|
11734
11888
|
|
|
11735
11889
|
// src/session-names.ts
|
|
11736
11890
|
var ADJECTIVES = [
|
|
@@ -11865,16 +12019,16 @@ function generateSessionName() {
|
|
|
11865
12019
|
|
|
11866
12020
|
// src/session.ts
|
|
11867
12021
|
var currentSession;
|
|
11868
|
-
var SESSION_LOGS_BASE =
|
|
12022
|
+
var SESSION_LOGS_BASE = join6(homedir4(), ".llmist", "logs");
|
|
11869
12023
|
function findUniqueName(baseName) {
|
|
11870
|
-
const baseDir =
|
|
12024
|
+
const baseDir = join6(SESSION_LOGS_BASE, baseName);
|
|
11871
12025
|
if (!existsSync4(baseDir)) {
|
|
11872
12026
|
return baseName;
|
|
11873
12027
|
}
|
|
11874
12028
|
let suffix = 2;
|
|
11875
12029
|
while (suffix < 1e3) {
|
|
11876
12030
|
const name = `${baseName}-${suffix}`;
|
|
11877
|
-
const dir =
|
|
12031
|
+
const dir = join6(SESSION_LOGS_BASE, name);
|
|
11878
12032
|
if (!existsSync4(dir)) {
|
|
11879
12033
|
return name;
|
|
11880
12034
|
}
|
|
@@ -11888,12 +12042,101 @@ async function initSession() {
|
|
|
11888
12042
|
}
|
|
11889
12043
|
const baseName = generateSessionName();
|
|
11890
12044
|
const name = findUniqueName(baseName);
|
|
11891
|
-
const logDir =
|
|
12045
|
+
const logDir = join6(SESSION_LOGS_BASE, name);
|
|
11892
12046
|
await mkdir2(logDir, { recursive: true });
|
|
11893
12047
|
currentSession = { name, logDir };
|
|
11894
12048
|
return currentSession;
|
|
11895
12049
|
}
|
|
11896
12050
|
|
|
12051
|
+
// src/skills/skill-command.ts
|
|
12052
|
+
function registerSkillCommand(program, env) {
|
|
12053
|
+
const skillCmd = program.command("skill").description("Manage Agent Skills (SKILL.md)");
|
|
12054
|
+
skillCmd.command("list").description("List available skills").action(async () => {
|
|
12055
|
+
const config = safeLoadConfig();
|
|
12056
|
+
const manager = new CLISkillManager();
|
|
12057
|
+
const registry = await manager.loadAll(config?.skills);
|
|
12058
|
+
const skills = registry.getAll();
|
|
12059
|
+
if (skills.length === 0) {
|
|
12060
|
+
env.stdout.write("No skills found.\n");
|
|
12061
|
+
env.stdout.write(
|
|
12062
|
+
"Add skills to ~/.llmist/skills/ or configure [skills].sources in ~/.llmist/cli.toml\n"
|
|
12063
|
+
);
|
|
12064
|
+
return;
|
|
12065
|
+
}
|
|
12066
|
+
env.stdout.write(`Found ${skills.length} skill(s):
|
|
12067
|
+
|
|
12068
|
+
`);
|
|
12069
|
+
for (const skill of skills) {
|
|
12070
|
+
const flags = [];
|
|
12071
|
+
if (!skill.isModelInvocable) flags.push("user-only");
|
|
12072
|
+
if (!skill.isUserInvocable) flags.push("background");
|
|
12073
|
+
if (skill.metadata.context === "fork") flags.push("fork");
|
|
12074
|
+
if (skill.metadata.model) flags.push(`model:${skill.metadata.model}`);
|
|
12075
|
+
const flagStr = flags.length > 0 ? ` [${flags.join(", ")}]` : "";
|
|
12076
|
+
const desc = skill.description.length > 80 ? `${skill.description.slice(0, 77)}...` : skill.description;
|
|
12077
|
+
env.stdout.write(` /${skill.name}${flagStr}
|
|
12078
|
+
`);
|
|
12079
|
+
env.stdout.write(` ${desc}
|
|
12080
|
+
|
|
12081
|
+
`);
|
|
12082
|
+
}
|
|
12083
|
+
});
|
|
12084
|
+
skillCmd.command("info <name>").description("Show detailed skill information").action(async (name) => {
|
|
12085
|
+
const config = safeLoadConfig();
|
|
12086
|
+
const manager = new CLISkillManager();
|
|
12087
|
+
const registry = await manager.loadAll(config?.skills);
|
|
12088
|
+
const skill = registry.get(name);
|
|
12089
|
+
if (!skill) {
|
|
12090
|
+
env.stderr.write(`Skill not found: ${name}
|
|
12091
|
+
`);
|
|
12092
|
+
env.stderr.write(`Available skills: ${registry.getNames().join(", ") || "(none)"}
|
|
12093
|
+
`);
|
|
12094
|
+
process.exitCode = 1;
|
|
12095
|
+
return;
|
|
12096
|
+
}
|
|
12097
|
+
env.stdout.write(`Skill: ${skill.name}
|
|
12098
|
+
`);
|
|
12099
|
+
env.stdout.write(`Description: ${skill.description}
|
|
12100
|
+
`);
|
|
12101
|
+
env.stdout.write(`Source: ${skill.sourcePath}
|
|
12102
|
+
`);
|
|
12103
|
+
if (skill.metadata.model) env.stdout.write(`Model: ${skill.metadata.model}
|
|
12104
|
+
`);
|
|
12105
|
+
if (skill.metadata.context) env.stdout.write(`Context: ${skill.metadata.context}
|
|
12106
|
+
`);
|
|
12107
|
+
if (skill.metadata.agent) env.stdout.write(`Agent: ${skill.metadata.agent}
|
|
12108
|
+
`);
|
|
12109
|
+
if (skill.metadata.allowedTools) {
|
|
12110
|
+
env.stdout.write(`Allowed tools: ${skill.metadata.allowedTools.join(", ")}
|
|
12111
|
+
`);
|
|
12112
|
+
}
|
|
12113
|
+
if (skill.metadata.paths) {
|
|
12114
|
+
env.stdout.write(`Paths: ${skill.metadata.paths.join(", ")}
|
|
12115
|
+
`);
|
|
12116
|
+
}
|
|
12117
|
+
const resources = skill.getResources();
|
|
12118
|
+
if (resources.length > 0) {
|
|
12119
|
+
env.stdout.write(`Resources: ${resources.length}
|
|
12120
|
+
`);
|
|
12121
|
+
for (const r of resources) {
|
|
12122
|
+
env.stdout.write(` ${r.category}/${r.relativePath}
|
|
12123
|
+
`);
|
|
12124
|
+
}
|
|
12125
|
+
}
|
|
12126
|
+
env.stdout.write("\n--- Instructions ---\n\n");
|
|
12127
|
+
const instructions = await skill.getInstructions();
|
|
12128
|
+
env.stdout.write(`${instructions}
|
|
12129
|
+
`);
|
|
12130
|
+
});
|
|
12131
|
+
}
|
|
12132
|
+
function safeLoadConfig() {
|
|
12133
|
+
try {
|
|
12134
|
+
return loadConfig();
|
|
12135
|
+
} catch {
|
|
12136
|
+
return void 0;
|
|
12137
|
+
}
|
|
12138
|
+
}
|
|
12139
|
+
|
|
11897
12140
|
// src/speech-command.ts
|
|
11898
12141
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
11899
12142
|
var DEFAULT_SPEECH_MODEL = "tts-1";
|
|
@@ -12005,6 +12248,7 @@ function createProgram(env, config) {
|
|
|
12005
12248
|
registerVisionCommand(program, env);
|
|
12006
12249
|
registerModelsCommand(program, env);
|
|
12007
12250
|
registerGadgetCommand(program, env);
|
|
12251
|
+
registerSkillCommand(program, env);
|
|
12008
12252
|
registerInitCommand(program, env);
|
|
12009
12253
|
registerConfigCommand(program, env, config);
|
|
12010
12254
|
if (config) {
|