agent.libx.js 0.93.37 → 0.93.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +68 -14
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ agentx --resume <id> "…" # resume a specific session
|
|
|
117
117
|
- **Any provider** — set `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GOOGLE_API_KEY` / `GROQ_API_KEY`; choose with `-m provider/model`.
|
|
118
118
|
- **@-file mentions & headless JSON** — reference files inline in a prompt with `@path` (e.g. `explain @src/Agent.ts`); script with `-p --output-format json` to get one machine-readable result object on stdout (activity stays on stderr).
|
|
119
119
|
- **Tab-completion** — `Tab` completes `/<command>` names and `@<path>` file/dir references (descends subdirs, dotfiles hidden unless typed) straight from the working tree.
|
|
120
|
-
- **Duplex mode** — `agentx --duplex` runs the full standard REPL (slash commands, sessions, postures, rewind, MCP) with the
|
|
120
|
+
- **Duplex mode** — `agentx --duplex` runs the full standard REPL (slash commands, sessions, postures, rewind, MCP) with the three-tier engine driving turns: a fast voice model (`--voice-model`, default `groq/openai/gpt-oss-120b`) answers every line instantly and delegates real work to background workers built with the same wiring as a normal run (fs mode, permissions, MCP); worker activity shows as dim chrome and results are re-voiced when ready. Switch any tier live with `/model` (opens a reflex/act/think picker), or the `/voice-model` · `/think-model` shortcuts.
|
|
121
121
|
- **MCP servers** — declare `mcpServers: { name: { command, args } | { url } }` in config and they're auto-mounted at startup (in parallel, with an optional `mountTimeoutMs` deadline so one slow/dead server never blocks the rest): the client does the JSON-RPC handshake (stdio or HTTP) + `tools/list`, and the discovered tools appear as `mcp__<name>__<tool>` in `/tools` (inspect with `/mcp`). A bad server is logged and skipped, never blocking the agent. For large tool sets, **deferred mode** (`makeMcpToolSearch` / `mountMcpDeferred`) exposes just two bounded tools (`ToolSearch` + `McpCall`) instead of N defs — dodging the provider tool-cap and improving selection accuracy. **`mountMcpCatalog`** goes further: a cached, hash-keyed catalog + lazy connect means a turn that uses no MCP tool opens **zero** connections, and one that uses a tool connects exactly that server — latency scales with tools-used, not servers-configured. A down server is **negative-cached** (`failureCooldownMs`) so it never re-floors a later turn at the deadline. For zero turn-path latency even on a cold process, call **`warmMcpCatalog`** at boot + on a timer (off-turn discovery) and mount with **`{ discover: 'cache-only' }`** — the turn then never synchronously connects: it serves the warmed catalog and discovers any miss in the background.
|
|
122
122
|
|
|
123
123
|
## 🧬 It improves itself
|
package/dist/cli.js
CHANGED
|
@@ -7907,21 +7907,40 @@ function readPlainLine() {
|
|
|
7907
7907
|
}
|
|
7908
7908
|
|
|
7909
7909
|
// cli/markdown.ts
|
|
7910
|
+
var vis = (s) => needsBidi(s) ? bidiLine(s).visual : s;
|
|
7911
|
+
function displayText(s) {
|
|
7912
|
+
return s.replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/(?<![\w*])[*_]([^*_\s][^*_]*?)[*_](?![\w*])/g, "$1");
|
|
7913
|
+
}
|
|
7910
7914
|
function mdInline(line, p) {
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
(
|
|
7914
|
-
|
|
7915
|
+
const re = /(`[^`]+`)|(\[[^\]]+\]\([^)]+\))|(\*\*[^*]+\*\*)|(~~[^~]+~~)|((?<![\w*])[*_][^*_\s][^*_]*?[*_](?![\w*]))/g;
|
|
7916
|
+
return line.replace(re, (_m, code, link2, bold2, strike2, italic2) => {
|
|
7917
|
+
if (code) return p.cyan(code.slice(1, -1));
|
|
7918
|
+
if (link2) {
|
|
7919
|
+
const m = /^\[([^\]]+)\]\(([^)]+)\)$/.exec(link2);
|
|
7920
|
+
return p.link ? p.link(m[1], m[2]) : p.cyan(m[1]);
|
|
7921
|
+
}
|
|
7922
|
+
if (bold2) return p.bold(bold2.slice(2, -2));
|
|
7923
|
+
if (strike2) return (p.strike ?? ((s) => s))(strike2.slice(2, -2));
|
|
7924
|
+
return (p.italic ?? ((s) => s))(italic2.slice(1, -1));
|
|
7925
|
+
});
|
|
7915
7926
|
}
|
|
7916
|
-
function renderMdLine(line, inFence, p) {
|
|
7927
|
+
function renderMdLine(line, inFence, p, cols = 80) {
|
|
7917
7928
|
if (/^\s*```/.test(line)) return { out: p.dim(line), inFence: !inFence };
|
|
7918
7929
|
if (inFence) return { out: p.cyan(line), inFence };
|
|
7930
|
+
if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) return { out: p.dim("\u2500".repeat(cols)), inFence };
|
|
7919
7931
|
const h = line.match(/^(#{1,6})\s+(.*)$/);
|
|
7920
|
-
if (h) return { out: p.bold(h[2]), inFence };
|
|
7921
|
-
|
|
7932
|
+
if (h) return { out: p.bold(vis(h[2])), inFence };
|
|
7933
|
+
const q2 = line.match(/^(\s*)>\s?(.*)$/);
|
|
7934
|
+
if (q2) return { out: q2[1] + p.dim("\u258E ") + p.dim(mdInline(vis(q2[2]), p)), inFence };
|
|
7935
|
+
const b = line.match(/^(\s*)[-*+]\s+(.*)$/);
|
|
7936
|
+
if (b) return { out: b[1] + p.cyan("\u2022") + " " + mdInline(vis(b[2]), p), inFence };
|
|
7937
|
+
return { out: mdInline(vis(line), p), inFence };
|
|
7938
|
+
}
|
|
7939
|
+
function isTableRow(line) {
|
|
7940
|
+
return /^\s*\|.*\|\s*$/.test(line);
|
|
7922
7941
|
}
|
|
7923
7942
|
var MarkdownStream = class {
|
|
7924
|
-
//
|
|
7943
|
+
// contiguous GFM table rows held until the block ends, then aligned
|
|
7925
7944
|
constructor(p, cols = 80) {
|
|
7926
7945
|
this.p = p;
|
|
7927
7946
|
this.cols = cols;
|
|
@@ -7932,12 +7951,38 @@ var MarkdownStream = class {
|
|
|
7932
7951
|
// the current (uncommitted) logical line's text
|
|
7933
7952
|
inFence = false;
|
|
7934
7953
|
lineRows = 0;
|
|
7954
|
+
// physical rows the in-progress line occupied last draw (for the next clear)
|
|
7955
|
+
tableBuf = [];
|
|
7935
7956
|
/** Update the wrap width (terminal resized). Recompute how many physical rows the in-progress line now spans
|
|
7936
7957
|
* so the next feed()'s clear-math matches the new width (the terminal reflows the drawn text on resize too). */
|
|
7937
7958
|
resize(cols) {
|
|
7938
7959
|
this.cols = Math.max(1, cols);
|
|
7939
7960
|
if (this.buf) this.lineRows = Math.max(1, Math.ceil(this.buf.length / this.cols));
|
|
7940
7961
|
}
|
|
7962
|
+
/** Render the held table block as aligned columns and reset the buffer. If the block lacks a `|---|`
|
|
7963
|
+
* separator row it isn't a real table — emit the rows verbatim (rendered as normal lines) instead. */
|
|
7964
|
+
flushTable() {
|
|
7965
|
+
const rows = this.tableBuf;
|
|
7966
|
+
this.tableBuf = [];
|
|
7967
|
+
const sepIdx = rows.findIndex((r, i) => i > 0 && r.includes("-") && /^\s*\|[\s:|-]+\|\s*$/.test(r));
|
|
7968
|
+
if (sepIdx < 0) return rows.map((r) => renderMdLine(r, false, this.p, this.cols).out + "\r\n").join("");
|
|
7969
|
+
const cells = (r) => r.trim().replace(/^\||\|$/g, "").split("|").map((c) => c.trim());
|
|
7970
|
+
const data = rows.filter((_, i) => i !== sepIdx).map(cells);
|
|
7971
|
+
const ncol = Math.max(...data.map((r) => r.length));
|
|
7972
|
+
const widths = Array.from({ length: ncol }, (_, i) => Math.max(...data.map((r) => displayText(r[i] ?? "").length)));
|
|
7973
|
+
const out = [];
|
|
7974
|
+
data.forEach((row, ri) => {
|
|
7975
|
+
const header = ri === 0;
|
|
7976
|
+
const line = " " + widths.map((w, ci) => {
|
|
7977
|
+
const c = row[ci] ?? "";
|
|
7978
|
+
const styled = header ? this.p.bold(displayText(vis(c))) : mdInline(vis(c), this.p);
|
|
7979
|
+
return styled + " ".repeat(Math.max(0, w - displayText(c).length));
|
|
7980
|
+
}).join(" ").replace(/\s+$/, "");
|
|
7981
|
+
out.push(line);
|
|
7982
|
+
if (header) out.push(" " + this.p.dim("\u2500".repeat(widths.reduce((a, b) => a + b, 0) + 3 * (ncol - 1))));
|
|
7983
|
+
});
|
|
7984
|
+
return out.map((l) => l + "\r\n").join("");
|
|
7985
|
+
}
|
|
7941
7986
|
feed(text) {
|
|
7942
7987
|
this.buf += text;
|
|
7943
7988
|
let out = "";
|
|
@@ -7948,25 +7993,31 @@ var MarkdownStream = class {
|
|
|
7948
7993
|
while ((nl = this.buf.indexOf("\n")) >= 0) {
|
|
7949
7994
|
const line = this.buf.slice(0, nl);
|
|
7950
7995
|
this.buf = this.buf.slice(nl + 1);
|
|
7951
|
-
|
|
7996
|
+
if (!this.inFence && isTableRow(line)) {
|
|
7997
|
+
this.tableBuf.push(line);
|
|
7998
|
+
continue;
|
|
7999
|
+
}
|
|
8000
|
+
if (this.tableBuf.length) out += this.flushTable();
|
|
8001
|
+
const r = renderMdLine(line, this.inFence, this.p, this.cols);
|
|
7952
8002
|
this.inFence = r.inFence;
|
|
7953
8003
|
out += r.out + "\r\n";
|
|
7954
8004
|
}
|
|
7955
8005
|
if (this.buf) {
|
|
7956
|
-
out += renderMdLine(this.buf, this.inFence, this.p).out;
|
|
8006
|
+
out += renderMdLine(this.buf, this.inFence, this.p, this.cols).out;
|
|
7957
8007
|
this.lineRows = Math.max(1, Math.ceil(this.buf.length / Math.max(1, this.cols)));
|
|
7958
8008
|
}
|
|
7959
8009
|
return out;
|
|
7960
8010
|
}
|
|
7961
|
-
/** Commit the in-progress line as-is (already on screen) and reset for
|
|
8011
|
+
/** Commit the in-progress line as-is (already on screen), emit any buffered table, and reset for next turn. */
|
|
7962
8012
|
flush() {
|
|
8013
|
+
const out = this.tableBuf.length ? this.flushTable() : "";
|
|
7963
8014
|
this.buf = "";
|
|
7964
8015
|
this.inFence = false;
|
|
7965
8016
|
this.lineRows = 0;
|
|
7966
|
-
return
|
|
8017
|
+
return out;
|
|
7967
8018
|
}
|
|
7968
8019
|
pending() {
|
|
7969
|
-
return this.buf.length > 0;
|
|
8020
|
+
return this.buf.length > 0 || this.tableBuf.length > 0;
|
|
7970
8021
|
}
|
|
7971
8022
|
};
|
|
7972
8023
|
|
|
@@ -7981,6 +8032,9 @@ var green = C("32");
|
|
|
7981
8032
|
var red = C("31");
|
|
7982
8033
|
var bold = C("1");
|
|
7983
8034
|
var yellow = C("33");
|
|
8035
|
+
var italic = C("3");
|
|
8036
|
+
var strike = C("9");
|
|
8037
|
+
var link = (text, url) => useColor ? `\x1B]8;;${url}\x1B\\${cyan(text)}\x1B]8;;\x1B\\` : `${text} (${url})`;
|
|
7984
8038
|
var err = (s) => process.stderr.write(s);
|
|
7985
8039
|
var log17 = forComponent("cli");
|
|
7986
8040
|
var VERSION = (() => {
|
|
@@ -8206,7 +8260,7 @@ function apiKeysFromEnv() {
|
|
|
8206
8260
|
function makeHost(format = "text", opts) {
|
|
8207
8261
|
const streamJson = format === "stream-json";
|
|
8208
8262
|
const cleanStdout = format === "json";
|
|
8209
|
-
const md = format === "text" && useColor && opts?.stream ? new MarkdownStream({ bold, dim, cyan }, process.stdout.columns ?? 80) : null;
|
|
8263
|
+
const md = format === "text" && useColor && opts?.stream ? new MarkdownStream({ bold, dim, cyan, italic, strike, link }, process.stdout.columns ?? 80) : null;
|
|
8210
8264
|
if (md) process.on("SIGWINCH", () => md.resize(process.stdout.columns ?? 80));
|
|
8211
8265
|
const flushText = () => {
|
|
8212
8266
|
if (md && md.pending()) process.stdout.write(md.flush());
|