@guangnao/agent-cli 1.1.6 → 1.1.7
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 +123 -27
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3413,7 +3413,7 @@ var shell = {
|
|
|
3413
3413
|
};
|
|
3414
3414
|
|
|
3415
3415
|
// src/tools/read_file.ts
|
|
3416
|
-
import { readFileSync
|
|
3416
|
+
import { readFileSync } from "node:fs";
|
|
3417
3417
|
|
|
3418
3418
|
// src/tools/file.ts
|
|
3419
3419
|
import { resolve, isAbsolute, relative } from "node:path";
|
|
@@ -3430,17 +3430,23 @@ function safePath(p) {
|
|
|
3430
3430
|
var MAX = 64 * 1024;
|
|
3431
3431
|
var readFile = {
|
|
3432
3432
|
name: "read_file",
|
|
3433
|
-
schema: { name: "read_file", description: "read a UTF-8 text file (confined to the launch dir)", parameters: { type: "object", required: ["path"], properties: {
|
|
3434
|
-
path: { type: "string", description: "file path, relative to the launch dir" }
|
|
3433
|
+
schema: { name: "read_file", description: "read a UTF-8 text file (confined to the launch dir). Large files page: pass `offset` (and the result\u2019s `nextOffset`) to read the rest.", parameters: { type: "object", required: ["path"], properties: {
|
|
3434
|
+
path: { type: "string", description: "file path, relative to the launch dir" },
|
|
3435
|
+
offset: { type: "number", description: "char index to start at (default 0); use the previous result\u2019s `nextOffset` to continue" },
|
|
3436
|
+
limit: { type: "number", description: `max chars to return (default & cap ${MAX})` }
|
|
3435
3437
|
} } },
|
|
3436
3438
|
run: (i) => {
|
|
3437
|
-
const { path } = i;
|
|
3439
|
+
const { path, offset, limit } = i;
|
|
3438
3440
|
const abs = safePath(path);
|
|
3439
3441
|
if (!abs) return { error: `path escapes the working directory: ${path}` };
|
|
3440
3442
|
try {
|
|
3441
|
-
const size = statSync(abs).size;
|
|
3442
3443
|
const content = readFileSync(abs, "utf8");
|
|
3443
|
-
|
|
3444
|
+
const total = content.length;
|
|
3445
|
+
const start = Math.max(0, Math.floor(offset ?? 0));
|
|
3446
|
+
if (start >= total) return total === 0 ? { path, content: "" } : { path, content: "", total, note: `offset ${start} is at/past end of file (${total} chars)` };
|
|
3447
|
+
const slice = content.slice(start, start + Math.min(limit ?? MAX, MAX));
|
|
3448
|
+
const end = start + slice.length;
|
|
3449
|
+
return end < total ? { path, content: slice, truncated: true, total, offset: start, nextOffset: end, note: `showing chars ${start}\u2013${end} of ${total}; call read_file again with offset=${end} for the rest` } : { path, content: slice, ...start > 0 ? { offset: start, total } : {} };
|
|
3444
3450
|
} catch (e) {
|
|
3445
3451
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
3446
3452
|
}
|
|
@@ -3470,7 +3476,7 @@ var listDir = {
|
|
|
3470
3476
|
};
|
|
3471
3477
|
|
|
3472
3478
|
// src/tools/grep.ts
|
|
3473
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync2, statSync
|
|
3479
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
3474
3480
|
import { join } from "node:path";
|
|
3475
3481
|
var SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "coverage", ".cache"]);
|
|
3476
3482
|
var MAX_HITS = 100;
|
|
@@ -3509,7 +3515,7 @@ var grep = {
|
|
|
3509
3515
|
const rootLen = base().length + 1;
|
|
3510
3516
|
for (const f of walk(root)) {
|
|
3511
3517
|
try {
|
|
3512
|
-
if (
|
|
3518
|
+
if (statSync(f).size > MAX_FILE) continue;
|
|
3513
3519
|
} catch {
|
|
3514
3520
|
continue;
|
|
3515
3521
|
}
|
|
@@ -5436,13 +5442,99 @@ function nursery(sys) {
|
|
|
5436
5442
|
};
|
|
5437
5443
|
}
|
|
5438
5444
|
|
|
5445
|
+
// ../agent-os/src/kernel/blob.ts
|
|
5446
|
+
var PAGE = 8 * 1024;
|
|
5447
|
+
var GREP_MAX = 50;
|
|
5448
|
+
var BlobStore = class {
|
|
5449
|
+
constructor(cap = 4 * 1024 * 1024) {
|
|
5450
|
+
this.cap = cap;
|
|
5451
|
+
}
|
|
5452
|
+
cap;
|
|
5453
|
+
map = /* @__PURE__ */ new Map();
|
|
5454
|
+
// insertion order = LRU age (re-set on touch → newest)
|
|
5455
|
+
seq = 0;
|
|
5456
|
+
bytes = 0;
|
|
5457
|
+
// 4 MB total
|
|
5458
|
+
/** Store content; return a fresh handle. Evict the oldest blobs while over the char cap. */
|
|
5459
|
+
put(content) {
|
|
5460
|
+
const handle = `blob_${(++this.seq).toString(36)}`;
|
|
5461
|
+
this.map.set(handle, content);
|
|
5462
|
+
this.bytes += content.length;
|
|
5463
|
+
while (this.bytes > this.cap && this.map.size > 1) {
|
|
5464
|
+
const [old, v] = this.map.entries().next().value;
|
|
5465
|
+
this.map.delete(old);
|
|
5466
|
+
this.bytes -= v.length;
|
|
5467
|
+
}
|
|
5468
|
+
return handle;
|
|
5469
|
+
}
|
|
5470
|
+
touch(handle) {
|
|
5471
|
+
const v = this.map.get(handle);
|
|
5472
|
+
if (v === void 0) return void 0;
|
|
5473
|
+
this.map.delete(handle);
|
|
5474
|
+
this.map.set(handle, v);
|
|
5475
|
+
return v;
|
|
5476
|
+
}
|
|
5477
|
+
/** A character window of a blob (paged like read_file). */
|
|
5478
|
+
read(handle, offset = 0, limit = PAGE) {
|
|
5479
|
+
const v = this.touch(handle);
|
|
5480
|
+
if (v === void 0) return { error: `unknown blob handle: ${handle}` };
|
|
5481
|
+
const total = v.length;
|
|
5482
|
+
const start = Math.max(0, Math.floor(offset));
|
|
5483
|
+
if (start >= total) return { handle, content: "", total, note: `offset ${start} is at/past end (${total} chars)` };
|
|
5484
|
+
const slice = v.slice(start, start + Math.min(Math.max(1, Math.floor(limit)), PAGE));
|
|
5485
|
+
const end = start + slice.length;
|
|
5486
|
+
return end < total ? { handle, content: slice, truncated: true, total, offset: start, nextOffset: end, note: `chars ${start}\u2013${end} of ${total}; call blob_read with offset=${end} for more` } : { handle, content: slice, total, offset: start };
|
|
5487
|
+
}
|
|
5488
|
+
/** Search a blob for a JS regex; return a short SNIPPET (char offset + surrounding window) per match. Snippet
|
|
5489
|
+
* rather than whole line because a blob is often one long line (JSON.stringify escapes newlines) — a line view
|
|
5490
|
+
* would return the entire blob and just overflow again. The offset lets the model blob_read around it. */
|
|
5491
|
+
grep(handle, pattern, max = GREP_MAX) {
|
|
5492
|
+
const v = this.touch(handle);
|
|
5493
|
+
if (v === void 0) return { error: `unknown blob handle: ${handle}` };
|
|
5494
|
+
let re;
|
|
5495
|
+
try {
|
|
5496
|
+
re = new RegExp(pattern, "g");
|
|
5497
|
+
} catch {
|
|
5498
|
+
return { error: `invalid pattern: ${pattern}` };
|
|
5499
|
+
}
|
|
5500
|
+
const PAD = 80, matches = [];
|
|
5501
|
+
let m;
|
|
5502
|
+
while ((m = re.exec(v)) && matches.length < max) {
|
|
5503
|
+
const at = m.index, from = Math.max(0, at - PAD), to = Math.min(v.length, at + m[0].length + PAD);
|
|
5504
|
+
matches.push(`@${at}: ${from > 0 ? "\u2026" : ""}${v.slice(from, to)}${to < v.length ? "\u2026" : ""}`);
|
|
5505
|
+
if (re.lastIndex === at) re.lastIndex++;
|
|
5506
|
+
}
|
|
5507
|
+
return { handle, total: v.length, matches, ...matches.length >= max ? { truncated: true } : {} };
|
|
5508
|
+
}
|
|
5509
|
+
};
|
|
5510
|
+
var BLOB_TOOLS = [
|
|
5511
|
+
{ name: "blob_read", description: "read a window of a large stored tool output by its blob handle (paged like read_file; use when a result said it was stored as blob_\u2026)", parameters: { type: "object", required: ["handle"], properties: {
|
|
5512
|
+
handle: { type: "string", description: "the blob_\u2026 handle from a truncated result" },
|
|
5513
|
+
offset: { type: "number", description: "char index to start at (default 0; use the previous result\u2019s nextOffset)" },
|
|
5514
|
+
limit: { type: "number", description: `max chars (default & cap ${PAGE})` }
|
|
5515
|
+
} } },
|
|
5516
|
+
{ name: "blob_grep", description: "find lines matching a JS regex inside a large stored tool output, by blob handle (search without re-reading it all)", parameters: { type: "object", required: ["handle", "pattern"], properties: {
|
|
5517
|
+
handle: { type: "string", description: "the blob_\u2026 handle" },
|
|
5518
|
+
pattern: { type: "string", description: "JS regex, matched per line" }
|
|
5519
|
+
} } }
|
|
5520
|
+
];
|
|
5521
|
+
var BLOB_NAMES = new Set(BLOB_TOOLS.map((t) => t.name));
|
|
5522
|
+
var isBlobTool = (name) => BLOB_NAMES.has(name);
|
|
5523
|
+
function execBlobTool(store, name, input) {
|
|
5524
|
+
const a = input ?? {};
|
|
5525
|
+
if (!a.handle) return { error: "handle is required" };
|
|
5526
|
+
if (name === "blob_read") return store.read(a.handle, a.offset, a.limit);
|
|
5527
|
+
if (name === "blob_grep") return a.pattern ? store.grep(a.handle, a.pattern) : { error: "pattern is required" };
|
|
5528
|
+
return { error: `not a blob tool: ${name}` };
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5439
5531
|
// ../agent-os/src/userland/agent.ts
|
|
5440
5532
|
var DEFAULT_SYSTEM = "You are a capable autonomous agent. Break the task into steps and keep going \u2014 investigate with tools, then act \u2014 until it is fully done; never stop at a plan or a partial result. Verify before answering, then reply concisely.";
|
|
5441
5533
|
var HARD_MAX = 384;
|
|
5442
5534
|
var MAX_TOOL_CHARS = 8e3;
|
|
5443
5535
|
var isMessage = (b) => !!b && typeof b.role === "string";
|
|
5444
|
-
var capResult = (s) => s.length
|
|
5445
|
-
\u2026[
|
|
5536
|
+
var capResult = (s, blobs) => s.length <= MAX_TOOL_CHARS ? s : s.slice(0, MAX_TOOL_CHARS) + `
|
|
5537
|
+
\u2026[+${s.length - MAX_TOOL_CHARS} chars \u2014 full result stored as ${blobs.put(s)}; call blob_read(handle, offset=${MAX_TOOL_CHARS}) or blob_grep(handle, pattern) for the rest]`;
|
|
5446
5538
|
function orderForCache(segs) {
|
|
5447
5539
|
const lead = [], sums = [], rest = [];
|
|
5448
5540
|
for (const s of segs) (s.pinned && !s.summary ? lead : s.summary ? sums : rest).push(s);
|
|
@@ -5470,7 +5562,7 @@ function unproductive(out) {
|
|
|
5470
5562
|
const st = o["status"];
|
|
5471
5563
|
return typeof st === "number" && (st < 200 || st >= 300);
|
|
5472
5564
|
}
|
|
5473
|
-
async function runTurn(sys, llm, tools2, spec) {
|
|
5565
|
+
async function runTurn(sys, llm, tools2, spec, blobs) {
|
|
5474
5566
|
const ceil = Math.max(1, Math.min(spec.maxSteps ?? HARD_MAX, HARD_MAX));
|
|
5475
5567
|
const base2 = Math.max(1, spec.baseSteps ?? 16);
|
|
5476
5568
|
const stallMax = Math.max(1, spec.stallLimit ?? 3);
|
|
@@ -5493,6 +5585,7 @@ async function runTurn(sys, llm, tools2, spec) {
|
|
|
5493
5585
|
}
|
|
5494
5586
|
const messages = promptMessages();
|
|
5495
5587
|
let offer = noTools ? void 0 : spec.tools;
|
|
5588
|
+
if (offer && tools2) offer = [...offer, ...BLOB_TOOLS];
|
|
5496
5589
|
if (steer && offer && del) offer = offer.filter((t) => !del.withhold.includes(t.name));
|
|
5497
5590
|
const reply = await sys.read(llm, { messages, tools: offer, maxTokens: spec.maxTokens });
|
|
5498
5591
|
for (const s of sys.workingSet()) {
|
|
@@ -5513,13 +5606,15 @@ async function runTurn(sys, llm, tools2, spec) {
|
|
|
5513
5606
|
}
|
|
5514
5607
|
}
|
|
5515
5608
|
if (fresh.length) {
|
|
5516
|
-
const
|
|
5517
|
-
|
|
5609
|
+
const viaDevice = fresh.filter((f) => !isBlobTool(f.req.tool));
|
|
5610
|
+
const devOuts = viaDevice.length ? await sys.readAll(tools2, viaDevice.map((f) => f.req)) : [];
|
|
5611
|
+
let di = 0;
|
|
5612
|
+
for (const f of fresh) cache.set(f.key, isBlobTool(f.req.tool) ? execBlobTool(blobs, f.req.tool, f.req.input) : devOuts[di++]);
|
|
5518
5613
|
}
|
|
5519
5614
|
let progressed = false;
|
|
5520
5615
|
for (let i = 0; i < calls.length; i++) {
|
|
5521
5616
|
const out = cache.get(keys[i]);
|
|
5522
|
-
await sys.remember({ role: "tool", toolCallId: calls[i].id, name: calls[i].name, content: capResult(JSON.stringify(out)) });
|
|
5617
|
+
await sys.remember({ role: "tool", toolCallId: calls[i].id, name: calls[i].name, content: capResult(JSON.stringify(out), blobs) });
|
|
5523
5618
|
if (ran.has(keys[i]) && !unproductive(out)) progressed = true;
|
|
5524
5619
|
}
|
|
5525
5620
|
if (del) {
|
|
@@ -5570,7 +5665,7 @@ function reactAgent(spec) {
|
|
|
5570
5665
|
const { llm, tools: tools2, parent } = await openDevices(sys);
|
|
5571
5666
|
await sys.remember({ role: "system", content: spec.system ?? DEFAULT_SYSTEM }, { pin: true });
|
|
5572
5667
|
await sys.remember({ role: "user", content: spec.task ?? "" }, { pin: true });
|
|
5573
|
-
const r = await runTurn(sys, llm, tools2, spec);
|
|
5668
|
+
const r = await runTurn(sys, llm, tools2, spec, new BlobStore());
|
|
5574
5669
|
if (parent) await sys.send(parent, { $: "result", answer: r.answer, steps: r.steps });
|
|
5575
5670
|
} };
|
|
5576
5671
|
}
|
|
@@ -5588,13 +5683,14 @@ function conversationAgent(spec = {}) {
|
|
|
5588
5683
|
} else {
|
|
5589
5684
|
await sys.remember({ role: "system", content: spec.system ?? DEFAULT_SYSTEM }, { pin: true });
|
|
5590
5685
|
}
|
|
5686
|
+
const blobs = new BlobStore();
|
|
5591
5687
|
for (; ; ) {
|
|
5592
5688
|
const msg = await sys.recv();
|
|
5593
5689
|
const userTurn = { role: "user", content: msg.body.task, ...msg.body.images?.length ? { images: msg.body.images } : {} };
|
|
5594
5690
|
await sys.remember(userTurn);
|
|
5595
5691
|
let r;
|
|
5596
5692
|
try {
|
|
5597
|
-
r = await runTurn(sys, llm, tools2, spec);
|
|
5693
|
+
r = await runTurn(sys, llm, tools2, spec, blobs);
|
|
5598
5694
|
} catch (e) {
|
|
5599
5695
|
r = { answer: "", steps: 0, error: e instanceof Error ? e.message : String(e) };
|
|
5600
5696
|
}
|
|
@@ -6037,7 +6133,7 @@ import { homedir } from "node:os";
|
|
|
6037
6133
|
import { join as join3 } from "node:path";
|
|
6038
6134
|
|
|
6039
6135
|
// src/skills/loader.ts
|
|
6040
|
-
import { readdirSync as readdirSync3, readFileSync as readFileSync6, existsSync as existsSync4, statSync as
|
|
6136
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync6, existsSync as existsSync4, statSync as statSync2, openSync, readSync, closeSync } from "node:fs";
|
|
6041
6137
|
import { join as join2, basename, extname } from "node:path";
|
|
6042
6138
|
var FM_RE = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
6043
6139
|
var HEAD_BYTES = 8192;
|
|
@@ -6083,7 +6179,7 @@ function loadSkillsDir(dir) {
|
|
|
6083
6179
|
for (const entry of readdirSync3(dir)) {
|
|
6084
6180
|
try {
|
|
6085
6181
|
const p = join2(dir, entry);
|
|
6086
|
-
if (
|
|
6182
|
+
if (statSync2(p).isDirectory()) {
|
|
6087
6183
|
const md = join2(p, "SKILL.md");
|
|
6088
6184
|
if (existsSync4(md)) out.push(lazyFromFile(md, entry));
|
|
6089
6185
|
} else if (extname(entry) === ".md") out.push(lazyFromFile(p, basename(entry, ".md")));
|
|
@@ -9910,7 +10006,7 @@ function codingReflect(plan) {
|
|
|
9910
10006
|
}
|
|
9911
10007
|
|
|
9912
10008
|
// src/agent/session.ts
|
|
9913
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5, statSync as
|
|
10009
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5, statSync as statSync3, renameSync as renameSync2, unlinkSync as unlinkSync3 } from "node:fs";
|
|
9914
10010
|
import { homedir as homedir3 } from "node:os";
|
|
9915
10011
|
import { join as join7 } from "node:path";
|
|
9916
10012
|
var oneLine = (s) => typeof s === "string" ? s.replace(/\s+/g, " ").trim() : "";
|
|
@@ -9968,7 +10064,7 @@ function sessionIdsByRecency() {
|
|
|
9968
10064
|
if (!existsSync8(dir)) return [];
|
|
9969
10065
|
return readdirSync5(dir).filter((f) => f.endsWith(".json")).map((f) => {
|
|
9970
10066
|
try {
|
|
9971
|
-
return { id: f.slice(0, -5), mt:
|
|
10067
|
+
return { id: f.slice(0, -5), mt: statSync3(join7(dir, f)).mtimeMs };
|
|
9972
10068
|
} catch {
|
|
9973
10069
|
return { id: f.slice(0, -5), mt: 0 };
|
|
9974
10070
|
}
|
|
@@ -9982,12 +10078,12 @@ function loadSessionMeta(id) {
|
|
|
9982
10078
|
// src/ui/app.ts
|
|
9983
10079
|
import { resolve as resolve3, join as join11 } from "node:path";
|
|
9984
10080
|
import { homedir as homedir6, tmpdir as tmpdir3 } from "node:os";
|
|
9985
|
-
import { statSync as
|
|
10081
|
+
import { statSync as statSync5, readFileSync as readFileSync14, unlinkSync as unlinkSync6 } from "node:fs";
|
|
9986
10082
|
|
|
9987
10083
|
// package.json
|
|
9988
10084
|
var package_default = {
|
|
9989
10085
|
name: "@guangnao/agent-cli",
|
|
9990
|
-
version: "1.1.
|
|
10086
|
+
version: "1.1.7",
|
|
9991
10087
|
description: "AgentOS terminal CLI \u2014 drive a real LLM agent on the microkernel; strongest-UX shell, advanced agent core",
|
|
9992
10088
|
type: "module",
|
|
9993
10089
|
bin: {
|
|
@@ -10145,7 +10241,7 @@ var modeLabel = (m) => m === "auto" ? "auto" : m === "acceptEdits" ? "auto-edits
|
|
|
10145
10241
|
|
|
10146
10242
|
// src/ui/clipboard.ts
|
|
10147
10243
|
import { execFile } from "node:child_process";
|
|
10148
|
-
import { existsSync as existsSync10, readFileSync as readFileSync12, statSync as
|
|
10244
|
+
import { existsSync as existsSync10, readFileSync as readFileSync12, statSync as statSync4, unlinkSync as unlinkSync5 } from "node:fs";
|
|
10149
10245
|
import { tmpdir } from "node:os";
|
|
10150
10246
|
import { join as join9 } from "node:path";
|
|
10151
10247
|
var MACOS_JXA = `(function(){
|
|
@@ -10249,7 +10345,7 @@ async function shrinkImage(src) {
|
|
|
10249
10345
|
const maxEdge = dims ? Math.max(dims.w, dims.h) : Infinity;
|
|
10250
10346
|
let origBytes = Infinity;
|
|
10251
10347
|
try {
|
|
10252
|
-
origBytes =
|
|
10348
|
+
origBytes = statSync4(src).size;
|
|
10253
10349
|
} catch {
|
|
10254
10350
|
}
|
|
10255
10351
|
if (maxEdge <= MAX_EDGE && origBytes <= PASSTHROUGH_BYTES) return fallback;
|
|
@@ -10265,7 +10361,7 @@ async function shrinkImage(src) {
|
|
|
10265
10361
|
await sips([...resize, "-s", "format", "png", src, "--out", pngOut]);
|
|
10266
10362
|
let pngBytes = Infinity;
|
|
10267
10363
|
try {
|
|
10268
|
-
pngBytes =
|
|
10364
|
+
pngBytes = statSync4(pngOut).size;
|
|
10269
10365
|
} catch {
|
|
10270
10366
|
}
|
|
10271
10367
|
if (pngBytes > PNG_TO_JPEG_BYTES) {
|
|
@@ -11954,7 +12050,7 @@ ${c.done("\u2713")} ${c.dim("Saved connection cleared. Run ")}${c.bold("agentos"
|
|
|
11954
12050
|
static dirOk(d) {
|
|
11955
12051
|
if (!d) return false;
|
|
11956
12052
|
try {
|
|
11957
|
-
return
|
|
12053
|
+
return statSync5(d).isDirectory();
|
|
11958
12054
|
} catch {
|
|
11959
12055
|
return false;
|
|
11960
12056
|
}
|
|
@@ -11982,7 +12078,7 @@ ${c.dim("set: /cwd <path> \xB7 global default: /cwd -g <path>")}`);
|
|
|
11982
12078
|
const expanded = path === "~" || path.startsWith("~/") ? homedir6() + path.slice(1) : path;
|
|
11983
12079
|
const abs = resolve3(process.env["AGENTOS_CWD"] || process.cwd(), expanded);
|
|
11984
12080
|
try {
|
|
11985
|
-
if (!
|
|
12081
|
+
if (!statSync5(abs).isDirectory()) {
|
|
11986
12082
|
this.note(c.fail(`not a directory: ${abs}`));
|
|
11987
12083
|
return;
|
|
11988
12084
|
}
|