llmist 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-QR5IQXEM.js +974 -0
- package/dist/chunk-QR5IQXEM.js.map +1 -0
- package/dist/{chunk-RZTAKIDE.js → chunk-X5XQ6M5P.js} +4715 -3246
- package/dist/chunk-X5XQ6M5P.js.map +1 -0
- package/dist/cli.cjs +1404 -275
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1190 -215
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +135 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -7
- package/dist/index.d.ts +12 -7
- package/dist/index.js +20 -973
- package/dist/index.js.map +1 -1
- package/dist/{mock-stream-DNt-HBTn.d.cts → mock-stream-Cc47j12U.d.cts} +71 -2
- package/dist/{mock-stream-DNt-HBTn.d.ts → mock-stream-Cc47j12U.d.ts} +71 -2
- package/dist/testing/index.cjs +135 -40
- 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, "");
|
|
@@ -830,38 +830,83 @@ function formatParamsAsBlock(params, prefix = "", argPrefix = GADGET_ARG_PREFIX)
|
|
|
830
830
|
}
|
|
831
831
|
return lines.join("\n");
|
|
832
832
|
}
|
|
833
|
-
function
|
|
833
|
+
function formatParamLine(key, propObj, isRequired, indent = "") {
|
|
834
|
+
const type = propObj.type;
|
|
835
|
+
const description = propObj.description;
|
|
836
|
+
const enumValues = propObj.enum;
|
|
837
|
+
let line = `${indent}- ${key}`;
|
|
838
|
+
if (type === "array") {
|
|
839
|
+
const items = propObj.items;
|
|
840
|
+
const itemType = items?.type || "any";
|
|
841
|
+
line += ` (array of ${itemType})`;
|
|
842
|
+
} else if (type === "object" && propObj.properties) {
|
|
843
|
+
line += " (object)";
|
|
844
|
+
} else {
|
|
845
|
+
line += ` (${type})`;
|
|
846
|
+
}
|
|
847
|
+
if (isRequired && indent !== "") {
|
|
848
|
+
line += " [required]";
|
|
849
|
+
}
|
|
850
|
+
if (description) {
|
|
851
|
+
line += `: ${description}`;
|
|
852
|
+
}
|
|
853
|
+
if (enumValues) {
|
|
854
|
+
line += ` - one of: ${enumValues.map((v) => `"${v}"`).join(", ")}`;
|
|
855
|
+
}
|
|
856
|
+
return line;
|
|
857
|
+
}
|
|
858
|
+
function formatSchemaAsPlainText(schema, indent = "", atRoot = true) {
|
|
834
859
|
const lines = [];
|
|
835
860
|
const properties = schema.properties || {};
|
|
836
861
|
const required = schema.required || [];
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
const
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const itemType = items?.type || "any";
|
|
847
|
-
line += ` (array of ${itemType})`;
|
|
848
|
-
} else if (type === "object" && propObj.properties) {
|
|
849
|
-
line += " (object)";
|
|
850
|
-
} else {
|
|
851
|
-
line += ` (${type})`;
|
|
862
|
+
if (atRoot && indent === "") {
|
|
863
|
+
const requiredProps = [];
|
|
864
|
+
const optionalProps = [];
|
|
865
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
866
|
+
if (required.includes(key)) {
|
|
867
|
+
requiredProps.push([key, prop]);
|
|
868
|
+
} else {
|
|
869
|
+
optionalProps.push([key, prop]);
|
|
870
|
+
}
|
|
852
871
|
}
|
|
853
|
-
|
|
854
|
-
|
|
872
|
+
const reqCount = requiredProps.length;
|
|
873
|
+
const optCount = optionalProps.length;
|
|
874
|
+
if (reqCount > 0 || optCount > 0) {
|
|
875
|
+
const parts = [];
|
|
876
|
+
if (reqCount > 0) parts.push(`${reqCount} required`);
|
|
877
|
+
if (optCount > 0) parts.push(`${optCount} optional`);
|
|
878
|
+
lines.push(parts.join(", "));
|
|
879
|
+
lines.push("");
|
|
855
880
|
}
|
|
856
|
-
if (
|
|
857
|
-
|
|
881
|
+
if (reqCount > 0) {
|
|
882
|
+
lines.push("REQUIRED Parameters:");
|
|
883
|
+
for (const [key, prop] of requiredProps) {
|
|
884
|
+
lines.push(formatParamLine(key, prop, true, ""));
|
|
885
|
+
const propObj = prop;
|
|
886
|
+
if (propObj.type === "object" && propObj.properties) {
|
|
887
|
+
lines.push(formatSchemaAsPlainText(propObj, " ", false));
|
|
888
|
+
}
|
|
889
|
+
}
|
|
858
890
|
}
|
|
859
|
-
if (
|
|
860
|
-
|
|
891
|
+
if (optCount > 0) {
|
|
892
|
+
if (reqCount > 0) lines.push("");
|
|
893
|
+
lines.push("OPTIONAL Parameters:");
|
|
894
|
+
for (const [key, prop] of optionalProps) {
|
|
895
|
+
lines.push(formatParamLine(key, prop, false, ""));
|
|
896
|
+
const propObj = prop;
|
|
897
|
+
if (propObj.type === "object" && propObj.properties) {
|
|
898
|
+
lines.push(formatSchemaAsPlainText(propObj, " ", false));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
861
901
|
}
|
|
862
|
-
lines.
|
|
863
|
-
|
|
864
|
-
|
|
902
|
+
return lines.join("\n");
|
|
903
|
+
}
|
|
904
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
905
|
+
const isRequired = required.includes(key);
|
|
906
|
+
lines.push(formatParamLine(key, prop, isRequired, indent));
|
|
907
|
+
const propObj = prop;
|
|
908
|
+
if (propObj.type === "object" && propObj.properties) {
|
|
909
|
+
lines.push(formatSchemaAsPlainText(propObj, indent + " ", false));
|
|
865
910
|
}
|
|
866
911
|
}
|
|
867
912
|
return lines.join("\n");
|
|
@@ -912,10 +957,11 @@ var init_gadget = __esm({
|
|
|
912
957
|
* Generate instruction text for the LLM.
|
|
913
958
|
* Combines name, description, and parameter schema into a formatted instruction.
|
|
914
959
|
*
|
|
915
|
-
* @param
|
|
960
|
+
* @param optionsOrArgPrefix - Optional custom prefixes for examples, or just argPrefix string for backwards compatibility
|
|
916
961
|
* @returns Formatted instruction string
|
|
917
962
|
*/
|
|
918
|
-
getInstruction(
|
|
963
|
+
getInstruction(optionsOrArgPrefix) {
|
|
964
|
+
const options = typeof optionsOrArgPrefix === "string" ? { argPrefix: optionsOrArgPrefix } : optionsOrArgPrefix;
|
|
919
965
|
const parts = [];
|
|
920
966
|
parts.push(this.description);
|
|
921
967
|
if (this.parameterSchema) {
|
|
@@ -929,18 +975,25 @@ var init_gadget = __esm({
|
|
|
929
975
|
}
|
|
930
976
|
if (this.examples && this.examples.length > 0) {
|
|
931
977
|
parts.push("\n\nExamples:");
|
|
932
|
-
const effectiveArgPrefix = argPrefix ?? GADGET_ARG_PREFIX;
|
|
978
|
+
const effectiveArgPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;
|
|
979
|
+
const effectiveStartPrefix = options?.startPrefix ?? GADGET_START_PREFIX;
|
|
980
|
+
const effectiveEndPrefix = options?.endPrefix ?? GADGET_END_PREFIX;
|
|
981
|
+
const gadgetName = this.name || this.constructor.name;
|
|
933
982
|
this.examples.forEach((example, index) => {
|
|
934
983
|
if (index > 0) {
|
|
935
984
|
parts.push("");
|
|
985
|
+
parts.push("---");
|
|
986
|
+
parts.push("");
|
|
936
987
|
}
|
|
937
988
|
if (example.comment) {
|
|
938
989
|
parts.push(`# ${example.comment}`);
|
|
939
990
|
}
|
|
940
|
-
parts.push(
|
|
991
|
+
parts.push(`${effectiveStartPrefix}${gadgetName}`);
|
|
941
992
|
parts.push(formatParamsAsBlock(example.params, "", effectiveArgPrefix));
|
|
993
|
+
parts.push(effectiveEndPrefix);
|
|
942
994
|
if (example.output !== void 0) {
|
|
943
|
-
parts.push("
|
|
995
|
+
parts.push("");
|
|
996
|
+
parts.push("Expected Output:");
|
|
944
997
|
parts.push(example.output);
|
|
945
998
|
}
|
|
946
999
|
});
|
|
@@ -2268,8 +2321,8 @@ var init_error_formatter = __esm({
|
|
|
2268
2321
|
const parts = [];
|
|
2269
2322
|
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
2270
2323
|
for (const issue of zodError.issues) {
|
|
2271
|
-
const
|
|
2272
|
-
parts.push(` - ${
|
|
2324
|
+
const path5 = issue.path.join(".") || "root";
|
|
2325
|
+
parts.push(` - ${path5}: ${issue.message}`);
|
|
2273
2326
|
}
|
|
2274
2327
|
parts.push("");
|
|
2275
2328
|
parts.push("Gadget Usage:");
|
|
@@ -3250,6 +3303,8 @@ var init_agent = __esm({
|
|
|
3250
3303
|
outputLimitCharLimit;
|
|
3251
3304
|
// Context compaction
|
|
3252
3305
|
compactionManager;
|
|
3306
|
+
// Cancellation
|
|
3307
|
+
signal;
|
|
3253
3308
|
/**
|
|
3254
3309
|
* Creates a new Agent instance.
|
|
3255
3310
|
* @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
|
|
@@ -3317,6 +3372,7 @@ var init_agent = __esm({
|
|
|
3317
3372
|
options.compactionConfig
|
|
3318
3373
|
);
|
|
3319
3374
|
}
|
|
3375
|
+
this.signal = options.signal;
|
|
3320
3376
|
}
|
|
3321
3377
|
/**
|
|
3322
3378
|
* Get the gadget registry for this agent.
|
|
@@ -3434,7 +3490,8 @@ var init_agent = __esm({
|
|
|
3434
3490
|
model: this.model,
|
|
3435
3491
|
messages: this.conversation.getMessages(),
|
|
3436
3492
|
temperature: this.temperature,
|
|
3437
|
-
maxTokens: this.defaultMaxTokens
|
|
3493
|
+
maxTokens: this.defaultMaxTokens,
|
|
3494
|
+
signal: this.signal
|
|
3438
3495
|
};
|
|
3439
3496
|
await this.safeObserve(async () => {
|
|
3440
3497
|
if (this.hooks.observers?.onLLMCallStart) {
|
|
@@ -4052,7 +4109,7 @@ var init_base_provider = __esm({
|
|
|
4052
4109
|
async *stream(options, descriptor, spec) {
|
|
4053
4110
|
const preparedMessages = this.prepareMessages(options.messages);
|
|
4054
4111
|
const payload = this.buildRequestPayload(options, descriptor, spec, preparedMessages);
|
|
4055
|
-
const rawStream = await this.executeStreamRequest(payload);
|
|
4112
|
+
const rawStream = await this.executeStreamRequest(payload, options.signal);
|
|
4056
4113
|
yield* this.wrapStream(rawStream);
|
|
4057
4114
|
}
|
|
4058
4115
|
/**
|
|
@@ -4170,9 +4227,9 @@ var init_anthropic = __esm({
|
|
|
4170
4227
|
};
|
|
4171
4228
|
return payload;
|
|
4172
4229
|
}
|
|
4173
|
-
async executeStreamRequest(payload) {
|
|
4230
|
+
async executeStreamRequest(payload, signal) {
|
|
4174
4231
|
const client = this.client;
|
|
4175
|
-
const stream2 = await client.messages.create(payload);
|
|
4232
|
+
const stream2 = await client.messages.create(payload, signal ? { signal } : void 0);
|
|
4176
4233
|
return stream2;
|
|
4177
4234
|
}
|
|
4178
4235
|
async *wrapStream(iterable) {
|
|
@@ -4504,9 +4561,15 @@ var init_gemini = __esm({
|
|
|
4504
4561
|
config
|
|
4505
4562
|
};
|
|
4506
4563
|
}
|
|
4507
|
-
async executeStreamRequest(payload) {
|
|
4564
|
+
async executeStreamRequest(payload, signal) {
|
|
4508
4565
|
const client = this.client;
|
|
4509
|
-
const streamResponse = await client.models.generateContentStream(
|
|
4566
|
+
const streamResponse = await client.models.generateContentStream({
|
|
4567
|
+
...payload,
|
|
4568
|
+
config: {
|
|
4569
|
+
...payload.config,
|
|
4570
|
+
...signal ? { abortSignal: signal } : {}
|
|
4571
|
+
}
|
|
4572
|
+
});
|
|
4510
4573
|
return streamResponse;
|
|
4511
4574
|
}
|
|
4512
4575
|
/**
|
|
@@ -5095,9 +5158,9 @@ var init_openai = __esm({
|
|
|
5095
5158
|
...shouldIncludeTemperature ? { temperature } : {}
|
|
5096
5159
|
};
|
|
5097
5160
|
}
|
|
5098
|
-
async executeStreamRequest(payload) {
|
|
5161
|
+
async executeStreamRequest(payload, signal) {
|
|
5099
5162
|
const client = this.client;
|
|
5100
|
-
const stream2 = await client.chat.completions.create(payload);
|
|
5163
|
+
const stream2 = await client.chat.completions.create(payload, signal ? { signal } : void 0);
|
|
5101
5164
|
return stream2;
|
|
5102
5165
|
}
|
|
5103
5166
|
async *wrapStream(iterable) {
|
|
@@ -5760,6 +5823,7 @@ var init_builder = __esm({
|
|
|
5760
5823
|
gadgetOutputLimit;
|
|
5761
5824
|
gadgetOutputLimitPercent;
|
|
5762
5825
|
compactionConfig;
|
|
5826
|
+
signal;
|
|
5763
5827
|
constructor(client) {
|
|
5764
5828
|
this.client = client;
|
|
5765
5829
|
}
|
|
@@ -6206,6 +6270,35 @@ var init_builder = __esm({
|
|
|
6206
6270
|
this.compactionConfig = { enabled: false };
|
|
6207
6271
|
return this;
|
|
6208
6272
|
}
|
|
6273
|
+
/**
|
|
6274
|
+
* Set an abort signal for cancelling requests mid-flight.
|
|
6275
|
+
*
|
|
6276
|
+
* When the signal is aborted, the current LLM request will be cancelled
|
|
6277
|
+
* and the agent loop will exit gracefully.
|
|
6278
|
+
*
|
|
6279
|
+
* @param signal - AbortSignal from an AbortController
|
|
6280
|
+
* @returns This builder for chaining
|
|
6281
|
+
*
|
|
6282
|
+
* @example
|
|
6283
|
+
* ```typescript
|
|
6284
|
+
* const controller = new AbortController();
|
|
6285
|
+
*
|
|
6286
|
+
* // Cancel after 30 seconds
|
|
6287
|
+
* setTimeout(() => controller.abort(), 30000);
|
|
6288
|
+
*
|
|
6289
|
+
* const agent = LLMist.createAgent()
|
|
6290
|
+
* .withModel("sonnet")
|
|
6291
|
+
* .withSignal(controller.signal)
|
|
6292
|
+
* .ask("Write a long story");
|
|
6293
|
+
*
|
|
6294
|
+
* // Or cancel on user action
|
|
6295
|
+
* document.getElementById("cancel").onclick = () => controller.abort();
|
|
6296
|
+
* ```
|
|
6297
|
+
*/
|
|
6298
|
+
withSignal(signal) {
|
|
6299
|
+
this.signal = signal;
|
|
6300
|
+
return this;
|
|
6301
|
+
}
|
|
6209
6302
|
/**
|
|
6210
6303
|
* Add a synthetic gadget call to the conversation history.
|
|
6211
6304
|
*
|
|
@@ -6322,7 +6415,8 @@ ${endPrefix}`
|
|
|
6322
6415
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6323
6416
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6324
6417
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6325
|
-
compactionConfig: this.compactionConfig
|
|
6418
|
+
compactionConfig: this.compactionConfig,
|
|
6419
|
+
signal: this.signal
|
|
6326
6420
|
};
|
|
6327
6421
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6328
6422
|
}
|
|
@@ -6425,7 +6519,8 @@ ${endPrefix}`
|
|
|
6425
6519
|
defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
|
|
6426
6520
|
gadgetOutputLimit: this.gadgetOutputLimit,
|
|
6427
6521
|
gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
|
|
6428
|
-
compactionConfig: this.compactionConfig
|
|
6522
|
+
compactionConfig: this.compactionConfig,
|
|
6523
|
+
signal: this.signal
|
|
6429
6524
|
};
|
|
6430
6525
|
return new Agent(AGENT_INTERNAL_KEY, options);
|
|
6431
6526
|
}
|
|
@@ -6484,7 +6579,7 @@ var import_commander2 = require("commander");
|
|
|
6484
6579
|
// package.json
|
|
6485
6580
|
var package_default = {
|
|
6486
6581
|
name: "llmist",
|
|
6487
|
-
version: "1.
|
|
6582
|
+
version: "1.4.0",
|
|
6488
6583
|
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
6584
|
type: "module",
|
|
6490
6585
|
main: "dist/index.cjs",
|
|
@@ -6568,6 +6663,7 @@ var package_default = {
|
|
|
6568
6663
|
"@google/genai": "^1.27.0",
|
|
6569
6664
|
chalk: "^5.6.2",
|
|
6570
6665
|
commander: "^12.1.0",
|
|
6666
|
+
diff: "^8.0.2",
|
|
6571
6667
|
eta: "^4.4.1",
|
|
6572
6668
|
"js-toml": "^1.0.2",
|
|
6573
6669
|
"js-yaml": "^4.1.0",
|
|
@@ -6584,6 +6680,7 @@ var package_default = {
|
|
|
6584
6680
|
"@commitlint/config-conventional": "^20.0.0",
|
|
6585
6681
|
"@semantic-release/changelog": "^6.0.3",
|
|
6586
6682
|
"@semantic-release/git": "^10.0.1",
|
|
6683
|
+
"@types/diff": "^8.0.0",
|
|
6587
6684
|
"@types/js-yaml": "^4.0.9",
|
|
6588
6685
|
"@types/marked-terminal": "^6.1.1",
|
|
6589
6686
|
"@types/node": "^20.12.7",
|
|
@@ -6597,12 +6694,274 @@ var package_default = {
|
|
|
6597
6694
|
};
|
|
6598
6695
|
|
|
6599
6696
|
// src/cli/agent-command.ts
|
|
6600
|
-
var
|
|
6601
|
-
var
|
|
6697
|
+
var import_promises3 = require("readline/promises");
|
|
6698
|
+
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
6602
6699
|
init_builder();
|
|
6700
|
+
|
|
6701
|
+
// src/core/errors.ts
|
|
6702
|
+
function isAbortError(error) {
|
|
6703
|
+
if (!(error instanceof Error)) return false;
|
|
6704
|
+
if (error.name === "AbortError") return true;
|
|
6705
|
+
if (error.name === "APIConnectionAbortedError") return true;
|
|
6706
|
+
if (error.name === "APIUserAbortError") return true;
|
|
6707
|
+
const message = error.message.toLowerCase();
|
|
6708
|
+
if (message.includes("abort")) return true;
|
|
6709
|
+
if (message.includes("cancelled")) return true;
|
|
6710
|
+
if (message.includes("canceled")) return true;
|
|
6711
|
+
return false;
|
|
6712
|
+
}
|
|
6713
|
+
|
|
6714
|
+
// src/cli/agent-command.ts
|
|
6603
6715
|
init_registry();
|
|
6604
6716
|
init_constants2();
|
|
6605
6717
|
|
|
6718
|
+
// src/cli/approval/manager.ts
|
|
6719
|
+
var import_promises = require("readline/promises");
|
|
6720
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
6721
|
+
|
|
6722
|
+
// src/cli/approval/context-providers.ts
|
|
6723
|
+
var import_node_fs2 = require("fs");
|
|
6724
|
+
var import_node_path2 = require("path");
|
|
6725
|
+
var import_diff = require("diff");
|
|
6726
|
+
|
|
6727
|
+
// src/cli/approval/diff-renderer.ts
|
|
6728
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
6729
|
+
function renderColoredDiff(diff) {
|
|
6730
|
+
return diff.split("\n").map((line) => {
|
|
6731
|
+
if (line.startsWith("---") || line.startsWith("+++")) {
|
|
6732
|
+
return import_chalk.default.bold(line);
|
|
6733
|
+
}
|
|
6734
|
+
if (line.startsWith("+")) {
|
|
6735
|
+
return import_chalk.default.green(line);
|
|
6736
|
+
}
|
|
6737
|
+
if (line.startsWith("-")) {
|
|
6738
|
+
return import_chalk.default.red(line);
|
|
6739
|
+
}
|
|
6740
|
+
if (line.startsWith("@@")) {
|
|
6741
|
+
return import_chalk.default.cyan(line);
|
|
6742
|
+
}
|
|
6743
|
+
return import_chalk.default.dim(line);
|
|
6744
|
+
}).join("\n");
|
|
6745
|
+
}
|
|
6746
|
+
function formatNewFileDiff(filePath, content) {
|
|
6747
|
+
const lines = content.split("\n");
|
|
6748
|
+
const header = `+++ ${filePath} (new file)`;
|
|
6749
|
+
const addedLines = lines.map((line) => `+ ${line}`).join("\n");
|
|
6750
|
+
return `${header}
|
|
6751
|
+
${addedLines}`;
|
|
6752
|
+
}
|
|
6753
|
+
|
|
6754
|
+
// src/cli/approval/context-providers.ts
|
|
6755
|
+
var WriteFileContextProvider = class {
|
|
6756
|
+
gadgetName = "WriteFile";
|
|
6757
|
+
async getContext(params) {
|
|
6758
|
+
const filePath = String(params.filePath ?? params.path ?? "");
|
|
6759
|
+
const newContent = String(params.content ?? "");
|
|
6760
|
+
const resolvedPath = (0, import_node_path2.resolve)(process.cwd(), filePath);
|
|
6761
|
+
if (!(0, import_node_fs2.existsSync)(resolvedPath)) {
|
|
6762
|
+
return {
|
|
6763
|
+
summary: `Create new file: ${filePath}`,
|
|
6764
|
+
details: formatNewFileDiff(filePath, newContent)
|
|
6765
|
+
};
|
|
6766
|
+
}
|
|
6767
|
+
const oldContent = (0, import_node_fs2.readFileSync)(resolvedPath, "utf-8");
|
|
6768
|
+
const diff = (0, import_diff.createPatch)(filePath, oldContent, newContent, "original", "modified");
|
|
6769
|
+
return {
|
|
6770
|
+
summary: `Modify: ${filePath}`,
|
|
6771
|
+
details: diff
|
|
6772
|
+
};
|
|
6773
|
+
}
|
|
6774
|
+
};
|
|
6775
|
+
var EditFileContextProvider = class {
|
|
6776
|
+
gadgetName = "EditFile";
|
|
6777
|
+
async getContext(params) {
|
|
6778
|
+
const filePath = String(params.filePath ?? params.path ?? "");
|
|
6779
|
+
const resolvedPath = (0, import_node_path2.resolve)(process.cwd(), filePath);
|
|
6780
|
+
if ("content" in params) {
|
|
6781
|
+
const newContent = String(params.content);
|
|
6782
|
+
if (!(0, import_node_fs2.existsSync)(resolvedPath)) {
|
|
6783
|
+
return {
|
|
6784
|
+
summary: `Create new file: ${filePath}`,
|
|
6785
|
+
details: formatNewFileDiff(filePath, newContent)
|
|
6786
|
+
};
|
|
6787
|
+
}
|
|
6788
|
+
const oldContent = (0, import_node_fs2.readFileSync)(resolvedPath, "utf-8");
|
|
6789
|
+
const diff = (0, import_diff.createPatch)(filePath, oldContent, newContent, "original", "modified");
|
|
6790
|
+
return {
|
|
6791
|
+
summary: `Modify: ${filePath}`,
|
|
6792
|
+
details: diff
|
|
6793
|
+
};
|
|
6794
|
+
}
|
|
6795
|
+
if ("commands" in params) {
|
|
6796
|
+
const commands = String(params.commands);
|
|
6797
|
+
return {
|
|
6798
|
+
summary: `Edit: ${filePath}`,
|
|
6799
|
+
details: `Commands:
|
|
6800
|
+
${commands}`
|
|
6801
|
+
};
|
|
6802
|
+
}
|
|
6803
|
+
return {
|
|
6804
|
+
summary: `Edit: ${filePath}`
|
|
6805
|
+
};
|
|
6806
|
+
}
|
|
6807
|
+
};
|
|
6808
|
+
var RunCommandContextProvider = class {
|
|
6809
|
+
gadgetName = "RunCommand";
|
|
6810
|
+
async getContext(params) {
|
|
6811
|
+
const command = String(params.command ?? "");
|
|
6812
|
+
const cwd = params.cwd ? ` (in ${params.cwd})` : "";
|
|
6813
|
+
return {
|
|
6814
|
+
summary: `Execute: ${command}${cwd}`
|
|
6815
|
+
};
|
|
6816
|
+
}
|
|
6817
|
+
};
|
|
6818
|
+
var DefaultContextProvider = class {
|
|
6819
|
+
constructor(gadgetName) {
|
|
6820
|
+
this.gadgetName = gadgetName;
|
|
6821
|
+
}
|
|
6822
|
+
async getContext(params) {
|
|
6823
|
+
const paramEntries = Object.entries(params);
|
|
6824
|
+
if (paramEntries.length === 0) {
|
|
6825
|
+
return {
|
|
6826
|
+
summary: `${this.gadgetName}()`
|
|
6827
|
+
};
|
|
6828
|
+
}
|
|
6829
|
+
const formatValue = (value) => {
|
|
6830
|
+
const MAX_LEN = 50;
|
|
6831
|
+
const str = JSON.stringify(value);
|
|
6832
|
+
return str.length > MAX_LEN ? `${str.slice(0, MAX_LEN - 3)}...` : str;
|
|
6833
|
+
};
|
|
6834
|
+
const paramStr = paramEntries.map(([k, v]) => `${k}=${formatValue(v)}`).join(", ");
|
|
6835
|
+
return {
|
|
6836
|
+
summary: `${this.gadgetName}(${paramStr})`
|
|
6837
|
+
};
|
|
6838
|
+
}
|
|
6839
|
+
};
|
|
6840
|
+
var builtinContextProviders = [
|
|
6841
|
+
new WriteFileContextProvider(),
|
|
6842
|
+
new EditFileContextProvider(),
|
|
6843
|
+
new RunCommandContextProvider()
|
|
6844
|
+
];
|
|
6845
|
+
|
|
6846
|
+
// src/cli/approval/manager.ts
|
|
6847
|
+
var ApprovalManager = class {
|
|
6848
|
+
/**
|
|
6849
|
+
* Creates a new ApprovalManager.
|
|
6850
|
+
*
|
|
6851
|
+
* @param config - Approval configuration with per-gadget modes
|
|
6852
|
+
* @param env - CLI environment for I/O operations
|
|
6853
|
+
* @param progress - Optional progress indicator to pause during prompts
|
|
6854
|
+
*/
|
|
6855
|
+
constructor(config, env, progress) {
|
|
6856
|
+
this.config = config;
|
|
6857
|
+
this.env = env;
|
|
6858
|
+
this.progress = progress;
|
|
6859
|
+
for (const provider of builtinContextProviders) {
|
|
6860
|
+
this.registerProvider(provider);
|
|
6861
|
+
}
|
|
6862
|
+
}
|
|
6863
|
+
providers = /* @__PURE__ */ new Map();
|
|
6864
|
+
/**
|
|
6865
|
+
* Registers a custom context provider for a gadget.
|
|
6866
|
+
*
|
|
6867
|
+
* @param provider - The context provider to register
|
|
6868
|
+
*/
|
|
6869
|
+
registerProvider(provider) {
|
|
6870
|
+
this.providers.set(provider.gadgetName.toLowerCase(), provider);
|
|
6871
|
+
}
|
|
6872
|
+
/**
|
|
6873
|
+
* Gets the approval mode for a gadget.
|
|
6874
|
+
*
|
|
6875
|
+
* Resolution order:
|
|
6876
|
+
* 1. Explicit configuration for the gadget name
|
|
6877
|
+
* 2. Wildcard "*" configuration
|
|
6878
|
+
* 3. Default mode from config
|
|
6879
|
+
*
|
|
6880
|
+
* @param gadgetName - Name of the gadget
|
|
6881
|
+
* @returns The approval mode to use
|
|
6882
|
+
*/
|
|
6883
|
+
getApprovalMode(gadgetName) {
|
|
6884
|
+
const normalizedName = gadgetName.toLowerCase();
|
|
6885
|
+
for (const [configName, mode] of Object.entries(this.config.gadgetApprovals)) {
|
|
6886
|
+
if (configName.toLowerCase() === normalizedName) {
|
|
6887
|
+
return mode;
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6890
|
+
if ("*" in this.config.gadgetApprovals) {
|
|
6891
|
+
return this.config.gadgetApprovals["*"];
|
|
6892
|
+
}
|
|
6893
|
+
return this.config.defaultMode;
|
|
6894
|
+
}
|
|
6895
|
+
/**
|
|
6896
|
+
* Requests approval for a gadget execution.
|
|
6897
|
+
*
|
|
6898
|
+
* Behavior depends on the gadget's approval mode:
|
|
6899
|
+
* - "allowed": Returns approved immediately
|
|
6900
|
+
* - "denied": Returns denied with configuration message
|
|
6901
|
+
* - "approval-required": Prompts user interactively
|
|
6902
|
+
*
|
|
6903
|
+
* @param gadgetName - Name of the gadget
|
|
6904
|
+
* @param params - The gadget's execution parameters
|
|
6905
|
+
* @returns Approval result indicating whether to proceed
|
|
6906
|
+
*/
|
|
6907
|
+
async requestApproval(gadgetName, params) {
|
|
6908
|
+
const mode = this.getApprovalMode(gadgetName);
|
|
6909
|
+
if (mode === "allowed") {
|
|
6910
|
+
return { approved: true };
|
|
6911
|
+
}
|
|
6912
|
+
if (mode === "denied") {
|
|
6913
|
+
return {
|
|
6914
|
+
approved: false,
|
|
6915
|
+
reason: `${gadgetName} is denied by configuration`
|
|
6916
|
+
};
|
|
6917
|
+
}
|
|
6918
|
+
return this.promptForApproval(gadgetName, params);
|
|
6919
|
+
}
|
|
6920
|
+
/**
|
|
6921
|
+
* Prompts the user for approval interactively.
|
|
6922
|
+
*/
|
|
6923
|
+
async promptForApproval(gadgetName, params) {
|
|
6924
|
+
const provider = this.providers.get(gadgetName.toLowerCase()) ?? new DefaultContextProvider(gadgetName);
|
|
6925
|
+
const context = await provider.getContext(params);
|
|
6926
|
+
this.progress?.pause();
|
|
6927
|
+
this.env.stderr.write(`
|
|
6928
|
+
${import_chalk2.default.yellow("\u{1F512} Approval required:")} ${context.summary}
|
|
6929
|
+
`);
|
|
6930
|
+
if (context.details) {
|
|
6931
|
+
this.env.stderr.write(`
|
|
6932
|
+
${renderColoredDiff(context.details)}
|
|
6933
|
+
`);
|
|
6934
|
+
}
|
|
6935
|
+
const response = await this.prompt(" \u23CE approve, or type to reject: ");
|
|
6936
|
+
const isApproved = response === "" || response.toLowerCase() === "y";
|
|
6937
|
+
if (isApproved) {
|
|
6938
|
+
this.env.stderr.write(` ${import_chalk2.default.green("\u2713 Approved")}
|
|
6939
|
+
|
|
6940
|
+
`);
|
|
6941
|
+
return { approved: true };
|
|
6942
|
+
}
|
|
6943
|
+
this.env.stderr.write(` ${import_chalk2.default.red("\u2717 Denied")}
|
|
6944
|
+
|
|
6945
|
+
`);
|
|
6946
|
+
return { approved: false, reason: response || "Rejected by user" };
|
|
6947
|
+
}
|
|
6948
|
+
/**
|
|
6949
|
+
* Prompts for user input.
|
|
6950
|
+
*/
|
|
6951
|
+
async prompt(message) {
|
|
6952
|
+
const rl = (0, import_promises.createInterface)({
|
|
6953
|
+
input: this.env.stdin,
|
|
6954
|
+
output: this.env.stderr
|
|
6955
|
+
});
|
|
6956
|
+
try {
|
|
6957
|
+
const answer = await rl.question(message);
|
|
6958
|
+
return answer.trim();
|
|
6959
|
+
} finally {
|
|
6960
|
+
rl.close();
|
|
6961
|
+
}
|
|
6962
|
+
}
|
|
6963
|
+
};
|
|
6964
|
+
|
|
6606
6965
|
// src/cli/builtin-gadgets.ts
|
|
6607
6966
|
var import_zod2 = require("zod");
|
|
6608
6967
|
init_create_gadget();
|
|
@@ -6682,11 +7041,483 @@ var finish = createGadget({
|
|
|
6682
7041
|
var builtinGadgets = [askUser, tellUser, finish];
|
|
6683
7042
|
|
|
6684
7043
|
// src/cli/gadgets.ts
|
|
6685
|
-
var
|
|
6686
|
-
var
|
|
7044
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
7045
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
6687
7046
|
var import_node_url = require("url");
|
|
6688
7047
|
init_gadget();
|
|
7048
|
+
|
|
7049
|
+
// src/cli/builtins/filesystem/list-directory.ts
|
|
7050
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
7051
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
7052
|
+
var import_zod4 = require("zod");
|
|
7053
|
+
|
|
7054
|
+
// src/index.ts
|
|
7055
|
+
var import_zod3 = require("zod");
|
|
7056
|
+
init_builder();
|
|
7057
|
+
init_event_handlers();
|
|
7058
|
+
|
|
7059
|
+
// src/agent/index.ts
|
|
7060
|
+
init_conversation_manager();
|
|
7061
|
+
init_stream_processor();
|
|
7062
|
+
init_gadget_output_store();
|
|
7063
|
+
|
|
7064
|
+
// src/agent/compaction/index.ts
|
|
7065
|
+
init_config();
|
|
7066
|
+
init_strategy();
|
|
7067
|
+
init_strategies();
|
|
7068
|
+
init_manager();
|
|
7069
|
+
|
|
7070
|
+
// src/agent/hints.ts
|
|
7071
|
+
init_prompt_config();
|
|
7072
|
+
|
|
7073
|
+
// src/index.ts
|
|
7074
|
+
init_client();
|
|
7075
|
+
init_messages();
|
|
7076
|
+
init_model_registry();
|
|
7077
|
+
init_model_shortcuts();
|
|
7078
|
+
init_options();
|
|
7079
|
+
init_prompt_config();
|
|
7080
|
+
init_quick_methods();
|
|
7081
|
+
init_create_gadget();
|
|
7082
|
+
init_output_viewer();
|
|
7083
|
+
init_exceptions();
|
|
7084
|
+
init_executor();
|
|
7085
|
+
init_gadget();
|
|
7086
|
+
init_parser();
|
|
7087
|
+
init_registry();
|
|
7088
|
+
|
|
7089
|
+
// src/gadgets/typed-gadget.ts
|
|
7090
|
+
init_gadget();
|
|
7091
|
+
|
|
7092
|
+
// src/index.ts
|
|
7093
|
+
init_logger();
|
|
7094
|
+
init_anthropic();
|
|
7095
|
+
init_discovery();
|
|
7096
|
+
init_gemini();
|
|
7097
|
+
init_openai();
|
|
7098
|
+
|
|
7099
|
+
// src/testing/mock-manager.ts
|
|
7100
|
+
init_logger();
|
|
7101
|
+
|
|
7102
|
+
// src/testing/mock-stream.ts
|
|
7103
|
+
init_constants();
|
|
7104
|
+
|
|
7105
|
+
// src/testing/mock-client.ts
|
|
7106
|
+
init_client();
|
|
7107
|
+
|
|
7108
|
+
// src/testing/mock-gadget.ts
|
|
7109
|
+
init_gadget();
|
|
7110
|
+
|
|
7111
|
+
// src/testing/cli-helpers.ts
|
|
7112
|
+
var import_node_stream = require("stream");
|
|
7113
|
+
|
|
7114
|
+
// src/cli/builtins/filesystem/utils.ts
|
|
7115
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
7116
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
7117
|
+
var PathSandboxException = class extends Error {
|
|
7118
|
+
constructor(inputPath, reason) {
|
|
7119
|
+
super(`Path access denied: ${inputPath}. ${reason}`);
|
|
7120
|
+
this.name = "PathSandboxException";
|
|
7121
|
+
}
|
|
7122
|
+
};
|
|
7123
|
+
function validatePathIsWithinCwd(inputPath) {
|
|
7124
|
+
const cwd = process.cwd();
|
|
7125
|
+
const resolvedPath = import_node_path3.default.resolve(cwd, inputPath);
|
|
7126
|
+
let finalPath;
|
|
7127
|
+
try {
|
|
7128
|
+
finalPath = import_node_fs3.default.realpathSync(resolvedPath);
|
|
7129
|
+
} catch (error) {
|
|
7130
|
+
const nodeError = error;
|
|
7131
|
+
if (nodeError.code === "ENOENT") {
|
|
7132
|
+
finalPath = resolvedPath;
|
|
7133
|
+
} else {
|
|
7134
|
+
throw error;
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
const cwdWithSep = cwd + import_node_path3.default.sep;
|
|
7138
|
+
if (!finalPath.startsWith(cwdWithSep) && finalPath !== cwd) {
|
|
7139
|
+
throw new PathSandboxException(inputPath, "Path is outside the current working directory");
|
|
7140
|
+
}
|
|
7141
|
+
return finalPath;
|
|
7142
|
+
}
|
|
7143
|
+
|
|
7144
|
+
// src/cli/builtins/filesystem/list-directory.ts
|
|
7145
|
+
function listFiles(dirPath, basePath = dirPath, maxDepth = 1, currentDepth = 1) {
|
|
7146
|
+
const entries = [];
|
|
7147
|
+
try {
|
|
7148
|
+
const items = import_node_fs4.default.readdirSync(dirPath);
|
|
7149
|
+
for (const item of items) {
|
|
7150
|
+
const fullPath = import_node_path4.default.join(dirPath, item);
|
|
7151
|
+
const relativePath = import_node_path4.default.relative(basePath, fullPath);
|
|
7152
|
+
try {
|
|
7153
|
+
const stats = import_node_fs4.default.lstatSync(fullPath);
|
|
7154
|
+
let type;
|
|
7155
|
+
let size;
|
|
7156
|
+
if (stats.isSymbolicLink()) {
|
|
7157
|
+
type = "symlink";
|
|
7158
|
+
size = 0;
|
|
7159
|
+
} else if (stats.isDirectory()) {
|
|
7160
|
+
type = "directory";
|
|
7161
|
+
size = 0;
|
|
7162
|
+
} else {
|
|
7163
|
+
type = "file";
|
|
7164
|
+
size = stats.size;
|
|
7165
|
+
}
|
|
7166
|
+
entries.push({
|
|
7167
|
+
name: item,
|
|
7168
|
+
relativePath,
|
|
7169
|
+
type,
|
|
7170
|
+
size,
|
|
7171
|
+
modified: Math.floor(stats.mtime.getTime() / 1e3)
|
|
7172
|
+
});
|
|
7173
|
+
if (type === "directory" && currentDepth < maxDepth) {
|
|
7174
|
+
try {
|
|
7175
|
+
validatePathIsWithinCwd(fullPath);
|
|
7176
|
+
const subEntries = listFiles(fullPath, basePath, maxDepth, currentDepth + 1);
|
|
7177
|
+
entries.push(...subEntries);
|
|
7178
|
+
} catch {
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
} catch {
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
} catch {
|
|
7185
|
+
return [];
|
|
7186
|
+
}
|
|
7187
|
+
return entries;
|
|
7188
|
+
}
|
|
7189
|
+
function formatAge(epochSeconds) {
|
|
7190
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
7191
|
+
const seconds = now - epochSeconds;
|
|
7192
|
+
if (seconds < 60) return `${seconds}s`;
|
|
7193
|
+
const minutes = Math.floor(seconds / 60);
|
|
7194
|
+
if (minutes < 60) return `${minutes}m`;
|
|
7195
|
+
const hours = Math.floor(minutes / 60);
|
|
7196
|
+
if (hours < 24) return `${hours}h`;
|
|
7197
|
+
const days = Math.floor(hours / 24);
|
|
7198
|
+
if (days < 7) return `${days}d`;
|
|
7199
|
+
const weeks = Math.floor(days / 7);
|
|
7200
|
+
if (weeks < 4) return `${weeks}w`;
|
|
7201
|
+
const months = Math.floor(days / 30);
|
|
7202
|
+
if (months < 12) return `${months}mo`;
|
|
7203
|
+
const years = Math.floor(days / 365);
|
|
7204
|
+
return `${years}y`;
|
|
7205
|
+
}
|
|
7206
|
+
function formatEntriesAsString(entries) {
|
|
7207
|
+
if (entries.length === 0) {
|
|
7208
|
+
return "#empty";
|
|
7209
|
+
}
|
|
7210
|
+
const sortedEntries = [...entries].sort((a, b) => {
|
|
7211
|
+
const typeOrder = { directory: 0, file: 1, symlink: 2 };
|
|
7212
|
+
const typeCompare = typeOrder[a.type] - typeOrder[b.type];
|
|
7213
|
+
if (typeCompare !== 0) return typeCompare;
|
|
7214
|
+
return a.relativePath.localeCompare(b.relativePath);
|
|
7215
|
+
});
|
|
7216
|
+
const typeCode = {
|
|
7217
|
+
directory: "D",
|
|
7218
|
+
file: "F",
|
|
7219
|
+
symlink: "L"
|
|
7220
|
+
};
|
|
7221
|
+
const encodeName = (name) => name.replace(/\|/g, "%7C").replace(/\n/g, "%0A");
|
|
7222
|
+
const header = "#T|N|S|A";
|
|
7223
|
+
const rows = sortedEntries.map(
|
|
7224
|
+
(e) => `${typeCode[e.type]}|${encodeName(e.relativePath)}|${e.size}|${formatAge(e.modified)}`
|
|
7225
|
+
);
|
|
7226
|
+
return [header, ...rows].join("\n");
|
|
7227
|
+
}
|
|
7228
|
+
var listDirectory = createGadget({
|
|
7229
|
+
name: "ListDirectory",
|
|
7230
|
+
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.",
|
|
7231
|
+
schema: import_zod4.z.object({
|
|
7232
|
+
directoryPath: import_zod4.z.string().default(".").describe("Path to the directory to list"),
|
|
7233
|
+
maxDepth: import_zod4.z.number().int().min(1).max(10).default(1).describe(
|
|
7234
|
+
"Maximum depth to recurse (1 = immediate children only, 2 = include grandchildren, etc.)"
|
|
7235
|
+
)
|
|
7236
|
+
}),
|
|
7237
|
+
examples: [
|
|
7238
|
+
{
|
|
7239
|
+
params: { directoryPath: ".", maxDepth: 1 },
|
|
7240
|
+
output: "path=. maxDepth=1\n\n#T|N|S|A\nD|src|0|2h\nD|tests|0|1d\nF|package.json|2841|3h",
|
|
7241
|
+
comment: "List current directory"
|
|
7242
|
+
},
|
|
7243
|
+
{
|
|
7244
|
+
params: { directoryPath: "src", maxDepth: 2 },
|
|
7245
|
+
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",
|
|
7246
|
+
comment: "List src directory recursively"
|
|
7247
|
+
}
|
|
7248
|
+
],
|
|
7249
|
+
execute: ({ directoryPath, maxDepth }) => {
|
|
7250
|
+
const validatedPath = validatePathIsWithinCwd(directoryPath);
|
|
7251
|
+
const stats = import_node_fs4.default.statSync(validatedPath);
|
|
7252
|
+
if (!stats.isDirectory()) {
|
|
7253
|
+
throw new Error(`Path is not a directory: ${directoryPath}`);
|
|
7254
|
+
}
|
|
7255
|
+
const entries = listFiles(validatedPath, validatedPath, maxDepth);
|
|
7256
|
+
const formattedList = formatEntriesAsString(entries);
|
|
7257
|
+
return `path=${directoryPath} maxDepth=${maxDepth}
|
|
7258
|
+
|
|
7259
|
+
${formattedList}`;
|
|
7260
|
+
}
|
|
7261
|
+
});
|
|
7262
|
+
|
|
7263
|
+
// src/cli/builtins/filesystem/read-file.ts
|
|
7264
|
+
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
7265
|
+
var import_zod5 = require("zod");
|
|
7266
|
+
var readFile = createGadget({
|
|
7267
|
+
name: "ReadFile",
|
|
7268
|
+
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.",
|
|
7269
|
+
schema: import_zod5.z.object({
|
|
7270
|
+
filePath: import_zod5.z.string().describe("Path to the file to read (relative or absolute)")
|
|
7271
|
+
}),
|
|
7272
|
+
examples: [
|
|
7273
|
+
{
|
|
7274
|
+
params: { filePath: "package.json" },
|
|
7275
|
+
output: 'path=package.json\n\n{\n "name": "my-project",\n "version": "1.0.0"\n ...\n}',
|
|
7276
|
+
comment: "Read a JSON config file"
|
|
7277
|
+
},
|
|
7278
|
+
{
|
|
7279
|
+
params: { filePath: "src/index.ts" },
|
|
7280
|
+
output: "path=src/index.ts\n\nexport function main() { ... }",
|
|
7281
|
+
comment: "Read a source file"
|
|
7282
|
+
}
|
|
7283
|
+
],
|
|
7284
|
+
execute: ({ filePath }) => {
|
|
7285
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7286
|
+
const content = import_node_fs5.default.readFileSync(validatedPath, "utf-8");
|
|
7287
|
+
return `path=${filePath}
|
|
7288
|
+
|
|
7289
|
+
${content}`;
|
|
7290
|
+
}
|
|
7291
|
+
});
|
|
7292
|
+
|
|
7293
|
+
// src/cli/builtins/filesystem/write-file.ts
|
|
7294
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
7295
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
7296
|
+
var import_zod6 = require("zod");
|
|
7297
|
+
var writeFile = createGadget({
|
|
7298
|
+
name: "WriteFile",
|
|
7299
|
+
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.",
|
|
7300
|
+
schema: import_zod6.z.object({
|
|
7301
|
+
filePath: import_zod6.z.string().describe("Path to the file to write (relative or absolute)"),
|
|
7302
|
+
content: import_zod6.z.string().describe("Content to write to the file")
|
|
7303
|
+
}),
|
|
7304
|
+
examples: [
|
|
7305
|
+
{
|
|
7306
|
+
params: { filePath: "output.txt", content: "Hello, World!" },
|
|
7307
|
+
output: "path=output.txt\n\nWrote 13 bytes",
|
|
7308
|
+
comment: "Write a simple text file"
|
|
7309
|
+
},
|
|
7310
|
+
{
|
|
7311
|
+
params: {
|
|
7312
|
+
filePath: "src/server.ts",
|
|
7313
|
+
content: `import { serve } from "bun";
|
|
7314
|
+
|
|
7315
|
+
const port = 3000;
|
|
7316
|
+
|
|
7317
|
+
serve({
|
|
7318
|
+
port,
|
|
7319
|
+
fetch: (req) => new Response(\`Hello from \${req.url}\`),
|
|
7320
|
+
});
|
|
7321
|
+
|
|
7322
|
+
console.log(\`Server running on http://localhost:\${port}\`);`
|
|
7323
|
+
},
|
|
7324
|
+
output: "path=src/server.ts\n\nWrote 198 bytes (created directory: src)",
|
|
7325
|
+
comment: "Write code with template literals - NO escaping needed inside heredoc (use <<<EOF...EOF)"
|
|
7326
|
+
}
|
|
7327
|
+
],
|
|
7328
|
+
execute: ({ filePath, content }) => {
|
|
7329
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7330
|
+
const parentDir = import_node_path5.default.dirname(validatedPath);
|
|
7331
|
+
let createdDir = false;
|
|
7332
|
+
if (!import_node_fs6.default.existsSync(parentDir)) {
|
|
7333
|
+
validatePathIsWithinCwd(parentDir);
|
|
7334
|
+
import_node_fs6.default.mkdirSync(parentDir, { recursive: true });
|
|
7335
|
+
createdDir = true;
|
|
7336
|
+
}
|
|
7337
|
+
import_node_fs6.default.writeFileSync(validatedPath, content, "utf-8");
|
|
7338
|
+
const bytesWritten = Buffer.byteLength(content, "utf-8");
|
|
7339
|
+
const dirNote = createdDir ? ` (created directory: ${import_node_path5.default.dirname(filePath)})` : "";
|
|
7340
|
+
return `path=${filePath}
|
|
7341
|
+
|
|
7342
|
+
Wrote ${bytesWritten} bytes${dirNote}`;
|
|
7343
|
+
}
|
|
7344
|
+
});
|
|
7345
|
+
|
|
7346
|
+
// src/cli/builtins/filesystem/edit-file.ts
|
|
7347
|
+
var import_zod7 = require("zod");
|
|
7348
|
+
function filterDangerousCommands(commands) {
|
|
7349
|
+
return commands.split("\n").filter((line) => !line.trimStart().startsWith("!")).join("\n");
|
|
7350
|
+
}
|
|
7351
|
+
var editFile = createGadget({
|
|
7352
|
+
name: "EditFile",
|
|
7353
|
+
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.",
|
|
7354
|
+
schema: import_zod7.z.object({
|
|
7355
|
+
filePath: import_zod7.z.string().describe("Path to the file to edit (relative or absolute)"),
|
|
7356
|
+
commands: import_zod7.z.string().describe("Ed commands to execute, one per line")
|
|
7357
|
+
}),
|
|
7358
|
+
examples: [
|
|
7359
|
+
{
|
|
7360
|
+
params: {
|
|
7361
|
+
filePath: "config.txt",
|
|
7362
|
+
commands: `1,$p
|
|
7363
|
+
q`
|
|
7364
|
+
},
|
|
7365
|
+
output: "path=config.txt\n\n32\nkey=value\noption=true",
|
|
7366
|
+
comment: "Print entire file contents (ed shows byte count, then content)"
|
|
7367
|
+
},
|
|
7368
|
+
{
|
|
7369
|
+
params: {
|
|
7370
|
+
filePath: "data.txt",
|
|
7371
|
+
commands: `1,$s/foo/bar/g
|
|
7372
|
+
w
|
|
7373
|
+
q`
|
|
7374
|
+
},
|
|
7375
|
+
output: "path=data.txt\n\n42\n42",
|
|
7376
|
+
comment: "Replace all 'foo' with 'bar' (ed shows bytes read, then bytes written)"
|
|
7377
|
+
},
|
|
7378
|
+
{
|
|
7379
|
+
params: {
|
|
7380
|
+
filePath: "list.txt",
|
|
7381
|
+
commands: `3d
|
|
7382
|
+
w
|
|
7383
|
+
q`
|
|
7384
|
+
},
|
|
7385
|
+
output: "path=list.txt\n\n45\n28",
|
|
7386
|
+
comment: "Delete line 3, save and quit"
|
|
7387
|
+
},
|
|
7388
|
+
{
|
|
7389
|
+
params: {
|
|
7390
|
+
filePath: "readme.txt",
|
|
7391
|
+
commands: `$a
|
|
7392
|
+
New last line
|
|
7393
|
+
.
|
|
7394
|
+
w
|
|
7395
|
+
q`
|
|
7396
|
+
},
|
|
7397
|
+
output: "path=readme.txt\n\n40\n56",
|
|
7398
|
+
comment: "Append text after last line ($ = last line, . = end input mode)"
|
|
7399
|
+
}
|
|
7400
|
+
],
|
|
7401
|
+
timeoutMs: 3e4,
|
|
7402
|
+
execute: async ({ filePath, commands }) => {
|
|
7403
|
+
const validatedPath = validatePathIsWithinCwd(filePath);
|
|
7404
|
+
const safeCommands = filterDangerousCommands(commands);
|
|
7405
|
+
try {
|
|
7406
|
+
const proc = Bun.spawn(["ed", validatedPath], {
|
|
7407
|
+
stdin: "pipe",
|
|
7408
|
+
stdout: "pipe",
|
|
7409
|
+
stderr: "pipe"
|
|
7410
|
+
});
|
|
7411
|
+
proc.stdin.write(`${safeCommands}
|
|
7412
|
+
`);
|
|
7413
|
+
proc.stdin.end();
|
|
7414
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7415
|
+
setTimeout(() => {
|
|
7416
|
+
proc.kill();
|
|
7417
|
+
reject(new Error("ed command timed out after 30000ms"));
|
|
7418
|
+
}, 3e4);
|
|
7419
|
+
});
|
|
7420
|
+
const exitCode = await Promise.race([proc.exited, timeoutPromise]);
|
|
7421
|
+
const stdout = await new Response(proc.stdout).text();
|
|
7422
|
+
const stderr = await new Response(proc.stderr).text();
|
|
7423
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
7424
|
+
if (exitCode !== 0) {
|
|
7425
|
+
return `path=${filePath}
|
|
7426
|
+
|
|
7427
|
+
${output || "ed exited with non-zero status"}`;
|
|
7428
|
+
}
|
|
7429
|
+
return `path=${filePath}
|
|
7430
|
+
|
|
7431
|
+
${output || "(no output)"}`;
|
|
7432
|
+
} catch (error) {
|
|
7433
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7434
|
+
return `path=${filePath}
|
|
7435
|
+
|
|
7436
|
+
error: ${message}`;
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
});
|
|
7440
|
+
|
|
7441
|
+
// src/cli/builtins/run-command.ts
|
|
7442
|
+
var import_zod8 = require("zod");
|
|
7443
|
+
var runCommand = createGadget({
|
|
7444
|
+
name: "RunCommand",
|
|
7445
|
+
description: "Execute a shell command and return its output. Returns both stdout and stderr combined with the exit status.",
|
|
7446
|
+
schema: import_zod8.z.object({
|
|
7447
|
+
command: import_zod8.z.string().describe("The shell command to execute"),
|
|
7448
|
+
cwd: import_zod8.z.string().optional().describe("Working directory for the command (default: current directory)"),
|
|
7449
|
+
timeout: import_zod8.z.number().default(3e4).describe("Timeout in milliseconds (default: 30000)")
|
|
7450
|
+
}),
|
|
7451
|
+
examples: [
|
|
7452
|
+
{
|
|
7453
|
+
params: { command: "ls -la", timeout: 3e4 },
|
|
7454
|
+
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",
|
|
7455
|
+
comment: "List directory contents with details"
|
|
7456
|
+
},
|
|
7457
|
+
{
|
|
7458
|
+
params: { command: "echo 'Hello World'", timeout: 3e4 },
|
|
7459
|
+
output: "status=0\n\nHello World",
|
|
7460
|
+
comment: "Simple echo command"
|
|
7461
|
+
},
|
|
7462
|
+
{
|
|
7463
|
+
params: { command: "cat nonexistent.txt", timeout: 3e4 },
|
|
7464
|
+
output: "status=1\n\ncat: nonexistent.txt: No such file or directory",
|
|
7465
|
+
comment: "Command that fails returns non-zero status"
|
|
7466
|
+
},
|
|
7467
|
+
{
|
|
7468
|
+
params: { command: "pwd", cwd: "/tmp", timeout: 3e4 },
|
|
7469
|
+
output: "status=0\n\n/tmp",
|
|
7470
|
+
comment: "Execute command in a specific directory"
|
|
7471
|
+
}
|
|
7472
|
+
],
|
|
7473
|
+
execute: async ({ command, cwd, timeout }) => {
|
|
7474
|
+
const workingDir = cwd ?? process.cwd();
|
|
7475
|
+
try {
|
|
7476
|
+
const proc = Bun.spawn(["sh", "-c", command], {
|
|
7477
|
+
cwd: workingDir,
|
|
7478
|
+
stdout: "pipe",
|
|
7479
|
+
stderr: "pipe"
|
|
7480
|
+
});
|
|
7481
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7482
|
+
setTimeout(() => {
|
|
7483
|
+
proc.kill();
|
|
7484
|
+
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
7485
|
+
}, timeout);
|
|
7486
|
+
});
|
|
7487
|
+
const exitCode = await Promise.race([proc.exited, timeoutPromise]);
|
|
7488
|
+
const stdout = await new Response(proc.stdout).text();
|
|
7489
|
+
const stderr = await new Response(proc.stderr).text();
|
|
7490
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
7491
|
+
return `status=${exitCode}
|
|
7492
|
+
|
|
7493
|
+
${output || "(no output)"}`;
|
|
7494
|
+
} catch (error) {
|
|
7495
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7496
|
+
return `status=1
|
|
7497
|
+
|
|
7498
|
+
error: ${message}`;
|
|
7499
|
+
}
|
|
7500
|
+
}
|
|
7501
|
+
});
|
|
7502
|
+
|
|
7503
|
+
// src/cli/builtins/index.ts
|
|
7504
|
+
var builtinGadgetRegistry = {
|
|
7505
|
+
ListDirectory: listDirectory,
|
|
7506
|
+
ReadFile: readFile,
|
|
7507
|
+
WriteFile: writeFile,
|
|
7508
|
+
EditFile: editFile,
|
|
7509
|
+
RunCommand: runCommand
|
|
7510
|
+
};
|
|
7511
|
+
function getBuiltinGadget(name) {
|
|
7512
|
+
return builtinGadgetRegistry[name];
|
|
7513
|
+
}
|
|
7514
|
+
function isBuiltinGadgetName(name) {
|
|
7515
|
+
return name in builtinGadgetRegistry;
|
|
7516
|
+
}
|
|
7517
|
+
|
|
7518
|
+
// src/cli/gadgets.ts
|
|
6689
7519
|
var PATH_PREFIXES = [".", "/", "~"];
|
|
7520
|
+
var BUILTIN_PREFIX = "builtin:";
|
|
6690
7521
|
function isGadgetLike(value) {
|
|
6691
7522
|
if (typeof value !== "object" || value === null) {
|
|
6692
7523
|
return false;
|
|
@@ -6709,18 +7540,34 @@ function expandHomePath(input) {
|
|
|
6709
7540
|
if (!home) {
|
|
6710
7541
|
return input;
|
|
6711
7542
|
}
|
|
6712
|
-
return
|
|
7543
|
+
return import_node_path6.default.join(home, input.slice(1));
|
|
6713
7544
|
}
|
|
6714
7545
|
function isFileLikeSpecifier(specifier) {
|
|
6715
|
-
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(
|
|
7546
|
+
return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(import_node_path6.default.sep);
|
|
7547
|
+
}
|
|
7548
|
+
function tryResolveBuiltin(specifier) {
|
|
7549
|
+
if (specifier.startsWith(BUILTIN_PREFIX)) {
|
|
7550
|
+
const name = specifier.slice(BUILTIN_PREFIX.length);
|
|
7551
|
+
const gadget = getBuiltinGadget(name);
|
|
7552
|
+
if (!gadget) {
|
|
7553
|
+
throw new Error(
|
|
7554
|
+
`Unknown builtin gadget: ${name}. Available builtins: ListDirectory, ReadFile, WriteFile, EditFile, RunCommand`
|
|
7555
|
+
);
|
|
7556
|
+
}
|
|
7557
|
+
return gadget;
|
|
7558
|
+
}
|
|
7559
|
+
if (!isFileLikeSpecifier(specifier) && isBuiltinGadgetName(specifier)) {
|
|
7560
|
+
return getBuiltinGadget(specifier);
|
|
7561
|
+
}
|
|
7562
|
+
return null;
|
|
6716
7563
|
}
|
|
6717
7564
|
function resolveGadgetSpecifier(specifier, cwd) {
|
|
6718
7565
|
if (!isFileLikeSpecifier(specifier)) {
|
|
6719
7566
|
return specifier;
|
|
6720
7567
|
}
|
|
6721
7568
|
const expanded = expandHomePath(specifier);
|
|
6722
|
-
const resolvedPath =
|
|
6723
|
-
if (!
|
|
7569
|
+
const resolvedPath = import_node_path6.default.resolve(cwd, expanded);
|
|
7570
|
+
if (!import_node_fs7.default.existsSync(resolvedPath)) {
|
|
6724
7571
|
throw new Error(`Gadget module not found at ${resolvedPath}`);
|
|
6725
7572
|
}
|
|
6726
7573
|
return (0, import_node_url.pathToFileURL)(resolvedPath).href;
|
|
@@ -6762,6 +7609,11 @@ function extractGadgetsFromModule(moduleExports) {
|
|
|
6762
7609
|
async function loadGadgets(specifiers, cwd, importer = (specifier) => import(specifier)) {
|
|
6763
7610
|
const gadgets = [];
|
|
6764
7611
|
for (const specifier of specifiers) {
|
|
7612
|
+
const builtin = tryResolveBuiltin(specifier);
|
|
7613
|
+
if (builtin) {
|
|
7614
|
+
gadgets.push(builtin);
|
|
7615
|
+
continue;
|
|
7616
|
+
}
|
|
6765
7617
|
const resolved = resolveGadgetSpecifier(specifier, cwd);
|
|
6766
7618
|
let exports2;
|
|
6767
7619
|
try {
|
|
@@ -6786,13 +7638,13 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
|
|
|
6786
7638
|
}
|
|
6787
7639
|
|
|
6788
7640
|
// src/cli/llm-logging.ts
|
|
6789
|
-
var
|
|
7641
|
+
var import_promises2 = require("fs/promises");
|
|
6790
7642
|
var import_node_os = require("os");
|
|
6791
|
-
var
|
|
6792
|
-
var DEFAULT_LLM_LOG_DIR = (0,
|
|
7643
|
+
var import_node_path7 = require("path");
|
|
7644
|
+
var DEFAULT_LLM_LOG_DIR = (0, import_node_path7.join)((0, import_node_os.homedir)(), ".llmist", "logs");
|
|
6793
7645
|
function resolveLogDir(option, subdir) {
|
|
6794
7646
|
if (option === true) {
|
|
6795
|
-
return (0,
|
|
7647
|
+
return (0, import_node_path7.join)(DEFAULT_LLM_LOG_DIR, subdir);
|
|
6796
7648
|
}
|
|
6797
7649
|
if (typeof option === "string") {
|
|
6798
7650
|
return option;
|
|
@@ -6809,44 +7661,44 @@ function formatLlmRequest(messages) {
|
|
|
6809
7661
|
return lines.join("\n");
|
|
6810
7662
|
}
|
|
6811
7663
|
async function writeLogFile(dir, filename, content) {
|
|
6812
|
-
await (0,
|
|
6813
|
-
await (0,
|
|
7664
|
+
await (0, import_promises2.mkdir)(dir, { recursive: true });
|
|
7665
|
+
await (0, import_promises2.writeFile)((0, import_node_path7.join)(dir, filename), content, "utf-8");
|
|
6814
7666
|
}
|
|
6815
7667
|
|
|
6816
7668
|
// src/cli/utils.ts
|
|
6817
|
-
var
|
|
7669
|
+
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
6818
7670
|
var import_commander = require("commander");
|
|
6819
7671
|
init_constants2();
|
|
6820
7672
|
|
|
6821
7673
|
// src/cli/ui/formatters.ts
|
|
6822
|
-
var
|
|
7674
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
6823
7675
|
var import_marked = require("marked");
|
|
6824
7676
|
var import_marked_terminal = require("marked-terminal");
|
|
6825
7677
|
var markedConfigured = false;
|
|
6826
7678
|
function ensureMarkedConfigured() {
|
|
6827
7679
|
if (!markedConfigured) {
|
|
6828
|
-
|
|
7680
|
+
import_chalk3.default.level = process.env.NO_COLOR ? 0 : 3;
|
|
6829
7681
|
import_marked.marked.use(
|
|
6830
7682
|
(0, import_marked_terminal.markedTerminal)({
|
|
6831
7683
|
// Text styling
|
|
6832
|
-
strong:
|
|
6833
|
-
em:
|
|
6834
|
-
del:
|
|
7684
|
+
strong: import_chalk3.default.bold,
|
|
7685
|
+
em: import_chalk3.default.italic,
|
|
7686
|
+
del: import_chalk3.default.dim.gray.strikethrough,
|
|
6835
7687
|
// Code styling
|
|
6836
|
-
code:
|
|
6837
|
-
codespan:
|
|
7688
|
+
code: import_chalk3.default.yellow,
|
|
7689
|
+
codespan: import_chalk3.default.yellow,
|
|
6838
7690
|
// Headings
|
|
6839
|
-
heading:
|
|
6840
|
-
firstHeading:
|
|
7691
|
+
heading: import_chalk3.default.green.bold,
|
|
7692
|
+
firstHeading: import_chalk3.default.magenta.underline.bold,
|
|
6841
7693
|
// Links
|
|
6842
|
-
link:
|
|
6843
|
-
href:
|
|
7694
|
+
link: import_chalk3.default.blue,
|
|
7695
|
+
href: import_chalk3.default.blue.underline,
|
|
6844
7696
|
// Block elements
|
|
6845
|
-
blockquote:
|
|
7697
|
+
blockquote: import_chalk3.default.gray.italic,
|
|
6846
7698
|
// List formatting - reduce indentation and add bullet styling
|
|
6847
7699
|
tab: 2,
|
|
6848
7700
|
// Reduce from default 4 to 2 spaces
|
|
6849
|
-
listitem:
|
|
7701
|
+
listitem: import_chalk3.default.reset
|
|
6850
7702
|
// Keep items readable (no dim)
|
|
6851
7703
|
})
|
|
6852
7704
|
);
|
|
@@ -6856,11 +7708,11 @@ function ensureMarkedConfigured() {
|
|
|
6856
7708
|
function renderMarkdown(text) {
|
|
6857
7709
|
ensureMarkedConfigured();
|
|
6858
7710
|
let rendered = import_marked.marked.parse(text);
|
|
6859
|
-
rendered = rendered.replace(/\*\*(.+?)\*\*/g, (_, content) =>
|
|
7711
|
+
rendered = rendered.replace(/\*\*(.+?)\*\*/g, (_, content) => import_chalk3.default.bold(content)).replace(/(?<!\*)\*(\S[^*]*)\*(?!\*)/g, (_, content) => import_chalk3.default.italic(content));
|
|
6860
7712
|
return rendered.trimEnd();
|
|
6861
7713
|
}
|
|
6862
7714
|
function createRainbowSeparator() {
|
|
6863
|
-
const colors = [
|
|
7715
|
+
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
7716
|
const char = "\u2500";
|
|
6865
7717
|
const width = process.stdout.columns || 80;
|
|
6866
7718
|
let result = "";
|
|
@@ -6896,58 +7748,58 @@ function formatCost(cost) {
|
|
|
6896
7748
|
function renderSummary(metadata) {
|
|
6897
7749
|
const parts = [];
|
|
6898
7750
|
if (metadata.iterations !== void 0) {
|
|
6899
|
-
const iterPart =
|
|
7751
|
+
const iterPart = import_chalk3.default.cyan(`#${metadata.iterations}`);
|
|
6900
7752
|
if (metadata.model) {
|
|
6901
|
-
parts.push(`${iterPart} ${
|
|
7753
|
+
parts.push(`${iterPart} ${import_chalk3.default.magenta(metadata.model)}`);
|
|
6902
7754
|
} else {
|
|
6903
7755
|
parts.push(iterPart);
|
|
6904
7756
|
}
|
|
6905
7757
|
} else if (metadata.model) {
|
|
6906
|
-
parts.push(
|
|
7758
|
+
parts.push(import_chalk3.default.magenta(metadata.model));
|
|
6907
7759
|
}
|
|
6908
7760
|
if (metadata.usage) {
|
|
6909
7761
|
const { inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens } = metadata.usage;
|
|
6910
|
-
parts.push(
|
|
7762
|
+
parts.push(import_chalk3.default.dim("\u2191") + import_chalk3.default.yellow(` ${formatTokens(inputTokens)}`));
|
|
6911
7763
|
if (cachedInputTokens && cachedInputTokens > 0) {
|
|
6912
|
-
parts.push(
|
|
7764
|
+
parts.push(import_chalk3.default.dim("\u27F3") + import_chalk3.default.blue(` ${formatTokens(cachedInputTokens)}`));
|
|
6913
7765
|
}
|
|
6914
7766
|
if (cacheCreationInputTokens && cacheCreationInputTokens > 0) {
|
|
6915
|
-
parts.push(
|
|
7767
|
+
parts.push(import_chalk3.default.dim("\u270E") + import_chalk3.default.magenta(` ${formatTokens(cacheCreationInputTokens)}`));
|
|
6916
7768
|
}
|
|
6917
|
-
parts.push(
|
|
7769
|
+
parts.push(import_chalk3.default.dim("\u2193") + import_chalk3.default.green(` ${formatTokens(outputTokens)}`));
|
|
6918
7770
|
}
|
|
6919
7771
|
if (metadata.elapsedSeconds !== void 0 && metadata.elapsedSeconds > 0) {
|
|
6920
|
-
parts.push(
|
|
7772
|
+
parts.push(import_chalk3.default.dim(`${metadata.elapsedSeconds}s`));
|
|
6921
7773
|
}
|
|
6922
7774
|
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
6923
|
-
parts.push(
|
|
7775
|
+
parts.push(import_chalk3.default.cyan(`$${formatCost(metadata.cost)}`));
|
|
6924
7776
|
}
|
|
6925
7777
|
if (metadata.finishReason) {
|
|
6926
|
-
parts.push(
|
|
7778
|
+
parts.push(import_chalk3.default.dim(metadata.finishReason));
|
|
6927
7779
|
}
|
|
6928
7780
|
if (parts.length === 0) {
|
|
6929
7781
|
return null;
|
|
6930
7782
|
}
|
|
6931
|
-
return parts.join(
|
|
7783
|
+
return parts.join(import_chalk3.default.dim(" | "));
|
|
6932
7784
|
}
|
|
6933
7785
|
function renderOverallSummary(metadata) {
|
|
6934
7786
|
const parts = [];
|
|
6935
7787
|
if (metadata.totalTokens !== void 0 && metadata.totalTokens > 0) {
|
|
6936
|
-
parts.push(
|
|
7788
|
+
parts.push(import_chalk3.default.dim("total:") + import_chalk3.default.magenta(` ${formatTokens(metadata.totalTokens)}`));
|
|
6937
7789
|
}
|
|
6938
7790
|
if (metadata.iterations !== void 0 && metadata.iterations > 0) {
|
|
6939
|
-
parts.push(
|
|
7791
|
+
parts.push(import_chalk3.default.cyan(`#${metadata.iterations}`));
|
|
6940
7792
|
}
|
|
6941
7793
|
if (metadata.elapsedSeconds !== void 0 && metadata.elapsedSeconds > 0) {
|
|
6942
|
-
parts.push(
|
|
7794
|
+
parts.push(import_chalk3.default.dim(`${metadata.elapsedSeconds}s`));
|
|
6943
7795
|
}
|
|
6944
7796
|
if (metadata.cost !== void 0 && metadata.cost > 0) {
|
|
6945
|
-
parts.push(
|
|
7797
|
+
parts.push(import_chalk3.default.cyan(`$${formatCost(metadata.cost)}`));
|
|
6946
7798
|
}
|
|
6947
7799
|
if (parts.length === 0) {
|
|
6948
7800
|
return null;
|
|
6949
7801
|
}
|
|
6950
|
-
return parts.join(
|
|
7802
|
+
return parts.join(import_chalk3.default.dim(" | "));
|
|
6951
7803
|
}
|
|
6952
7804
|
function formatParametersInline(params) {
|
|
6953
7805
|
if (!params || Object.keys(params).length === 0) {
|
|
@@ -6963,8 +7815,8 @@ function formatParametersInline(params) {
|
|
|
6963
7815
|
const json = JSON.stringify(value);
|
|
6964
7816
|
formatted = json.length > 30 ? `${json.slice(0, 30)}\u2026` : json;
|
|
6965
7817
|
}
|
|
6966
|
-
return `${
|
|
6967
|
-
}).join(
|
|
7818
|
+
return `${import_chalk3.default.dim(key)}${import_chalk3.default.dim("=")}${import_chalk3.default.cyan(formatted)}`;
|
|
7819
|
+
}).join(import_chalk3.default.dim(", "));
|
|
6968
7820
|
}
|
|
6969
7821
|
function formatBytes(bytes) {
|
|
6970
7822
|
if (bytes < 1024) {
|
|
@@ -6976,25 +7828,25 @@ function formatBytes(bytes) {
|
|
|
6976
7828
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
6977
7829
|
}
|
|
6978
7830
|
function formatGadgetSummary(result) {
|
|
6979
|
-
const gadgetLabel =
|
|
6980
|
-
const timeLabel =
|
|
7831
|
+
const gadgetLabel = import_chalk3.default.magenta.bold(result.gadgetName);
|
|
7832
|
+
const timeLabel = import_chalk3.default.dim(`${Math.round(result.executionTimeMs)}ms`);
|
|
6981
7833
|
const paramsStr = formatParametersInline(result.parameters);
|
|
6982
|
-
const paramsLabel = paramsStr ? `${
|
|
7834
|
+
const paramsLabel = paramsStr ? `${import_chalk3.default.dim("(")}${paramsStr}${import_chalk3.default.dim(")")}` : "";
|
|
6983
7835
|
if (result.error) {
|
|
6984
7836
|
const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}\u2026` : result.error;
|
|
6985
|
-
return `${
|
|
7837
|
+
return `${import_chalk3.default.red("\u2717")} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.red("error:")} ${errorMsg} ${timeLabel}`;
|
|
6986
7838
|
}
|
|
6987
7839
|
let outputLabel;
|
|
6988
7840
|
if (result.tokenCount !== void 0 && result.tokenCount > 0) {
|
|
6989
|
-
outputLabel =
|
|
7841
|
+
outputLabel = import_chalk3.default.green(`${formatTokens(result.tokenCount)} tokens`);
|
|
6990
7842
|
} else if (result.result) {
|
|
6991
7843
|
const outputBytes = Buffer.byteLength(result.result, "utf-8");
|
|
6992
|
-
outputLabel = outputBytes > 0 ?
|
|
7844
|
+
outputLabel = outputBytes > 0 ? import_chalk3.default.green(formatBytes(outputBytes)) : import_chalk3.default.dim("no output");
|
|
6993
7845
|
} else {
|
|
6994
|
-
outputLabel =
|
|
7846
|
+
outputLabel = import_chalk3.default.dim("no output");
|
|
6995
7847
|
}
|
|
6996
|
-
const icon = result.breaksLoop ?
|
|
6997
|
-
const summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${
|
|
7848
|
+
const icon = result.breaksLoop ? import_chalk3.default.yellow("\u23F9") : import_chalk3.default.green("\u2713");
|
|
7849
|
+
const summaryLine = `${icon} ${gadgetLabel}${paramsLabel} ${import_chalk3.default.dim("\u2192")} ${outputLabel} ${timeLabel}`;
|
|
6998
7850
|
if (result.gadgetName === "TellUser" && result.parameters?.message) {
|
|
6999
7851
|
const message = String(result.parameters.message);
|
|
7000
7852
|
const rendered = renderMarkdownWithSeparators(message);
|
|
@@ -7058,6 +7910,66 @@ var StreamPrinter = class {
|
|
|
7058
7910
|
function isInteractive(stream2) {
|
|
7059
7911
|
return Boolean(stream2.isTTY);
|
|
7060
7912
|
}
|
|
7913
|
+
var ESC_KEY = 27;
|
|
7914
|
+
var ESC_TIMEOUT_MS = 50;
|
|
7915
|
+
function createEscKeyListener(stdin, onEsc) {
|
|
7916
|
+
if (!stdin.isTTY || typeof stdin.setRawMode !== "function") {
|
|
7917
|
+
return null;
|
|
7918
|
+
}
|
|
7919
|
+
let escTimeout = null;
|
|
7920
|
+
const handleData = (data) => {
|
|
7921
|
+
if (data[0] === ESC_KEY) {
|
|
7922
|
+
if (data.length === 1) {
|
|
7923
|
+
escTimeout = setTimeout(() => {
|
|
7924
|
+
onEsc();
|
|
7925
|
+
}, ESC_TIMEOUT_MS);
|
|
7926
|
+
} else {
|
|
7927
|
+
if (escTimeout) {
|
|
7928
|
+
clearTimeout(escTimeout);
|
|
7929
|
+
escTimeout = null;
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7932
|
+
} else {
|
|
7933
|
+
if (escTimeout) {
|
|
7934
|
+
clearTimeout(escTimeout);
|
|
7935
|
+
escTimeout = null;
|
|
7936
|
+
}
|
|
7937
|
+
}
|
|
7938
|
+
};
|
|
7939
|
+
stdin.setRawMode(true);
|
|
7940
|
+
stdin.resume();
|
|
7941
|
+
stdin.on("data", handleData);
|
|
7942
|
+
return () => {
|
|
7943
|
+
if (escTimeout) {
|
|
7944
|
+
clearTimeout(escTimeout);
|
|
7945
|
+
}
|
|
7946
|
+
stdin.removeListener("data", handleData);
|
|
7947
|
+
stdin.setRawMode(false);
|
|
7948
|
+
stdin.pause();
|
|
7949
|
+
};
|
|
7950
|
+
}
|
|
7951
|
+
var SIGINT_DOUBLE_PRESS_MS = 1e3;
|
|
7952
|
+
function createSigintListener(onCancel, onQuit, isOperationActive, stderr = process.stderr) {
|
|
7953
|
+
let lastSigintTime = 0;
|
|
7954
|
+
const handler = () => {
|
|
7955
|
+
const now = Date.now();
|
|
7956
|
+
if (isOperationActive()) {
|
|
7957
|
+
onCancel();
|
|
7958
|
+
lastSigintTime = now;
|
|
7959
|
+
return;
|
|
7960
|
+
}
|
|
7961
|
+
if (now - lastSigintTime < SIGINT_DOUBLE_PRESS_MS) {
|
|
7962
|
+
onQuit();
|
|
7963
|
+
return;
|
|
7964
|
+
}
|
|
7965
|
+
lastSigintTime = now;
|
|
7966
|
+
stderr.write(import_chalk4.default.dim("\n[Press Ctrl+C again to quit]\n"));
|
|
7967
|
+
};
|
|
7968
|
+
process.on("SIGINT", handler);
|
|
7969
|
+
return () => {
|
|
7970
|
+
process.removeListener("SIGINT", handler);
|
|
7971
|
+
};
|
|
7972
|
+
}
|
|
7061
7973
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7062
7974
|
var SPINNER_DELAY_MS = 500;
|
|
7063
7975
|
var StreamProgress = class {
|
|
@@ -7229,9 +8141,9 @@ var StreamProgress = class {
|
|
|
7229
8141
|
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
7230
8142
|
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
7231
8143
|
const parts = [];
|
|
7232
|
-
const iterPart =
|
|
8144
|
+
const iterPart = import_chalk4.default.cyan(`#${this.currentIteration}`);
|
|
7233
8145
|
if (this.model) {
|
|
7234
|
-
parts.push(`${iterPart} ${
|
|
8146
|
+
parts.push(`${iterPart} ${import_chalk4.default.magenta(this.model)}`);
|
|
7235
8147
|
} else {
|
|
7236
8148
|
parts.push(iterPart);
|
|
7237
8149
|
}
|
|
@@ -7239,27 +8151,27 @@ var StreamProgress = class {
|
|
|
7239
8151
|
if (usagePercent !== null) {
|
|
7240
8152
|
const formatted = `${Math.round(usagePercent)}%`;
|
|
7241
8153
|
if (usagePercent >= 80) {
|
|
7242
|
-
parts.push(
|
|
8154
|
+
parts.push(import_chalk4.default.red(formatted));
|
|
7243
8155
|
} else if (usagePercent >= 50) {
|
|
7244
|
-
parts.push(
|
|
8156
|
+
parts.push(import_chalk4.default.yellow(formatted));
|
|
7245
8157
|
} else {
|
|
7246
|
-
parts.push(
|
|
8158
|
+
parts.push(import_chalk4.default.green(formatted));
|
|
7247
8159
|
}
|
|
7248
8160
|
}
|
|
7249
8161
|
if (this.callInputTokens > 0) {
|
|
7250
8162
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
7251
|
-
parts.push(
|
|
8163
|
+
parts.push(import_chalk4.default.dim("\u2191") + import_chalk4.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`));
|
|
7252
8164
|
}
|
|
7253
8165
|
if (this.isStreaming || outTokens > 0) {
|
|
7254
8166
|
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
7255
|
-
parts.push(
|
|
8167
|
+
parts.push(import_chalk4.default.dim("\u2193") + import_chalk4.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
7256
8168
|
}
|
|
7257
|
-
parts.push(
|
|
8169
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7258
8170
|
const callCost = this.calculateCurrentCallCost(outTokens);
|
|
7259
8171
|
if (callCost > 0) {
|
|
7260
|
-
parts.push(
|
|
8172
|
+
parts.push(import_chalk4.default.cyan(`$${formatCost(callCost)}`));
|
|
7261
8173
|
}
|
|
7262
|
-
this.target.write(`\r${parts.join(
|
|
8174
|
+
this.target.write(`\r${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`);
|
|
7263
8175
|
}
|
|
7264
8176
|
/**
|
|
7265
8177
|
* Calculates live cost estimate for the current streaming call.
|
|
@@ -7300,19 +8212,19 @@ var StreamProgress = class {
|
|
|
7300
8212
|
const elapsed = ((Date.now() - this.totalStartTime) / 1e3).toFixed(1);
|
|
7301
8213
|
const parts = [];
|
|
7302
8214
|
if (this.model) {
|
|
7303
|
-
parts.push(
|
|
8215
|
+
parts.push(import_chalk4.default.cyan(this.model));
|
|
7304
8216
|
}
|
|
7305
8217
|
if (this.totalTokens > 0) {
|
|
7306
|
-
parts.push(
|
|
8218
|
+
parts.push(import_chalk4.default.dim("total:") + import_chalk4.default.magenta(` ${this.totalTokens}`));
|
|
7307
8219
|
}
|
|
7308
8220
|
if (this.iterations > 0) {
|
|
7309
|
-
parts.push(
|
|
8221
|
+
parts.push(import_chalk4.default.dim("iter:") + import_chalk4.default.blue(` ${this.iterations}`));
|
|
7310
8222
|
}
|
|
7311
8223
|
if (this.totalCost > 0) {
|
|
7312
|
-
parts.push(
|
|
8224
|
+
parts.push(import_chalk4.default.dim("cost:") + import_chalk4.default.cyan(` $${formatCost(this.totalCost)}`));
|
|
7313
8225
|
}
|
|
7314
|
-
parts.push(
|
|
7315
|
-
this.target.write(`\r${parts.join(
|
|
8226
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
8227
|
+
this.target.write(`\r${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.cyan(spinner)}`);
|
|
7316
8228
|
}
|
|
7317
8229
|
/**
|
|
7318
8230
|
* Pauses the progress indicator and clears the line.
|
|
@@ -7346,6 +8258,25 @@ var StreamProgress = class {
|
|
|
7346
8258
|
getTotalCost() {
|
|
7347
8259
|
return this.totalCost;
|
|
7348
8260
|
}
|
|
8261
|
+
/**
|
|
8262
|
+
* Returns a formatted stats string for cancellation messages.
|
|
8263
|
+
* Format: "↑ 1.2k | ↓ 300 | 5.0s"
|
|
8264
|
+
*/
|
|
8265
|
+
formatStats() {
|
|
8266
|
+
const parts = [];
|
|
8267
|
+
const elapsed = ((Date.now() - this.callStartTime) / 1e3).toFixed(1);
|
|
8268
|
+
const outTokens = this.callOutputTokensEstimated ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN) : this.callOutputTokens;
|
|
8269
|
+
if (this.callInputTokens > 0) {
|
|
8270
|
+
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
8271
|
+
parts.push(`\u2191 ${prefix}${formatTokens(this.callInputTokens)}`);
|
|
8272
|
+
}
|
|
8273
|
+
if (outTokens > 0) {
|
|
8274
|
+
const prefix = this.callOutputTokensEstimated ? "~" : "";
|
|
8275
|
+
parts.push(`\u2193 ${prefix}${formatTokens(outTokens)}`);
|
|
8276
|
+
}
|
|
8277
|
+
parts.push(`${elapsed}s`);
|
|
8278
|
+
return parts.join(" | ");
|
|
8279
|
+
}
|
|
7349
8280
|
/**
|
|
7350
8281
|
* Returns a formatted prompt string with stats (like bash PS1).
|
|
7351
8282
|
* Shows current call stats during streaming, cumulative stats otherwise.
|
|
@@ -7360,28 +8291,28 @@ var StreamProgress = class {
|
|
|
7360
8291
|
if (this.callInputTokens > 0) {
|
|
7361
8292
|
const prefix = this.callInputTokensEstimated ? "~" : "";
|
|
7362
8293
|
parts.push(
|
|
7363
|
-
|
|
8294
|
+
import_chalk4.default.dim("\u2191") + import_chalk4.default.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`)
|
|
7364
8295
|
);
|
|
7365
8296
|
}
|
|
7366
8297
|
if (outTokens > 0) {
|
|
7367
8298
|
const prefix = outEstimated ? "~" : "";
|
|
7368
|
-
parts.push(
|
|
8299
|
+
parts.push(import_chalk4.default.dim("\u2193") + import_chalk4.default.green(` ${prefix}${formatTokens(outTokens)}`));
|
|
7369
8300
|
}
|
|
7370
|
-
parts.push(
|
|
8301
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7371
8302
|
} else {
|
|
7372
8303
|
const elapsed = Math.round((Date.now() - this.totalStartTime) / 1e3);
|
|
7373
8304
|
if (this.totalTokens > 0) {
|
|
7374
|
-
parts.push(
|
|
8305
|
+
parts.push(import_chalk4.default.magenta(formatTokens(this.totalTokens)));
|
|
7375
8306
|
}
|
|
7376
8307
|
if (this.iterations > 0) {
|
|
7377
|
-
parts.push(
|
|
8308
|
+
parts.push(import_chalk4.default.blue(`i${this.iterations}`));
|
|
7378
8309
|
}
|
|
7379
8310
|
if (this.totalCost > 0) {
|
|
7380
|
-
parts.push(
|
|
8311
|
+
parts.push(import_chalk4.default.cyan(`$${formatCost(this.totalCost)}`));
|
|
7381
8312
|
}
|
|
7382
|
-
parts.push(
|
|
8313
|
+
parts.push(import_chalk4.default.dim(`${elapsed}s`));
|
|
7383
8314
|
}
|
|
7384
|
-
return `${parts.join(
|
|
8315
|
+
return `${parts.join(import_chalk4.default.dim(" | "))} ${import_chalk4.default.green(">")} `;
|
|
7385
8316
|
}
|
|
7386
8317
|
};
|
|
7387
8318
|
async function readStream(stream2) {
|
|
@@ -7416,7 +8347,7 @@ async function executeAction(action, env) {
|
|
|
7416
8347
|
await action();
|
|
7417
8348
|
} catch (error) {
|
|
7418
8349
|
const message = error instanceof Error ? error.message : String(error);
|
|
7419
|
-
env.stderr.write(`${
|
|
8350
|
+
env.stderr.write(`${import_chalk4.default.red.bold("Error:")} ${message}
|
|
7420
8351
|
`);
|
|
7421
8352
|
env.setExitCode(1);
|
|
7422
8353
|
}
|
|
@@ -7441,7 +8372,7 @@ function addAgentOptions(cmd, defaults) {
|
|
|
7441
8372
|
...previous,
|
|
7442
8373
|
value
|
|
7443
8374
|
];
|
|
7444
|
-
const defaultGadgets = defaults?.gadget ?? [];
|
|
8375
|
+
const defaultGadgets = defaults?.gadgets ?? defaults?.gadget ?? [];
|
|
7445
8376
|
return cmd.option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, defaults?.model ?? DEFAULT_MODEL).option(OPTION_FLAGS.systemPrompt, OPTION_DESCRIPTIONS.systemPrompt, defaults?.system).option(
|
|
7446
8377
|
OPTION_FLAGS.temperature,
|
|
7447
8378
|
OPTION_DESCRIPTIONS.temperature,
|
|
@@ -7477,7 +8408,8 @@ function configToAgentOptions(config) {
|
|
|
7477
8408
|
if (config.system !== void 0) result.system = config.system;
|
|
7478
8409
|
if (config.temperature !== void 0) result.temperature = config.temperature;
|
|
7479
8410
|
if (config["max-iterations"] !== void 0) result.maxIterations = config["max-iterations"];
|
|
7480
|
-
|
|
8411
|
+
const gadgets = config.gadgets ?? config.gadget;
|
|
8412
|
+
if (gadgets !== void 0) result.gadget = gadgets;
|
|
7481
8413
|
if (config.builtins !== void 0) result.builtins = config.builtins;
|
|
7482
8414
|
if (config["builtin-interaction"] !== void 0)
|
|
7483
8415
|
result.builtinInteraction = config["builtin-interaction"];
|
|
@@ -7487,6 +8419,8 @@ function configToAgentOptions(config) {
|
|
|
7487
8419
|
result.gadgetEndPrefix = config["gadget-end-prefix"];
|
|
7488
8420
|
if (config["gadget-arg-prefix"] !== void 0)
|
|
7489
8421
|
result.gadgetArgPrefix = config["gadget-arg-prefix"];
|
|
8422
|
+
if (config["gadget-approval"] !== void 0)
|
|
8423
|
+
result.gadgetApproval = config["gadget-approval"];
|
|
7490
8424
|
if (config.quiet !== void 0) result.quiet = config.quiet;
|
|
7491
8425
|
if (config["log-llm-requests"] !== void 0) result.logLlmRequests = config["log-llm-requests"];
|
|
7492
8426
|
if (config["log-llm-responses"] !== void 0) result.logLlmResponses = config["log-llm-responses"];
|
|
@@ -7494,23 +8428,18 @@ function configToAgentOptions(config) {
|
|
|
7494
8428
|
}
|
|
7495
8429
|
|
|
7496
8430
|
// 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) {
|
|
8431
|
+
function createHumanInputHandler(env, progress, keyboard) {
|
|
7507
8432
|
const stdout = env.stdout;
|
|
7508
8433
|
if (!isInteractive(env.stdin) || typeof stdout.isTTY !== "boolean" || !stdout.isTTY) {
|
|
7509
8434
|
return void 0;
|
|
7510
8435
|
}
|
|
7511
8436
|
return async (question) => {
|
|
7512
8437
|
progress.pause();
|
|
7513
|
-
|
|
8438
|
+
if (keyboard.cleanupEsc) {
|
|
8439
|
+
keyboard.cleanupEsc();
|
|
8440
|
+
keyboard.cleanupEsc = null;
|
|
8441
|
+
}
|
|
8442
|
+
const rl = (0, import_promises3.createInterface)({ input: env.stdin, output: env.stdout });
|
|
7514
8443
|
try {
|
|
7515
8444
|
const questionLine = question.trim() ? `
|
|
7516
8445
|
${renderMarkdownWithSeparators(question.trim())}` : "";
|
|
@@ -7528,6 +8457,7 @@ ${statsPrompt}` : statsPrompt;
|
|
|
7528
8457
|
}
|
|
7529
8458
|
} finally {
|
|
7530
8459
|
rl.close();
|
|
8460
|
+
keyboard.restore();
|
|
7531
8461
|
}
|
|
7532
8462
|
};
|
|
7533
8463
|
}
|
|
@@ -7554,6 +8484,77 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7554
8484
|
const printer = new StreamPrinter(env.stdout);
|
|
7555
8485
|
const stderrTTY = env.stderr.isTTY === true;
|
|
7556
8486
|
const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);
|
|
8487
|
+
const abortController = new AbortController();
|
|
8488
|
+
let wasCancelled = false;
|
|
8489
|
+
let isStreaming = false;
|
|
8490
|
+
const stdinStream = env.stdin;
|
|
8491
|
+
const handleCancel = () => {
|
|
8492
|
+
if (!abortController.signal.aborted) {
|
|
8493
|
+
wasCancelled = true;
|
|
8494
|
+
abortController.abort();
|
|
8495
|
+
progress.pause();
|
|
8496
|
+
env.stderr.write(import_chalk5.default.yellow(`
|
|
8497
|
+
[Cancelled] ${progress.formatStats()}
|
|
8498
|
+
`));
|
|
8499
|
+
}
|
|
8500
|
+
};
|
|
8501
|
+
const keyboard = {
|
|
8502
|
+
cleanupEsc: null,
|
|
8503
|
+
cleanupSigint: null,
|
|
8504
|
+
restore: () => {
|
|
8505
|
+
if (stdinIsInteractive && stdinStream.isTTY && !wasCancelled) {
|
|
8506
|
+
keyboard.cleanupEsc = createEscKeyListener(stdinStream, handleCancel);
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
};
|
|
8510
|
+
const handleQuit = () => {
|
|
8511
|
+
keyboard.cleanupEsc?.();
|
|
8512
|
+
keyboard.cleanupSigint?.();
|
|
8513
|
+
progress.complete();
|
|
8514
|
+
printer.ensureNewline();
|
|
8515
|
+
const summary = renderOverallSummary({
|
|
8516
|
+
totalTokens: usage?.totalTokens,
|
|
8517
|
+
iterations,
|
|
8518
|
+
elapsedSeconds: progress.getTotalElapsedSeconds(),
|
|
8519
|
+
cost: progress.getTotalCost()
|
|
8520
|
+
});
|
|
8521
|
+
if (summary) {
|
|
8522
|
+
env.stderr.write(`${import_chalk5.default.dim("\u2500".repeat(40))}
|
|
8523
|
+
`);
|
|
8524
|
+
env.stderr.write(`${summary}
|
|
8525
|
+
`);
|
|
8526
|
+
}
|
|
8527
|
+
env.stderr.write(import_chalk5.default.dim("[Quit]\n"));
|
|
8528
|
+
process.exit(130);
|
|
8529
|
+
};
|
|
8530
|
+
if (stdinIsInteractive && stdinStream.isTTY) {
|
|
8531
|
+
keyboard.cleanupEsc = createEscKeyListener(stdinStream, handleCancel);
|
|
8532
|
+
}
|
|
8533
|
+
keyboard.cleanupSigint = createSigintListener(
|
|
8534
|
+
handleCancel,
|
|
8535
|
+
handleQuit,
|
|
8536
|
+
() => isStreaming && !abortController.signal.aborted,
|
|
8537
|
+
env.stderr
|
|
8538
|
+
);
|
|
8539
|
+
const DEFAULT_APPROVAL_REQUIRED = ["RunCommand", "WriteFile", "EditFile"];
|
|
8540
|
+
const userApprovals = options.gadgetApproval ?? {};
|
|
8541
|
+
const gadgetApprovals = {
|
|
8542
|
+
...userApprovals
|
|
8543
|
+
};
|
|
8544
|
+
for (const gadget of DEFAULT_APPROVAL_REQUIRED) {
|
|
8545
|
+
const normalizedGadget = gadget.toLowerCase();
|
|
8546
|
+
const isConfigured = Object.keys(userApprovals).some(
|
|
8547
|
+
(key) => key.toLowerCase() === normalizedGadget
|
|
8548
|
+
);
|
|
8549
|
+
if (!isConfigured) {
|
|
8550
|
+
gadgetApprovals[gadget] = "approval-required";
|
|
8551
|
+
}
|
|
8552
|
+
}
|
|
8553
|
+
const approvalConfig = {
|
|
8554
|
+
gadgetApprovals,
|
|
8555
|
+
defaultMode: "allowed"
|
|
8556
|
+
};
|
|
8557
|
+
const approvalManager = new ApprovalManager(approvalConfig, env, progress);
|
|
7557
8558
|
let usage;
|
|
7558
8559
|
let iterations = 0;
|
|
7559
8560
|
const llmRequestsDir = resolveLogDir(options.logLlmRequests, "requests");
|
|
@@ -7581,6 +8582,7 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7581
8582
|
// onLLMCallStart: Start progress indicator for each LLM call
|
|
7582
8583
|
// This showcases how to react to agent lifecycle events
|
|
7583
8584
|
onLLMCallStart: async (context) => {
|
|
8585
|
+
isStreaming = true;
|
|
7584
8586
|
llmCallCounter++;
|
|
7585
8587
|
const inputTokens = await countMessagesTokens(
|
|
7586
8588
|
context.options.model,
|
|
@@ -7614,6 +8616,7 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7614
8616
|
// onLLMCallComplete: Finalize metrics after each LLM call
|
|
7615
8617
|
// This is where you'd typically log metrics or update dashboards
|
|
7616
8618
|
onLLMCallComplete: async (context) => {
|
|
8619
|
+
isStreaming = false;
|
|
7617
8620
|
usage = context.usage;
|
|
7618
8621
|
iterations = Math.max(iterations, context.iteration + 1);
|
|
7619
8622
|
if (context.usage) {
|
|
@@ -7661,47 +8664,53 @@ async function executeAgent(promptArg, options, env) {
|
|
|
7661
8664
|
}
|
|
7662
8665
|
}
|
|
7663
8666
|
},
|
|
7664
|
-
// SHOWCASE: Controller-based approval gating for
|
|
8667
|
+
// SHOWCASE: Controller-based approval gating for gadgets
|
|
7665
8668
|
//
|
|
7666
8669
|
// This demonstrates how to add safety layers WITHOUT modifying gadgets.
|
|
7667
|
-
// The
|
|
7668
|
-
//
|
|
8670
|
+
// The ApprovalManager handles approval flows externally via beforeGadgetExecution.
|
|
8671
|
+
// Approval modes are configurable via cli.toml:
|
|
8672
|
+
// - "allowed": auto-proceed
|
|
8673
|
+
// - "denied": auto-reject, return message to LLM
|
|
8674
|
+
// - "approval-required": prompt user interactively
|
|
7669
8675
|
//
|
|
7670
|
-
//
|
|
7671
|
-
// any gadget (DeleteFile, SendEmail, etc.) without changing the gadgets.
|
|
8676
|
+
// Default: RunCommand, WriteFile, EditFile require approval unless overridden.
|
|
7672
8677
|
controllers: {
|
|
7673
8678
|
beforeGadgetExecution: async (ctx) => {
|
|
7674
|
-
|
|
8679
|
+
const mode = approvalManager.getApprovalMode(ctx.gadgetName);
|
|
8680
|
+
if (mode === "allowed") {
|
|
7675
8681
|
return { action: "proceed" };
|
|
7676
8682
|
}
|
|
7677
8683
|
const stdinTTY = isInteractive(env.stdin);
|
|
7678
8684
|
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")}
|
|
8685
|
+
const canPrompt = stdinTTY && stderrTTY2;
|
|
8686
|
+
if (!canPrompt) {
|
|
8687
|
+
if (mode === "approval-required") {
|
|
8688
|
+
return {
|
|
8689
|
+
action: "skip",
|
|
8690
|
+
syntheticResult: `status=denied
|
|
7694
8691
|
|
|
7695
|
-
|
|
8692
|
+
${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`
|
|
8693
|
+
};
|
|
8694
|
+
}
|
|
8695
|
+
if (mode === "denied") {
|
|
8696
|
+
return {
|
|
8697
|
+
action: "skip",
|
|
8698
|
+
syntheticResult: `status=denied
|
|
8699
|
+
|
|
8700
|
+
${ctx.gadgetName} is denied by configuration.`
|
|
8701
|
+
};
|
|
8702
|
+
}
|
|
8703
|
+
return { action: "proceed" };
|
|
8704
|
+
}
|
|
8705
|
+
const result = await approvalManager.requestApproval(ctx.gadgetName, ctx.parameters);
|
|
8706
|
+
if (!result.approved) {
|
|
7696
8707
|
return {
|
|
7697
8708
|
action: "skip",
|
|
7698
8709
|
syntheticResult: `status=denied
|
|
7699
8710
|
|
|
7700
|
-
|
|
8711
|
+
Denied: ${result.reason ?? "by user"}`
|
|
7701
8712
|
};
|
|
7702
8713
|
}
|
|
7703
|
-
env.stderr.write(` ${import_chalk3.default.green("\u2713 Approved")}
|
|
7704
|
-
`);
|
|
7705
8714
|
return { action: "proceed" };
|
|
7706
8715
|
}
|
|
7707
8716
|
}
|
|
@@ -7715,10 +8724,11 @@ Command rejected by user with message: "${response}"`
|
|
|
7715
8724
|
if (options.temperature !== void 0) {
|
|
7716
8725
|
builder.withTemperature(options.temperature);
|
|
7717
8726
|
}
|
|
7718
|
-
const humanInputHandler = createHumanInputHandler(env, progress);
|
|
8727
|
+
const humanInputHandler = createHumanInputHandler(env, progress, keyboard);
|
|
7719
8728
|
if (humanInputHandler) {
|
|
7720
8729
|
builder.onHumanInput(humanInputHandler);
|
|
7721
8730
|
}
|
|
8731
|
+
builder.withSignal(abortController.signal);
|
|
7722
8732
|
const gadgets = registry.getAll();
|
|
7723
8733
|
if (gadgets.length > 0) {
|
|
7724
8734
|
builder.withGadgets(...gadgets);
|
|
@@ -7756,31 +8766,41 @@ Command rejected by user with message: "${response}"`
|
|
|
7756
8766
|
textBuffer = "";
|
|
7757
8767
|
}
|
|
7758
8768
|
};
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
if (
|
|
7768
|
-
|
|
7769
|
-
|
|
8769
|
+
try {
|
|
8770
|
+
for await (const event of agent.run()) {
|
|
8771
|
+
if (event.type === "text") {
|
|
8772
|
+
progress.pause();
|
|
8773
|
+
textBuffer += event.content;
|
|
8774
|
+
} else if (event.type === "gadget_result") {
|
|
8775
|
+
flushTextBuffer();
|
|
8776
|
+
progress.pause();
|
|
8777
|
+
if (options.quiet) {
|
|
8778
|
+
if (event.result.gadgetName === "TellUser" && event.result.parameters?.message) {
|
|
8779
|
+
const message = String(event.result.parameters.message);
|
|
8780
|
+
env.stdout.write(`${message}
|
|
7770
8781
|
`);
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
8782
|
+
}
|
|
8783
|
+
} else {
|
|
8784
|
+
const tokenCount = await countGadgetOutputTokens(event.result.result);
|
|
8785
|
+
env.stderr.write(`${formatGadgetSummary({ ...event.result, tokenCount })}
|
|
7775
8786
|
`);
|
|
8787
|
+
}
|
|
7776
8788
|
}
|
|
7777
8789
|
}
|
|
8790
|
+
} catch (error) {
|
|
8791
|
+
if (!isAbortError(error)) {
|
|
8792
|
+
throw error;
|
|
8793
|
+
}
|
|
8794
|
+
} finally {
|
|
8795
|
+
isStreaming = false;
|
|
8796
|
+
keyboard.cleanupEsc?.();
|
|
8797
|
+
keyboard.cleanupSigint?.();
|
|
7778
8798
|
}
|
|
7779
8799
|
flushTextBuffer();
|
|
7780
8800
|
progress.complete();
|
|
7781
8801
|
printer.ensureNewline();
|
|
7782
8802
|
if (!options.quiet && iterations > 1) {
|
|
7783
|
-
env.stderr.write(`${
|
|
8803
|
+
env.stderr.write(`${import_chalk5.default.dim("\u2500".repeat(40))}
|
|
7784
8804
|
`);
|
|
7785
8805
|
const summary = renderOverallSummary({
|
|
7786
8806
|
totalTokens: usage?.totalTokens,
|
|
@@ -7798,7 +8818,13 @@ function registerAgentCommand(program, env, config) {
|
|
|
7798
8818
|
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
8819
|
addAgentOptions(cmd, config);
|
|
7800
8820
|
cmd.action(
|
|
7801
|
-
(prompt, options) => executeAction(() =>
|
|
8821
|
+
(prompt, options) => executeAction(() => {
|
|
8822
|
+
const mergedOptions = {
|
|
8823
|
+
...options,
|
|
8824
|
+
gadgetApproval: config?.["gadget-approval"]
|
|
8825
|
+
};
|
|
8826
|
+
return executeAgent(prompt, mergedOptions, env);
|
|
8827
|
+
}, env)
|
|
7802
8828
|
);
|
|
7803
8829
|
}
|
|
7804
8830
|
|
|
@@ -7882,9 +8908,9 @@ function registerCompleteCommand(program, env, config) {
|
|
|
7882
8908
|
}
|
|
7883
8909
|
|
|
7884
8910
|
// src/cli/config.ts
|
|
7885
|
-
var
|
|
8911
|
+
var import_node_fs8 = require("fs");
|
|
7886
8912
|
var import_node_os2 = require("os");
|
|
7887
|
-
var
|
|
8913
|
+
var import_node_path8 = require("path");
|
|
7888
8914
|
var import_js_toml = require("js-toml");
|
|
7889
8915
|
|
|
7890
8916
|
// src/cli/templates.ts
|
|
@@ -7969,6 +8995,7 @@ function hasTemplateSyntax(str) {
|
|
|
7969
8995
|
}
|
|
7970
8996
|
|
|
7971
8997
|
// src/cli/config.ts
|
|
8998
|
+
var VALID_APPROVAL_MODES = ["allowed", "denied", "approval-required"];
|
|
7972
8999
|
var GLOBAL_CONFIG_KEYS = /* @__PURE__ */ new Set(["log-level", "log-file", "log-reset"]);
|
|
7973
9000
|
var VALID_LOG_LEVELS = ["silly", "trace", "debug", "info", "warn", "error", "fatal"];
|
|
7974
9001
|
var COMPLETE_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -7991,12 +9018,20 @@ var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
7991
9018
|
"system",
|
|
7992
9019
|
"temperature",
|
|
7993
9020
|
"max-iterations",
|
|
9021
|
+
"gadgets",
|
|
9022
|
+
// Full replacement (preferred)
|
|
9023
|
+
"gadget-add",
|
|
9024
|
+
// Add to inherited gadgets
|
|
9025
|
+
"gadget-remove",
|
|
9026
|
+
// Remove from inherited gadgets
|
|
7994
9027
|
"gadget",
|
|
9028
|
+
// DEPRECATED: alias for gadgets
|
|
7995
9029
|
"builtins",
|
|
7996
9030
|
"builtin-interaction",
|
|
7997
9031
|
"gadget-start-prefix",
|
|
7998
9032
|
"gadget-end-prefix",
|
|
7999
9033
|
"gadget-arg-prefix",
|
|
9034
|
+
"gadget-approval",
|
|
8000
9035
|
"quiet",
|
|
8001
9036
|
"inherits",
|
|
8002
9037
|
"log-level",
|
|
@@ -8014,12 +9049,12 @@ var CUSTOM_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
8014
9049
|
"description"
|
|
8015
9050
|
]);
|
|
8016
9051
|
function getConfigPath() {
|
|
8017
|
-
return (0,
|
|
9052
|
+
return (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".llmist", "cli.toml");
|
|
8018
9053
|
}
|
|
8019
9054
|
var ConfigError = class extends Error {
|
|
8020
|
-
constructor(message,
|
|
8021
|
-
super(
|
|
8022
|
-
this.path =
|
|
9055
|
+
constructor(message, path5) {
|
|
9056
|
+
super(path5 ? `${path5}: ${message}` : message);
|
|
9057
|
+
this.path = path5;
|
|
8023
9058
|
this.name = "ConfigError";
|
|
8024
9059
|
}
|
|
8025
9060
|
};
|
|
@@ -8075,6 +9110,28 @@ function validateInherits(value, section) {
|
|
|
8075
9110
|
}
|
|
8076
9111
|
throw new ConfigError(`[${section}].inherits must be a string or array of strings`);
|
|
8077
9112
|
}
|
|
9113
|
+
function validateGadgetApproval(value, section) {
|
|
9114
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
9115
|
+
throw new ConfigError(
|
|
9116
|
+
`[${section}].gadget-approval must be a table (e.g., { WriteFile = "approval-required" })`
|
|
9117
|
+
);
|
|
9118
|
+
}
|
|
9119
|
+
const result = {};
|
|
9120
|
+
for (const [gadgetName, mode] of Object.entries(value)) {
|
|
9121
|
+
if (typeof mode !== "string") {
|
|
9122
|
+
throw new ConfigError(
|
|
9123
|
+
`[${section}].gadget-approval.${gadgetName} must be a string`
|
|
9124
|
+
);
|
|
9125
|
+
}
|
|
9126
|
+
if (!VALID_APPROVAL_MODES.includes(mode)) {
|
|
9127
|
+
throw new ConfigError(
|
|
9128
|
+
`[${section}].gadget-approval.${gadgetName} must be one of: ${VALID_APPROVAL_MODES.join(", ")}`
|
|
9129
|
+
);
|
|
9130
|
+
}
|
|
9131
|
+
result[gadgetName] = mode;
|
|
9132
|
+
}
|
|
9133
|
+
return result;
|
|
9134
|
+
}
|
|
8078
9135
|
function validateLoggingConfig(raw, section) {
|
|
8079
9136
|
const result = {};
|
|
8080
9137
|
if ("log-level" in raw) {
|
|
@@ -8184,6 +9241,15 @@ function validateAgentConfig(raw, section) {
|
|
|
8184
9241
|
min: 1
|
|
8185
9242
|
});
|
|
8186
9243
|
}
|
|
9244
|
+
if ("gadgets" in rawObj) {
|
|
9245
|
+
result.gadgets = validateStringArray(rawObj.gadgets, "gadgets", section);
|
|
9246
|
+
}
|
|
9247
|
+
if ("gadget-add" in rawObj) {
|
|
9248
|
+
result["gadget-add"] = validateStringArray(rawObj["gadget-add"], "gadget-add", section);
|
|
9249
|
+
}
|
|
9250
|
+
if ("gadget-remove" in rawObj) {
|
|
9251
|
+
result["gadget-remove"] = validateStringArray(rawObj["gadget-remove"], "gadget-remove", section);
|
|
9252
|
+
}
|
|
8187
9253
|
if ("gadget" in rawObj) {
|
|
8188
9254
|
result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
|
|
8189
9255
|
}
|
|
@@ -8218,6 +9284,9 @@ function validateAgentConfig(raw, section) {
|
|
|
8218
9284
|
section
|
|
8219
9285
|
);
|
|
8220
9286
|
}
|
|
9287
|
+
if ("gadget-approval" in rawObj) {
|
|
9288
|
+
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
9289
|
+
}
|
|
8221
9290
|
if ("quiet" in rawObj) {
|
|
8222
9291
|
result.quiet = validateBoolean(rawObj.quiet, "quiet", section);
|
|
8223
9292
|
}
|
|
@@ -8274,6 +9343,15 @@ function validateCustomConfig(raw, section) {
|
|
|
8274
9343
|
min: 1
|
|
8275
9344
|
});
|
|
8276
9345
|
}
|
|
9346
|
+
if ("gadgets" in rawObj) {
|
|
9347
|
+
result.gadgets = validateStringArray(rawObj.gadgets, "gadgets", section);
|
|
9348
|
+
}
|
|
9349
|
+
if ("gadget-add" in rawObj) {
|
|
9350
|
+
result["gadget-add"] = validateStringArray(rawObj["gadget-add"], "gadget-add", section);
|
|
9351
|
+
}
|
|
9352
|
+
if ("gadget-remove" in rawObj) {
|
|
9353
|
+
result["gadget-remove"] = validateStringArray(rawObj["gadget-remove"], "gadget-remove", section);
|
|
9354
|
+
}
|
|
8277
9355
|
if ("gadget" in rawObj) {
|
|
8278
9356
|
result.gadget = validateStringArray(rawObj.gadget, "gadget", section);
|
|
8279
9357
|
}
|
|
@@ -8308,6 +9386,9 @@ function validateCustomConfig(raw, section) {
|
|
|
8308
9386
|
section
|
|
8309
9387
|
);
|
|
8310
9388
|
}
|
|
9389
|
+
if ("gadget-approval" in rawObj) {
|
|
9390
|
+
result["gadget-approval"] = validateGadgetApproval(rawObj["gadget-approval"], section);
|
|
9391
|
+
}
|
|
8311
9392
|
if ("max-tokens" in rawObj) {
|
|
8312
9393
|
result["max-tokens"] = validateNumber(rawObj["max-tokens"], "max-tokens", section, {
|
|
8313
9394
|
integer: true,
|
|
@@ -8363,12 +9444,12 @@ function validateConfig(raw, configPath) {
|
|
|
8363
9444
|
}
|
|
8364
9445
|
function loadConfig() {
|
|
8365
9446
|
const configPath = getConfigPath();
|
|
8366
|
-
if (!(0,
|
|
9447
|
+
if (!(0, import_node_fs8.existsSync)(configPath)) {
|
|
8367
9448
|
return {};
|
|
8368
9449
|
}
|
|
8369
9450
|
let content;
|
|
8370
9451
|
try {
|
|
8371
|
-
content = (0,
|
|
9452
|
+
content = (0, import_node_fs8.readFileSync)(configPath, "utf-8");
|
|
8372
9453
|
} catch (error) {
|
|
8373
9454
|
throw new ConfigError(
|
|
8374
9455
|
`Failed to read config file: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
@@ -8463,6 +9544,39 @@ function resolveTemplatesInConfig(config, configPath) {
|
|
|
8463
9544
|
}
|
|
8464
9545
|
return result;
|
|
8465
9546
|
}
|
|
9547
|
+
function resolveGadgets(section, inheritedGadgets, sectionName, configPath) {
|
|
9548
|
+
const hasGadgets = "gadgets" in section;
|
|
9549
|
+
const hasGadgetLegacy = "gadget" in section;
|
|
9550
|
+
const hasGadgetAdd = "gadget-add" in section;
|
|
9551
|
+
const hasGadgetRemove = "gadget-remove" in section;
|
|
9552
|
+
if (hasGadgetLegacy && !hasGadgets) {
|
|
9553
|
+
console.warn(
|
|
9554
|
+
`[config] Warning: [${sectionName}].gadget is deprecated, use 'gadgets' (plural) instead`
|
|
9555
|
+
);
|
|
9556
|
+
}
|
|
9557
|
+
if ((hasGadgets || hasGadgetLegacy) && (hasGadgetAdd || hasGadgetRemove)) {
|
|
9558
|
+
throw new ConfigError(
|
|
9559
|
+
`[${sectionName}] Cannot use 'gadgets' with 'gadget-add'/'gadget-remove'. Use either full replacement (gadgets) OR modification (gadget-add/gadget-remove).`,
|
|
9560
|
+
configPath
|
|
9561
|
+
);
|
|
9562
|
+
}
|
|
9563
|
+
if (hasGadgets) {
|
|
9564
|
+
return section.gadgets;
|
|
9565
|
+
}
|
|
9566
|
+
if (hasGadgetLegacy) {
|
|
9567
|
+
return section.gadget;
|
|
9568
|
+
}
|
|
9569
|
+
let result = [...inheritedGadgets];
|
|
9570
|
+
if (hasGadgetRemove) {
|
|
9571
|
+
const toRemove = new Set(section["gadget-remove"]);
|
|
9572
|
+
result = result.filter((g) => !toRemove.has(g));
|
|
9573
|
+
}
|
|
9574
|
+
if (hasGadgetAdd) {
|
|
9575
|
+
const toAdd = section["gadget-add"];
|
|
9576
|
+
result.push(...toAdd);
|
|
9577
|
+
}
|
|
9578
|
+
return result;
|
|
9579
|
+
}
|
|
8466
9580
|
function resolveInheritance(config, configPath) {
|
|
8467
9581
|
const resolved = {};
|
|
8468
9582
|
const resolving = /* @__PURE__ */ new Set();
|
|
@@ -8486,8 +9600,23 @@ function resolveInheritance(config, configPath) {
|
|
|
8486
9600
|
const parentResolved = resolveSection(parent);
|
|
8487
9601
|
merged = { ...merged, ...parentResolved };
|
|
8488
9602
|
}
|
|
8489
|
-
const
|
|
9603
|
+
const inheritedGadgets = merged.gadgets ?? [];
|
|
9604
|
+
const {
|
|
9605
|
+
inherits: _inherits,
|
|
9606
|
+
gadgets: _gadgets,
|
|
9607
|
+
gadget: _gadget,
|
|
9608
|
+
"gadget-add": _gadgetAdd,
|
|
9609
|
+
"gadget-remove": _gadgetRemove,
|
|
9610
|
+
...ownValues
|
|
9611
|
+
} = sectionObj;
|
|
8490
9612
|
merged = { ...merged, ...ownValues };
|
|
9613
|
+
const resolvedGadgets = resolveGadgets(sectionObj, inheritedGadgets, name, configPath);
|
|
9614
|
+
if (resolvedGadgets.length > 0) {
|
|
9615
|
+
merged.gadgets = resolvedGadgets;
|
|
9616
|
+
}
|
|
9617
|
+
delete merged["gadget"];
|
|
9618
|
+
delete merged["gadget-add"];
|
|
9619
|
+
delete merged["gadget-remove"];
|
|
8491
9620
|
resolving.delete(name);
|
|
8492
9621
|
resolved[name] = merged;
|
|
8493
9622
|
return merged;
|
|
@@ -8499,13 +9628,13 @@ function resolveInheritance(config, configPath) {
|
|
|
8499
9628
|
}
|
|
8500
9629
|
|
|
8501
9630
|
// src/cli/gadget-command.ts
|
|
8502
|
-
var
|
|
9631
|
+
var import_chalk7 = __toESM(require("chalk"), 1);
|
|
8503
9632
|
init_schema_to_json();
|
|
8504
9633
|
init_schema_validator();
|
|
8505
9634
|
|
|
8506
9635
|
// src/cli/gadget-prompts.ts
|
|
8507
|
-
var
|
|
8508
|
-
var
|
|
9636
|
+
var import_promises4 = require("readline/promises");
|
|
9637
|
+
var import_chalk6 = __toESM(require("chalk"), 1);
|
|
8509
9638
|
init_schema_to_json();
|
|
8510
9639
|
async function promptForParameters(schema, ctx) {
|
|
8511
9640
|
if (!schema) {
|
|
@@ -8515,7 +9644,7 @@ async function promptForParameters(schema, ctx) {
|
|
|
8515
9644
|
if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {
|
|
8516
9645
|
return {};
|
|
8517
9646
|
}
|
|
8518
|
-
const rl = (0,
|
|
9647
|
+
const rl = (0, import_promises4.createInterface)({ input: ctx.stdin, output: ctx.stdout });
|
|
8519
9648
|
const params = {};
|
|
8520
9649
|
try {
|
|
8521
9650
|
for (const [key, prop] of Object.entries(jsonSchema.properties)) {
|
|
@@ -8538,16 +9667,16 @@ ${issues}`);
|
|
|
8538
9667
|
async function promptForField(rl, key, prop, required) {
|
|
8539
9668
|
const isRequired = required.includes(key);
|
|
8540
9669
|
const typeHint = formatTypeHint(prop);
|
|
8541
|
-
const defaultHint = prop.default !== void 0 ?
|
|
8542
|
-
const requiredMarker = isRequired ?
|
|
9670
|
+
const defaultHint = prop.default !== void 0 ? import_chalk6.default.dim(` [default: ${JSON.stringify(prop.default)}]`) : "";
|
|
9671
|
+
const requiredMarker = isRequired ? import_chalk6.default.red("*") : "";
|
|
8543
9672
|
let prompt = `
|
|
8544
|
-
${
|
|
9673
|
+
${import_chalk6.default.cyan.bold(key)}${requiredMarker}`;
|
|
8545
9674
|
if (prop.description) {
|
|
8546
|
-
prompt +=
|
|
9675
|
+
prompt += import_chalk6.default.dim(` - ${prop.description}`);
|
|
8547
9676
|
}
|
|
8548
9677
|
prompt += `
|
|
8549
9678
|
${typeHint}${defaultHint}
|
|
8550
|
-
${
|
|
9679
|
+
${import_chalk6.default.green(">")} `;
|
|
8551
9680
|
const answer = await rl.question(prompt);
|
|
8552
9681
|
const trimmed = answer.trim();
|
|
8553
9682
|
if (!trimmed) {
|
|
@@ -8563,20 +9692,20 @@ ${import_chalk4.default.cyan.bold(key)}${requiredMarker}`;
|
|
|
8563
9692
|
}
|
|
8564
9693
|
function formatTypeHint(prop) {
|
|
8565
9694
|
if (prop.enum) {
|
|
8566
|
-
return
|
|
9695
|
+
return import_chalk6.default.yellow(`(${prop.enum.join(" | ")})`);
|
|
8567
9696
|
}
|
|
8568
9697
|
if (prop.type === "array") {
|
|
8569
9698
|
const items = prop.items;
|
|
8570
9699
|
if (items?.enum) {
|
|
8571
|
-
return
|
|
9700
|
+
return import_chalk6.default.yellow(`(${items.enum.join(" | ")})[] comma-separated`);
|
|
8572
9701
|
}
|
|
8573
9702
|
const itemType = items?.type ?? "any";
|
|
8574
|
-
return
|
|
9703
|
+
return import_chalk6.default.yellow(`(${itemType}[]) comma-separated`);
|
|
8575
9704
|
}
|
|
8576
9705
|
if (prop.type === "object" && prop.properties) {
|
|
8577
|
-
return
|
|
9706
|
+
return import_chalk6.default.yellow("(object) enter as JSON");
|
|
8578
9707
|
}
|
|
8579
|
-
return
|
|
9708
|
+
return import_chalk6.default.yellow(`(${prop.type ?? "any"})`);
|
|
8580
9709
|
}
|
|
8581
9710
|
function parseValue(input, prop, key) {
|
|
8582
9711
|
const type = prop.type;
|
|
@@ -8687,7 +9816,7 @@ Available gadgets:
|
|
|
8687
9816
|
async function executeGadgetRun(file, options, env) {
|
|
8688
9817
|
const cwd = process.cwd();
|
|
8689
9818
|
const { gadget, name } = await selectGadget(file, options.name, cwd);
|
|
8690
|
-
env.stderr.write(
|
|
9819
|
+
env.stderr.write(import_chalk7.default.cyan.bold(`
|
|
8691
9820
|
\u{1F527} Running gadget: ${name}
|
|
8692
9821
|
`));
|
|
8693
9822
|
let params;
|
|
@@ -8698,7 +9827,7 @@ async function executeGadgetRun(file, options, env) {
|
|
|
8698
9827
|
// Prompts go to stderr to keep stdout clean
|
|
8699
9828
|
});
|
|
8700
9829
|
} else {
|
|
8701
|
-
env.stderr.write(
|
|
9830
|
+
env.stderr.write(import_chalk7.default.dim("Reading parameters from stdin...\n"));
|
|
8702
9831
|
const stdinParams = await readStdinJson(env.stdin);
|
|
8703
9832
|
if (gadget.parameterSchema) {
|
|
8704
9833
|
const result2 = gadget.parameterSchema.safeParse(stdinParams);
|
|
@@ -8712,7 +9841,7 @@ ${issues}`);
|
|
|
8712
9841
|
params = stdinParams;
|
|
8713
9842
|
}
|
|
8714
9843
|
}
|
|
8715
|
-
env.stderr.write(
|
|
9844
|
+
env.stderr.write(import_chalk7.default.dim("\nExecuting...\n"));
|
|
8716
9845
|
const startTime = Date.now();
|
|
8717
9846
|
let result;
|
|
8718
9847
|
try {
|
|
@@ -8734,7 +9863,7 @@ ${issues}`);
|
|
|
8734
9863
|
throw new Error(`Execution failed: ${message}`);
|
|
8735
9864
|
}
|
|
8736
9865
|
const elapsed = Date.now() - startTime;
|
|
8737
|
-
env.stderr.write(
|
|
9866
|
+
env.stderr.write(import_chalk7.default.green(`
|
|
8738
9867
|
\u2713 Completed in ${elapsed}ms
|
|
8739
9868
|
|
|
8740
9869
|
`));
|
|
@@ -8770,37 +9899,37 @@ async function executeGadgetInfo(file, options, env) {
|
|
|
8770
9899
|
return;
|
|
8771
9900
|
}
|
|
8772
9901
|
env.stdout.write("\n");
|
|
8773
|
-
env.stdout.write(
|
|
9902
|
+
env.stdout.write(import_chalk7.default.cyan.bold(`${name}
|
|
8774
9903
|
`));
|
|
8775
|
-
env.stdout.write(
|
|
8776
|
-
env.stdout.write(
|
|
9904
|
+
env.stdout.write(import_chalk7.default.cyan("\u2550".repeat(name.length)) + "\n\n");
|
|
9905
|
+
env.stdout.write(import_chalk7.default.bold("Description:\n"));
|
|
8777
9906
|
env.stdout.write(` ${gadget.description}
|
|
8778
9907
|
|
|
8779
9908
|
`);
|
|
8780
9909
|
if (gadget.parameterSchema) {
|
|
8781
|
-
env.stdout.write(
|
|
9910
|
+
env.stdout.write(import_chalk7.default.bold("Parameters:\n"));
|
|
8782
9911
|
const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: "draft-7" });
|
|
8783
9912
|
env.stdout.write(formatSchemaAsText(jsonSchema, " ") + "\n\n");
|
|
8784
9913
|
} else {
|
|
8785
|
-
env.stdout.write(
|
|
9914
|
+
env.stdout.write(import_chalk7.default.dim("No parameters required.\n\n"));
|
|
8786
9915
|
}
|
|
8787
9916
|
if (gadget.timeoutMs) {
|
|
8788
|
-
env.stdout.write(
|
|
9917
|
+
env.stdout.write(import_chalk7.default.bold("Timeout:\n"));
|
|
8789
9918
|
env.stdout.write(` ${gadget.timeoutMs}ms
|
|
8790
9919
|
|
|
8791
9920
|
`);
|
|
8792
9921
|
}
|
|
8793
9922
|
if (gadget.examples && gadget.examples.length > 0) {
|
|
8794
|
-
env.stdout.write(
|
|
9923
|
+
env.stdout.write(import_chalk7.default.bold("Examples:\n"));
|
|
8795
9924
|
for (const example of gadget.examples) {
|
|
8796
9925
|
if (example.comment) {
|
|
8797
|
-
env.stdout.write(
|
|
9926
|
+
env.stdout.write(import_chalk7.default.dim(` # ${example.comment}
|
|
8798
9927
|
`));
|
|
8799
9928
|
}
|
|
8800
|
-
env.stdout.write(` Input: ${
|
|
9929
|
+
env.stdout.write(` Input: ${import_chalk7.default.cyan(JSON.stringify(example.params))}
|
|
8801
9930
|
`);
|
|
8802
9931
|
if (example.output !== void 0) {
|
|
8803
|
-
env.stdout.write(` Output: ${
|
|
9932
|
+
env.stdout.write(` Output: ${import_chalk7.default.green(example.output)}
|
|
8804
9933
|
`);
|
|
8805
9934
|
}
|
|
8806
9935
|
env.stdout.write("\n");
|
|
@@ -8833,27 +9962,27 @@ function formatSchemaAsText(schema, indent = "") {
|
|
|
8833
9962
|
const isRequired = required.includes(key);
|
|
8834
9963
|
const enumValues = prop.enum;
|
|
8835
9964
|
const defaultValue = prop.default;
|
|
8836
|
-
let line = `${indent}${
|
|
9965
|
+
let line = `${indent}${import_chalk7.default.cyan(key)}`;
|
|
8837
9966
|
if (isRequired) {
|
|
8838
|
-
line +=
|
|
9967
|
+
line += import_chalk7.default.red("*");
|
|
8839
9968
|
}
|
|
8840
9969
|
if (type === "array") {
|
|
8841
9970
|
const items = prop.items;
|
|
8842
9971
|
const itemType = items?.type || "any";
|
|
8843
|
-
line +=
|
|
9972
|
+
line += import_chalk7.default.dim(` (${itemType}[])`);
|
|
8844
9973
|
} else if (type === "object" && prop.properties) {
|
|
8845
|
-
line +=
|
|
9974
|
+
line += import_chalk7.default.dim(" (object)");
|
|
8846
9975
|
} else {
|
|
8847
|
-
line +=
|
|
9976
|
+
line += import_chalk7.default.dim(` (${type})`);
|
|
8848
9977
|
}
|
|
8849
9978
|
if (defaultValue !== void 0) {
|
|
8850
|
-
line +=
|
|
9979
|
+
line += import_chalk7.default.dim(` [default: ${JSON.stringify(defaultValue)}]`);
|
|
8851
9980
|
}
|
|
8852
9981
|
if (description) {
|
|
8853
9982
|
line += `: ${description}`;
|
|
8854
9983
|
}
|
|
8855
9984
|
if (enumValues) {
|
|
8856
|
-
line +=
|
|
9985
|
+
line += import_chalk7.default.yellow(` - one of: ${enumValues.join(", ")}`);
|
|
8857
9986
|
}
|
|
8858
9987
|
lines.push(line);
|
|
8859
9988
|
if (type === "object" && prop.properties) {
|
|
@@ -8893,20 +10022,20 @@ async function executeGadgetValidate(file, env) {
|
|
|
8893
10022
|
throw new Error(`Validation issues:
|
|
8894
10023
|
${issues.map((i) => ` - ${i}`).join("\n")}`);
|
|
8895
10024
|
}
|
|
8896
|
-
env.stdout.write(
|
|
8897
|
-
env.stdout.write(
|
|
10025
|
+
env.stdout.write(import_chalk7.default.green.bold("\n\u2713 Valid\n\n"));
|
|
10026
|
+
env.stdout.write(import_chalk7.default.bold("Gadgets found:\n"));
|
|
8898
10027
|
for (const gadget of gadgets) {
|
|
8899
10028
|
const name = gadget.name ?? gadget.constructor.name;
|
|
8900
|
-
const schemaInfo = gadget.parameterSchema ?
|
|
8901
|
-
env.stdout.write(` ${
|
|
10029
|
+
const schemaInfo = gadget.parameterSchema ? import_chalk7.default.cyan("(with schema)") : import_chalk7.default.dim("(no schema)");
|
|
10030
|
+
env.stdout.write(` ${import_chalk7.default.bold(name)} ${schemaInfo}
|
|
8902
10031
|
`);
|
|
8903
|
-
env.stdout.write(
|
|
10032
|
+
env.stdout.write(import_chalk7.default.dim(` ${gadget.description}
|
|
8904
10033
|
`));
|
|
8905
10034
|
}
|
|
8906
10035
|
env.stdout.write("\n");
|
|
8907
10036
|
} catch (error) {
|
|
8908
10037
|
const message = error instanceof Error ? error.message : String(error);
|
|
8909
|
-
env.stdout.write(
|
|
10038
|
+
env.stdout.write(import_chalk7.default.red.bold(`
|
|
8910
10039
|
\u2717 Invalid
|
|
8911
10040
|
|
|
8912
10041
|
`));
|
|
@@ -8930,7 +10059,7 @@ function registerGadgetCommand(program, env) {
|
|
|
8930
10059
|
}
|
|
8931
10060
|
|
|
8932
10061
|
// src/cli/models-command.ts
|
|
8933
|
-
var
|
|
10062
|
+
var import_chalk8 = __toESM(require("chalk"), 1);
|
|
8934
10063
|
init_model_shortcuts();
|
|
8935
10064
|
async function handleModelsCommand(options, env) {
|
|
8936
10065
|
const client = env.createClient();
|
|
@@ -8950,13 +10079,13 @@ function renderTable(models, verbose, stream2) {
|
|
|
8950
10079
|
}
|
|
8951
10080
|
grouped.get(provider).push(model);
|
|
8952
10081
|
}
|
|
8953
|
-
stream2.write(
|
|
8954
|
-
stream2.write(
|
|
10082
|
+
stream2.write(import_chalk8.default.bold.cyan("\nAvailable Models\n"));
|
|
10083
|
+
stream2.write(import_chalk8.default.cyan("=".repeat(80)) + "\n\n");
|
|
8955
10084
|
const providers = Array.from(grouped.keys()).sort();
|
|
8956
10085
|
for (const provider of providers) {
|
|
8957
10086
|
const providerModels = grouped.get(provider);
|
|
8958
10087
|
const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
8959
|
-
stream2.write(
|
|
10088
|
+
stream2.write(import_chalk8.default.bold.yellow(`${providerName} Models
|
|
8960
10089
|
`));
|
|
8961
10090
|
if (verbose) {
|
|
8962
10091
|
renderVerboseTable(providerModels, stream2);
|
|
@@ -8965,11 +10094,11 @@ function renderTable(models, verbose, stream2) {
|
|
|
8965
10094
|
}
|
|
8966
10095
|
stream2.write("\n");
|
|
8967
10096
|
}
|
|
8968
|
-
stream2.write(
|
|
8969
|
-
stream2.write(
|
|
10097
|
+
stream2.write(import_chalk8.default.bold.magenta("Model Shortcuts\n"));
|
|
10098
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(80)) + "\n");
|
|
8970
10099
|
const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));
|
|
8971
10100
|
for (const [shortcut, fullName] of shortcuts) {
|
|
8972
|
-
stream2.write(
|
|
10101
|
+
stream2.write(import_chalk8.default.cyan(` ${shortcut.padEnd(15)}`) + import_chalk8.default.dim(" \u2192 ") + import_chalk8.default.white(fullName) + "\n");
|
|
8973
10102
|
}
|
|
8974
10103
|
stream2.write("\n");
|
|
8975
10104
|
}
|
|
@@ -8979,45 +10108,45 @@ function renderCompactTable(models, stream2) {
|
|
|
8979
10108
|
const contextWidth = 13;
|
|
8980
10109
|
const inputWidth = 10;
|
|
8981
10110
|
const outputWidth = 10;
|
|
8982
|
-
stream2.write(
|
|
10111
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
8983
10112
|
stream2.write(
|
|
8984
|
-
|
|
10113
|
+
import_chalk8.default.bold(
|
|
8985
10114
|
"Model ID".padEnd(idWidth) + " " + "Display Name".padEnd(nameWidth) + " " + "Context".padEnd(contextWidth) + " " + "Input".padEnd(inputWidth) + " " + "Output".padEnd(outputWidth)
|
|
8986
10115
|
) + "\n"
|
|
8987
10116
|
);
|
|
8988
|
-
stream2.write(
|
|
10117
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
8989
10118
|
for (const model of models) {
|
|
8990
10119
|
const contextFormatted = formatTokens2(model.contextWindow);
|
|
8991
10120
|
const inputPrice = `$${model.pricing.input.toFixed(2)}`;
|
|
8992
10121
|
const outputPrice = `$${model.pricing.output.toFixed(2)}`;
|
|
8993
10122
|
stream2.write(
|
|
8994
|
-
|
|
10123
|
+
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
10124
|
);
|
|
8996
10125
|
}
|
|
8997
|
-
stream2.write(
|
|
8998
|
-
stream2.write(
|
|
10126
|
+
stream2.write(import_chalk8.default.dim("\u2500".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + "\n");
|
|
10127
|
+
stream2.write(import_chalk8.default.dim(` * Prices are per 1M tokens
|
|
8999
10128
|
`));
|
|
9000
10129
|
}
|
|
9001
10130
|
function renderVerboseTable(models, stream2) {
|
|
9002
10131
|
for (const model of models) {
|
|
9003
|
-
stream2.write(
|
|
10132
|
+
stream2.write(import_chalk8.default.bold.green(`
|
|
9004
10133
|
${model.modelId}
|
|
9005
10134
|
`));
|
|
9006
|
-
stream2.write(
|
|
9007
|
-
stream2.write(` ${
|
|
10135
|
+
stream2.write(import_chalk8.default.dim(" " + "\u2500".repeat(60)) + "\n");
|
|
10136
|
+
stream2.write(` ${import_chalk8.default.dim("Name:")} ${import_chalk8.default.white(model.displayName)}
|
|
9008
10137
|
`);
|
|
9009
|
-
stream2.write(` ${
|
|
10138
|
+
stream2.write(` ${import_chalk8.default.dim("Context:")} ${import_chalk8.default.yellow(formatTokens2(model.contextWindow))}
|
|
9010
10139
|
`);
|
|
9011
|
-
stream2.write(` ${
|
|
10140
|
+
stream2.write(` ${import_chalk8.default.dim("Max Output:")} ${import_chalk8.default.yellow(formatTokens2(model.maxOutputTokens))}
|
|
9012
10141
|
`);
|
|
9013
|
-
stream2.write(` ${
|
|
10142
|
+
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
10143
|
`);
|
|
9015
10144
|
if (model.pricing.cachedInput !== void 0) {
|
|
9016
|
-
stream2.write(` ${
|
|
10145
|
+
stream2.write(` ${import_chalk8.default.dim("Cached Input:")} ${import_chalk8.default.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}
|
|
9017
10146
|
`);
|
|
9018
10147
|
}
|
|
9019
10148
|
if (model.knowledgeCutoff) {
|
|
9020
|
-
stream2.write(` ${
|
|
10149
|
+
stream2.write(` ${import_chalk8.default.dim("Knowledge:")} ${model.knowledgeCutoff}
|
|
9021
10150
|
`);
|
|
9022
10151
|
}
|
|
9023
10152
|
const features = [];
|
|
@@ -9028,20 +10157,20 @@ function renderVerboseTable(models, stream2) {
|
|
|
9028
10157
|
if (model.features.structuredOutputs) features.push("structured-outputs");
|
|
9029
10158
|
if (model.features.fineTuning) features.push("fine-tuning");
|
|
9030
10159
|
if (features.length > 0) {
|
|
9031
|
-
stream2.write(` ${
|
|
10160
|
+
stream2.write(` ${import_chalk8.default.dim("Features:")} ${import_chalk8.default.blue(features.join(", "))}
|
|
9032
10161
|
`);
|
|
9033
10162
|
}
|
|
9034
10163
|
if (model.metadata) {
|
|
9035
10164
|
if (model.metadata.family) {
|
|
9036
|
-
stream2.write(` ${
|
|
10165
|
+
stream2.write(` ${import_chalk8.default.dim("Family:")} ${model.metadata.family}
|
|
9037
10166
|
`);
|
|
9038
10167
|
}
|
|
9039
10168
|
if (model.metadata.releaseDate) {
|
|
9040
|
-
stream2.write(` ${
|
|
10169
|
+
stream2.write(` ${import_chalk8.default.dim("Released:")} ${model.metadata.releaseDate}
|
|
9041
10170
|
`);
|
|
9042
10171
|
}
|
|
9043
10172
|
if (model.metadata.notes) {
|
|
9044
|
-
stream2.write(` ${
|
|
10173
|
+
stream2.write(` ${import_chalk8.default.dim("Notes:")} ${import_chalk8.default.italic(model.metadata.notes)}
|
|
9045
10174
|
`);
|
|
9046
10175
|
}
|
|
9047
10176
|
}
|
|
@@ -9091,7 +10220,7 @@ function registerModelsCommand(program, env) {
|
|
|
9091
10220
|
|
|
9092
10221
|
// src/cli/environment.ts
|
|
9093
10222
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
9094
|
-
var
|
|
10223
|
+
var import_chalk9 = __toESM(require("chalk"), 1);
|
|
9095
10224
|
init_client();
|
|
9096
10225
|
init_logger();
|
|
9097
10226
|
var LOG_LEVEL_MAP = {
|
|
@@ -9134,22 +10263,22 @@ function createLoggerFactory(config) {
|
|
|
9134
10263
|
}
|
|
9135
10264
|
function createPromptFunction(stdin, stdout) {
|
|
9136
10265
|
return (question) => {
|
|
9137
|
-
return new Promise((
|
|
10266
|
+
return new Promise((resolve2) => {
|
|
9138
10267
|
const rl = import_node_readline.default.createInterface({
|
|
9139
10268
|
input: stdin,
|
|
9140
10269
|
output: stdout
|
|
9141
10270
|
});
|
|
9142
10271
|
stdout.write("\n");
|
|
9143
|
-
stdout.write(`${
|
|
10272
|
+
stdout.write(`${import_chalk9.default.cyan("\u2500".repeat(60))}
|
|
9144
10273
|
`);
|
|
9145
|
-
stdout.write(
|
|
10274
|
+
stdout.write(import_chalk9.default.cyan.bold("\u{1F916} Agent asks:\n"));
|
|
9146
10275
|
stdout.write(`${question}
|
|
9147
10276
|
`);
|
|
9148
|
-
stdout.write(`${
|
|
10277
|
+
stdout.write(`${import_chalk9.default.cyan("\u2500".repeat(60))}
|
|
9149
10278
|
`);
|
|
9150
|
-
rl.question(
|
|
10279
|
+
rl.question(import_chalk9.default.green.bold("You: "), (answer) => {
|
|
9151
10280
|
rl.close();
|
|
9152
|
-
|
|
10281
|
+
resolve2(answer);
|
|
9153
10282
|
});
|
|
9154
10283
|
});
|
|
9155
10284
|
};
|