miii-agent 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +198 -56
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -145,27 +145,64 @@ var init_client = __esm({
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
// src/tools/paths.ts
|
|
148
|
-
import { resolve, relative as relative2, isAbsolute, sep } from "path";
|
|
148
|
+
import { resolve, relative as relative2, isAbsolute, sep, join as join4 } from "path";
|
|
149
|
+
import { homedir as homedir3 } from "os";
|
|
150
|
+
function isUnder(parent, child) {
|
|
151
|
+
const rel = relative2(parent, child);
|
|
152
|
+
return rel === "" || !rel.startsWith(".." + sep) && rel !== ".." && !isAbsolute(rel);
|
|
153
|
+
}
|
|
149
154
|
function confinePath(p) {
|
|
150
155
|
if (typeof p !== "string" || p.length === 0) {
|
|
151
156
|
throw new Error("Path is required.");
|
|
152
157
|
}
|
|
153
158
|
const root = process.cwd();
|
|
154
159
|
const abs = resolve(root, p);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
throw new Error(`Path "${p}" is outside the working directory (${root}). Access denied.`);
|
|
160
|
+
if (isUnder(root, abs) || isUnder(SPILL_DIR, abs)) {
|
|
161
|
+
return abs;
|
|
158
162
|
}
|
|
159
|
-
|
|
163
|
+
throw new Error(`Path "${p}" is outside the working directory (${root}). Access denied.`);
|
|
160
164
|
}
|
|
165
|
+
var SPILL_DIR;
|
|
161
166
|
var init_paths = __esm({
|
|
162
167
|
"src/tools/paths.ts"() {
|
|
163
168
|
"use strict";
|
|
169
|
+
SPILL_DIR = resolve(join4(homedir3(), ".miii", "output"));
|
|
164
170
|
}
|
|
165
171
|
});
|
|
166
172
|
|
|
167
173
|
// src/tools/edit_file.ts
|
|
168
174
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
175
|
+
function similarity(a, b) {
|
|
176
|
+
const x = a.trim();
|
|
177
|
+
const y = b.trim();
|
|
178
|
+
if (!x && !y) return 1;
|
|
179
|
+
const len = Math.max(x.length, y.length);
|
|
180
|
+
if (len === 0) return 0;
|
|
181
|
+
let same = 0;
|
|
182
|
+
for (let i = 0; i < Math.min(x.length, y.length); i++) if (x[i] === y[i]) same++;
|
|
183
|
+
return same / len;
|
|
184
|
+
}
|
|
185
|
+
function nearMiss(src, old_str) {
|
|
186
|
+
const srcLines = src.split("\n");
|
|
187
|
+
const needle = old_str.split("\n").find((l) => l.trim()) ?? old_str;
|
|
188
|
+
let bestIdx = -1;
|
|
189
|
+
let bestScore = 0;
|
|
190
|
+
for (let i = 0; i < srcLines.length; i++) {
|
|
191
|
+
const s = similarity(srcLines[i], needle);
|
|
192
|
+
if (s > bestScore) {
|
|
193
|
+
bestScore = s;
|
|
194
|
+
bestIdx = i;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (bestIdx === -1 || bestScore < 0.4) return "";
|
|
198
|
+
const from = Math.max(0, bestIdx - 3);
|
|
199
|
+
const to = Math.min(srcLines.length, bestIdx + 4);
|
|
200
|
+
const width = String(to).length;
|
|
201
|
+
const ctx = srcLines.slice(from, to).map((l, i) => `${String(from + i + 1).padStart(width, " ")} ${l}`).join("\n");
|
|
202
|
+
return `
|
|
203
|
+
Closest text in file (lines ${from + 1}-${to}):
|
|
204
|
+
${ctx}`;
|
|
205
|
+
}
|
|
169
206
|
var edit_file;
|
|
170
207
|
var init_edit_file = __esm({
|
|
171
208
|
"src/tools/edit_file.ts"() {
|
|
@@ -173,29 +210,39 @@ var init_edit_file = __esm({
|
|
|
173
210
|
init_paths();
|
|
174
211
|
edit_file = {
|
|
175
212
|
name: "edit_file",
|
|
176
|
-
description: "Replace an exact string in a file. old_str must be unique.",
|
|
213
|
+
description: "Replace an exact string in a file. old_str must be unique unless replace_all is set. On no match, returns the closest text in the file.",
|
|
177
214
|
input_schema: {
|
|
178
215
|
type: "object",
|
|
179
216
|
properties: {
|
|
180
217
|
path: { type: "string", description: "File path" },
|
|
181
|
-
old_str: { type: "string", description: "Exact text to replace" },
|
|
182
|
-
new_str: { type: "string", description: "Replacement text" }
|
|
218
|
+
old_str: { type: "string", description: "Exact text to replace (whitespace-sensitive)" },
|
|
219
|
+
new_str: { type: "string", description: "Replacement text" },
|
|
220
|
+
replace_all: { type: "boolean", description: "Replace every occurrence instead of requiring uniqueness" }
|
|
183
221
|
},
|
|
184
222
|
required: ["path", "old_str", "new_str"]
|
|
185
223
|
},
|
|
186
|
-
handler: ({ path, old_str, new_str }) => {
|
|
224
|
+
handler: ({ path, old_str, new_str, replace_all }) => {
|
|
187
225
|
try {
|
|
226
|
+
if (old_str === new_str) {
|
|
227
|
+
return { content: `old_str and new_str are identical \u2014 nothing to change in ${path}.`, is_error: true };
|
|
228
|
+
}
|
|
188
229
|
const abs = confinePath(path);
|
|
189
230
|
const src = readFileSync3(abs, "utf-8");
|
|
190
231
|
const first = src.indexOf(old_str);
|
|
191
232
|
if (first === -1) {
|
|
192
|
-
return { content: `old_str not found in ${path}`, is_error: true };
|
|
233
|
+
return { content: `old_str not found in ${path}.${nearMiss(src, old_str)}`, is_error: true };
|
|
193
234
|
}
|
|
194
|
-
|
|
195
|
-
|
|
235
|
+
const all = replace_all === true;
|
|
236
|
+
if (!all && src.indexOf(old_str, first + 1) !== -1) {
|
|
237
|
+
return {
|
|
238
|
+
content: `old_str not unique in ${path}. Add surrounding context to disambiguate, or set replace_all.`,
|
|
239
|
+
is_error: true
|
|
240
|
+
};
|
|
196
241
|
}
|
|
197
|
-
|
|
198
|
-
|
|
242
|
+
const out = all ? src.split(old_str).join(new_str) : src.slice(0, first) + new_str + src.slice(first + old_str.length);
|
|
243
|
+
const n = all ? src.split(old_str).length - 1 : 1;
|
|
244
|
+
writeFileSync3(abs, out, "utf-8");
|
|
245
|
+
return { content: `Edited ${path}${all ? ` (${n} occurrences)` : ""}` };
|
|
199
246
|
} catch (err) {
|
|
200
247
|
return { content: err instanceof Error ? err.message : String(err), is_error: true };
|
|
201
248
|
}
|
|
@@ -206,6 +253,10 @@ var init_edit_file = __esm({
|
|
|
206
253
|
|
|
207
254
|
// src/tools/read_file.ts
|
|
208
255
|
import { readFileSync as readFileSync4 } from "fs";
|
|
256
|
+
function numbered(lines, start) {
|
|
257
|
+
const width = String(start + lines.length - 1).length;
|
|
258
|
+
return lines.map((l, i) => `${String(start + i).padStart(width, " ")} ${l}`).join("\n");
|
|
259
|
+
}
|
|
209
260
|
var read_file;
|
|
210
261
|
var init_read_file = __esm({
|
|
211
262
|
"src/tools/read_file.ts"() {
|
|
@@ -213,21 +264,40 @@ var init_read_file = __esm({
|
|
|
213
264
|
init_paths();
|
|
214
265
|
read_file = {
|
|
215
266
|
name: "read_file",
|
|
216
|
-
description: "Read
|
|
267
|
+
description: "Read file contents as UTF-8 text with line numbers. Use offset/limit to read a range of a large file instead of the whole thing.",
|
|
217
268
|
input_schema: {
|
|
218
269
|
type: "object",
|
|
219
270
|
properties: {
|
|
220
|
-
path: { type: "string", description: "File path" }
|
|
271
|
+
path: { type: "string", description: "File path" },
|
|
272
|
+
offset: { type: "number", description: "1-based line to start from (default 1)" },
|
|
273
|
+
limit: { type: "number", description: "Max lines to return (default all / capped)" }
|
|
221
274
|
},
|
|
222
275
|
required: ["path"]
|
|
223
276
|
},
|
|
224
|
-
handler: ({ path }) => {
|
|
277
|
+
handler: ({ path, offset, limit }) => {
|
|
225
278
|
try {
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
279
|
+
const MAX_CHARS = 2e5;
|
|
280
|
+
const buf = readFileSync4(confinePath(path));
|
|
281
|
+
if (buf.subarray(0, 8e3).includes(0)) {
|
|
282
|
+
return { content: `${path} looks binary (${buf.length} bytes); not reading as text.`, is_error: true };
|
|
283
|
+
}
|
|
284
|
+
const raw = buf.toString("utf-8").replace(/\r\n/g, "\n");
|
|
285
|
+
const allLines = raw.split("\n");
|
|
286
|
+
const total = allLines.length;
|
|
287
|
+
const start = Math.max(1, Math.floor(offset ?? 1));
|
|
288
|
+
const ranged = offset != null || limit != null;
|
|
289
|
+
const count = limit != null ? Math.max(0, Math.floor(limit)) : total;
|
|
290
|
+
const slice = allLines.slice(start - 1, start - 1 + count);
|
|
291
|
+
let body = numbered(slice, start);
|
|
292
|
+
if (body.length > MAX_CHARS) {
|
|
293
|
+
body = body.slice(0, MAX_CHARS) + `
|
|
294
|
+
[truncated: output exceeded ${MAX_CHARS} chars \u2014 use offset/limit]`;
|
|
295
|
+
}
|
|
296
|
+
if (ranged) {
|
|
297
|
+
const end = start - 1 + slice.length;
|
|
298
|
+
body += `
|
|
299
|
+
[showing lines ${start}-${end} of ${total}]`;
|
|
300
|
+
}
|
|
231
301
|
return { content: body };
|
|
232
302
|
} catch (err) {
|
|
233
303
|
return { content: err instanceof Error ? err.message : String(err), is_error: true };
|
|
@@ -270,12 +340,63 @@ var init_write_file = __esm({
|
|
|
270
340
|
}
|
|
271
341
|
});
|
|
272
342
|
|
|
343
|
+
// src/tools/spill.ts
|
|
344
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, rmSync as rmSync2, readdirSync as readdirSync3, statSync } from "fs";
|
|
345
|
+
import { join as join5 } from "path";
|
|
346
|
+
import { homedir as homedir4 } from "os";
|
|
347
|
+
import { randomBytes } from "crypto";
|
|
348
|
+
function ensureDir() {
|
|
349
|
+
mkdirSync4(OUTPUT_DIR, { recursive: true });
|
|
350
|
+
return OUTPUT_DIR;
|
|
351
|
+
}
|
|
352
|
+
function spillIfLarge(full, label = "output", budget = INLINE_BUDGET) {
|
|
353
|
+
if (full.length <= budget) return full;
|
|
354
|
+
const id = randomBytes(6).toString("hex");
|
|
355
|
+
const file = join5(ensureDir(), `${id}.txt`);
|
|
356
|
+
let path = file;
|
|
357
|
+
try {
|
|
358
|
+
writeFileSync5(file, full, "utf-8");
|
|
359
|
+
} catch {
|
|
360
|
+
path = "";
|
|
361
|
+
}
|
|
362
|
+
const head = Math.floor(budget * HEAD_FRACTION);
|
|
363
|
+
const tail = budget - head;
|
|
364
|
+
const totalLines = full.split("\n").length;
|
|
365
|
+
const preview = full.slice(0, head) + "\n\u2026\n" + full.slice(-tail);
|
|
366
|
+
const notice = path ? `[${label} truncated: ${totalLines} lines / ${full.length} bytes. Full output at ${path} \u2014 read it with read_file offset/limit to see the elided middle.]` : `[${label} truncated to ${budget} bytes; spill to disk failed, middle is lost.]`;
|
|
367
|
+
return `${preview}
|
|
368
|
+
${notice}`;
|
|
369
|
+
}
|
|
370
|
+
function cleanupSpill(maxAgeMs = 24 * 60 * 60 * 1e3) {
|
|
371
|
+
try {
|
|
372
|
+
const now = Date.now();
|
|
373
|
+
for (const name of readdirSync3(OUTPUT_DIR)) {
|
|
374
|
+
const f = join5(OUTPUT_DIR, name);
|
|
375
|
+
try {
|
|
376
|
+
if (now - statSync(f).mtimeMs > maxAgeMs) rmSync2(f, { force: true });
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
var OUTPUT_DIR, INLINE_BUDGET, HEAD_FRACTION;
|
|
384
|
+
var init_spill = __esm({
|
|
385
|
+
"src/tools/spill.ts"() {
|
|
386
|
+
"use strict";
|
|
387
|
+
OUTPUT_DIR = join5(homedir4(), ".miii", "output");
|
|
388
|
+
INLINE_BUDGET = 1e4;
|
|
389
|
+
HEAD_FRACTION = 0.3;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
273
393
|
// src/tools/run_bash.ts
|
|
274
394
|
import { execa } from "execa";
|
|
275
395
|
var run_bash;
|
|
276
396
|
var init_run_bash = __esm({
|
|
277
397
|
"src/tools/run_bash.ts"() {
|
|
278
398
|
"use strict";
|
|
399
|
+
init_spill();
|
|
279
400
|
run_bash = {
|
|
280
401
|
name: "run_bash",
|
|
281
402
|
description: "Execute a shell command (bash on Unix, cmd on Windows). Returns stdout+stderr. Non-interactive only.",
|
|
@@ -300,10 +421,10 @@ var init_run_bash = __esm({
|
|
|
300
421
|
const out = [stdout, stderr].filter(Boolean).join("\n");
|
|
301
422
|
const is_error = exitCode !== 0;
|
|
302
423
|
const body = out || (is_error ? `(no output)` : "");
|
|
303
|
-
const content = `${body}
|
|
424
|
+
const content = `${spillIfLarge(body, "command output")}
|
|
304
425
|
[exit ${exitCode}]`;
|
|
305
426
|
return {
|
|
306
|
-
content
|
|
427
|
+
content,
|
|
307
428
|
is_error
|
|
308
429
|
};
|
|
309
430
|
} catch (err) {
|
|
@@ -329,7 +450,7 @@ var init_grep = __esm({
|
|
|
329
450
|
pattern: { type: "string", description: "Regex pattern" },
|
|
330
451
|
path: { type: "string", description: "Root path to search (default cwd)" },
|
|
331
452
|
glob: { type: "string", description: 'File glob filter, e.g. "*.ts"' },
|
|
332
|
-
case_insensitive: { type: "
|
|
453
|
+
case_insensitive: { type: "boolean", description: "Case-insensitive match" },
|
|
333
454
|
max_results: { type: "number", description: "Max matching lines (default 200)" }
|
|
334
455
|
},
|
|
335
456
|
required: ["pattern"]
|
|
@@ -377,8 +498,25 @@ var init_grep = __esm({
|
|
|
377
498
|
|
|
378
499
|
// src/tools/glob.ts
|
|
379
500
|
import { execa as execa3 } from "execa";
|
|
380
|
-
|
|
381
|
-
|
|
501
|
+
import { statSync as statSync2 } from "fs";
|
|
502
|
+
function byMtimeDesc(paths) {
|
|
503
|
+
const mtime = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const p of paths) {
|
|
505
|
+
try {
|
|
506
|
+
mtime.set(p, statSync2(p).mtimeMs);
|
|
507
|
+
} catch {
|
|
508
|
+
mtime.set(p, 0);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return [...paths].sort((a, b) => (mtime.get(b) ?? 0) - (mtime.get(a) ?? 0));
|
|
512
|
+
}
|
|
513
|
+
function globToFindArgs(root, glob2) {
|
|
514
|
+
const stripped = glob2.replace(/^\*\*\//, "");
|
|
515
|
+
if (!stripped.includes("/")) {
|
|
516
|
+
return [root, "-type", "f", "-name", stripped];
|
|
517
|
+
}
|
|
518
|
+
const pathPat = "*/" + glob2.replace(/\*\*/g, "*");
|
|
519
|
+
return [root, "-type", "f", "-path", pathPat];
|
|
382
520
|
}
|
|
383
521
|
var glob;
|
|
384
522
|
var init_glob = __esm({
|
|
@@ -403,13 +541,10 @@ var init_glob = __esm({
|
|
|
403
541
|
reject: false,
|
|
404
542
|
timeout: 2e4
|
|
405
543
|
});
|
|
406
|
-
const tryFind = () => {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
timeout: 2e4
|
|
411
|
-
});
|
|
412
|
-
};
|
|
544
|
+
const tryFind = () => execa3("find", globToFindArgs(root, pattern), {
|
|
545
|
+
reject: false,
|
|
546
|
+
timeout: 2e4
|
|
547
|
+
});
|
|
413
548
|
try {
|
|
414
549
|
let res;
|
|
415
550
|
try {
|
|
@@ -420,8 +555,9 @@ var init_glob = __esm({
|
|
|
420
555
|
} catch {
|
|
421
556
|
res = await tryFind();
|
|
422
557
|
}
|
|
423
|
-
const
|
|
424
|
-
if (
|
|
558
|
+
const all = (res.stdout ?? "").split("\n").filter(Boolean);
|
|
559
|
+
if (all.length === 0) return { content: "No files matched." };
|
|
560
|
+
const lines = byMtimeDesc(all).slice(0, limit);
|
|
425
561
|
return { content: lines.join("\n") };
|
|
426
562
|
} catch (err) {
|
|
427
563
|
return { content: err instanceof Error ? err.message : String(err), is_error: true };
|
|
@@ -576,10 +712,14 @@ ${toolLines}
|
|
|
576
712
|
# Rules
|
|
577
713
|
- Always read a file before updating it. Never edit, overwrite, or create-over a file you have not read first this turn.
|
|
578
714
|
- Prefer editing existing files over creating new ones.
|
|
579
|
-
- For edit_file,
|
|
715
|
+
- For edit_file, make old_str unique by including surrounding context, or set replace_all to change every occurrence.
|
|
580
716
|
- Never invent file paths. Read, glob, or grep before editing.
|
|
581
717
|
- No filler, no pleasantries, no apologies.
|
|
582
718
|
|
|
719
|
+
# Context discipline
|
|
720
|
+
- read_file returns line numbers and accepts offset/limit. For large files, grep or glob to the relevant region first, then read only that range with offset/limit. Do not read a whole large file when you need a few functions \u2014 it wastes the context window.
|
|
721
|
+
- Reference code by the line numbers read_file returns.
|
|
722
|
+
|
|
583
723
|
# Testing and verification
|
|
584
724
|
- Always test the code after a change. Run the project's tests (e.g. npm test, pytest, go test) or the relevant script via run_bash before declaring a task done.
|
|
585
725
|
- If no test exists for the change, run the affected entry point via run_bash to verify it behaves correctly.
|
|
@@ -597,9 +737,9 @@ var init_system = __esm({
|
|
|
597
737
|
});
|
|
598
738
|
|
|
599
739
|
// src/permissions/policy.ts
|
|
600
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
601
|
-
import { join as
|
|
602
|
-
import { homedir as
|
|
740
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync3, renameSync } from "fs";
|
|
741
|
+
import { join as join6 } from "path";
|
|
742
|
+
import { homedir as homedir5 } from "os";
|
|
603
743
|
function loadRules() {
|
|
604
744
|
if (!existsSync3(RULES_PATH)) return [];
|
|
605
745
|
try {
|
|
@@ -610,9 +750,9 @@ function loadRules() {
|
|
|
610
750
|
}
|
|
611
751
|
}
|
|
612
752
|
function saveRules(rules) {
|
|
613
|
-
|
|
753
|
+
mkdirSync5(RULES_DIR, { recursive: true });
|
|
614
754
|
const tmp = RULES_PATH + ".tmp";
|
|
615
|
-
|
|
755
|
+
writeFileSync6(tmp, JSON.stringify({ rules }, null, 2), "utf-8");
|
|
616
756
|
renameSync(tmp, RULES_PATH);
|
|
617
757
|
}
|
|
618
758
|
function addRule(tool, pattern) {
|
|
@@ -654,8 +794,8 @@ var RULES_DIR, RULES_PATH, ALWAYS_ALLOW;
|
|
|
654
794
|
var init_policy = __esm({
|
|
655
795
|
"src/permissions/policy.ts"() {
|
|
656
796
|
"use strict";
|
|
657
|
-
RULES_DIR =
|
|
658
|
-
RULES_PATH =
|
|
797
|
+
RULES_DIR = join6(homedir5(), ".miii");
|
|
798
|
+
RULES_PATH = join6(RULES_DIR, "permissions.json");
|
|
659
799
|
ALWAYS_ALLOW = /* @__PURE__ */ new Set(["read_file", "grep", "glob"]);
|
|
660
800
|
}
|
|
661
801
|
});
|
|
@@ -985,16 +1125,16 @@ var init_loop = __esm({
|
|
|
985
1125
|
});
|
|
986
1126
|
|
|
987
1127
|
// eval/runner.ts
|
|
988
|
-
import { mkdtempSync, writeFileSync as
|
|
989
|
-
import { dirname as dirname2, join as
|
|
1128
|
+
import { mkdtempSync, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, rmSync as rmSync3 } from "fs";
|
|
1129
|
+
import { dirname as dirname2, join as join7 } from "path";
|
|
990
1130
|
import { tmpdir } from "os";
|
|
991
1131
|
async function runScenario(model, s) {
|
|
992
|
-
const dir = mkdtempSync(
|
|
1132
|
+
const dir = mkdtempSync(join7(tmpdir(), "miii-eval-"));
|
|
993
1133
|
const prevCwd = process.cwd();
|
|
994
1134
|
for (const [rel, content] of Object.entries(s.files ?? {})) {
|
|
995
|
-
const abs =
|
|
996
|
-
|
|
997
|
-
|
|
1135
|
+
const abs = join7(dir, rel);
|
|
1136
|
+
mkdirSync6(dirname2(abs), { recursive: true });
|
|
1137
|
+
writeFileSync7(abs, content, "utf-8");
|
|
998
1138
|
}
|
|
999
1139
|
const r = {
|
|
1000
1140
|
name: s.name,
|
|
@@ -1032,7 +1172,7 @@ async function runScenario(model, s) {
|
|
|
1032
1172
|
r.durationMs = Date.now() - start;
|
|
1033
1173
|
if (r.error) {
|
|
1034
1174
|
r.reason = `loop error: ${r.error}`;
|
|
1035
|
-
|
|
1175
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
1036
1176
|
return r;
|
|
1037
1177
|
}
|
|
1038
1178
|
try {
|
|
@@ -1042,7 +1182,7 @@ async function runScenario(model, s) {
|
|
|
1042
1182
|
} catch (err) {
|
|
1043
1183
|
r.reason = `check threw: ${err instanceof Error ? err.message : String(err)}`;
|
|
1044
1184
|
}
|
|
1045
|
-
|
|
1185
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
1046
1186
|
return r;
|
|
1047
1187
|
}
|
|
1048
1188
|
var autoYes;
|
|
@@ -1056,12 +1196,12 @@ var init_runner = __esm({
|
|
|
1056
1196
|
|
|
1057
1197
|
// eval/scenarios.ts
|
|
1058
1198
|
import { readFileSync as readFileSync6, existsSync as existsSync4 } from "fs";
|
|
1059
|
-
import { join as
|
|
1199
|
+
import { join as join8 } from "path";
|
|
1060
1200
|
var read, scenarios;
|
|
1061
1201
|
var init_scenarios = __esm({
|
|
1062
1202
|
"eval/scenarios.ts"() {
|
|
1063
1203
|
"use strict";
|
|
1064
|
-
read = (dir, f) => existsSync4(
|
|
1204
|
+
read = (dir, f) => existsSync4(join8(dir, f)) ? readFileSync6(join8(dir, f), "utf-8") : null;
|
|
1065
1205
|
scenarios = [
|
|
1066
1206
|
{
|
|
1067
1207
|
name: "edit-exact-string",
|
|
@@ -1210,7 +1350,7 @@ import { createElement } from "react";
|
|
|
1210
1350
|
init_client();
|
|
1211
1351
|
import { useState as useState4, useEffect as useEffect3 } from "react";
|
|
1212
1352
|
import { Box as Box10, Text as Text10, useApp } from "ink";
|
|
1213
|
-
import { homedir as
|
|
1353
|
+
import { homedir as homedir6 } from "os";
|
|
1214
1354
|
import { sep as sep2 } from "path";
|
|
1215
1355
|
|
|
1216
1356
|
// src/config.ts
|
|
@@ -2497,7 +2637,7 @@ async function checkForUpdate() {
|
|
|
2497
2637
|
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2498
2638
|
function App() {
|
|
2499
2639
|
const { exit } = useApp();
|
|
2500
|
-
const cwd = process.cwd().replace(
|
|
2640
|
+
const cwd = process.cwd().replace(homedir6(), "~").split(sep2).join("/");
|
|
2501
2641
|
const [cfg, setCfg] = useState4(loadConfig());
|
|
2502
2642
|
const [models, setModels] = useState4([]);
|
|
2503
2643
|
const [contexts, setContexts] = useState4({});
|
|
@@ -2635,6 +2775,8 @@ function App() {
|
|
|
2635
2775
|
}
|
|
2636
2776
|
|
|
2637
2777
|
// src/cli.tsx
|
|
2778
|
+
init_spill();
|
|
2779
|
+
cleanupSpill();
|
|
2638
2780
|
var [, , cmd, ...rest] = process.argv;
|
|
2639
2781
|
if (cmd === "update" || cmd === "--update" || cmd === "-u") {
|
|
2640
2782
|
const { spawnSync } = await import("child_process");
|