llmist 1.3.0 → 1.4.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 -18
- package/dist/chunk-UEEESLOA.js +974 -0
- package/dist/chunk-UEEESLOA.js.map +1 -0
- package/dist/{chunk-RZTAKIDE.js → chunk-VGZCFUPX.js} +4627 -3211
- package/dist/chunk-VGZCFUPX.js.map +1 -0
- package/dist/cli.cjs +1321 -245
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1190 -215
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +52 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +20 -973
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-DNt-HBTn.d.cts → mock-stream-DD5yJM44.d.cts} +65 -0
- package/dist/{mock-stream-DNt-HBTn.d.ts → mock-stream-DD5yJM44.d.ts} +65 -0
- package/dist/testing/index.cjs +52 -10
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -2
- package/package.json +3 -1
- package/dist/chunk-RZTAKIDE.js.map +0 -1
- package/dist/chunk-TFIKR2RK.js +0 -1394
- package/dist/chunk-TFIKR2RK.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -172,7 +172,7 @@ Example fixes:
|
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
function findUnknownTypes(schema,
|
|
175
|
+
function findUnknownTypes(schema, path5 = []) {
|
|
176
176
|
const issues = [];
|
|
177
177
|
if (!schema || typeof schema !== "object") {
|
|
178
178
|
return issues;
|
|
@@ -184,7 +184,7 @@ function findUnknownTypes(schema, path2 = []) {
|
|
|
184
184
|
}
|
|
185
185
|
if (schema.properties) {
|
|
186
186
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
187
|
-
const propPath = [...
|
|
187
|
+
const propPath = [...path5, propName];
|
|
188
188
|
if (hasNoType(propSchema)) {
|
|
189
189
|
issues.push(propPath.join(".") || propName);
|
|
190
190
|
}
|
|
@@ -192,7 +192,7 @@ function findUnknownTypes(schema, path2 = []) {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
if (schema.items) {
|
|
195
|
-
const itemPath = [...
|
|
195
|
+
const itemPath = [...path5, "[]"];
|
|
196
196
|
if (hasNoType(schema.items)) {
|
|
197
197
|
issues.push(itemPath.join("."));
|
|
198
198
|
}
|
|
@@ -200,17 +200,17 @@ function findUnknownTypes(schema, path2 = []) {
|
|
|
200
200
|
}
|
|
201
201
|
if (schema.anyOf) {
|
|
202
202
|
schema.anyOf.forEach((subSchema, index) => {
|
|
203
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
203
|
+
issues.push(...findUnknownTypes(subSchema, [...path5, `anyOf[${index}]`]));
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
if (schema.oneOf) {
|
|
207
207
|
schema.oneOf.forEach((subSchema, index) => {
|
|
208
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
208
|
+
issues.push(...findUnknownTypes(subSchema, [...path5, `oneOf[${index}]`]));
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
if (schema.allOf) {
|
|
212
212
|
schema.allOf.forEach((subSchema, index) => {
|
|
213
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
213
|
+
issues.push(...findUnknownTypes(subSchema, [...path5, `allOf[${index}]`]));
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
return issues;
|
|
@@ -737,29 +737,29 @@ function schemaToJSONSchema(schema, options) {
|
|
|
737
737
|
}
|
|
738
738
|
function detectDescriptionMismatch(schema, jsonSchema) {
|
|
739
739
|
const mismatches = [];
|
|
740
|
-
function checkSchema(zodSchema, json,
|
|
740
|
+
function checkSchema(zodSchema, json, path5) {
|
|
741
741
|
if (!zodSchema || typeof zodSchema !== "object") return;
|
|
742
742
|
const def = zodSchema._def;
|
|
743
743
|
const jsonObj = json;
|
|
744
744
|
if (def?.description && !jsonObj?.description) {
|
|
745
|
-
mismatches.push(
|
|
745
|
+
mismatches.push(path5 || "root");
|
|
746
746
|
}
|
|
747
747
|
if (def?.typeName === "ZodObject" && def?.shape) {
|
|
748
748
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
749
749
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
750
750
|
const properties = jsonObj?.properties;
|
|
751
751
|
const jsonProp = properties?.[key];
|
|
752
|
-
checkSchema(fieldSchema, jsonProp,
|
|
752
|
+
checkSchema(fieldSchema, jsonProp, path5 ? `${path5}.${key}` : key);
|
|
753
753
|
}
|
|
754
754
|
}
|
|
755
755
|
if (def?.typeName === "ZodArray" && def?.type) {
|
|
756
|
-
checkSchema(def.type, jsonObj?.items,
|
|
756
|
+
checkSchema(def.type, jsonObj?.items, path5 ? `${path5}[]` : "[]");
|
|
757
757
|
}
|
|
758
758
|
if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
|
|
759
|
-
checkSchema(def.innerType, json,
|
|
759
|
+
checkSchema(def.innerType, json, path5);
|
|
760
760
|
}
|
|
761
761
|
if (def?.typeName === "ZodDefault" && def?.innerType) {
|
|
762
|
-
checkSchema(def.innerType, json,
|
|
762
|
+
checkSchema(def.innerType, json, path5);
|
|
763
763
|
}
|
|
764
764
|
}
|
|
765
765
|
checkSchema(schema, jsonSchema, "");
|
|
@@ -2268,8 +2268,8 @@ var init_error_formatter = __esm({
|
|
|
2268
2268
|
const parts = [];
|
|
2269
2269
|
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
2270
2270
|
for (const issue of zodError.issues) {
|
|
2271
|
-
const
|
|
2272
|
-
parts.push(` - ${
|
|
2271
|
+
const path5 = issue.path.join(".") || "root";
|
|
2272
|
+
parts.push(` - ${path5}: ${issue.message}`);
|
|
2273
2273
|
}
|
|
2274
2274
|
parts.push("");
|
|
2275
2275
|
parts.push("Gadget Usage:");
|
|
@@ -3250,6 +3250,8 @@ var init_agent = __esm({
|
|
|
3250
3250
|
outputLimitCharLimit;
|
|
3251
3251
|
// Context compaction
|
|
3252
3252
|
compactionManager;
|
|
3253
|
+
// Cancellation
|
|
3254
|
+
signal;
|
|
3253
3255
|
/**
|
|
3254
3256
|
* Creates a new Agent instance.
|
|
3255
3257
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -3317,6 +3319,7 @@ var init_agent = __esm({
|
|
|
3317
3319
|
options.compactionConfig
|
|
3318
3320
|
);
|
|
3319
3321
|
}
|
|
3322
|
+
this.signal = options.signal;
|
|
3320
3323
|
}
|
|
3321
3324
|
/**
|
|
3322
3325
|
* Get the gadget registry for this agent.
|
|
@@ -3434,7 +3437,8 @@ var init_agent = __esm({
|
|
|
3434
3437
|
model: this.model,
|
|
3435
3438
|
messages: this.conversation.getMessages(),
|
|
3436
3439
|
temperature: this.temperature,
|
|
3437
|
-
maxTokens: this.defaultMaxTokens
|
|
3440
|
+
maxTokens: this.defaultMaxTokens,
|
|
3441
|
+
signal: this.signal
|
|
3438
3442
|
};
|
|
3439
3443
|
await this.safeObserve(async () => {
|
|
3440
3444
|
if (this.hooks.observers?.onLLMCallStart) {
|
|
@@ -4052,7 +4056,7 @@ var init_base_provider = __esm({
|
|
|
4052
4056
|
async *stream(options, descriptor, spec) {
|
|
4053
4057
|
const preparedMessages = this.prepareMessages(options.messages);
|
|
4054
4058
|
const payload = this.buildRequestPayload(options, descriptor, spec, preparedMessages);
|
|
4055
|
-
const rawStream = await this.executeStreamRequest(payload);
|
|
4059
|
+
const rawStream = await this.executeStreamRequest(payload, options.signal);
|
|
4056
4060
|
yield* this.wrapStream(rawStream);
|
|
4057
4061
|
}
|
|
4058
4062
|
/**
|
|
@@ -4170,9 +4174,9 @@ var init_anthropic = __esm({
|
|
|
4170
4174
|
};
|
|
4171
4175
|
return payload;
|
|
4172
4176
|
}
|
|
4173
|
-
async executeStreamRequest(payload) {
|
|
4177
|
+
async executeStreamRequest(payload, signal) {
|
|
4174
4178
|
const client = this.client;
|
|
4175
|
-
const stream2 = await client.messages.create(payload);
|
|
4179
|
+
const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
|
|
4176
4180
|
return stream2;
|
|
4177
4181
|
}
|
|
4178
4182
|
async *wrapStream(iterable) {
|
|
@@ -4504,9 +4508,15 @@ var init_gemini = __esm({
|
|
|
4504
4508
|
config
|
|
4505
4509
|
};
|
|
4506
4510
|
}
|
|
4507
|
-
async executeStreamRequest(payload) {
|
|
4511
|
+
async executeStreamRequest(payload, signal) {
|
|
4508
4512
|
const client = this.client;
|
|
4509
|
-
const streamResponse = await client.models.generateContentStream(
|
|
4513
|
+
const streamResponse = await client.models.generateContentStream({
|
|
4514
|
+
...payload,
|
|
4515
|
+
config: {
|
|
4516
|
+
...payload.config,
|
|
4517
|
+
...signal ? { abortSignal: signal } : {}
|
|
4518
|
+
}
|
|
4519
|
+
});
|
|
4510
4520
|
return streamResponse;
|
|
4511
4521
|
}
|
|
4512
4522
|
/**
|
|
@@ -5095,9 +5105,9 @@ var init_openai = __esm({
|
|
|
5095
5105
|
...shouldIncludeTemperature ? { temperature } : {}
|
|
5096
5106
|
};
|
|
5097
5107
|
}
|
|
5098
|
-
async executeStreamRequest(payload) {
|
|
5108
|
+
async executeStreamRequest(payload, signal) {
|
|
5099
5109
|
const client = this.client;
|
|
5100
|
-
const stream2 = await client.chat.completions.create(payload);
|
|
5110
|
+
const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
|
|
5101
5111
|
return stream2;
|
|
5102
5112
|
}
|
|
5103
5113
|
async *wrapStream(iterable) {
|
|
@@ -5760,6 +5770,7 @@ var init_builder = __esm({
|
|
|
5760
5770
|
gadgetOutputLimit;
|
|
5761
5771
|
gadgetOutputLimitPercent;
|
|
5762
5772
|
compactionConfig;
|
|
5773
|
+
signal;
|
|
5763
5774
|
constructor(client) {
|
|
5764
5775
|
this.client = client;
|
|
5765
5776
|
}
|
|
@@ -6206,6 +6217,35 @@ var init_builder = __esm({
|
|
|
6206
6217
|
this.compactionConfig = { enabled: false };
|
|
6207
6218
|
return this;
|
|
6208
6219
|
}
|
|
6220
|
+
/**
|
|
6221
|
+
* Set an abort signal for cancelling requests mid-flight.
|
|
6222
|
+
*
|
|
6223
|
+
* When the signal is aborted, the current LLM request will be cancelled
|
|
6224
|
+
* and the agent loop will exit gracefully.
|
|
6225
|
+
*
|
|
6226
|
+
* @param signal - AbortSignal from an AbortController
|
|
6227
|
+
* @returns This builder for chaining
|
|
6228
|
+
*
|
|
6229
|
+
* @example
|
|
6230
|
+
* ```typescript
|
|
6231
|
+
* const controller = new AbortController();
|
|
6232
|
+
*
|
|
6233
|
+
* // Cancel after 30 seconds
|
|
6234
|
+
* setTimeout(() => controller.abort(), 30000);
|
|
6235
|
+
*
|
|
6236
|
+
* const agent = LLMist.createAgent()
|
|
6237
|
+
* .withModel("sonnet")
|
|
6238
|
+
* .withSignal(controller.signal)
|
|
6239
|
+
* .ask("Write a long story");
|
|
6240
|
+
*
|
|
6241
|
+
* // Or cancel on user action
|
|
6242
|
+
* document.getElementById("cancel").onclick = () => controller.abort();
|
|
6243
|
+
* ```
|
|
6244
|
+
*/
|
|
6245
|
+
withSignal(signal) {
|
|
6246
|
+
this.signal = signal;
|
|
6247
|
+
return this;
|
|
6248
|
+
}
|
|
6209
6249
|
/**
|
|
6210
6250
|
* Add a synthetic gadget call to the conversation history.
|
|
6211
6251
|
*
|
|
@@ -6322,7 +6362,8 @@ ${endPrefix}`
|
|
|
6322
6362
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6323
6363
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6324
6364
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6325
|
-
compactionConfig: this.compactionConfig
|
|
6365
|
+
compactionConfig: this.compactionConfig,
|
|
6366
|
+
signal: this.signal
|
|
6326
6367
|
};
|
|
6327
6368
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6328
6369
|
}
|
|
@@ -6425,7 +6466,8 @@ ${endPrefix}`
|
|
|
6425
6466
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6426
6467
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6427
6468
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6428
|
-
compactionConfig: this.compactionConfig
|
|
6469
|
+
compactionConfig: this.compactionConfig,
|
|
6470
|
+
signal: this.signal
|
|
6429
6471
|
};
|
|
6430
6472
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6431
6473
|
}
|
|
@@ -6484,7 +6526,7 @@ var import_commander2 = require("commander");
|
|
|
6484
6526
|
// package.json
|
|
6485
6527
|
var package_default = {
|
|
6486
6528
|
name: "llmist",
|
|
6487
|
-
version: "1.
|
|
6529
|
+
version: "1.3.1",
|
|
6488
6530
|
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.",
|
|
6489
6531
|
type: "module",
|
|
6490
6532
|
main: "dist/index.cjs",
|
|
@@ -6568,6 +6610,7 @@ var package_default = {
|
|
|
6568
6610
|
"@google/genai": "^1.27.0",
|
|
6569
6611
|
chalk: "^5.6.2",
|
|
6570
6612
|
commander: "^12.1.0",
|
|
6613
|
+
diff: "^8.0.2",
|
|
6571
6614
|
eta: "^4.4.1",
|
|
6572
6615
|
"js-toml": "^1.0.2",
|
|
6573
6616
|
"js-yaml": "^4.1.0",
|
|
@@ -6584,6 +6627,7 @@ var package_default = {
|
|
|
6584
6627
|
"@commitlint/config-conventional": "^20.0.0",
|
|
6585
6628
|
"@semantic-release/changelog": "^6.0.3",
|
|
6586
6629
|
"@semantic-release/git": "^10.0.1",
|
|
6630
|
+
"@types/diff": "^8.0.0",
|
|
6587
6631
|
"@types/js-yaml": "^4.0.9",
|
|
6588
6632
|
"@types/marked-terminal": "^6.1.1",
|
|
6589
6633
|
"@types/node": "^20.12.7",
|
|
@@ -6597,12 +6641,274 @@ var package_default = {
|
|
|
6597
6641
|
};
|
|
6598
6642
|
|
|
6599
6643
|
// src/cli/agent-command.ts
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
6644
|
+
var import_promises3 = require("readline/promises");
|
|
6645
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
6602
6646
|
init_builder();
|
|
6647
|
+
|
|
6648
|
+
// src/core/errors.ts
|
|
6649
|
+
function isAbortError(error) {
|
|
6650
|
+
if (!(error instanceof Error)) return false;
|
|
6651
|
+
if (error.name === "AbortError") return true;
|
|
6652
|
+
if (error.name === "APIConnectionAbortedError") return true;
|
|
6653
|
+
if (error.name === "APIUserAbortError") return true;
|
|
6654
|
+
const message = error.message.toLowerCase();
|
|
6655
|
+
if (message.includes("abort")) return true;
|
|
6656
|
+
if (message.includes("cancelled")) return true;
|
|
6657
|
+
if (message.includes("canceled")) return true;
|
|
6658
|
+
return false;
|
|
6659
|
+
}
|
|
6660
|
+
|
|
6661
|
+
// src/cli/agent-command.ts
|
|
6603
6662
|
init_registry();
|
|
6604
6663
|
init_constants2();
|
|
6605
6664
|
|
|
6665
|
+
// src/cli/approval/manager.ts
|
|
6666
|
+
var import_promises = require("readline/promises");
|
|
6667
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
6668
|
+
|
|
6669
|
+
// src/cli/approval/context-providers.ts
|
|
6670
|
+
var import_node_fs2 = require("fs");
|
|
6671
|
+
var import_node_path2 = require("path");
|
|
6672
|
+
var import_diff = require("diff");
|
|
6673
|
+
|
|
6674
|
+
// src/cli/approval/diff-renderer.ts
|
|
6675
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
6676
|
+
function renderColoredDiff(diff) {
|
|
6677
|
+
return diff.split("\n").map((line) => {
|
|
6678
|
+
if (line.startsWith("---") || line.startsWith("+++")) {
|
|
6679
|
+
return import_chalk.default.bold(line);
|
|
6680
|
+
}
|
|
6681
|
+
if (line.startsWith("+")) {
|
|
6682
|
+
return import_chalk.default.green(line);
|
|
6683
|
+
}
|
|
6684
|
+
if (line.startsWith("-")) {
|
|
6685
|
+
return import_chalk.default.red(line);
|
|
6686
|
+
}
|
|
6687
|
+
if (line.startsWith("@@")) {
|
|
6688
|
+
return import_chalk.default.cyan(line);
|
|
6689
|
+
}
|
|
6690
|
+
return import_chalk.default.dim(line);
|
|
6691
|
+
}).join("\n");
|
|
6692
|
+
}
|
|
6693
|
+
function formatNewFileDiff(filePath, content) {
|
|
6694
|
+
const lines = content.split("\n");
|
|
6695
|
+
const header = `+++ ${filePath} (new file)`;
|
|
6696
|
+
const addedLines = lines.map((line) => `+ ${line}`).join("\n");
|
|
6697
|
+
return `${header}
|
|
6698
|
+
${addedLines}`;
|
|
6699
|
+
}
|
|
6700
|
+
|
|
6701
|
+
// src/cli/approval/context-providers.ts
|
|
6702
|
+
var WriteFileContextProvider = class {
|
|
6703
|
+
gadgetName = "WriteFile";
|
|
6704
|
+
async getContext(params) {
|
|
6705
|
+
const filePath = String(params.filePath ?? params.path ?? "");
|
|
6706
|
+
const newContent = String(params.content ?? "");
|
|
6707
|
+
const resolvedPath = (0, import_node_path2.resolve)(process.cwd(), filePath);
|
|
6708
|
+
if (!(0, import_node_fs2.existsSync)(resolvedPath)) {
|
|
6709
|
+
return {
|
|
6710
|
+
summary: `Create new file: ${filePath}`,
|
|
6711
|
+
details: formatNewFileDiff(filePath, newContent)
|
|
6712
|
+
};
|
|
6713
|
+
}
|
|
6714
|
+
const oldContent = (0, import_node_fs2.readFileSync)(resolvedPath, "utf-8");
|
|
6715
|
+
const diff = (0, import_diff.createPatch)(filePath, oldContent, newContent, "original", "modified");
|
|
6716
|
+
return {
|
|
6717
|
+
summary: `Modify: ${filePath}`,
|
|
6718
|
+
details: diff
|
|
6719
|
+
};
|
|
6720
|
+
}
|
|
6721
|
+
};
|
|
6722
|
+
var EditFileContextProvider = class {
|
|
6723
|
+
gadgetName = "EditFile";
|
|
6724
|
+
async getContext(params) {
|
|
6725
|
+
const filePath = String(params.filePath ?? params.path ?? "");
|
|
6726
|
+
const resolvedPath = (0, import_node_path2.resolve)(process.cwd(), filePath);
|
|
6727
|
+
if ("content" in params) {
|
|
6728
|
+
const newContent = String(params.content);
|
|
6729
|
+
if (!(0, import_node_fs2.existsSync)(resolvedPath)) {
|
|
6730
|
+
return {
|
|
6731
|
+
summary: `Create new file: ${filePath}`,
|
|
6732
|
+
details: formatNewFileDiff(filePath, newContent)
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6735
|
+
const oldContent = (0, import_node_fs2.readFileSync)(resolvedPath, "utf-8");
|
|
6736
|
+
const diff = (0, import_diff.createPatch)(filePath, oldContent, newContent, "original", "modified");
|
|
6737
|
+
return {
|
|
6738
|
+
summary: `Modify: ${filePath}`,
|
|
6739
|
+
details: diff
|
|
6740
|
+
};
|
|
6741
|
+
}
|
|
6742
|
+
if ("commands" in params) {
|
|
6743
|
+
const commands = String(params.commands);
|
|
6744
|
+
return {
|
|
6745
|
+
summary: `Edit: ${filePath}`,
|
|
6746
|
+
details: `Commands:
|
|
6747
|
+
${commands}`
|
|
6748
|
+
};
|
|
6749
|
+
}
|
|
6750
|
+
return {
|
|
6751
|
+
summary: `Edit: ${filePath}`
|
|
6752
|
+
};
|
|
6753
|
+
}
|
|
6754
|
+
};
|
|
6755
|
+
var RunCommandContextProvider = class {
|
|
6756
|
+
gadgetName = "RunCommand";
|
|
6757
|
+
async getContext(params) {
|
|
6758
|
+
const command = String(params.command ?? "");
|
|
6759
|
+
const cwd = params.cwd ? ` (in ${params.cwd})` : "";
|
|
6760
|
+
return {
|
|
6761
|
+
summary: `Execute: ${command}${cwd}`
|
|
6762
|
+
};
|
|
6763
|
+
}
|
|
6764
|
+
};
|
|
6765
|
+
var DefaultContextProvider = class {
|
|
6766
|
+
constructor(gadgetName) {
|
|
6767
|
+
this.gadgetName = gadgetName;
|
|
6768
|
+
}
|
|
6769
|
+
async getContext(params) {
|
|
6770
|
+
const paramEntries = Object.entries(params);
|
|
6771
|
+
if (paramEntries.length === 0) {
|
|
6772
|
+
return {
|
|
6773
|
+
summary: `${this.gadgetName}()`
|
|
6774
|
+
};
|
|
6775
|
+
}
|
|
6776
|
+
const formatValue = (value) => {
|
|
6777
|
+
const MAX_LEN = 50;
|
|
6778
|
+
const str = JSON.stringify(value);
|
|
6779
|
+
return str.length > MAX_LEN ? `${str.slice(0, MAX_LEN - 3)}...` : str;
|
|
6780
|
+
};
|
|
6781
|
+
const paramStr = paramEntries.map(([k, v]) => `${k}=${formatValue(v)}`).join(", ");
|
|
6782
|
+
return {
|
|
6783
|
+
summary: `${this.gadgetName}(${paramStr})`
|
|
6784
|
+
};
|
|
6785
|
+
}
|
|
6786
|
+
};
|
|
6787
|
+
var builtinContextProviders = [
|
|
6788
|
+
new WriteFileContextProvider(),
|
|
6789
|
+
new EditFileContextProvider(),
|
|
6790
|
+
new RunCommandContextProvider()
|
|
6791
|
+
];
|
|
6792
|
+
|
|
6793
|
+
// src/cli/approval/manager.ts
|
|
6794
|
+
var ApprovalManager = class {
|
|
6795
|
+
/**
|
|
6796
|
+
* Creates a new ApprovalManager.
|
|
6797
|
+
*
|
|
6798
|
+
* @param config - Approval configuration with per-gadget modes
|
|
6799
|
+
* @param env - CLI environment for I/O operations
|
|
6800
|
+
* @param progress - Optional progress indicator to pause during prompts
|
|
6801
|
+
*/
|
|
6802
|
+
constructor(config, env, progress) {
|
|
6803
|
+
this.config = config;
|
|
6804
|
+
this.env = env;
|
|
6805
|
+
this.progress = progress;
|
|
6806
|
+
for (const provider of builtinContextProviders) {
|
|
6807
|
+
this.registerProvider(provider);
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
providers = /* @__PURE__ */ new Map();
|
|
6811
|
+
/**
|
|
6812
|
+
* Registers a custom context provider for a gadget.
|
|
6813
|
+
*
|
|
6814
|
+
* @param provider - The context provider to register
|
|
6815
|
+
*/
|
|
6816
|
+
registerProvider(provider) {
|
|
6817
|
+
this.providers.set(provider.gadgetName.toLowerCase(), provider);
|
|
6818
|
+
}
|
|
6819
|
+
/**
|
|
6820
|
+
* Gets the approval mode for a gadget.
|
|
6821
|
+
*
|
|
6822
|
+
* Resolution order:
|
|
6823
|
+
* 1. Explicit configuration for the gadget name
|
|
6824
|
+
* 2. Wildcard "*" configuration
|
|
6825
|
+
* 3. Default mode from config
|
|
6826
|
+
*
|
|
6827
|
+
* @param gadgetName - Name of the gadget
|
|
6828
|
+
* @returns The approval mode to use
|
|
6829
|
+
*/
|
|
6830
|
+
getApprovalMode(gadgetName) {
|
|
6831
|
+
const normalizedName = gadgetName.toLowerCase();
|
|
6832
|
+
for (const [configName, mode] of Object.entries(this.config.gadgetApprovals)) {
|
|
6833
|
+
if (configName.toLowerCase() === normalizedName) {
|
|
6834
|
+
return mode;
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
if ("*" in this.config.gadgetApprovals) {
|
|
6838
|
+
return this.config.gadgetApprovals["*"];
|
|
6839
|
+
}
|
|
6840
|
+
return this.config.defaultMode;
|
|
6841
|
+
}
|
|
6842
|
+
/**
|
|
6843
|
+
* Requests approval for a gadget execution.
|
|
6844
|
+
*
|
|
6845
|
+
* Behavior depends on the gadget's approval mode:
|
|
6846
|
+
* - "allowed": Returns approved immediately
|
|
6847
|
+
* - "denied": Returns denied with configuration message
|
|
6848
|
+
* - "approval-required": Prompts user interactively
|
|
6849
|
+
*
|
|
6850
|
+
* @param gadgetName - Name of the gadget
|
|
6851
|
+
* @param params - The gadget's execution parameters
|
|
6852
|
+
* @returns Approval result indicating whether to proceed
|
|
6853
|
+
*/
|
|
6854
|
+
async requestApproval(gadgetName, params) {
|
|
6855
|
+
const mode = this.getApprovalMode(gadgetName);
|
|
6856
|
+
if (mode === "allowed") {
|
|
6857
|
+
return { approved: true };
|
|
6858
|
+
}
|
|
6859
|
+
if (mode === "denied") {
|
|
6860
|
+
return {
|
|
6861
|
+
approved: false,
|
|
6862
|
+
reason: `${gadgetName} is denied by configuration`
|
|
6863
|
+
};
|
|
6864
|
+
}
|
|
6865
|
+
return this.promptForApproval(gadgetName, params);
|
|
6866
|
+
}
|
|
6867
|
+
/**
|
|
6868
|
+
* Prompts the user for approval interactively.
|
|
6869
|
+
*/
|
|
6870
|
+
async promptForApproval(gadgetName, params) {
|
|
6871
|
+
const provider = this.providers.get(gadgetName.toLowerCase()) ?? new DefaultContextProvider(gadgetName);
|
|
6872
|
+
const context = await provider.getContext(params);
|
|
6873
|
+
this.progress?.pause();
|
|
6874
|
+
this.env.stderr.write(`
|
|
6875
|
+
${import_chalk2.default.yellow("\u{1F512} Approval required:")} ${context.summary}
|
|
6876
|
+
`);
|
|
6877
|
+
if (context.details) {
|
|
6878
|
+
this.env.stderr.write(`
|
|
6879
|
+
${renderColoredDiff(context.details)}
|
|
6880
|
+
`);
|
|
6881
|
+
}
|
|
6882
|
+
const response = await this.prompt(" \u23CE approve, or type to reject: ");
|
|
6883
|
+
const isApproved = response === "" || response.toLowerCase() === "y";
|
|
6884
|
+
if (isApproved) {
|
|
6885
|
+
this.env.stderr.write(` ${import_chalk2.default.green("\u2713 Approved")}
|
|
6886
|
+
|
|
6887
|
+
`);
|
|
6888
|
+
return { approved: true };
|
|
6889
|
+
}
|
|
6890
|
+
this.env.stderr.write(` ${import_chalk2.default.red("\u2717 Denied")}
|
|
6891
|
+
|
|
6892
|
+
`);
|
|
6893
|
+
return { approved: false, reason: response || "Rejected by user" };
|
|
6894
|
+
}
|
|
6895
|
+
/**
|
|
6896
|
+
* Prompts for user input.
|
|
6897
|
+
*/
|
|
6898
|
+
async prompt(message) {
|
|
6899
|
+
const rl = (0, import_promises.createInterface)({
|
|
6900
|
+
input: this.env.stdin,
|
|
6901
|
+
output: this.env.stderr
|
|
6902
|
+
});
|
|
6903
|
+
try {
|
|
6904
|
+
const answer = await rl.question(message);
|
|
6905
|
+
return answer.trim();
|
|
6906
|
+
} finally {
|
|
6907
|
+
rl.close();
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
};
|
|
6911
|
+
|
|
6606
6912
|
// src/cli/builtin-gadgets.ts
|
|
6607
6913
|
var import_zod2 = require("zod");
|
|
6608
6914
|
init_create_gadget();
|
|
@@ -6682,11 +6988,483 @@ var finish = createGadget({
|
|
|
6682
6988
|
var builtinGadgets = [askUser, tellUser, finish];
|
|
6683
6989
|
|
|
6684
6990
|
// src/cli/gadgets.ts
|
|
6685
|
-
var
|
|
6686
|
-
var
|
|
6991
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
6992
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
6687
6993
|
var import_node_url = require("url");
|
|
6688
6994
|
init_gadget();
|
|
6995
|
+
|
|
6996
|
+
// src/cli/builtins/filesystem/list-directory.ts
|
|
6997
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
6998
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
6999
|
+
var import_zod4 = require("zod");
|
|
7000
|
+
|
|
7001
|
+
// src/index.ts
|
|
7002
|
+
var import_zod3 = require("zod");
|
|
7003
|
+
init_builder();
|
|
7004
|
+
init_event_handlers();
|
|
7005
|
+
|
|
7006
|
+
// src/agent/index.ts
|
|
7007
|
+
init_conversation_manager();
|
|
7008
|
+
init_stream_processor();
|
|
7009
|
+
init_gadget_output_store();
|
|
7010
|
+
|
|
7011
|
+
// src/agent/compaction/index.ts
|
|
7012
|
+
init_config();
|
|
7013
|
+
init_strategy();
|
|
7014
|
+
init_strategies();
|
|
7015
|
+
init_manager();
|
|
7016
|
+
|
|
7017
|
+
// src/agent/hints.ts
|
|
7018
|
+
init_prompt_config();
|
|
7019
|
+
|
|
7020
|
+
// src/index.ts
|
|
7021
|
+
init_client();
|
|
7022
|
+
init_messages();
|
|
7023
|
+
init_model_registry();
|
|
7024
|
+
init_model_shortcuts();
|
|
7025
|
+
init_options();
|
|
7026
|
+
init_prompt_config();
|
|
7027
|
+
init_quick_methods();
|
|
7028
|
+
init_create_gadget();
|
|
7029
|
+
init_output_viewer();
|
|
7030
|
+
init_exceptions();
|
|
7031
|
+
init_executor();
|
|
7032
|
+
init_gadget();
|
|
7033
|
+
init_parser();
|
|
7034
|
+
init_registry();
|
|
7035
|
+
|
|
7036
|
+
// src/gadgets/typed-gadget.ts
|
|
7037
|
+
init_gadget();
|
|
7038
|
+
|
|
7039
|
+
// src/index.ts
|
|
7040
|
+
init_logger();
|
|
7041
|
+
init_anthropic();
|
|
7042
|
+
init_discovery();
|
|
7043
|
+
init_gemini();
|
|
7044
|
+
init_openai();
|
|
7045
|
+
|
|
7046
|
+
// src/testing/mock-manager.ts
|
|
7047
|
+
init_logger();
|
|
7048
|
+
|
|
7049
|
+
// src/testing/mock-stream.ts
|
|
7050
|
+
init_constants();
|
|
7051
|
+
|
|
7052
|
+
// src/testing/mock-client.ts
|
|
7053
|
+
init_client();
|
|
7054
|
+
|
|
7055
|
+
// src/testing/mock-gadget.ts
|
|
7056
|
+
init_gadget();
|
|
7057
|
+
|
|
7058
|
+
// src/testing/cli-helpers.ts
|
|
7059
|
+
var import_node_stream = require("stream");
|
|
7060
|
+
|
|
7061
|
+
// src/cli/builtins/filesystem/utils.ts
|
|
7062
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
7063
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
7064
|
+
var PathSandboxException = class extends Error {
|
|
7065
|
+
constructor(inputPath, reason) {
|
|
7066
|
+
super(`Path access denied: ${inputPath}. ${reason}`);
|
|
7067
|
+
this.name = "PathSandboxException";
|
|
7068
|
+
}
|
|
7069
|
+
};
|
|
7070
|
+
function validatePathIsWithinCwd(inputPath) {
|
|
7071
|
+
const cwd = process.cwd();
|
|
7072
|
+
const resolvedPath = import_node_path3.default.resolve(cwd, inputPath);
|
|
7073
|
+
let finalPath;
|
|
7074
|
+
try {
|
|
7075
|
+
finalPath = import_node_fs3.default.realpathSync(resolvedPath);
|
|
7076
|
+
} catch (error) {
|
|
7077
|
+
const nodeError = error;
|
|
7078
|
+
if (nodeError.code === "ENOENT") {
|
|
7079
|
+
finalPath = resolvedPath;
|
|
7080
|
+
} else {
|
|
7081
|
+
throw error;
|
|
7082
|
+
}
|
|
7083
|
+
}
|
|
7084
|
+
const cwdWithSep = cwd + import_node_path3.default.sep;
|
|
7085
|
+
if (!finalPath.startsWith(cwdWithSep) && finalPath !== cwd) {
|
|
7086
|
+
throw new PathSandboxException(inputPath, "Path is outside the current working directory");
|
|
7087
|
+
}
|
|
7088
|
+
return finalPath;
|
|
7089
|
+
}
|
|
7090
|
+
|
|
7091
|
+
// src/cli/builtins/filesystem/list-directory.ts
|
|
7092
|
+
function listFiles(dirPath, basePath = dirPath, maxDepth = 1, currentDepth = 1) {
|
|
7093
|
+
const entries = [];
|
|
7094
|
+
try {
|
|
7095
|
+
const items = import_node_fs4.default.readdirSync(dirPath);
|
|
7096
|
+
for (const item of items) {
|
|
7097
|
+
const fullPath = import_node_path4.default.join(dirPath, item);
|
|
7098
|
+
const relativePath = import_node_path4.default.relative(basePath, fullPath);
|
|
7099
|
+
try {
|
|
7100
|
+
const stats = import_node_fs4.default.lstatSync(fullPath);
|
|
7101
|
+
let type;
|
|
7102
|
+
let size;
|
|
7103
|
+
if (stats.isSymbolicLink()) {
|
|
7104
|
+
type = "symlink";
|
|
7105
|
+
size = 0;
|
|
7106
|
+
} else if (stats.isDirectory()) {
|
|
7107
|
+
type = "directory";
|
|
7108
|
+
size = 0;
|
|
7109
|
+
} else {
|
|
7110
|
+
type = "file";
|
|
7111
|
+
size = stats.size;
|
|
7112
|
+
}
|
|
7113
|
+
entries.push({
|
|
7114
|
+
name: item,
|
|
7115
|
+
relativePath,
|
|
7116
|
+
type,
|
|
7117
|
+
size,
|
|
7118
|
+
modified: Math.floor(stats.mtime.getTime() / 1e3)
|
|
7119
|
+
});
|
|
7120
|
+
if (type === "directory" && currentDepth < maxDepth) {
|
|
7121
|
+
try {
|
|
7122
|
+
validatePathIsWithinCwd(fullPath);
|
|
7123
|
+
const subEntries = listFiles(fullPath, basePath, maxDepth, currentDepth + 1);
|
|
7124
|
+
entries.push(...subEntries);
|
|
7125
|
+
} catch {
|
|
7126
|
+
}
|
|
7127
|
+
}
|
|
7128
|
+
} catch {
|
|
7129
|
+
}
|
|
7130
|
+
}
|
|
7131
|
+
} catch {
|
|
7132
|
+
return [];
|
|
7133
|
+
}
|
|
7134
|
+
return entries;
|
|
7135
|
+
}
|
|
7136
|
+
function formatAge(epochSeconds) {
|
|
7137
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
7138
|
+
const seconds = now - epochSeconds;
|
|
7139
|
+
if (seconds < 60) return `${seconds}s`;
|
|
7140
|
+
const minutes = Math.floor(seconds / 60);
|
|
7141
|
+
if (minutes < 60) return `${minutes}m`;
|
|
7142
|
+
const hours = Math.floor(minutes / 60);
|
|
7143
|
+
if (hours < 24) return `${hours}h`;
|
|
7144
|
+
const days = Math.floor(hours / 24);
|
|
7145
|
+
if (days < 7) return `${days}d`;
|
|
7146
|
+
const weeks = Math.floor(days / 7);
|
|
7147
|
+
if (weeks < 4) return `${weeks}w`;
|
|
7148
|
+
const months = Math.floor(days / 30);
|
|
7149
|
+
if (months < 12) return `${months}mo`;
|
|
7150
|
+
const years = Math.floor(days / 365);
|
|
7151
|
+
return `${years}y`;
|
|
7152
|
+
}
|
|
7153
|
+
function formatEntriesAsString(entries) {
|
|
7154
|
+
if (entries.length === 0) {
|
|
7155
|
+
return "#empty";
|
|
7156
|
+
}
|
|
7157
|
+
const sortedEntries = [...entries].sort((a, b) => {
|
|
7158
|
+
const typeOrder = { directory: 0, file: 1, symlink: 2 };
|
|
7159
|
+
const typeCompare = typeOrder[a.type] - typeOrder[b.type];
|
|
7160
|
+
if (typeCompare !== 0) return typeCompare;
|
|
7161
|
+
return a.relativePath.localeCompare(b.relativePath);
|
|
7162
|
+
});
|
|
7163
|
+
const typeCode = {
|
|
7164
|
+
directory: "D",
|
|
7165
|
+
file: "F",
|
|
7166
|
+
symlink: "L"
|
|
7167
|
+
};
|
|
7168
|
+
const encodeName = (name) => name.replace(/\|/g, "%7C").replace(/\n/g, "%0A");
|
|
7169
|
+
const header = "#T|N|S|A";
|
|
7170
|
+
const rows = sortedEntries.map(
|
|
7171
|
+
(e) => `${typeCode[e.type]}|${encodeName(e.relativePath)}|${e.size}|${formatAge(e.modified)}`
|
|
7172
|
+
);
|
|
7173
|
+
return [header, ...rows].join("\n");
|
|
7174
|
+
}
|
|
7175
|
+
var listDirectory = createGadget({
|
|
7176
|
+
name: "ListDirectory",
|
|
7177
|
+
description: "List files and directories in a directory with full details (names, types, sizes, modification dates). Use maxDepth to explore subdirectories recursively. The directory path must be within the current working directory or its subdirectories.",
|
|
7178
|
+
schema: import_zod4.z.object({
|
|
7179
|
+
directoryPath: import_zod4.z.string().default(".").describe("Path to the directory to list"),
|
|
7180
|
+
maxDepth: import_zod4.z.number().int().min(1).max(10).default(1).describe(
|
|
7181
|
+
"Maximum depth to recurse (1 = immediate children only, 2 = include grandchildren, etc.)"
|
|
7182
|
+
)
|
|
7183
|
+
}),
|
|
7184
|
+
examples: [
|
|
7185
|
+
{
|
|
7186
|
+
params: { directoryPath: ".", maxDepth: 1 },
|
|
7187
|
+
output: "path=. maxDepth=1\n\n#T|N|S|A\nD|src|0|2h\nD|tests|0|1d\nF|package.json|2841|3h",
|
|
7188
|
+
comment: "List current directory"
|
|
7189
|
+
},
|
|
7190
|
+
{
|
|
7191
|
+
params: { directoryPath: "src", maxDepth: 2 },
|
|
7192
|
+
output: "path=src maxDepth=2\n\n#T|N|S|A\nD|components|0|1d\nD|utils|0|2d\nF|index.ts|512|1h\nF|components/Button.tsx|1024|3h",
|
|
7193
|
+
comment: "List src directory recursively"
|
|
7194
|
+
}
|
|
7195
|
+
],
|
|
7196
|
+
execute: ({ directoryPath, maxDepth }) => {
|
|
7197
|
+
const validatedPath = validatePathIsWithinCwd(directoryPath);
|
|
7198
|
+
const stats = import_node_fs4.default.statSync(validatedPath);
|
|
7199
|
+
if (!stats.isDirectory()) {
|
|
7200
|
+
throw new Error(`Path is not a directory: ${directoryPath}`);
|
|
7201
|
+
}
|
|
7202
|
+
const entries = listFiles(validatedPath, validatedPath, maxDepth);
|
|
7203
|
+
const formattedList = formatEntriesAsString(entries);
|
|
7204
|
+
return `path=${directoryPath} maxDepth=${maxDepth}
|
|
7205
|
+
|
|
7206
|
+
${formattedList}`;
|
|
7207
|
+
}
|
|
7208
|
+
});
|
|
7209
|
+
|
|
7210
|
+
// src/cli/builtins/filesystem/read-file.ts
|
|
7211
|
+
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
7212
|
+
var import_zod5 = require("zod");
|
|
7213
|
+
var readFile = createGadget({
|
|
7214
|
+
name: "ReadFile",
|
|
7215
|
+
description: "Read the entire content of a file and return it as text. The file path must be within the current working directory or its subdirectories.",
|
|
7216
|
+
schema: import_zod5.z.object({
|
|
7217
|
+
filePath: import_zod5.z.string().describe("Path to the file to read (relative or absolute)")
|
|
7218
|
+
}),
|
|
7219
|
+
examples: [
|
|
7220
|
+
{
|
|
7221
|
+
params: { filePath: "package.json" },
|
|
7222
|
+
output: 'path=package.json\n\n{\n "name": "my-project",\n "version": "1.0.0"\n ...\n}',
|
|
7223
|
+
comment: "Read a JSON config file"
|
|
7224
|
+
},
|
|
7225
|
+
{
|
|
7226
|
+
params: { filePath: "src/index.ts" },
|
|
7227
|
+
output: "path=src/index.ts\n\nexport function main() { ... }",
|
|
7228
|
+
comment: "Read a source file"
|
|
7229
|
+
}
|
|
7230
|
+
],
|
|
7231
|
+
execute: ({ filePath }) => {
|
|
7232
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7233
|
+
const content = import_node_fs5.default.readFileSync(validatedPath, "utf-8");
|
|
7234
|
+
return `path=${filePath}
|
|
7235
|
+
|
|
7236
|
+
${content}`;
|
|
7237
|
+
}
|
|
7238
|
+
});
|
|
7239
|
+
|
|
7240
|
+
// src/cli/builtins/filesystem/write-file.ts
|
|
7241
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
7242
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
7243
|
+
var import_zod6 = require("zod");
|
|
7244
|
+
var writeFile = createGadget({
|
|
7245
|
+
name: "WriteFile",
|
|
7246
|
+
description: "Write content to a file. Creates parent directories if needed. Overwrites existing files. The file path must be within the current working directory or its subdirectories.",
|
|
7247
|
+
schema: import_zod6.z.object({
|
|
7248
|
+
filePath: import_zod6.z.string().describe("Path to the file to write (relative or absolute)"),
|
|
7249
|
+
content: import_zod6.z.string().describe("Content to write to the file")
|
|
7250
|
+
}),
|
|
7251
|
+
examples: [
|
|
7252
|
+
{
|
|
7253
|
+
params: { filePath: "output.txt", content: "Hello, World!" },
|
|
7254
|
+
output: "path=output.txt\n\nWrote 13 bytes",
|
|
7255
|
+
comment: "Write a simple text file"
|
|
7256
|
+
},
|
|
7257
|
+
{
|
|
7258
|
+
params: {
|
|
7259
|
+
filePath: "src/server.ts",
|
|
7260
|
+
content: `import { serve } from "bun";
|
|
7261
|
+
|
|
7262
|
+
const port = 3000;
|
|
7263
|
+
|
|
7264
|
+
serve({
|
|
7265
|
+
port,
|
|
7266
|
+
fetch: (req) => new Response(\`Hello from \${req.url}\`),
|
|
7267
|
+
});
|
|
7268
|
+
|
|
7269
|
+
console.log(\`Server running on http://localhost:\${port}\`);`
|
|
7270
|
+
},
|
|
7271
|
+
output: "path=src/server.ts\n\nWrote 198 bytes (created directory: src)",
|
|
7272
|
+
comment: "Write code with template literals - NO escaping needed inside heredoc (use <<<EOF...EOF)"
|
|
7273
|
+
}
|
|
7274
|
+
],
|
|
7275
|
+
execute: ({ filePath, content }) => {
|
|
7276
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7277
|
+
const parentDir = import_node_path5.default.dirname(validatedPath);
|
|
7278
|
+
let createdDir = false;
|
|
7279
|
+
if (!import_node_fs6.default.existsSync(parentDir)) {
|
|
7280
|
+
validatePathIsWithinCwd(parentDir);
|
|
7281
|
+
import_node_fs6.default.mkdirSync(parentDir, { recursive: true });
|
|
7282
|
+
createdDir = true;
|
|
7283
|
+
}
|
|
7284
|
+
import_node_fs6.default.writeFileSync(validatedPath, content, "utf-8");
|
|
7285
|
+
const bytesWritten = Buffer.byteLength(content, "utf-8");
|
|
7286
|
+
const dirNote = createdDir ? ` (created directory: ${import_node_path5.default.dirname(filePath)})` : "";
|
|
7287
|
+
return `path=${filePath}
|
|
7288
|
+
|
|
7289
|
+
Wrote ${bytesWritten} bytes${dirNote}`;
|
|
7290
|
+
}
|
|
7291
|
+
});
|
|
7292
|
+
|
|
7293
|
+
// src/cli/builtins/filesystem/edit-file.ts
|
|
7294
|
+
var import_zod7 = require("zod");
|
|
7295
|
+
function filterDangerousCommands(commands) {
|
|
7296
|
+
return commands.split("\n").filter((line) => !line.trimStart().startsWith("!")).join("\n");
|
|
7297
|
+
}
|
|
7298
|
+
var editFile = createGadget({
|
|
7299
|
+
name: "EditFile",
|
|
7300
|
+
description: "Edit a file using ed commands. Ed is a line-oriented text editor - pipe commands to it for precise file modifications. Commands are executed in sequence. Remember to end with 'w' (write) and 'q' (quit). Shell escape commands (!) are filtered for security.",
|
|
7301
|
+
schema: import_zod7.z.object({
|
|
7302
|
+
filePath: import_zod7.z.string().describe("Path to the file to edit (relative or absolute)"),
|
|
7303
|
+
commands: import_zod7.z.string().describe("Ed commands to execute, one per line")
|
|
7304
|
+
}),
|
|
7305
|
+
examples: [
|
|
7306
|
+
{
|
|
7307
|
+
params: {
|
|
7308
|
+
filePath: "config.txt",
|
|
7309
|
+
commands: `1,$p
|
|
7310
|
+
q`
|
|
7311
|
+
},
|
|
7312
|
+
output: "path=config.txt\n\n32\nkey=value\noption=true",
|
|
7313
|
+
comment: "Print entire file contents (ed shows byte count, then content)"
|
|
7314
|
+
},
|
|
7315
|
+
{
|
|
7316
|
+
params: {
|
|
7317
|
+
filePath: "data.txt",
|
|
7318
|
+
commands: `1,$s/foo/bar/g
|
|
7319
|
+
w
|
|
7320
|
+
q`
|
|
7321
|
+
},
|
|
7322
|
+
output: "path=data.txt\n\n42\n42",
|
|
7323
|
+
comment: "Replace all 'foo' with 'bar' (ed shows bytes read, then bytes written)"
|
|
7324
|
+
},
|
|
7325
|
+
{
|
|
7326
|
+
params: {
|
|
7327
|
+
filePath: "list.txt",
|
|
7328
|
+
commands: `3d
|
|
7329
|
+
w
|
|
7330
|
+
q`
|
|
7331
|
+
},
|
|
7332
|
+
output: "path=list.txt\n\n45\n28",
|
|
7333
|
+
comment: "Delete line 3, save and quit"
|
|
7334
|
+
},
|
|
7335
|
+
{
|
|
7336
|
+
params: {
|
|
7337
|
+
filePath: "readme.txt",
|
|
7338
|
+
commands: `$a
|
|
7339
|
+
New last line
|
|
7340
|
+
.
|
|
7341
|
+
w
|
|
7342
|
+
q`
|
|
7343
|
+
},
|
|
7344
|
+
output: "path=readme.txt\n\n40\n56",
|
|
7345
|
+
comment: "Append text after last line ($ = last line, . = end input mode)"
|
|
7346
|
+
}
|
|
7347
|
+
],
|
|
7348
|
+
timeoutMs: 3e4,
|
|
7349
|
+
execute: async ({ filePath, commands }) => {
|
|
7350
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7351
|
+
const safeCommands = filterDangerousCommands(commands);
|
|
7352
|
+
try {
|
|
7353
|
+
const proc = Bun.spawn(["ed", validatedPath], {
|
|
7354
|
+
stdin: "pipe",
|
|
7355
|
+
stdout: "pipe",
|
|
7356
|
+
stderr: "pipe"
|
|
7357
|
+
});
|
|
7358
|
+
proc.stdin.write(`${safeCommands}
|
|
7359
|
+
`);
|
|
7360
|
+
proc.stdin.end();
|
|
7361
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7362
|
+
setTimeout(() => {
|
|
7363
|
+
proc.kill();
|
|
7364
|
+
reject(new Error("ed command timed out after 30000ms"));
|
|
7365
|
+
}, 3e4);
|
|
7366
|
+
});
|
|
7367
|
+
const exitCode = await Promise.race([proc.exited, timeoutPromise]);
|
|
7368
|
+
const stdout = await new Response(proc.stdout).text();
|
|
7369
|
+
const stderr = await new Response(proc.stderr).text();
|
|
7370
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
7371
|
+
if (exitCode !== 0) {
|
|
7372
|
+
return `path=${filePath}
|
|
7373
|
+
|
|
7374
|
+
${output || "ed exited with non-zero status"}`;
|
|
7375
|
+
}
|
|
7376
|
+
return `path=${filePath}
|
|
7377
|
+
|
|
7378
|
+
${output || "(no output)"}`;
|
|
7379
|
+
} catch (error) {
|
|
7380
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7381
|
+
return `path=${filePath}
|
|
7382
|
+
|
|
7383
|
+
error: ${message}`;
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
});
|
|
7387
|
+
|
|
7388
|
+
// src/cli/builtins/run-command.ts
|
|
7389
|
+
var import_zod8 = require("zod");
|
|
7390
|
+
var runCommand = createGadget({
|
|
7391
|
+
name: "RunCommand",
|
|
7392
|
+
description: "Execute a shell command and return its output. Returns both stdout and stderr combined with the exit status.",
|
|
7393
|
+
schema: import_zod8.z.object({
|
|
7394
|
+
command: import_zod8.z.string().describe("The shell command to execute"),
|
|
7395
|
+
cwd: import_zod8.z.string().optional().describe("Working directory for the command (default: current directory)"),
|
|
7396
|
+
timeout: import_zod8.z.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
|
|
7397
|
+
}),
|
|
7398
|
+
examples: [
|
|
7399
|
+
{
|
|
7400
|
+
params: { command: "ls -la", timeout: 3e4 },
|
|
7401
|
+
output: "status=0\n\ntotal 24\ndrwxr-xr-x 5 user staff 160 Nov 27 10:00 .\ndrwxr-xr-x 3 user staff 96 Nov 27 09:00 ..\n-rw-r--r-- 1 user staff 1024 Nov 27 10:00 package.json",
|
|
7402
|
+
comment: "List directory contents with details"
|
|
7403
|
+
},
|
|
7404
|
+
{
|
|
7405
|
+
params: { command: "echo 'Hello World'", timeout: 3e4 },
|
|
7406
|
+
output: "status=0\n\nHello World",
|
|
7407
|
+
comment: "Simple echo command"
|
|
7408
|
+
},
|
|
7409
|
+
{
|
|
7410
|
+
params: { command: "cat nonexistent.txt", timeout: 3e4 },
|
|
7411
|
+
output: "status=1\n\ncat: nonexistent.txt: No such file or directory",
|
|
7412
|
+
comment: "Command that fails returns non-zero status"
|
|
7413
|
+
},
|
|
7414
|
+
{
|
|
7415
|
+
params: { command: "pwd", cwd: "/tmp", timeout: 3e4 },
|
|
7416
|
+
output: "status=0\n\n/tmp",
|
|
7417
|
+
comment: "Execute command in a specific directory"
|
|
7418
|
+
}
|
|
7419
|
+
],
|
|
7420
|
+
execute: async ({ command, cwd, timeout }) => {
|
|
7421
|
+
const workingDir = cwd ?? process.cwd();
|
|
7422
|
+
try {
|
|
7423
|
+
const proc = Bun.spawn(["sh", "-c", command], {
|
|
7424
|
+
cwd: workingDir,
|
|
7425
|
+
stdout: "pipe",
|
|
7426
|
+
stderr: "pipe"
|
|
7427
|
+
});
|
|
7428
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7429
|
+
setTimeout(() => {
|
|
7430
|
+
proc.kill();
|
|
7431
|
+
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
7432
|
+
}, timeout);
|
|
7433
|
+
});
|
|
7434
|
+
const exitCode = await Promise.race([proc.exited, timeoutPromise]);
|
|
7435
|
+
const stdout = await new Response(proc.stdout).text();
|
|
7436
|
+
const stderr = await new Response(proc.stderr).text();
|
|
7437
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
7438
|
+
return `status=${exitCode}
|
|
7439
|
+
|
|
7440
|
+
${output || "(no output)"}`;
|
|
7441
|
+
} catch (error) {
|
|
7442
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7443
|
+
return `status=1
|
|
7444
|
+
|
|
7445
|
+
error: ${message}`;
|
|
7446
|
+
}
|
|
7447
|
+
}
|
|
7448
|
+
});
|
|
7449
|
+
|
|
7450
|
+
// src/cli/builtins/index.ts
|
|
7451
|
+
var builtinGadgetRegistry = {
|
|
7452
|
+
ListDirectory: listDirectory,
|
|
7453
|
+
ReadFile: readFile,
|
|
7454
|
+
WriteFile: writeFile,
|
|
7455
|
+
EditFile: editFile,
|
|
7456
|
+
RunCommand: runCommand
|
|
7457
|
+
};
|
|
7458
|
+
function getBuiltinGadget(name) {
|
|
7459
|
+
return builtinGadgetRegistry[name];
|
|
7460
|
+
}
|
|
7461
|
+
function isBuiltinGadgetName(name) {
|
|
7462
|
+
return name in builtinGadgetRegistry;
|
|
7463
|
+
}
|
|
7464
|
+
|
|
7465
|
+
// src/cli/gadgets.ts
|
|
6689
7466
|
var PATH_PREFIXES = [".", "/", "~"];
|
|
7467
|
+
var BUILTIN_PREFIX = "builtin:";
|
|
6690
7468
|
function isGadgetLike(value) {
|
|
6691
7469
|
if (typeof value !== "object" || value === null) {
|
|
6692
7470
|
return false;
|
|
@@ -6709,18 +7487,34 @@ function expandHomePath(input) {
|
|
|
6709
7487
|
if (!home) {
|
|
6710
7488
|
return input;
|
|
6711
7489
|
}
|
|
6712
|
-
return
|
|
7490
|
+
return import_node_path6.default.join(home, input.slice(1));
|
|
6713
7491
|
}
|
|
6714
7492
|
function isFileLikeSpecifier(specifier) {
|
|
6715
|
-
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(
|
|
7493
|
+
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(import_node_path6.default.sep);
|
|
7494
|
+
}
|
|
7495
|
+
function tryResolveBuiltin(specifier) {
|
|
7496
|
+
if (specifier.startsWith(BUILTIN_PREFIX)) {
|
|
7497
|
+
const name = specifier.slice(BUILTIN_PREFIX.length);
|
|
7498
|
+
const gadget = getBuiltinGadget(name);
|
|
7499
|
+
if (!gadget) {
|
|
7500
|
+
throw new Error(
|
|
7501
|
+
`Unknown builtin gadget: ${name}. Available builtins: ListDirectory, ReadFile, WriteFile, EditFile, RunCommand`
|
|
7502
|
+
);
|
|
7503
|
+
}
|
|
7504
|
+
return gadget;
|
|
7505
|
+
}
|
|
7506
|
+
if (!isFileLikeSpecifier(specifier) && isBuiltinGadgetName(specifier)) {
|
|
7507
|
+
return getBuiltinGadget(specifier);
|
|
7508
|
+
}
|
|
7509
|
+
return null;
|
|
6716
7510
|
}
|
|
6717
7511
|
function resolveGadgetSpecifier(specifier, cwd) {
|
|
6718
7512
|
if (!isFileLikeSpecifier(specifier)) {
|
|
6719
7513
|
return specifier;
|
|
6720
7514
|
}
|
|
6721
7515
|
const expanded = expandHomePath(specifier);
|
|
6722
|
-
const resolvedPath =
|
|
6723
|
-
if (!
|
|
7516
|
+
const resolvedPath = import_node_path6.default.resolve(cwd, expanded);
|
|
7517
|
+
if (!import_node_fs7.default.existsSync(resolvedPath)) {
|
|
6724
7518
|
throw new Error(`Gadget module not found at ${resolvedPath}`);
|
|
6725
7519
|
}
|
|
6726
7520
|
return (0, import_node_url.pathToFileURL)(resolvedPath).href;
|
|
@@ -6762,6 +7556,11 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
6762
7556
|
async function loadGadgets(specifiers, cwd, importer = (specifier) => import(specifier)) {
|
|
6763
7557
|
const gadgets = [];
|
|
6764
7558
|
for (const specifier of specifiers) {
|
|
7559
|
+
const builtin = tryResolveBuiltin(specifier);
|
|
7560
|
+
if (builtin) {
|
|
7561
|
+
gadgets.push(builtin);
|
|
7562
|
+
continue;
|
|
7563
|
+
}
|
|
6765
7564
|
const resolved = resolveGadgetSpecifier(specifier, cwd);
|
|
6766
7565
|
let exports2;
|
|
6767
7566
|
try {
|
|
@@ -6786,13 +7585,13 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
|
|
|
6786
7585
|
}
|
|
6787
7586
|
|
|
6788
7587
|
// src/cli/llm-logging.ts
|
|
6789
|
-
var
|
|
7588
|
+
var import_promises2 = require("fs/promises");
|
|
6790
7589
|
var import_node_os = require("os");
|
|
6791
|
-
var
|
|
6792
|
-
var DEFAULT_LLM_LOG_DIR = (0,
|
|
7590
|
+
var import_node_path7 = require("path");
|
|
7591
|
+
var DEFAULT_LLM_LOG_DIR = (0, import_node_path7.join)((0, import_node_os.homedir)(), ".llmist", "logs");
|
|
6793
7592
|
function resolveLogDir(option, subdir) {
|
|
6794
7593
|
if (option === true) {
|
|
6795
|
-
return (0,
|
|
7594
|
+
return (0, import_node_path7.join)(DEFAULT_LLM_LOG_DIR, subdir);
|
|
6796
7595
|
}
|
|
6797
7596
|
if (typeof option === "string") {
|
|
6798
7597
|
return option;
|
|
@@ -6809,44 +7608,44 @@ function formatLlmRequest(messages) {
|
|
|
6809
7608
|
return lines.join("\n");
|
|
6810
7609
|
}
|
|
6811
7610
|
async function writeLogFile(dir, filename, content) {
|
|
6812
|
-
await (0,
|
|
6813
|
-
await (0,
|
|
7611
|
+
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
7612
|
+
await (0, import_promises2.writeFile)((0, import_node_path7.join)(dir, filename), content, "utf-8");
|
|
6814
7613
|
}
|
|
6815
7614
|
|
|
6816
7615
|
// src/cli/utils.ts
|
|
6817
|
-
var
|
|
7616
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
6818
7617
|
var import_commander = require("commander");
|
|
6819
7618
|
init_constants2();
|
|
6820
7619
|
|
|
6821
7620
|
// src/cli/ui/formatters.ts
|
|
6822
|
-
var
|
|
7621
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
6823
7622
|
var import_marked = require("marked");
|
|
6824
7623
|
var import_marked_terminal = require("marked-terminal");
|
|
6825
7624
|
var markedConfigured = false;
|
|
6826
7625
|
function ensureMarkedConfigured() {
|
|
6827
7626
|
if (!markedConfigured) {
|
|
6828
|
-
|
|
7627
|
+
import_chalk3.default.level = process.env.NO_COLOR ? 0 : 3;
|
|
6829
7628
|
import_marked.marked.use(
|
|
6830
7629
|
(0, import_marked_terminal.markedTerminal)({
|
|
6831
7630
|
// Text styling
|
|
6832
|
-
strong:
|
|
6833
|
-
em:
|
|
6834
|
-
del:
|
|
7631
|
+
strong: import_chalk3.default.bold,
|
|
7632
|
+
em: import_chalk3.default.italic,
|
|
7633
|
+
del: import_chalk3.default.dim.gray.strikethrough,
|
|
6835
7634
|
// Code styling
|
|
6836
|
-
code:
|
|
6837
|
-
codespan:
|
|
7635
|
+
code: import_chalk3.default.yellow,
|
|
7636
|
+
codespan: import_chalk3.default.yellow,
|
|
6838
7637
|
// Headings
|
|
6839
|
-
heading:
|
|
6840
|
-
firstHeading:
|
|
7638
|
+
heading: import_chalk3.default.green.bold,
|
|
7639
|
+
firstHeading: import_chalk3.default.magenta.underline.bold,
|
|
6841
7640
|
// Links
|
|
6842
|
-
link:
|
|
6843
|
-
href:
|
|
7641
|
+
link: import_chalk3.default.blue,
|
|
7642
|
+
href: import_chalk3.default.blue.underline,
|
|
6844
7643
|
// Block elements
|
|
6845
|
-
blockquote:
|
|
7644
|
+
blockquote: import_chalk3.default.gray.italic,
|
|
6846
7645
|
// List formatting - reduce indentation and add bullet styling
|
|
6847
7646
|
tab: 2,
|
|
6848
7647
|
// Reduce from default 4 to 2 spaces
|
|
6849
|
-
listitem:
|
|
7648
|
+
listitem: import_chalk3.default.reset
|
|
6850
7649
|
// Keep items readable (no dim)
|
|
6851
7650
|
})
|
|
6852
7651
|
);
|
|
@@ -6856,11 +7655,11 @@ function ensureMarkedConfigured() {
|
|
|
6856
7655
|
function renderMarkdown(text) {
|
|
6857
7656
|
ensureMarkedConfigured();
|
|
6858
7657
|
let rendered = import_marked.marked.parse(text);
|
|
6859
|
-
rendered = rendered.replace(/\*\*(.+?)\*\*/g, (_, content) =>
|
|
7658
|
+
rendered = rendered.replace(/\*\*(.+?)\*\*/g, (_, content) => import_chalk3.default.bold(content)).replace(/(?<!\*)\*(\S[^*]*)\*(?!\*)/g, (_, content) => import_chalk3.default.italic(content));
|
|
6860
7659
|
return rendered.trimEnd();
|
|
6861
7660
|
}
|
|
6862
7661
|
function createRainbowSeparator() {
|
|
6863
|
-
const colors = [
|
|
7662
|
+
const colors = [import_chalk3.default.red, import_chalk3.default.yellow, import_chalk3.default.green, import_chalk3.default.cyan, import_chalk3.default.blue, import_chalk3.default.magenta];
|
|
6864
7663
|
const char = "\u2500";
|
|
6865
7664
|
const width = process.stdout.columns || 80;
|
|
6866
7665
|
let result = "";
|
|
@@ -6896,58 +7695,58 @@ function formatCost(cost) {
|
|
|
6896
7695
|
function renderSummary(metadata) {
|
|
6897
7696
|
const parts = [];
|
|
6898
7697
|
if (metadata.iterations !== void 0) {
|
|
6899
|
-
const iterPart =
|
|
7698
|
+
const iterPart = import_chalk3.default.cyan(`#${metadata.iterations}`);
|
|
6900
7699
|
if (metadata.model) {
|
|
6901
|
-
parts.push(`${iterPart} ${
|
|
7700
|
+
parts.push(`${iterPart} ${import_chalk3.default.magenta(metadata.model)}`);
|
|
6902
7701
|
} else {
|
|
6903
7702
|
parts.push(iterPart);
|
|
6904
7703
|
}
|
|
6905
7704
|
} else if (metadata.model) {
|
|
6906
|
-
parts.push(
|
|
7705
|
+
parts.push(import_chalk3.default.magenta(metadata.model));
|
|
6907
7706
|
}
|
|
6908
7707
|
if (metadata.usage) {
|
|
6909
7708
|
const { inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens } = metadata.usage;
|
|
6910
|
-
parts.push(
|
|
7709
|
+
parts.push(import_chalk3.default.dim("\u2191") + import_chalk3.default.yellow(` ${formatTokens(inputTokens)}`));
|
|
6911
7710
|
if (cachedInputTokens && cachedInputTokens > 0) {
|
|
6912
|
-
parts.push(
|
|
7711
|
+
parts.push(import_chalk3.default.dim("\u27F3") + import_chalk3.default.blue(` ${formatTokens(cachedInputTokens)}`));
|
|
6913
7712
|
}
|
|
6914
7713
|
if (cacheCreationInputTokens && cacheCreationInputTokens > 0) {
|
|
6915
|
-
parts.push(
|
|
7714
|
+
parts.push(import_chalk3.default.dim("\u270E") + import_chalk3.default.magenta(` ${formatTokens(cacheCreationInputTokens)}`));
|
|
6916
7715
|
}
|
|
6917
|
-
parts.push(
|
|
7716
|
+
parts.push(import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(outputTokens)}`));
|
|
6918
7717
|
}
|
|
6919
7718
|
if (metadata.elapsedSeconds !== void 0 && metadata.elapsedSeconds > 0) {
|
|
6920
|
-
parts.push(
|
|
7719
|
+
parts.push(import_chalk3.default.dim(`${metadata.elapsedSeconds}s`));
|
|
6921
7720
|
}
|
|
6922
7721
|
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
6923
|
-
parts.push(
|
|
7722
|
+
parts.push(import_chalk3.default.cyan(`$${formatCost(metadata.cost)}`));
|
|
6924
7723
|
}
|
|
6925
7724
|
if (metadata.finishReason) {
|
|
6926
|
-
parts.push(
|
|
7725
|
+
parts.push(import_chalk3.default.dim(metadata.finishReason));
|
|
6927
7726
|
}
|
|
6928
7727
|
if (parts.length === 0) {
|
|
6929
7728
|
return null;
|
|
6930
7729
|
}
|
|
6931
|
-
return parts.join(
|
|
7730
|
+
return parts.join(import_chalk3.default.dim(" | "));
|
|
6932
7731
|
}
|
|
6933
7732
|
function renderOverallSummary(metadata) {
|
|
6934
7733
|
const parts = [];
|
|
6935
7734
|
if (metadata.totalTokens !== void 0 && metadata.totalTokens > 0) {
|
|
6936
|
-
parts.push(
|
|
7735
|
+
parts.push(import_chalk3.default.dim("total:") + import_chalk3.default.magenta(` ${formatTokens(metadata.totalTokens)}`));
|
|
6937
7736
|
}
|
|
6938
7737
|
if (metadata.iterations !== void 0 && metadata.iterations > 0) {
|
|
6939
|
-
parts.push(
|
|
7738
|
+
parts.push(import_chalk3.default.cyan(`#${metadata.iterations}`));
|
|
6940
7739
|
}
|
|
6941
7740
|
if (metadata.elapsedSeconds !== void 0 && metadata.elapsedSeconds > 0) {
|
|
6942
|
-
parts.push(
|
|
7741
|
+
parts.push(import_chalk3.default.dim(`${metadata.elapsedSeconds}s`));
|
|
6943
7742
|
}
|
|
6944
7743
|
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
6945
|
-
parts.push(
|
|
7744
|
+
parts.push(import_chalk3.default.cyan(`$${formatCost(metadata.cost)}`));
|
|
6946
7745
|
}
|
|
6947
7746
|
if (parts.length === 0) {
|
|
6948
7747
|
return null;
|
|
6949
7748
|
}
|
|
6950
|
-
return parts.join(
|
|
7749
|
+
return parts.join(import_chalk3.default.dim(" | "));
|
|
6951
7750
|
}
|
|
6952
7751
|
function formatParametersInline(params) {
|
|
6953
7752
|
if (!params || Object.keys(params).length === 0) {
|
|
@@ -6963,8 +7762,8 @@ function formatParametersInline(params) {
|
|
|
6963
7762
|
const json = JSON.stringify(value);
|
|
6964
7763
|
formatted = json.length > 30 ? `${json.slice(0, 30)}\u2026` : json;
|
|
6965
7764
|
}
|
|
6966
|
-
return `${
|
|
6967
|
-
}).join(
|
|
7765
|
+
return `${import_chalk3.default.dim(key)}${import_chalk3.default.dim("=")}${import_chalk3.default.cyan(formatted)}`;
|
|
7766
|
+
}).join(import_chalk3.default.dim(", "));
|
|
6968
7767
|
}
|
|
6969
7768
|
function formatBytes(bytes) {
|
|
6970
7769
|
if (bytes < 1024) {
|
|
@@ -6976,25 +7775,25 @@ function formatBytes(bytes) {
|
|
|
6976
7775
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
6977
7776
|
}
|
|
6978
7777
|
function formatGadgetSummary(result) {
|
|
6979
|
-
const gadgetLabel =
|
|
6980
|
-
const timeLabel =
|
|
7778
|
+
const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
|
|
7779
|
+
const timeLabel = import_chalk3.default.dim(`${Math.round(result.executionTimeMs)}ms`);
|
|
6981
7780
|
const paramsStr = formatParametersInline(result.parameters);
|
|
6982
|
-
const paramsLabel = paramsStr ? `${
|
|
7781
|
+
const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
|
|
6983
7782
|
if (result.error) {
|
|
6984
7783
|
const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
|
|
6985
|
-
return `${
|
|
7784
|
+
return `${import_chalk3.default.red("\u2717")} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
|
|
6986
7785
|
}
|
|
6987
7786
|
let outputLabel;
|
|
6988
7787
|
if (result.tokenCount !== void 0 && result.tokenCount > 0) {
|
|
6989
|
-
outputLabel =
|
|
7788
|
+
outputLabel = import_chalk3.default.green(`${formatTokens(result.tokenCount)} tokens`);
|
|
6990
7789
|
} else if (result.result) {
|
|
6991
7790
|
const outputBytes = Buffer.byteLength(result.result, "utf-8");
|
|
6992
|
-
outputLabel = outputBytes > 0 ?
|
|
7791
|
+
outputLabel = outputBytes > 0 ? import_chalk3.default.green(formatBytes(outputBytes)) : import_chalk3.default.dim("no output");
|
|
6993
7792
|
} else {
|
|
6994
|
-
outputLabel =
|
|
7793
|
+
outputLabel = import_chalk3.default.dim("no output");
|
|
6995
7794
|
}
|
|
6996
|
-
const icon = result.breaksLoop ?
|
|
6997
|
-
const summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${
|
|
7795
|
+
const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
|
|
7796
|
+
const summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
|
|
6998
7797
|
if (result.gadgetName === "TellUser" && result.parameters?.message) {
|
|
6999
7798
|
const message = String(result.parameters.message);
|
|
7000
7799
|
const rendered = renderMarkdownWithSeparators(message);
|
|
@@ -7058,6 +7857,66 @@ var StreamPrinter = class {
|
|
|
7058
7857
|
function isInteractive(stream2) {
|
|
7059
7858
|
return Boolean(stream2.isTTY);
|
|
7060
7859
|
}
|
|
7860
|
+
var ESC_KEY = 27;
|
|
7861
|
+
var ESC_TIMEOUT_MS = 50;
|
|
7862
|
+
function createEscKeyListener(stdin, onEsc) {
|
|
7863
|
+
if (!stdin.isTTY || typeof stdin.setRawMode !== "function") {
|
|
7864
|
+
return null;
|
|
7865
|
+
}
|
|
7866
|
+
let escTimeout = null;
|
|
7867
|
+
const handleData = (data) => {
|
|
7868
|
+
if (data[0] === ESC_KEY) {
|
|
7869
|
+
if (data.length === 1) {
|
|
7870
|
+
escTimeout = setTimeout(() => {
|
|
7871
|
+
onEsc();
|
|
7872
|
+
}, ESC_TIMEOUT_MS);
|
|
7873
|
+
} else {
|
|
7874
|
+
if (escTimeout) {
|
|
7875
|
+
clearTimeout(escTimeout);
|
|
7876
|
+
escTimeout = null;
|
|
7877
|
+
}
|
|
7878
|
+
}
|
|
7879
|
+
} else {
|
|
7880
|
+
if (escTimeout) {
|
|
7881
|
+
clearTimeout(escTimeout);
|
|
7882
|
+
escTimeout = null;
|
|
7883
|
+
}
|
|
7884
|
+
}
|
|
7885
|
+
};
|
|
7886
|
+
stdin.setRawMode(true);
|
|
7887
|
+
stdin.resume();
|
|
7888
|
+
stdin.on("data", handleData);
|
|
7889
|
+
return () => {
|
|
7890
|
+
if (escTimeout) {
|
|
7891
|
+
clearTimeout(escTimeout);
|
|
7892
|
+
}
|
|
7893
|
+
stdin.removeListener("data", handleData);
|
|
7894
|
+
stdin.setRawMode(false);
|
|
7895
|
+
stdin.pause();
|
|
7896
|
+
};
|
|
7897
|
+
}
|
|
7898
|
+
var SIGINT_DOUBLE_PRESS_MS = 1e3;
|
|
7899
|
+
function createSigintListener(onCancel, onQuit, isOperationActive, stderr = process.stderr) {
|
|
7900
|
+
let lastSigintTime = 0;
|
|
7901
|
+
const handler = () => {
|
|
7902
|
+
const now = Date.now();
|
|
7903
|
+
if (isOperationActive()) {
|
|
7904
|
+
onCancel();
|
|
7905
|
+
lastSigintTime = now;
|
|
7906
|
+
return;
|
|
7907
|
+
}
|
|
7908
|
+
if (now - lastSigintTime < SIGINT_DOUBLE_PRESS_MS) {
|
|
7909
|
+
onQuit();
|
|
7910
|
+
return;
|
|
7911
|
+
}
|
|
7912
|
+
lastSigintTime = now;
|
|
7913
|
+
stderr.write(import_chalk4.default.dim("\n[Press Ctrl+C again to quit]\n"));
|
|
7914
|
+
};
|
|
7915
|
+
process.on("SIGINT", handler);
|
|
7916
|
+
return () => {
|
|
7917
|
+
process.removeListener("SIGINT", handler);
|
|
7918
|
+
};
|
|
7919
|
+
}
|
|
7061
7920
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7062
7921
|
var SPINNER_DELAY_MS = 500;
|
|
7063
7922
|
var StreamProgress = class {
|
|
@@ -7229,9 +8088,9 @@ var StreamProgress = class {
|
|
|
7229
8088
|
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
7230
8089
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
7231
8090
|
const parts = [];
|
|
7232
|
-
const iterPart =
|
|
8091
|
+
const iterPart = import_chalk4.default.cyan(`#${this.currentIteration}`);
|
|
7233
8092
|
if (this.model) {
|
|
7234
|
-
parts.push(`${iterPart} ${
|
|
8093
|
+
parts.push(`${iterPart} ${import_chalk4.default.magenta(this.model)}`);
|
|
7235
8094
|
} else {
|
|
7236
8095
|
parts.push(iterPart);
|
|
7237
8096
|
}
|
|
@@ -7239,27 +8098,27 @@ var StreamProgress = class {
|
|
|
7239
8098
|
if (usagePercent !== null) {
|
|
7240
8099
|
const formatted = `${Math.round(usagePercent)}%`;
|
|
7241
8100
|
if (usagePercent >= 80) {
|
|
7242
|
-
parts.push(
|
|
8101
|
+
parts.push(import_chalk4.default.red(formatted));
|
|
7243
8102
|
} else if (usagePercent >= 50) {
|
|
7244
|
-
parts.push(
|
|
8103
|
+
parts.push(import_chalk4.default.yellow(formatted));
|
|
7245
8104
|
} else {
|
|
7246
|
-
parts.push(
|
|
8105
|
+
parts.push(import_chalk4.default.green(formatted));
|
|
7247
8106
|
}
|
|
7248
8107
|
}
|
|
7249
8108
|
if (this.callInputTokens > 0) {
|
|
7250
8109
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
7251
|
-
parts.push(
|
|
8110
|
+
parts.push(import_chalk4.default.dim("\u2191") + import_chalk4.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`));
|
|
7252
8111
|
}
|
|
7253
8112
|
if (this.isStreaming || outTokens > 0) {
|
|
7254
8113
|
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
7255
|
-
parts.push(
|
|
8114
|
+
parts.push(import_chalk4.default.dim("\u2193") + import_chalk4.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
7256
8115
|
}
|
|
7257
|
-
parts.push(
|
|
8116
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7258
8117
|
const callCost = this.calculateCurrentCallCost(outTokens);
|
|
7259
8118
|
if (callCost > 0) {
|
|
7260
|
-
parts.push(
|
|
8119
|
+
parts.push(import_chalk4.default.cyan(`$${formatCost(callCost)}`));
|
|
7261
8120
|
}
|
|
7262
|
-
this.target.write(`\r${parts.join(
|
|
8121
|
+
this.target.write(`\r${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`);
|
|
7263
8122
|
}
|
|
7264
8123
|
/**
|
|
7265
8124
|
* Calculates live cost estimate for the current streaming call.
|
|
@@ -7300,19 +8159,19 @@ var StreamProgress = class {
|
|
|
7300
8159
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
7301
8160
|
const parts = [];
|
|
7302
8161
|
if (this.model) {
|
|
7303
|
-
parts.push(
|
|
8162
|
+
parts.push(import_chalk4.default.cyan(this.model));
|
|
7304
8163
|
}
|
|
7305
8164
|
if (this.totalTokens > 0) {
|
|
7306
|
-
parts.push(
|
|
8165
|
+
parts.push(import_chalk4.default.dim("total:") + import_chalk4.default.magenta(` ${this.totalTokens}`));
|
|
7307
8166
|
}
|
|
7308
8167
|
if (this.iterations > 0) {
|
|
7309
|
-
parts.push(
|
|
8168
|
+
parts.push(import_chalk4.default.dim("iter:") + import_chalk4.default.blue(` ${this.iterations}`));
|
|
7310
8169
|
}
|
|
7311
8170
|
if (this.totalCost > 0) {
|
|
7312
|
-
parts.push(
|
|
8171
|
+
parts.push(import_chalk4.default.dim("cost:") + import_chalk4.default.cyan(` $${formatCost(this.totalCost)}`));
|
|
7313
8172
|
}
|
|
7314
|
-
parts.push(
|
|
7315
|
-
this.target.write(`\r${parts.join(
|
|
8173
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
8174
|
+
this.target.write(`\r${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`);
|
|
7316
8175
|
}
|
|
7317
8176
|
/**
|
|
7318
8177
|
* Pauses the progress indicator and clears the line.
|
|
@@ -7346,6 +8205,25 @@ var StreamProgress = class {
|
|
|
7346
8205
|
getTotalCost() {
|
|
7347
8206
|
return this.totalCost;
|
|
7348
8207
|
}
|
|
8208
|
+
/**
|
|
8209
|
+
* Returns a formatted stats string for cancellation messages.
|
|
8210
|
+
* Format: "↑ 1.2k | ↓ 300 | 5.0s"
|
|
8211
|
+
*/
|
|
8212
|
+
formatStats() {
|
|
8213
|
+
const parts = [];
|
|
8214
|
+
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
8215
|
+
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
8216
|
+
if (this.callInputTokens > 0) {
|
|
8217
|
+
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
8218
|
+
parts.push(`\u2191 ${prefix}${formatTokens(this.callInputTokens)}`);
|
|
8219
|
+
}
|
|
8220
|
+
if (outTokens > 0) {
|
|
8221
|
+
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
8222
|
+
parts.push(`\u2193 ${prefix}${formatTokens(outTokens)}`);
|
|
8223
|
+
}
|
|
8224
|
+
parts.push(`${elapsed}s`);
|
|
8225
|
+
return parts.join(" | ");
|
|
8226
|
+
}
|
|
7349
8227
|
/**
|
|
7350
8228
|
* Returns a formatted prompt string with stats (like bash PS1).
|
|
7351
8229
|
* Shows current call stats during streaming, cumulative stats otherwise.
|
|
@@ -7360,28 +8238,28 @@ var StreamProgress = class {
|
|
|
7360
8238
|
if (this.callInputTokens > 0) {
|
|
7361
8239
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
7362
8240
|
parts.push(
|
|
7363
|
-
|
|
8241
|
+
import_chalk4.default.dim("\u2191") + import_chalk4.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`)
|
|
7364
8242
|
);
|
|
7365
8243
|
}
|
|
7366
8244
|
if (outTokens > 0) {
|
|
7367
8245
|
const prefix = outEstimated ? "~" : "";
|
|
7368
|
-
parts.push(
|
|
8246
|
+
parts.push(import_chalk4.default.dim("\u2193") + import_chalk4.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
7369
8247
|
}
|
|
7370
|
-
parts.push(
|
|
8248
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7371
8249
|
} else {
|
|
7372
8250
|
const elapsed = Math.round((Date.now() - this.totalStartTime) / 1e3);
|
|
7373
8251
|
if (this.totalTokens > 0) {
|
|
7374
|
-
parts.push(
|
|
8252
|
+
parts.push(import_chalk4.default.magenta(formatTokens(this.totalTokens)));
|
|
7375
8253
|
}
|
|
7376
8254
|
if (this.iterations > 0) {
|
|
7377
|
-
parts.push(
|
|
8255
|
+
parts.push(import_chalk4.default.blue(`i${this.iterations}`));
|
|
7378
8256
|
}
|
|
7379
8257
|
if (this.totalCost > 0) {
|
|
7380
|
-
parts.push(
|
|
8258
|
+
parts.push(import_chalk4.default.cyan(`$${formatCost(this.totalCost)}`));
|
|
7381
8259
|
}
|
|
7382
|
-
parts.push(
|
|
8260
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7383
8261
|
}
|
|
7384
|
-
return `${parts.join(
|
|
8262
|
+
return `${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.green(">")} `;
|
|
7385
8263
|
}
|
|
7386
8264
|
};
|
|
7387
8265
|
async function readStream(stream2) {
|
|
@@ -7416,7 +8294,7 @@ async function executeAction(action, env) {
|
|
|
7416
8294
|
await action();
|
|
7417
8295
|
} catch (error) {
|
|
7418
8296
|
const message = error instanceof Error ? error.message : String(error);
|
|
7419
|
-
env.stderr.write(`${
|
|
8297
|
+
env.stderr.write(`${import_chalk4.default.red.bold("Error:")} ${message}
|
|
7420
8298
|
`);
|
|
7421
8299
|
env.setExitCode(1);
|
|
7422
8300
|
}
|
|
@@ -7441,7 +8319,7 @@ function addAgentOptions(cmd, defaults) {
|
|
|
7441
8319
|
...previous,
|
|
7442
8320
|
value
|
|
7443
8321
|
];
|
|
7444
|
-
const defaultGadgets = defaults?.gadget ?? [];
|
|
8322
|
+
const defaultGadgets = defaults?.gadgets ?? defaults?.gadget ?? [];
|
|
7445
8323
|
return cmd.option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, defaults?.model ?? DEFAULT_MODEL).option(OPTION_FLAGS.systemPrompt, OPTION_DESCRIPTIONS.systemPrompt, defaults?.system).option(
|
|
7446
8324
|
OPTION_FLAGS.temperature,
|
|
7447
8325
|
OPTION_DESCRIPTIONS.temperature,
|
|
@@ -7477,7 +8355,8 @@ function configToAgentOptions(config) {
|
|
|
7477
8355
|
if (config.system !== void 0) result.system = config.system;
|
|
7478
8356
|
if (config.temperature !== void 0) result.temperature = config.temperature;
|
|
7479
8357
|
if (config["max-iterations"] !== void 0) result.maxIterations = config["max-iterations"];
|
|
7480
|
-
|
|
8358
|
+
const gadgets = config.gadgets ?? config.gadget;
|
|
8359
|
+
if (gadgets !== void 0) result.gadget = gadgets;
|
|
7481
8360
|
if (config.builtins !== void 0) result.builtins = config.builtins;
|
|
7482
8361
|
if (config["builtin-interaction"] !== void 0)
|
|
7483
8362
|
result.builtinInteraction = config["builtin-interaction"];
|
|
@@ -7487,6 +8366,8 @@ function configToAgentOptions(config) {
|
|
|
7487
8366
|
result.gadgetEndPrefix = config["gadget-end-prefix"];
|
|
7488
8367
|
if (config["gadget-arg-prefix"] !== void 0)
|
|
7489
8368
|
result.gadgetArgPrefix = config["gadget-arg-prefix"];
|
|
8369
|
+
if (config["gadget-approval"] !== void 0)
|
|
8370
|
+
result.gadgetApproval = config["gadget-approval"];
|
|
7490
8371
|
if (config.quiet !== void 0) result.quiet = config.quiet;
|
|
7491
8372
|
if (config["log-llm-requests"] !== void 0) result.logLlmRequests = config["log-llm-requests"];
|
|
7492
8373
|
if (config["log-llm-responses"] !== void 0) result.logLlmResponses = config["log-llm-responses"];
|
|
@@ -7494,23 +8375,18 @@ function configToAgentOptions(config) {
|
|
|
7494
8375
|
}
|
|
7495
8376
|
|
|
7496
8377
|
// src/cli/agent-command.ts
|
|
7497
|
-
|
|
7498
|
-
const rl = (0, import_promises2.createInterface)({ input: env.stdin, output: env.stderr });
|
|
7499
|
-
try {
|
|
7500
|
-
const answer = await rl.question(prompt);
|
|
7501
|
-
return answer.trim();
|
|
7502
|
-
} finally {
|
|
7503
|
-
rl.close();
|
|
7504
|
-
}
|
|
7505
|
-
}
|
|
7506
|
-
function createHumanInputHandler(env, progress) {
|
|
8378
|
+
function createHumanInputHandler(env, progress, keyboard) {
|
|
7507
8379
|
const stdout = env.stdout;
|
|
7508
8380
|
if (!isInteractive(env.stdin) || typeof stdout.isTTY !== "boolean" || !stdout.isTTY) {
|
|
7509
8381
|
return void 0;
|
|
7510
8382
|
}
|
|
7511
8383
|
return async (question) => {
|
|
7512
8384
|
progress.pause();
|
|
7513
|
-
|
|
8385
|
+
if (keyboard.cleanupEsc) {
|
|
8386
|
+
keyboard.cleanupEsc();
|
|
8387
|
+
keyboard.cleanupEsc = null;
|
|
8388
|
+
}
|
|
8389
|
+
const rl = (0, import_promises3.createInterface)({ input: env.stdin, output: env.stdout });
|
|
7514
8390
|
try {
|
|
7515
8391
|
const questionLine = question.trim() ? `
|
|
7516
8392
|
${renderMarkdownWithSeparators(question.trim())}` : "";
|
|
@@ -7528,6 +8404,7 @@ ${statsPrompt}` : statsPrompt;
|
|
|
7528
8404
|
}
|
|
7529
8405
|
} finally {
|
|
7530
8406
|
rl.close();
|
|
8407
|
+
keyboard.restore();
|
|
7531
8408
|
}
|
|
7532
8409
|
};
|
|
7533
8410
|
}
|
|
@@ -7554,6 +8431,77 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7554
8431
|
const printer = new StreamPrinter(env.stdout);
|
|
7555
8432
|
const stderrTTY = env.stderr.isTTY === true;
|
|
7556
8433
|
const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
|
|
8434
|
+
const abortController = new AbortController();
|
|
8435
|
+
let wasCancelled = false;
|
|
8436
|
+
let isStreaming = false;
|
|
8437
|
+
const stdinStream = env.stdin;
|
|
8438
|
+
const handleCancel = () => {
|
|
8439
|
+
if (!abortController.signal.aborted) {
|
|
8440
|
+
wasCancelled = true;
|
|
8441
|
+
abortController.abort();
|
|
8442
|
+
progress.pause();
|
|
8443
|
+
env.stderr.write(import_chalk5.default.yellow(`
|
|
8444
|
+
[Cancelled] ${progress.formatStats()}
|
|
8445
|
+
`));
|
|
8446
|
+
}
|
|
8447
|
+
};
|
|
8448
|
+
const keyboard = {
|
|
8449
|
+
cleanupEsc: null,
|
|
8450
|
+
cleanupSigint: null,
|
|
8451
|
+
restore: () => {
|
|
8452
|
+
if (stdinIsInteractive && stdinStream.isTTY && !wasCancelled) {
|
|
8453
|
+
keyboard.cleanupEsc = createEscKeyListener(stdinStream, handleCancel);
|
|
8454
|
+
}
|
|
8455
|
+
}
|
|
8456
|
+
};
|
|
8457
|
+
const handleQuit = () => {
|
|
8458
|
+
keyboard.cleanupEsc?.();
|
|
8459
|
+
keyboard.cleanupSigint?.();
|
|
8460
|
+
progress.complete();
|
|
8461
|
+
printer.ensureNewline();
|
|
8462
|
+
const summary = renderOverallSummary({
|
|
8463
|
+
totalTokens: usage?.totalTokens,
|
|
8464
|
+
iterations,
|
|
8465
|
+
elapsedSeconds: progress.getTotalElapsedSeconds(),
|
|
8466
|
+
cost: progress.getTotalCost()
|
|
8467
|
+
});
|
|
8468
|
+
if (summary) {
|
|
8469
|
+
env.stderr.write(`${import_chalk5.default.dim("\u2500".repeat(40))}
|
|
8470
|
+
`);
|
|
8471
|
+
env.stderr.write(`${summary}
|
|
8472
|
+
`);
|
|
8473
|
+
}
|
|
8474
|
+
env.stderr.write(import_chalk5.default.dim("[Quit]\n"));
|
|
8475
|
+
process.exit(130);
|
|
8476
|
+
};
|
|
8477
|
+
if (stdinIsInteractive && stdinStream.isTTY) {
|
|
8478
|
+
keyboard.cleanupEsc = createEscKeyListener(stdinStream, handleCancel);
|
|
8479
|
+
}
|
|
8480
|
+
keyboard.cleanupSigint = createSigintListener(
|
|
8481
|
+
handleCancel,
|
|
8482
|
+
handleQuit,
|
|
8483
|
+
() => isStreaming && !abortController.signal.aborted,
|
|
8484
|
+
env.stderr
|
|
8485
|
+
);
|
|
8486
|
+
const DEFAULT_APPROVAL_REQUIRED = ["RunCommand", "WriteFile", "EditFile"];
|
|
8487
|
+
const userApprovals = options.gadgetApproval ?? {};
|
|
8488
|
+
const gadgetApprovals = {
|
|
8489
|
+
...userApprovals
|
|
8490
|
+
};
|
|
8491
|
+
for (const gadget of DEFAULT_APPROVAL_REQUIRED) {
|
|
8492
|
+
const normalizedGadget = gadget.toLowerCase();
|
|
8493
|
+
const isConfigured = Object.keys(userApprovals).some(
|
|
8494
|
+
(key) => key.toLowerCase() === normalizedGadget
|
|
8495
|
+
);
|
|
8496
|
+
if (!isConfigured) {
|
|
8497
|
+
gadgetApprovals[gadget] = "approval-required";
|
|
8498
|
+
}
|
|
8499
|
+
}
|
|
8500
|
+
const approvalConfig = {
|
|
8501
|
+
gadgetApprovals,
|
|
8502
|
+
defaultMode: "allowed"
|
|
8503
|
+
};
|
|
8504
|
+
const approvalManager = new ApprovalManager(approvalConfig, env, progress);
|
|
7557
8505
|
let usage;
|
|
7558
8506
|
let iterations = 0;
|
|
7559
8507
|
const llmRequestsDir = resolveLogDir(options.logLlmRequests, "requests");
|
|
@@ -7581,6 +8529,7 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7581
8529
|
// onLLMCallStart: Start progress indicator for each LLM call
|
|
7582
8530
|
// This showcases how to react to agent lifecycle events
|
|
7583
8531
|
onLLMCallStart: async (context) => {
|
|
8532
|
+
isStreaming = true;
|
|
7584
8533
|
llmCallCounter++;
|
|
7585
8534
|
const inputTokens = await countMessagesTokens(
|
|
7586
8535
|
context.options.model,
|
|
@@ -7614,6 +8563,7 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7614
8563
|
// onLLMCallComplete: Finalize metrics after each LLM call
|
|
7615
8564
|
// This is where you'd typically log metrics or update dashboards
|
|
7616
8565
|
onLLMCallComplete: async (context) => {
|
|
8566
|
+
isStreaming = false;
|
|
7617
8567
|
usage = context.usage;
|
|
7618
8568
|
iterations = Math.max(iterations, context.iteration + 1);
|
|
7619
8569
|
if (context.usage) {
|
|
@@ -7661,47 +8611,53 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7661
8611
|
}
|
|
7662
8612
|
}
|
|
7663
8613
|
},
|
|
7664
|
-
// SHOWCASE: Controller-based approval gating for
|
|
8614
|
+
// SHOWCASE: Controller-based approval gating for gadgets
|
|
7665
8615
|
//
|
|
7666
8616
|
// This demonstrates how to add safety layers WITHOUT modifying gadgets.
|
|
7667
|
-
// The
|
|
7668
|
-
//
|
|
8617
|
+
// The ApprovalManager handles approval flows externally via beforeGadgetExecution.
|
|
8618
|
+
// Approval modes are configurable via cli.toml:
|
|
8619
|
+
// - "allowed": auto-proceed
|
|
8620
|
+
// - "denied": auto-reject, return message to LLM
|
|
8621
|
+
// - "approval-required": prompt user interactively
|
|
7669
8622
|
//
|
|
7670
|
-
//
|
|
7671
|
-
// any gadget (DeleteFile, SendEmail, etc.) without changing the gadgets.
|
|
8623
|
+
// Default: RunCommand, WriteFile, EditFile require approval unless overridden.
|
|
7672
8624
|
controllers: {
|
|
7673
8625
|
beforeGadgetExecution: async (ctx) => {
|
|
7674
|
-
|
|
8626
|
+
const mode = approvalManager.getApprovalMode(ctx.gadgetName);
|
|
8627
|
+
if (mode === "allowed") {
|
|
7675
8628
|
return { action: "proceed" };
|
|
7676
8629
|
}
|
|
7677
8630
|
const stdinTTY = isInteractive(env.stdin);
|
|
7678
8631
|
const stderrTTY2 = env.stderr.isTTY === true;
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
const command = ctx.parameters.command;
|
|
7686
|
-
progress.pause();
|
|
7687
|
-
env.stderr.write(`
|
|
7688
|
-
\u{1F512} Execute: ${import_chalk3.default.cyan(command)}
|
|
7689
|
-
`);
|
|
7690
|
-
const response = await promptApproval(env, " \u23CE approve, or type to reject: ");
|
|
7691
|
-
const isApproved = response === "" || response.toLowerCase() === "y";
|
|
7692
|
-
if (!isApproved) {
|
|
7693
|
-
env.stderr.write(` ${import_chalk3.default.red("\u2717 Denied")}
|
|
8632
|
+
const canPrompt = stdinTTY && stderrTTY2;
|
|
8633
|
+
if (!canPrompt) {
|
|
8634
|
+
if (mode === "approval-required") {
|
|
8635
|
+
return {
|
|
8636
|
+
action: "skip",
|
|
8637
|
+
syntheticResult: `status=denied
|
|
7694
8638
|
|
|
7695
|
-
|
|
8639
|
+
${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`
|
|
8640
|
+
};
|
|
8641
|
+
}
|
|
8642
|
+
if (mode === "denied") {
|
|
8643
|
+
return {
|
|
8644
|
+
action: "skip",
|
|
8645
|
+
syntheticResult: `status=denied
|
|
8646
|
+
|
|
8647
|
+
${ctx.gadgetName} is denied by configuration.`
|
|
8648
|
+
};
|
|
8649
|
+
}
|
|
8650
|
+
return { action: "proceed" };
|
|
8651
|
+
}
|
|
8652
|
+
const result = await approvalManager.requestApproval(ctx.gadgetName, ctx.parameters);
|
|
8653
|
+
if (!result.approved) {
|
|
7696
8654
|
return {
|
|
7697
8655
|
action: "skip",
|
|
7698
8656
|
syntheticResult: `status=denied
|
|
7699
8657
|
|
|
7700
|
-
|
|
8658
|
+
Denied: ${result.reason ?? "by user"}`
|
|
7701
8659
|
};
|
|
7702
8660
|
}
|
|
7703
|
-
env.stderr.write(` ${import_chalk3.default.green("\u2713 Approved")}
|
|
7704
|
-
`);
|
|
7705
8661
|
return { action: "proceed" };
|
|
7706
8662
|
}
|
|
7707
8663
|
}
|
|
@@ -7715,10 +8671,11 @@ Command rejected by user with message: "${response}"`
|
|
|
7715
8671
|
if (options.temperature !== void 0) {
|
|
7716
8672
|
builder.withTemperature(options.temperature);
|
|
7717
8673
|
}
|
|
7718
|
-
const humanInputHandler = createHumanInputHandler(env, progress);
|
|
8674
|
+
const humanInputHandler = createHumanInputHandler(env, progress, keyboard);
|
|
7719
8675
|
if (humanInputHandler) {
|
|
7720
8676
|
builder.onHumanInput(humanInputHandler);
|
|
7721
8677
|
}
|
|
8678
|
+
builder.withSignal(abortController.signal);
|
|
7722
8679
|
const gadgets = registry.getAll();
|
|
7723
8680
|
if (gadgets.length > 0) {
|
|
7724
8681
|
builder.withGadgets(...gadgets);
|
|
@@ -7756,31 +8713,41 @@ Command rejected by user with message: "${response}"`
|
|
|
7756
8713
|
textBuffer = "";
|
|
7757
8714
|
}
|
|
7758
8715
|
};
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
if (
|
|
7768
|
-
|
|
7769
|
-
|
|
8716
|
+
try {
|
|
8717
|
+
for await (const event of agent.run()) {
|
|
8718
|
+
if (event.type === "text") {
|
|
8719
|
+
progress.pause();
|
|
8720
|
+
textBuffer += event.content;
|
|
8721
|
+
} else if (event.type === "gadget_result") {
|
|
8722
|
+
flushTextBuffer();
|
|
8723
|
+
progress.pause();
|
|
8724
|
+
if (options.quiet) {
|
|
8725
|
+
if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
|
|
8726
|
+
const message = String(event.result.parameters.message);
|
|
8727
|
+
env.stdout.write(`${message}
|
|
7770
8728
|
`);
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
8729
|
+
}
|
|
8730
|
+
} else {
|
|
8731
|
+
const tokenCount = await countGadgetOutputTokens(event.result.result);
|
|
8732
|
+
env.stderr.write(`${formatGadgetSummary({ ...event.result, tokenCount })}
|
|
7775
8733
|
`);
|
|
8734
|
+
}
|
|
7776
8735
|
}
|
|
7777
8736
|
}
|
|
8737
|
+
} catch (error) {
|
|
8738
|
+
if (!isAbortError(error)) {
|
|
8739
|
+
throw error;
|
|
8740
|
+
}
|
|
8741
|
+
} finally {
|
|
8742
|
+
isStreaming = false;
|
|
8743
|
+
keyboard.cleanupEsc?.();
|
|
8744
|
+
keyboard.cleanupSigint?.();
|
|
7778
8745
|
}
|
|
7779
8746
|
flushTextBuffer();
|
|
7780
8747
|
progress.complete();
|
|
7781
8748
|
printer.ensureNewline();
|
|
7782
8749
|
if (!options.quiet && iterations > 1) {
|
|
7783
|
-
env.stderr.write(`${
|
|
8750
|
+
env.stderr.write(`${import_chalk5.default.dim("\u2500".repeat(40))}
|
|
7784
8751
|
`);
|
|
7785
8752
|
const summary = renderOverallSummary({
|
|
7786
8753
|
totalTokens: usage?.totalTokens,
|
|
@@ -7798,7 +8765,13 @@ function registerAgentCommand(program, env, config) {
|
|
|
7798
8765
|
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.");
|
|
7799
8766
|
addAgentOptions(cmd, config);
|
|
7800
8767
|
cmd.action(
|
|
7801
|
-
(prompt, options) => executeAction(() =>
|
|
8768
|
+
(prompt, options) => executeAction(() => {
|
|
8769
|
+
const mergedOptions = {
|
|
8770
|
+
...options,
|
|
8771
|
+
gadgetApproval: config?.["gadget-approval"]
|
|
8772
|
+
};
|
|
8773
|
+
return executeAgent(prompt, mergedOptions, env);
|
|
8774
|
+
}, env)
|
|
7802
8775
|
);
|
|
7803
8776
|
}
|
|
7804
8777
|
|
|
@@ -7882,9 +8855,9 @@ function registerCompleteCommand(program, env, config) {
|
|
|
7882
8855
|
}
|
|
7883
8856
|
|
|
7884
8857
|
// src/cli/config.ts
|
|
7885
|
-
var
|
|
8858
|
+
var import_node_fs8 = require("fs");
|
|
7886
8859
|
var import_node_os2 = require("os");
|
|
7887
|
-
var
|
|
8860
|
+
var import_node_path8 = require("path");
|
|
7888
8861
|
var import_js_toml = require("js-toml");
|
|
7889
8862
|
|
|
7890
8863
|
// src/cli/templates.ts
|
|
@@ -7969,6 +8942,7 @@ function hasTemplateSyntax(str) {
|
|
|
7969
8942
|
}
|
|
7970
8943
|
|
|
7971
8944
|
// src/cli/config.ts
|
|
8945
|
+
var VALID_APPROVAL_MODES = ["allowed", "denied", "approval-required"];
|
|
7972
8946
|
var GLOBAL_CONFIG_KEYS = /* @__PURE__ */ new Set(["log-level", "log-file", "log-reset"]);
|
|
7973
8947
|
var VALID_LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
7974
8948
|
var COMPLETE_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -7991,12 +8965,20 @@ var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
7991
8965
|
"system",
|
|
7992
8966
|
"temperature",
|
|
7993
8967
|
"max-iterations",
|
|
8968
|
+
"gadgets",
|
|
8969
|
+
// Full replacement (preferred)
|
|
8970
|
+
"gadget-add",
|
|
8971
|
+
// Add to inherited gadgets
|
|
8972
|
+
"gadget-remove",
|
|
8973
|
+
// Remove from inherited gadgets
|
|
7994
8974
|
"gadget",
|
|
8975
|
+
// DEPRECATED: alias for gadgets
|
|
7995
8976
|
"builtins",
|
|
7996
8977
|
"builtin-interaction",
|
|
7997
8978
|
"gadget-start-prefix",
|
|
7998
8979
|
"gadget-end-prefix",
|
|
7999
8980
|
"gadget-arg-prefix",
|
|
8981
|
+
"gadget-approval",
|
|
8000
8982
|
"quiet",
|
|
8001
8983
|
"inherits",
|
|
8002
8984
|
"log-level",
|
|
@@ -8014,12 +8996,12 @@ var CUSTOM_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
8014
8996
|
"description"
|
|
8015
8997
|
]);
|
|
8016
8998
|
function getConfigPath() {
|
|
8017
|
-
return (0,
|
|
8999
|
+
return (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".llmist", "cli.toml");
|
|
8018
9000
|
}
|
|
8019
9001
|
var ConfigError = class extends Error {
|
|
8020
|
-
constructor(message,
|
|
8021
|
-
super(
|
|
8022
|
-
this.path =
|
|
9002
|
+
constructor(message, path5) {
|
|
9003
|
+
super(path5 ? `${path5}: ${message}` : message);
|
|
9004
|
+
this.path = path5;
|
|
8023
9005
|
this.name = "ConfigError";
|
|
8024
9006
|
}
|
|
8025
9007
|
};
|
|
@@ -8075,6 +9057,28 @@ function validateInherits(value, section) {
|
|
|
8075
9057
|
}
|
|
8076
9058
|
throw new ConfigError(`[${section}].inherits must be a string or array of strings`);
|
|
8077
9059
|
}
|
|
9060
|
+
function validateGadgetApproval(value, section) {
|
|
9061
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
9062
|
+
throw new ConfigError(
|
|
9063
|
+
`[${section}].gadget-approval must be a table (e.g., { WriteFile = "approval-required" })`
|
|
9064
|
+
);
|
|
9065
|
+
}
|
|
9066
|
+
const result = {};
|
|
9067
|
+
for (const [gadgetName, mode] of Object.entries(value)) {
|
|
9068
|
+
if (typeof mode !== "string") {
|
|
9069
|
+
throw new ConfigError(
|
|
9070
|
+
`[${section}].gadget-approval.${gadgetName} must be a string`
|
|
9071
|
+
);
|
|
9072
|
+
}
|
|
9073
|
+
if (!VALID_APPROVAL_MODES.includes(mode)) {
|
|
9074
|
+
throw new ConfigError(
|
|
9075
|
+
`[${section}].gadget-approval.${gadgetName} must be one of: ${VALID_APPROVAL_MODES.join(", ")}`
|
|
9076
|
+
);
|
|
9077
|
+
}
|
|
9078
|
+
result[gadgetName] = mode;
|
|
9079
|
+
}
|
|
9080
|
+
return result;
|
|
9081
|
+
}
|
|
8078
9082
|
function validateLoggingConfig(raw, section) {
|
|
8079
9083
|
const result = {};
|
|
8080
9084
|
if ("log-level" in raw) {
|
|
@@ -8184,6 +9188,15 @@ function validateAgentConfig(raw, section) {
|
|
|
8184
9188
|
min: 1
|
|
8185
9189
|
});
|
|
8186
9190
|
}
|
|
9191
|
+
if ("gadgets" in rawObj) {
|
|
9192
|
+
result.gadgets = validateStringArray(rawObj.gadgets, "gadgets", section);
|
|
9193
|
+
}
|
|
9194
|
+
if ("gadget-add" in rawObj) {
|
|
9195
|
+
result["gadget-add"] = validateStringArray(rawObj["gadget-add"], "gadget-add", section);
|
|
9196
|
+
}
|
|
9197
|
+
if ("gadget-remove" in rawObj) {
|
|
9198
|
+
result["gadget-remove"] = validateStringArray(rawObj["gadget-remove"], "gadget-remove", section);
|
|
9199
|
+
}
|
|
8187
9200
|
if ("gadget" in rawObj) {
|
|
8188
9201
|
result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
|
|
8189
9202
|
}
|
|
@@ -8218,6 +9231,9 @@ function validateAgentConfig(raw, section) {
|
|
|
8218
9231
|
section
|
|
8219
9232
|
);
|
|
8220
9233
|
}
|
|
9234
|
+
if ("gadget-approval" in rawObj) {
|
|
9235
|
+
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
9236
|
+
}
|
|
8221
9237
|
if ("quiet" in rawObj) {
|
|
8222
9238
|
result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
|
|
8223
9239
|
}
|
|
@@ -8274,6 +9290,15 @@ function validateCustomConfig(raw, section) {
|
|
|
8274
9290
|
min: 1
|
|
8275
9291
|
});
|
|
8276
9292
|
}
|
|
9293
|
+
if ("gadgets" in rawObj) {
|
|
9294
|
+
result.gadgets = validateStringArray(rawObj.gadgets, "gadgets", section);
|
|
9295
|
+
}
|
|
9296
|
+
if ("gadget-add" in rawObj) {
|
|
9297
|
+
result["gadget-add"] = validateStringArray(rawObj["gadget-add"], "gadget-add", section);
|
|
9298
|
+
}
|
|
9299
|
+
if ("gadget-remove" in rawObj) {
|
|
9300
|
+
result["gadget-remove"] = validateStringArray(rawObj["gadget-remove"], "gadget-remove", section);
|
|
9301
|
+
}
|
|
8277
9302
|
if ("gadget" in rawObj) {
|
|
8278
9303
|
result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
|
|
8279
9304
|
}
|
|
@@ -8308,6 +9333,9 @@ function validateCustomConfig(raw, section) {
|
|
|
8308
9333
|
section
|
|
8309
9334
|
);
|
|
8310
9335
|
}
|
|
9336
|
+
if ("gadget-approval" in rawObj) {
|
|
9337
|
+
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
9338
|
+
}
|
|
8311
9339
|
if ("max-tokens" in rawObj) {
|
|
8312
9340
|
result["max-tokens"] = validateNumber(rawObj["max-tokens"], "max-tokens", section, {
|
|
8313
9341
|
integer: true,
|
|
@@ -8363,12 +9391,12 @@ function validateConfig(raw, configPath) {
|
|
|
8363
9391
|
}
|
|
8364
9392
|
function loadConfig() {
|
|
8365
9393
|
const configPath = getConfigPath();
|
|
8366
|
-
if (!(0,
|
|
9394
|
+
if (!(0, import_node_fs8.existsSync)(configPath)) {
|
|
8367
9395
|
return {};
|
|
8368
9396
|
}
|
|
8369
9397
|
let content;
|
|
8370
9398
|
try {
|
|
8371
|
-
content = (0,
|
|
9399
|
+
content = (0, import_node_fs8.readFileSync)(configPath, "utf-8");
|
|
8372
9400
|
} catch (error) {
|
|
8373
9401
|
throw new ConfigError(
|
|
8374
9402
|
`Failed to read config file: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
@@ -8463,6 +9491,39 @@ function resolveTemplatesInConfig(config, configPath) {
|
|
|
8463
9491
|
}
|
|
8464
9492
|
return result;
|
|
8465
9493
|
}
|
|
9494
|
+
function resolveGadgets(section, inheritedGadgets, sectionName, configPath) {
|
|
9495
|
+
const hasGadgets = "gadgets" in section;
|
|
9496
|
+
const hasGadgetLegacy = "gadget" in section;
|
|
9497
|
+
const hasGadgetAdd = "gadget-add" in section;
|
|
9498
|
+
const hasGadgetRemove = "gadget-remove" in section;
|
|
9499
|
+
if (hasGadgetLegacy && !hasGadgets) {
|
|
9500
|
+
console.warn(
|
|
9501
|
+
`[config] Warning: [${sectionName}].gadget is deprecated, use 'gadgets' (plural) instead`
|
|
9502
|
+
);
|
|
9503
|
+
}
|
|
9504
|
+
if ((hasGadgets || hasGadgetLegacy) && (hasGadgetAdd || hasGadgetRemove)) {
|
|
9505
|
+
throw new ConfigError(
|
|
9506
|
+
`[${sectionName}] Cannot use 'gadgets' with 'gadget-add'/'gadget-remove'. Use either full replacement (gadgets) OR modification (gadget-add/gadget-remove).`,
|
|
9507
|
+
configPath
|
|
9508
|
+
);
|
|
9509
|
+
}
|
|
9510
|
+
if (hasGadgets) {
|
|
9511
|
+
return section.gadgets;
|
|
9512
|
+
}
|
|
9513
|
+
if (hasGadgetLegacy) {
|
|
9514
|
+
return section.gadget;
|
|
9515
|
+
}
|
|
9516
|
+
let result = [...inheritedGadgets];
|
|
9517
|
+
if (hasGadgetRemove) {
|
|
9518
|
+
const toRemove = new Set(section["gadget-remove"]);
|
|
9519
|
+
result = result.filter((g) => !toRemove.has(g));
|
|
9520
|
+
}
|
|
9521
|
+
if (hasGadgetAdd) {
|
|
9522
|
+
const toAdd = section["gadget-add"];
|
|
9523
|
+
result.push(...toAdd);
|
|
9524
|
+
}
|
|
9525
|
+
return result;
|
|
9526
|
+
}
|
|
8466
9527
|
function resolveInheritance(config, configPath) {
|
|
8467
9528
|
const resolved = {};
|
|
8468
9529
|
const resolving = /* @__PURE__ */ new Set();
|
|
@@ -8486,8 +9547,23 @@ function resolveInheritance(config, configPath) {
|
|
|
8486
9547
|
const parentResolved = resolveSection(parent);
|
|
8487
9548
|
merged = { ...merged, ...parentResolved };
|
|
8488
9549
|
}
|
|
8489
|
-
const
|
|
9550
|
+
const inheritedGadgets = merged.gadgets ?? [];
|
|
9551
|
+
const {
|
|
9552
|
+
inherits: _inherits,
|
|
9553
|
+
gadgets: _gadgets,
|
|
9554
|
+
gadget: _gadget,
|
|
9555
|
+
"gadget-add": _gadgetAdd,
|
|
9556
|
+
"gadget-remove": _gadgetRemove,
|
|
9557
|
+
...ownValues
|
|
9558
|
+
} = sectionObj;
|
|
8490
9559
|
merged = { ...merged, ...ownValues };
|
|
9560
|
+
const resolvedGadgets = resolveGadgets(sectionObj, inheritedGadgets, name, configPath);
|
|
9561
|
+
if (resolvedGadgets.length > 0) {
|
|
9562
|
+
merged.gadgets = resolvedGadgets;
|
|
9563
|
+
}
|
|
9564
|
+
delete merged["gadget"];
|
|
9565
|
+
delete merged["gadget-add"];
|
|
9566
|
+
delete merged["gadget-remove"];
|
|
8491
9567
|
resolving.delete(name);
|
|
8492
9568
|
resolved[name] = merged;
|
|
8493
9569
|
return merged;
|
|
@@ -8499,13 +9575,13 @@ function resolveInheritance(config, configPath) {
|
|
|
8499
9575
|
}
|
|
8500
9576
|
|
|
8501
9577
|
// src/cli/gadget-command.ts
|
|
8502
|
-
var
|
|
9578
|
+
var import_chalk7 = __toESM(require("chalk"), 1);
|
|
8503
9579
|
init_schema_to_json();
|
|
8504
9580
|
init_schema_validator();
|
|
8505
9581
|
|
|
8506
9582
|
// src/cli/gadget-prompts.ts
|
|
8507
|
-
var
|
|
8508
|
-
var
|
|
9583
|
+
var import_promises4 = require("readline/promises");
|
|
9584
|
+
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
8509
9585
|
init_schema_to_json();
|
|
8510
9586
|
async function promptForParameters(schema, ctx) {
|
|
8511
9587
|
if (!schema) {
|
|
@@ -8515,7 +9591,7 @@ async function promptForParameters(schema, ctx) {
|
|
|
8515
9591
|
if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {
|
|
8516
9592
|
return {};
|
|
8517
9593
|
}
|
|
8518
|
-
const rl = (0,
|
|
9594
|
+
const rl = (0, import_promises4.createInterface)({ input: ctx.stdin, output: ctx.stdout });
|
|
8519
9595
|
const params = {};
|
|
8520
9596
|
try {
|
|
8521
9597
|
for (const [key, prop] of Object.entries(jsonSchema.properties)) {
|
|
@@ -8538,16 +9614,16 @@ ${issues}`);
|
|
|
8538
9614
|
async function promptForField(rl, key, prop, required) {
|
|
8539
9615
|
const isRequired = required.includes(key);
|
|
8540
9616
|
const typeHint = formatTypeHint(prop);
|
|
8541
|
-
const defaultHint = prop.default !== void 0 ?
|
|
8542
|
-
const requiredMarker = isRequired ?
|
|
9617
|
+
const defaultHint = prop.default !== void 0 ? import_chalk6.default.dim(` [default: ${JSON.stringify(prop.default)}]`) : "";
|
|
9618
|
+
const requiredMarker = isRequired ? import_chalk6.default.red("*") : "";
|
|
8543
9619
|
let prompt = `
|
|
8544
|
-
${
|
|
9620
|
+
${import_chalk6.default.cyan.bold(key)}${requiredMarker}`;
|
|
8545
9621
|
if (prop.description) {
|
|
8546
|
-
prompt +=
|
|
9622
|
+
prompt += import_chalk6.default.dim(` - ${prop.description}`);
|
|
8547
9623
|
}
|
|
8548
9624
|
prompt += `
|
|
8549
9625
|
${typeHint}${defaultHint}
|
|
8550
|
-
${
|
|
9626
|
+
${import_chalk6.default.green(">")} `;
|
|
8551
9627
|
const answer = await rl.question(prompt);
|
|
8552
9628
|
const trimmed = answer.trim();
|
|
8553
9629
|
if (!trimmed) {
|
|
@@ -8563,20 +9639,20 @@ ${import_chalk4.default.cyan.bold(key)}${requiredMarker}`;
|
|
|
8563
9639
|
}
|
|
8564
9640
|
function formatTypeHint(prop) {
|
|
8565
9641
|
if (prop.enum) {
|
|
8566
|
-
return
|
|
9642
|
+
return import_chalk6.default.yellow(`(${prop.enum.join(" | ")})`);
|
|
8567
9643
|
}
|
|
8568
9644
|
if (prop.type === "array") {
|
|
8569
9645
|
const items = prop.items;
|
|
8570
9646
|
if (items?.enum) {
|
|
8571
|
-
return
|
|
9647
|
+
return import_chalk6.default.yellow(`(${items.enum.join(" | ")})[] comma-separated`);
|
|
8572
9648
|
}
|
|
8573
9649
|
const itemType = items?.type ?? "any";
|
|
8574
|
-
return
|
|
9650
|
+
return import_chalk6.default.yellow(`(${itemType}[]) comma-separated`);
|
|
8575
9651
|
}
|
|
8576
9652
|
if (prop.type === "object" && prop.properties) {
|
|
8577
|
-
return
|
|
9653
|
+
return import_chalk6.default.yellow("(object) enter as JSON");
|
|
8578
9654
|
}
|
|
8579
|
-
return
|
|
9655
|
+
return import_chalk6.default.yellow(`(${prop.type ?? "any"})`);
|
|
8580
9656
|
}
|
|
8581
9657
|
function parseValue(input, prop, key) {
|
|
8582
9658
|
const type = prop.type;
|
|
@@ -8687,7 +9763,7 @@ Available gadgets:
|
|
|
8687
9763
|
async function executeGadgetRun(file, options, env) {
|
|
8688
9764
|
const cwd = process.cwd();
|
|
8689
9765
|
const { gadget, name } = await selectGadget(file, options.name, cwd);
|
|
8690
|
-
env.stderr.write(
|
|
9766
|
+
env.stderr.write(import_chalk7.default.cyan.bold(`
|
|
8691
9767
|
\u{1F527} Running gadget: ${name}
|
|
8692
9768
|
`));
|
|
8693
9769
|
let params;
|
|
@@ -8698,7 +9774,7 @@ async function executeGadgetRun(file, options, env) {
|
|
|
8698
9774
|
// Prompts go to stderr to keep stdout clean
|
|
8699
9775
|
});
|
|
8700
9776
|
} else {
|
|
8701
|
-
env.stderr.write(
|
|
9777
|
+
env.stderr.write(import_chalk7.default.dim("Reading parameters from stdin...\n"));
|
|
8702
9778
|
const stdinParams = await readStdinJson(env.stdin);
|
|
8703
9779
|
if (gadget.parameterSchema) {
|
|
8704
9780
|
const result2 = gadget.parameterSchema.safeParse(stdinParams);
|
|
@@ -8712,7 +9788,7 @@ ${issues}`);
|
|
|
8712
9788
|
params = stdinParams;
|
|
8713
9789
|
}
|
|
8714
9790
|
}
|
|
8715
|
-
env.stderr.write(
|
|
9791
|
+
env.stderr.write(import_chalk7.default.dim("\nExecuting...\n"));
|
|
8716
9792
|
const startTime = Date.now();
|
|
8717
9793
|
let result;
|
|
8718
9794
|
try {
|
|
@@ -8734,7 +9810,7 @@ ${issues}`);
|
|
|
8734
9810
|
throw new Error(`Execution failed: ${message}`);
|
|
8735
9811
|
}
|
|
8736
9812
|
const elapsed = Date.now() - startTime;
|
|
8737
|
-
env.stderr.write(
|
|
9813
|
+
env.stderr.write(import_chalk7.default.green(`
|
|
8738
9814
|
\u2713 Completed in ${elapsed}ms
|
|
8739
9815
|
|
|
8740
9816
|
`));
|
|
@@ -8770,37 +9846,37 @@ async function executeGadgetInfo(file, options, env) {
|
|
|
8770
9846
|
return;
|
|
8771
9847
|
}
|
|
8772
9848
|
env.stdout.write("\n");
|
|
8773
|
-
env.stdout.write(
|
|
9849
|
+
env.stdout.write(import_chalk7.default.cyan.bold(`${name}
|
|
8774
9850
|
`));
|
|
8775
|
-
env.stdout.write(
|
|
8776
|
-
env.stdout.write(
|
|
9851
|
+
env.stdout.write(import_chalk7.default.cyan("\u2550".repeat(name.length)) + "\n\n");
|
|
9852
|
+
env.stdout.write(import_chalk7.default.bold("Description:\n"));
|
|
8777
9853
|
env.stdout.write(` ${gadget.description}
|
|
8778
9854
|
|
|
8779
9855
|
`);
|
|
8780
9856
|
if (gadget.parameterSchema) {
|
|
8781
|
-
env.stdout.write(
|
|
9857
|
+
env.stdout.write(import_chalk7.default.bold("Parameters:\n"));
|
|
8782
9858
|
const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
|
|
8783
9859
|
env.stdout.write(formatSchemaAsText(jsonSchema, " ") + "\n\n");
|
|
8784
9860
|
} else {
|
|
8785
|
-
env.stdout.write(
|
|
9861
|
+
env.stdout.write(import_chalk7.default.dim("No parameters required.\n\n"));
|
|
8786
9862
|
}
|
|
8787
9863
|
if (gadget.timeoutMs) {
|
|
8788
|
-
env.stdout.write(
|
|
9864
|
+
env.stdout.write(import_chalk7.default.bold("Timeout:\n"));
|
|
8789
9865
|
env.stdout.write(` ${gadget.timeoutMs}ms
|
|
8790
9866
|
|
|
8791
9867
|
`);
|
|
8792
9868
|
}
|
|
8793
9869
|
if (gadget.examples && gadget.examples.length > 0) {
|
|
8794
|
-
env.stdout.write(
|
|
9870
|
+
env.stdout.write(import_chalk7.default.bold("Examples:\n"));
|
|
8795
9871
|
for (const example of gadget.examples) {
|
|
8796
9872
|
if (example.comment) {
|
|
8797
|
-
env.stdout.write(
|
|
9873
|
+
env.stdout.write(import_chalk7.default.dim(` # ${example.comment}
|
|
8798
9874
|
`));
|
|
8799
9875
|
}
|
|
8800
|
-
env.stdout.write(` Input: ${
|
|
9876
|
+
env.stdout.write(` Input: ${import_chalk7.default.cyan(JSON.stringify(example.params))}
|
|
8801
9877
|
`);
|
|
8802
9878
|
if (example.output !== void 0) {
|
|
8803
|
-
env.stdout.write(` Output: ${
|
|
9879
|
+
env.stdout.write(` Output: ${import_chalk7.default.green(example.output)}
|
|
8804
9880
|
`);
|
|
8805
9881
|
}
|
|
8806
9882
|
env.stdout.write("\n");
|
|
@@ -8833,27 +9909,27 @@ function formatSchemaAsText(schema, indent = "") {
|
|
|
8833
9909
|
const isRequired = required.includes(key);
|
|
8834
9910
|
const enumValues = prop.enum;
|
|
8835
9911
|
const defaultValue = prop.default;
|
|
8836
|
-
let line = `${indent}${
|
|
9912
|
+
let line = `${indent}${import_chalk7.default.cyan(key)}`;
|
|
8837
9913
|
if (isRequired) {
|
|
8838
|
-
line +=
|
|
9914
|
+
line += import_chalk7.default.red("*");
|
|
8839
9915
|
}
|
|
8840
9916
|
if (type === "array") {
|
|
8841
9917
|
const items = prop.items;
|
|
8842
9918
|
const itemType = items?.type || "any";
|
|
8843
|
-
line +=
|
|
9919
|
+
line += import_chalk7.default.dim(` (${itemType}[])`);
|
|
8844
9920
|
} else if (type === "object" && prop.properties) {
|
|
8845
|
-
line +=
|
|
9921
|
+
line += import_chalk7.default.dim(" (object)");
|
|
8846
9922
|
} else {
|
|
8847
|
-
line +=
|
|
9923
|
+
line += import_chalk7.default.dim(` (${type})`);
|
|
8848
9924
|
}
|
|
8849
9925
|
if (defaultValue !== void 0) {
|
|
8850
|
-
line +=
|
|
9926
|
+
line += import_chalk7.default.dim(` [default: ${JSON.stringify(defaultValue)}]`);
|
|
8851
9927
|
}
|
|
8852
9928
|
if (description) {
|
|
8853
9929
|
line += `: ${description}`;
|
|
8854
9930
|
}
|
|
8855
9931
|
if (enumValues) {
|
|
8856
|
-
line +=
|
|
9932
|
+
line += import_chalk7.default.yellow(` - one of: ${enumValues.join(", ")}`);
|
|
8857
9933
|
}
|
|
8858
9934
|
lines.push(line);
|
|
8859
9935
|
if (type === "object" && prop.properties) {
|
|
@@ -8893,20 +9969,20 @@ async function executeGadgetValidate(file, env) {
|
|
|
8893
9969
|
throw new Error(`Validation issues:
|
|
8894
9970
|
${issues.map((i) => ` - ${i}`).join("\n")}`);
|
|
8895
9971
|
}
|
|
8896
|
-
env.stdout.write(
|
|
8897
|
-
env.stdout.write(
|
|
9972
|
+
env.stdout.write(import_chalk7.default.green.bold("\n\u2713 Valid\n\n"));
|
|
9973
|
+
env.stdout.write(import_chalk7.default.bold("Gadgets found:\n"));
|
|
8898
9974
|
for (const gadget of gadgets) {
|
|
8899
9975
|
const name = gadget.name ?? gadget.constructor.name;
|
|
8900
|
-
const schemaInfo = gadget.parameterSchema ?
|
|
8901
|
-
env.stdout.write(` ${
|
|
9976
|
+
const schemaInfo = gadget.parameterSchema ? import_chalk7.default.cyan("(with schema)") : import_chalk7.default.dim("(no schema)");
|
|
9977
|
+
env.stdout.write(` ${import_chalk7.default.bold(name)} ${schemaInfo}
|
|
8902
9978
|
`);
|
|
8903
|
-
env.stdout.write(
|
|
9979
|
+
env.stdout.write(import_chalk7.default.dim(` ${gadget.description}
|
|
8904
9980
|
`));
|
|
8905
9981
|
}
|
|
8906
9982
|
env.stdout.write("\n");
|
|
8907
9983
|
} catch (error) {
|
|
8908
9984
|
const message = error instanceof Error ? error.message : String(error);
|
|
8909
|
-
env.stdout.write(
|
|
9985
|
+
env.stdout.write(import_chalk7.default.red.bold(`
|
|
8910
9986
|
\u2717 Invalid
|
|
8911
9987
|
|
|
8912
9988
|
`));
|
|
@@ -8930,7 +10006,7 @@ function registerGadgetCommand(program, env) {
|
|
|
8930
10006
|
}
|
|
8931
10007
|
|
|
8932
10008
|
// src/cli/models-command.ts
|
|
8933
|
-
var
|
|
10009
|
+
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
8934
10010
|
init_model_shortcuts();
|
|
8935
10011
|
async function handleModelsCommand(options, env) {
|
|
8936
10012
|
const client = env.createClient();
|
|
@@ -8950,13 +10026,13 @@ function renderTable(models, verbose, stream2) {
|
|
|
8950
10026
|
}
|
|
8951
10027
|
grouped.get(provider).push(model);
|
|
8952
10028
|
}
|
|
8953
|
-
stream2.write(
|
|
8954
|
-
stream2.write(
|
|
10029
|
+
stream2.write(import_chalk8.default.bold.cyan("\nAvailable Models\n"));
|
|
10030
|
+
stream2.write(import_chalk8.default.cyan("=".repeat(80)) + "\n\n");
|
|
8955
10031
|
const providers = Array.from(grouped.keys()).sort();
|
|
8956
10032
|
for (const provider of providers) {
|
|
8957
10033
|
const providerModels = grouped.get(provider);
|
|
8958
10034
|
const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
8959
|
-
stream2.write(
|
|
10035
|
+
stream2.write(import_chalk8.default.bold.yellow(`${providerName} Models
|
|
8960
10036
|
`));
|
|
8961
10037
|
if (verbose) {
|
|
8962
10038
|
renderVerboseTable(providerModels, stream2);
|
|
@@ -8965,11 +10041,11 @@ function renderTable(models, verbose, stream2) {
|
|
|
8965
10041
|
}
|
|
8966
10042
|
stream2.write("\n");
|
|
8967
10043
|
}
|
|
8968
|
-
stream2.write(
|
|
8969
|
-
stream2.write(
|
|
10044
|
+
stream2.write(import_chalk8.default.bold.magenta("Model Shortcuts\n"));
|
|
10045
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(80)) + "\n");
|
|
8970
10046
|
const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));
|
|
8971
10047
|
for (const [shortcut, fullName] of shortcuts) {
|
|
8972
|
-
stream2.write(
|
|
10048
|
+
stream2.write(import_chalk8.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk8.default.dim(" \u2192 ") + import_chalk8.default.white(fullName) + "\n");
|
|
8973
10049
|
}
|
|
8974
10050
|
stream2.write("\n");
|
|
8975
10051
|
}
|
|
@@ -8979,45 +10055,45 @@ function renderCompactTable(models, stream2) {
|
|
|
8979
10055
|
const contextWidth = 13;
|
|
8980
10056
|
const inputWidth = 10;
|
|
8981
10057
|
const outputWidth = 10;
|
|
8982
|
-
stream2.write(
|
|
10058
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
8983
10059
|
stream2.write(
|
|
8984
|
-
|
|
10060
|
+
import_chalk8.default.bold(
|
|
8985
10061
|
"Model ID".padEnd(idWidth) + " " + "Display Name".padEnd(nameWidth) + " " + "Context".padEnd(contextWidth) + " " + "Input".padEnd(inputWidth) + " " + "Output".padEnd(outputWidth)
|
|
8986
10062
|
) + "\n"
|
|
8987
10063
|
);
|
|
8988
|
-
stream2.write(
|
|
10064
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
8989
10065
|
for (const model of models) {
|
|
8990
10066
|
const contextFormatted = formatTokens2(model.contextWindow);
|
|
8991
10067
|
const inputPrice = `$${model.pricing.input.toFixed(2)}`;
|
|
8992
10068
|
const outputPrice = `$${model.pricing.output.toFixed(2)}`;
|
|
8993
10069
|
stream2.write(
|
|
8994
|
-
|
|
10070
|
+
import_chalk8.default.green(model.modelId.padEnd(idWidth)) + " " + import_chalk8.default.white(model.displayName.padEnd(nameWidth)) + " " + import_chalk8.default.yellow(contextFormatted.padEnd(contextWidth)) + " " + import_chalk8.default.cyan(inputPrice.padEnd(inputWidth)) + " " + import_chalk8.default.cyan(outputPrice.padEnd(outputWidth)) + "\n"
|
|
8995
10071
|
);
|
|
8996
10072
|
}
|
|
8997
|
-
stream2.write(
|
|
8998
|
-
stream2.write(
|
|
10073
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
10074
|
+
stream2.write(import_chalk8.default.dim(` * Prices are per 1M tokens
|
|
8999
10075
|
`));
|
|
9000
10076
|
}
|
|
9001
10077
|
function renderVerboseTable(models, stream2) {
|
|
9002
10078
|
for (const model of models) {
|
|
9003
|
-
stream2.write(
|
|
10079
|
+
stream2.write(import_chalk8.default.bold.green(`
|
|
9004
10080
|
${model.modelId}
|
|
9005
10081
|
`));
|
|
9006
|
-
stream2.write(
|
|
9007
|
-
stream2.write(` ${
|
|
10082
|
+
stream2.write(import_chalk8.default.dim(" " + "\u2500".repeat(60)) + "\n");
|
|
10083
|
+
stream2.write(` ${import_chalk8.default.dim("Name:")} ${import_chalk8.default.white(model.displayName)}
|
|
9008
10084
|
`);
|
|
9009
|
-
stream2.write(` ${
|
|
10085
|
+
stream2.write(` ${import_chalk8.default.dim("Context:")} ${import_chalk8.default.yellow(formatTokens2(model.contextWindow))}
|
|
9010
10086
|
`);
|
|
9011
|
-
stream2.write(` ${
|
|
10087
|
+
stream2.write(` ${import_chalk8.default.dim("Max Output:")} ${import_chalk8.default.yellow(formatTokens2(model.maxOutputTokens))}
|
|
9012
10088
|
`);
|
|
9013
|
-
stream2.write(` ${
|
|
10089
|
+
stream2.write(` ${import_chalk8.default.dim("Pricing:")} ${import_chalk8.default.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${import_chalk8.default.dim("/")} ${import_chalk8.default.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${import_chalk8.default.dim("(per 1M tokens)")}
|
|
9014
10090
|
`);
|
|
9015
10091
|
if (model.pricing.cachedInput !== void 0) {
|
|
9016
|
-
stream2.write(` ${
|
|
10092
|
+
stream2.write(` ${import_chalk8.default.dim("Cached Input:")} ${import_chalk8.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
|
|
9017
10093
|
`);
|
|
9018
10094
|
}
|
|
9019
10095
|
if (model.knowledgeCutoff) {
|
|
9020
|
-
stream2.write(` ${
|
|
10096
|
+
stream2.write(` ${import_chalk8.default.dim("Knowledge:")} ${model.knowledgeCutoff}
|
|
9021
10097
|
`);
|
|
9022
10098
|
}
|
|
9023
10099
|
const features = [];
|
|
@@ -9028,20 +10104,20 @@ function renderVerboseTable(models, stream2) {
|
|
|
9028
10104
|
if (model.features.structuredOutputs) features.push("structured-outputs");
|
|
9029
10105
|
if (model.features.fineTuning) features.push("fine-tuning");
|
|
9030
10106
|
if (features.length > 0) {
|
|
9031
|
-
stream2.write(` ${
|
|
10107
|
+
stream2.write(` ${import_chalk8.default.dim("Features:")} ${import_chalk8.default.blue(features.join(", "))}
|
|
9032
10108
|
`);
|
|
9033
10109
|
}
|
|
9034
10110
|
if (model.metadata) {
|
|
9035
10111
|
if (model.metadata.family) {
|
|
9036
|
-
stream2.write(` ${
|
|
10112
|
+
stream2.write(` ${import_chalk8.default.dim("Family:")} ${model.metadata.family}
|
|
9037
10113
|
`);
|
|
9038
10114
|
}
|
|
9039
10115
|
if (model.metadata.releaseDate) {
|
|
9040
|
-
stream2.write(` ${
|
|
10116
|
+
stream2.write(` ${import_chalk8.default.dim("Released:")} ${model.metadata.releaseDate}
|
|
9041
10117
|
`);
|
|
9042
10118
|
}
|
|
9043
10119
|
if (model.metadata.notes) {
|
|
9044
|
-
stream2.write(` ${
|
|
10120
|
+
stream2.write(` ${import_chalk8.default.dim("Notes:")} ${import_chalk8.default.italic(model.metadata.notes)}
|
|
9045
10121
|
`);
|
|
9046
10122
|
}
|
|
9047
10123
|
}
|
|
@@ -9091,7 +10167,7 @@ function registerModelsCommand(program, env) {
|
|
|
9091
10167
|
|
|
9092
10168
|
// src/cli/environment.ts
|
|
9093
10169
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
9094
|
-
var
|
|
10170
|
+
var import_chalk9 = __toESM(require("chalk"), 1);
|
|
9095
10171
|
init_client();
|
|
9096
10172
|
init_logger();
|
|
9097
10173
|
var LOG_LEVEL_MAP = {
|
|
@@ -9134,22 +10210,22 @@ function createLoggerFactory(config) {
|
|
|
9134
10210
|
}
|
|
9135
10211
|
function createPromptFunction(stdin, stdout) {
|
|
9136
10212
|
return (question) => {
|
|
9137
|
-
return new Promise((
|
|
10213
|
+
return new Promise((resolve2) => {
|
|
9138
10214
|
const rl = import_node_readline.default.createInterface({
|
|
9139
10215
|
input: stdin,
|
|
9140
10216
|
output: stdout
|
|
9141
10217
|
});
|
|
9142
10218
|
stdout.write("\n");
|
|
9143
|
-
stdout.write(`${
|
|
10219
|
+
stdout.write(`${import_chalk9.default.cyan("\u2500".repeat(60))}
|
|
9144
10220
|
`);
|
|
9145
|
-
stdout.write(
|
|
10221
|
+
stdout.write(import_chalk9.default.cyan.bold("\u{1F916} Agent asks:\n"));
|
|
9146
10222
|
stdout.write(`${question}
|
|
9147
10223
|
`);
|
|
9148
|
-
stdout.write(`${
|
|
10224
|
+
stdout.write(`${import_chalk9.default.cyan("\u2500".repeat(60))}
|
|
9149
10225
|
`);
|
|
9150
|
-
rl.question(
|
|
10226
|
+
rl.question(import_chalk9.default.green.bold("You: "), (answer) => {
|
|
9151
10227
|
rl.close();
|
|
9152
|
-
|
|
10228
|
+
resolve2(answer);
|
|
9153
10229
|
});
|
|
9154
10230
|
});
|
|
9155
10231
|
};
|