@livx.cc/agentx 0.99.58 → 0.99.59
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/{Agent-CXkPfYX2.d.ts → Agent-DqFJubs5.d.ts} +104 -2
- package/dist/cli.d.ts +16 -3
- package/dist/cli.js +359 -87
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +250 -0
- package/dist/index.js.map +1 -1
- package/dist/models.js +1 -0
- package/dist/models.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2561,7 +2561,7 @@ async function psGroupCpuSeconds(pgid) {
|
|
|
2561
2561
|
const out = await new Promise((res, rej) => execFile4("ps", ["-A", "-o", "pid=,ppid=,pgid=,time="], { timeout: 5e3, env: { ...process.env, LC_ALL: "C" } }, (e, so) => e ? rej(e) : res(String(so))));
|
|
2562
2562
|
return sumTreeCpu(out, pgid);
|
|
2563
2563
|
} catch (e) {
|
|
2564
|
-
|
|
2564
|
+
log23.debug(`ps cpu probe failed for group ${pgid}: ${e}`);
|
|
2565
2565
|
return void 0;
|
|
2566
2566
|
}
|
|
2567
2567
|
}
|
|
@@ -2709,7 +2709,7 @@ function makeRealShellTool(options) {
|
|
|
2709
2709
|
proc.stderr?.on("data", collect);
|
|
2710
2710
|
proc.on("error", (err2) => {
|
|
2711
2711
|
if (err2?.name === "AbortError" || ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean2(out)));
|
|
2712
|
-
|
|
2712
|
+
log23.debug("shell spawn error", err2);
|
|
2713
2713
|
finish(`[exit 1] ${err2?.message ?? err2}${out ? "\n" + clean2(out) : ""}`);
|
|
2714
2714
|
});
|
|
2715
2715
|
proc.on("close", (code) => {
|
|
@@ -2782,7 +2782,7 @@ ${clean2(out) || "(no output yet)"}`;
|
|
|
2782
2782
|
}
|
|
2783
2783
|
];
|
|
2784
2784
|
}
|
|
2785
|
-
var
|
|
2785
|
+
var log23, clean2, DETACHED, SECRET_ENV_RE, _spawn, ShellJobRegistry, shellStatus, NO_JOB2;
|
|
2786
2786
|
var init_tools_shell = __esm({
|
|
2787
2787
|
"src/tools.shell.ts"() {
|
|
2788
2788
|
"use strict";
|
|
@@ -2791,7 +2791,7 @@ var init_tools_shell = __esm({
|
|
|
2791
2791
|
init_logging();
|
|
2792
2792
|
init_shell_sandbox();
|
|
2793
2793
|
init_tools_jobs();
|
|
2794
|
-
|
|
2794
|
+
log23 = forComponent("shell");
|
|
2795
2795
|
clean2 = (s) => truncateOutput(redactSecrets(s.replace(/\n+$/, "")));
|
|
2796
2796
|
DETACHED = { stdio: ["ignore", "pipe", "pipe"], detached: true };
|
|
2797
2797
|
SECRET_ENV_RE = /(_API_KEY|_TOKEN|_SECRET|_PASSWORD|_PRIVATE_KEY|^AWS_|^GITHUB_TOKEN$|^OPENAI_|^ANTHROPIC_|^GOOGLE_|^GEMINI_|^GROQ_|^NPM_TOKEN$)/i;
|
|
@@ -3571,6 +3571,7 @@ function resolveModelAlias(input) {
|
|
|
3571
3571
|
const slash = input.indexOf("/");
|
|
3572
3572
|
const prefix = slash === -1 ? "" : input.slice(0, slash + 1);
|
|
3573
3573
|
const rest = slash === -1 ? input : input.slice(slash + 1);
|
|
3574
|
+
if (prefix === "claude-code/") return input;
|
|
3574
3575
|
return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);
|
|
3575
3576
|
}
|
|
3576
3577
|
function modelProvider(model) {
|
|
@@ -10662,6 +10663,250 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
10662
10663
|
}
|
|
10663
10664
|
};
|
|
10664
10665
|
|
|
10666
|
+
// src/modelRouter.ts
|
|
10667
|
+
init_llm();
|
|
10668
|
+
init_logging();
|
|
10669
|
+
var log21 = forComponent("ModelRouter");
|
|
10670
|
+
var ModelRouterOptions = class {
|
|
10671
|
+
classifier = jevClassifier();
|
|
10672
|
+
/** Capability tiers → model id (any provider). fast/standard run the main session; premium is only ever an offload. */
|
|
10673
|
+
models = { fast: "anthropic/claude-haiku-4-5-20251001", standard: "anthropic/claude-sonnet-4-6", premium: "anthropic/claude-opus-5-5" };
|
|
10674
|
+
/** Escalate to a stronger tier when it holds at least this much probability mass (upward bias). */
|
|
10675
|
+
threshold = 0.25;
|
|
10676
|
+
/** P(same thread) at or above which the previous premium side-conversation is resumed. */
|
|
10677
|
+
sameThreadAt = 0.5;
|
|
10678
|
+
classifyTimeoutMs = 1e4;
|
|
10679
|
+
/** Host-supplied pricing (model, usage) → USD, so mixed-model turns are costed per model. */
|
|
10680
|
+
costOf = () => 0;
|
|
10681
|
+
/** Step budget for the premium sub-agent. */
|
|
10682
|
+
offloadMaxSteps = 40;
|
|
10683
|
+
/** Host-supplied provider options per model (e.g. claude-code's subscription env); applied on every tier switch + the offload child. */
|
|
10684
|
+
providerOptionsFor;
|
|
10685
|
+
};
|
|
10686
|
+
function pickTier(c, th) {
|
|
10687
|
+
const o = c.probs.premium ?? 0, s = c.probs.standard ?? 0;
|
|
10688
|
+
if (o >= th || c.choice === "premium") return "premium";
|
|
10689
|
+
if (c.choice === "standard" || s + o >= th) return "standard";
|
|
10690
|
+
return "fast";
|
|
10691
|
+
}
|
|
10692
|
+
function textTurns(msgs) {
|
|
10693
|
+
const out = [];
|
|
10694
|
+
for (const m of msgs) {
|
|
10695
|
+
if (m.role === "user") {
|
|
10696
|
+
const t = contentText(m.content).trim();
|
|
10697
|
+
if (t) out.push({ user: t, assistant: "" });
|
|
10698
|
+
} else if (m.role === "assistant" && out.length) {
|
|
10699
|
+
const t = contentText(m.content).trim();
|
|
10700
|
+
if (t) out[out.length - 1].assistant = (out[out.length - 1].assistant + "\n" + t).trim();
|
|
10701
|
+
}
|
|
10702
|
+
}
|
|
10703
|
+
return out;
|
|
10704
|
+
}
|
|
10705
|
+
var fmtTurns = (ts) => ts.map((t) => `USER: ${t.user}
|
|
10706
|
+
ASSISTANT: ${t.assistant || "(no text reply)"}`).join("\n\n");
|
|
10707
|
+
var addUsage = (a, b) => {
|
|
10708
|
+
if (!a) return b;
|
|
10709
|
+
if (!b) return a;
|
|
10710
|
+
return {
|
|
10711
|
+
promptTokens: a.promptTokens + b.promptTokens,
|
|
10712
|
+
completionTokens: a.completionTokens + b.completionTokens,
|
|
10713
|
+
totalTokens: a.totalTokens + b.totalTokens,
|
|
10714
|
+
cacheCreationTokens: (a.cacheCreationTokens ?? 0) + (b.cacheCreationTokens ?? 0),
|
|
10715
|
+
cacheReadTokens: (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0)
|
|
10716
|
+
};
|
|
10717
|
+
};
|
|
10718
|
+
var ModelRouter = class {
|
|
10719
|
+
constructor(options) {
|
|
10720
|
+
this.options = options;
|
|
10721
|
+
this.options = { ...new ModelRouterOptions(), ...options };
|
|
10722
|
+
}
|
|
10723
|
+
options;
|
|
10724
|
+
state = {};
|
|
10725
|
+
get o() {
|
|
10726
|
+
return this.options;
|
|
10727
|
+
}
|
|
10728
|
+
/** Classify one turn. Never throws: classifier failure/timeout ⇒ standard. */
|
|
10729
|
+
async decide(transcript, next) {
|
|
10730
|
+
const o = this.o;
|
|
10731
|
+
const main2 = this.state.main === o.models.fast ? "fast" : "standard";
|
|
10732
|
+
const input = {
|
|
10733
|
+
previousModel: main2,
|
|
10734
|
+
history: textTurns(transcript).slice(-4).map((t) => ({ user: t.user.slice(0, 1500), assistant: t.assistant.slice(0, 1500) })),
|
|
10735
|
+
next,
|
|
10736
|
+
lastOffload: this.state.offload?.question
|
|
10737
|
+
};
|
|
10738
|
+
const t0 = performance.now();
|
|
10739
|
+
let d;
|
|
10740
|
+
try {
|
|
10741
|
+
let timer;
|
|
10742
|
+
const c = await Promise.race([
|
|
10743
|
+
o.classifier(input),
|
|
10744
|
+
new Promise((_, rej) => {
|
|
10745
|
+
timer = setTimeout(() => rej(new Error(`classifier timeout ${o.classifyTimeoutMs}ms`)), o.classifyTimeoutMs);
|
|
10746
|
+
})
|
|
10747
|
+
]).finally(() => clearTimeout(timer));
|
|
10748
|
+
const tier = pickTier(c, o.threshold);
|
|
10749
|
+
d = { tier, model: o.models[tier], probs: c.probs, choice: c.choice, sameThread: c.sameThread, classifyMs: Math.round(performance.now() - t0) };
|
|
10750
|
+
if (tier === "premium") d.offload = this.state.offload && (c.sameThread ?? 0) >= o.sameThreadAt ? "continue" : "fresh";
|
|
10751
|
+
} catch (e) {
|
|
10752
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
10753
|
+
log21.warn(`classifier failed, falling back to standard: ${msg}`);
|
|
10754
|
+
d = { tier: "standard", model: o.models.standard, probs: {}, fallback: msg, classifyMs: Math.round(performance.now() - t0) };
|
|
10755
|
+
}
|
|
10756
|
+
log21.info(`route ${d.tier}${d.offload ? `(${d.offload})` : ""} \xB7 argmax=${d.choice ?? "-"} \xB7 p=${JSON.stringify(d.probs)}${d.sameThread != null ? ` \xB7 same=${d.sameThread.toFixed(2)}` : ""} \xB7 ${d.classifyMs}ms`);
|
|
10757
|
+
return d;
|
|
10758
|
+
}
|
|
10759
|
+
/** Run one user turn on `agent` with routing. Returns a RunResult carrying `costUsd` + `routing`. */
|
|
10760
|
+
async send(agent, content) {
|
|
10761
|
+
const o = this.o;
|
|
10762
|
+
const text = contentText(content);
|
|
10763
|
+
const d = await this.decide(agent.transcript, text);
|
|
10764
|
+
if (d.tier !== "premium") {
|
|
10765
|
+
this.use(agent, this.state.main = d.model);
|
|
10766
|
+
const res = await agent.send(content);
|
|
10767
|
+
return { ...res, costUsd: o.costOf(d.model, res.usage), routing: d };
|
|
10768
|
+
}
|
|
10769
|
+
this.use(agent, this.state.main ??= o.models.standard);
|
|
10770
|
+
return this.offload(agent, content, text, d);
|
|
10771
|
+
}
|
|
10772
|
+
async offload(agent, content, text, d) {
|
|
10773
|
+
const o = this.o, main2 = this.state.main;
|
|
10774
|
+
const prev = this.state.offload;
|
|
10775
|
+
const cont = d.offload === "continue" && prev && prev.mainLen <= agent.transcript.length;
|
|
10776
|
+
let briefUsage, prompt;
|
|
10777
|
+
if (cont) {
|
|
10778
|
+
const delta = textTurns(agent.transcript.slice(prev.mainLen));
|
|
10779
|
+
prompt = `Follow-up in the same thread.${delta.length ? ` Since your last answer the main conversation continued:
|
|
10780
|
+
|
|
10781
|
+
${fmtTurns(delta)}
|
|
10782
|
+
` : ""}
|
|
10783
|
+
|
|
10784
|
+
New request:
|
|
10785
|
+
${text}`;
|
|
10786
|
+
} else {
|
|
10787
|
+
const b = await this.brief(agent, text);
|
|
10788
|
+
briefUsage = b.usage;
|
|
10789
|
+
const last2 = textTurns(agent.transcript).slice(-2);
|
|
10790
|
+
prompt = `You are handling a hard turn delegated by the main agent of an ongoing session. You do NOT see its conversation \u2014 only this brief. Do the work with your tools, then reply to the user directly (your reply is shown as the session's answer).
|
|
10791
|
+
|
|
10792
|
+
--- brief from the main agent ---
|
|
10793
|
+
${b.text}
|
|
10794
|
+
|
|
10795
|
+
${last2.length ? `--- last turns (verbatim) ---
|
|
10796
|
+
${fmtTurns(last2)}
|
|
10797
|
+
|
|
10798
|
+
` : ""}--- current user request (verbatim) ---
|
|
10799
|
+
${text}`;
|
|
10800
|
+
}
|
|
10801
|
+
const child = this.spawn(agent);
|
|
10802
|
+
const res = cont ? (child.transcript = prev.messages, await child.send(prompt)) : await child.run(prompt);
|
|
10803
|
+
this.state.offloads = (this.state.offloads ?? 0) + 1;
|
|
10804
|
+
if (cont) this.state.reuses = (this.state.reuses ?? 0) + 1;
|
|
10805
|
+
const answer = res.text || `(premium sub-agent finished with no reply; finishReason=${res.finishReason})`;
|
|
10806
|
+
agent.transcript.push({ role: "user", content }, { role: "assistant", content: answer });
|
|
10807
|
+
this.state.offload = { messages: child.transcript, mainLen: agent.transcript.length, question: text };
|
|
10808
|
+
log21.info(`offload ${cont ? "continue" : "fresh"} done \xB7 ${res.finishReason} \xB7 ${res.steps} steps`);
|
|
10809
|
+
const costUsd = o.costOf(main2, briefUsage) + o.costOf(o.models.premium, res.usage);
|
|
10810
|
+
return { ...res, text: answer, messages: agent.transcript, usage: addUsage(briefUsage, res.usage), costUsd, routing: d };
|
|
10811
|
+
}
|
|
10812
|
+
/** The main model writes the task brief on its own (cached) context, tools off; the transcript is restored after. */
|
|
10813
|
+
async brief(agent, text) {
|
|
10814
|
+
const snap = agent.transcript.slice();
|
|
10815
|
+
const { host, toolChoice, maxSteps } = agent.options;
|
|
10816
|
+
Object.assign(agent.options, { host: void 0, toolChoice: "none", maxSteps: 1 });
|
|
10817
|
+
try {
|
|
10818
|
+
const r = await agent.send(`[router] The next request is being delegated to a stronger sub-agent that will NOT see this conversation. Write the self-contained brief you would hand it (<=200 words): the task, the relevant facts/files/decisions established so far, constraints. Output only the brief.
|
|
10819
|
+
|
|
10820
|
+
The request:
|
|
10821
|
+
${text}`);
|
|
10822
|
+
return { text: r.text.trim() || text, usage: r.usage };
|
|
10823
|
+
} catch (e) {
|
|
10824
|
+
log21.warn(`brief failed, sending the raw request: ${e instanceof Error ? e.message : String(e)}`);
|
|
10825
|
+
return { text };
|
|
10826
|
+
} finally {
|
|
10827
|
+
agent.transcript = snap;
|
|
10828
|
+
Object.assign(agent.options, { host, toolChoice, maxSteps });
|
|
10829
|
+
}
|
|
10830
|
+
}
|
|
10831
|
+
use(agent, model) {
|
|
10832
|
+
agent.options.model = model;
|
|
10833
|
+
if (this.o.providerOptionsFor) agent.options.providerOptions = this.o.providerOptionsFor(model);
|
|
10834
|
+
}
|
|
10835
|
+
spawn(agent) {
|
|
10836
|
+
const a = agent.options;
|
|
10837
|
+
const co = childOptionsFor(
|
|
10838
|
+
{ ai: a.ai, model: a.model, fs: a.fs, tools: a.tools, systemPrompt: a.systemPrompt, hooks: a.hooks, maxSteps: this.o.offloadMaxSteps, traceDir: a.traceDir, providerOptionsFor: this.o.providerOptionsFor },
|
|
10839
|
+
a.fs,
|
|
10840
|
+
a.depth ?? 0,
|
|
10841
|
+
a.maxDepth ?? 2,
|
|
10842
|
+
void 0,
|
|
10843
|
+
this.o.models.premium
|
|
10844
|
+
);
|
|
10845
|
+
if (typeof co === "string") throw new Error(co);
|
|
10846
|
+
co.signal = a.signal;
|
|
10847
|
+
return new Agent(co);
|
|
10848
|
+
}
|
|
10849
|
+
};
|
|
10850
|
+
var JEV_KEYS = ["AI_GATEWAY_API_KEY", "OPENROUTER_API_KEY", "TYPESAFE_API_KEY"];
|
|
10851
|
+
async function loadJev(opts) {
|
|
10852
|
+
const mod = await import(opts.jevModule ?? process.env.AGENTX_JEV_MODULE ?? "@livx.cc/mcp-jev/jev");
|
|
10853
|
+
const env = { ...process.env };
|
|
10854
|
+
const file = opts.envFile ?? process.env.AGENTX_JEV_ENV;
|
|
10855
|
+
if (file) {
|
|
10856
|
+
const { readFileSync: readFileSync10 } = await import("fs");
|
|
10857
|
+
for (const l of readFileSync10(file, "utf8").split("\n")) {
|
|
10858
|
+
const m = l.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);
|
|
10859
|
+
if (m && !env[m[1]]) env[m[1]] = m[2].replace(/^['"]|['"]$/g, "");
|
|
10860
|
+
}
|
|
10861
|
+
}
|
|
10862
|
+
return { mod, env };
|
|
10863
|
+
}
|
|
10864
|
+
async function jevAvailable(opts = {}) {
|
|
10865
|
+
try {
|
|
10866
|
+
const { env } = await loadJev(opts);
|
|
10867
|
+
return JEV_KEYS.some((k) => env[k]?.trim());
|
|
10868
|
+
} catch (e) {
|
|
10869
|
+
log21.debug(`jev unavailable: ${e instanceof Error ? e.message : String(e)}`);
|
|
10870
|
+
return false;
|
|
10871
|
+
}
|
|
10872
|
+
}
|
|
10873
|
+
function jevClassifier(opts = {}) {
|
|
10874
|
+
let router;
|
|
10875
|
+
const load = async () => {
|
|
10876
|
+
const { mod, env } = await loadJev(opts);
|
|
10877
|
+
return new mod.JevRouter({ env });
|
|
10878
|
+
};
|
|
10879
|
+
return async (input) => {
|
|
10880
|
+
const jev = await (router ??= load().catch((e) => {
|
|
10881
|
+
router = void 0;
|
|
10882
|
+
throw e;
|
|
10883
|
+
}));
|
|
10884
|
+
const questions = [{
|
|
10885
|
+
id: "tier",
|
|
10886
|
+
type: "choice",
|
|
10887
|
+
instructions: "Pick the CHEAPEST model that will handle the NEXT assistant turn correctly for this coding-agent conversation. Staying on previousModel keeps its prompt cache warm; switch only when the next turn clearly needs more (or much less) capability.",
|
|
10888
|
+
criteria: {
|
|
10889
|
+
fast: "Trivial: commands, lookups, acknowledgements, commits, mechanical single-file edits, short rewrites.",
|
|
10890
|
+
standard: "Standard engineering: features, bounded refactors, reviews, tests, following a clear trace, summarising.",
|
|
10891
|
+
premium: "Hard: root-causing subtle/intermittent bugs, concurrency, security semantics, architecture trade-offs, quantitative reasoning."
|
|
10892
|
+
}
|
|
10893
|
+
}];
|
|
10894
|
+
if (input.lastOffload) questions.push({
|
|
10895
|
+
id: "sameThread",
|
|
10896
|
+
type: "boolean",
|
|
10897
|
+
instructions: "Does nextUserMessage continue the same line of work as lastOffload (the previous hard request, handled by a specialist) \u2014 a follow-up, refinement or next step of it \u2014 rather than a new, unrelated topic?"
|
|
10898
|
+
});
|
|
10899
|
+
const state = { previousModel: input.previousModel, history: input.history, nextUserMessage: input.next, ...input.lastOffload ? { lastOffload: input.lastOffload } : {} };
|
|
10900
|
+
const r = await jev.evaluate({ state, questions }, opts.provider);
|
|
10901
|
+
const a = r.answers.tier;
|
|
10902
|
+
const map = (k) => k;
|
|
10903
|
+
const probs = {};
|
|
10904
|
+
for (const [k, v] of Object.entries(a.probabilities ?? {})) probs[map(k)] = v;
|
|
10905
|
+
const st = r.answers.sameThread;
|
|
10906
|
+
return { choice: map(a.choice), probs, sameThread: st ? st.probability ?? (st.value ? 1 : 0) : void 0 };
|
|
10907
|
+
};
|
|
10908
|
+
}
|
|
10909
|
+
|
|
10665
10910
|
// src/mcp.ts
|
|
10666
10911
|
function toResult(result) {
|
|
10667
10912
|
if (result == null) return { text: "" };
|
|
@@ -10849,7 +11094,7 @@ import { MemFilesystem as MemFilesystem3, IndexedDbFilesystem, CommandExecutor a
|
|
|
10849
11094
|
init_logging();
|
|
10850
11095
|
import { spawn } from "child_process";
|
|
10851
11096
|
import { createHash } from "crypto";
|
|
10852
|
-
var
|
|
11097
|
+
var log22 = forComponent("mcp");
|
|
10853
11098
|
var PROTOCOL_VERSION = "2025-06-18";
|
|
10854
11099
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
10855
11100
|
var DEFAULT_CALL_TIMEOUT_MS = 30 * 6e4;
|
|
@@ -10879,7 +11124,7 @@ var StdioTransport = class {
|
|
|
10879
11124
|
proc.stdout.setEncoding("utf8");
|
|
10880
11125
|
proc.stdout.on("data", (chunk) => this.onData(chunk));
|
|
10881
11126
|
proc.stderr.setEncoding("utf8");
|
|
10882
|
-
proc.stderr.on("data", (chunk) =>
|
|
11127
|
+
proc.stderr.on("data", (chunk) => log22.debug(`[${command}] stderr:`, chunk.trimEnd()));
|
|
10883
11128
|
proc.on("exit", (code) => this.failAll(new Error(`MCP server "${command}" exited (code ${code})`)));
|
|
10884
11129
|
proc.on("error", (e) => this.failAll(e instanceof Error ? e : new Error(String(e))));
|
|
10885
11130
|
}
|
|
@@ -10893,7 +11138,7 @@ var StdioTransport = class {
|
|
|
10893
11138
|
try {
|
|
10894
11139
|
this.dispatch(JSON.parse(line));
|
|
10895
11140
|
} catch (e) {
|
|
10896
|
-
|
|
11141
|
+
log22.debug("dropping non-JSON line from MCP server:", line, e);
|
|
10897
11142
|
}
|
|
10898
11143
|
}
|
|
10899
11144
|
}
|
|
@@ -10903,7 +11148,7 @@ var StdioTransport = class {
|
|
|
10903
11148
|
try {
|
|
10904
11149
|
p2?.onProgress?.(msg.params ?? {});
|
|
10905
11150
|
} catch (e) {
|
|
10906
|
-
|
|
11151
|
+
log22.debug("onProgress handler threw", e);
|
|
10907
11152
|
}
|
|
10908
11153
|
return;
|
|
10909
11154
|
}
|
|
@@ -10941,7 +11186,7 @@ var StdioTransport = class {
|
|
|
10941
11186
|
const onAbort = () => {
|
|
10942
11187
|
if (!this.pending.delete(id)) return;
|
|
10943
11188
|
clearTimeout(timer);
|
|
10944
|
-
this.notify("notifications/cancelled", { requestId: id, reason: String(signal?.reason?.message ?? "cancelled") }).catch((e) =>
|
|
11189
|
+
this.notify("notifications/cancelled", { requestId: id, reason: String(signal?.reason?.message ?? "cancelled") }).catch((e) => log22.debug("cancel notify failed", e));
|
|
10945
11190
|
reject(abortError(signal));
|
|
10946
11191
|
};
|
|
10947
11192
|
const done = () => signal?.removeEventListener("abort", onAbort);
|
|
@@ -10965,7 +11210,7 @@ var StdioTransport = class {
|
|
|
10965
11210
|
try {
|
|
10966
11211
|
this.proc?.stdin?.end();
|
|
10967
11212
|
} catch (e) {
|
|
10968
|
-
|
|
11213
|
+
log22.debug("stdin end failed", e);
|
|
10969
11214
|
}
|
|
10970
11215
|
this.proc?.kill();
|
|
10971
11216
|
}
|
|
@@ -11000,7 +11245,7 @@ var HttpTransport = class {
|
|
|
11000
11245
|
return await this.post({ jsonrpc: "2.0", id, method, params: opts.onProgress ? withProgressToken(params, id) : params }, false, signal, opts.onProgress);
|
|
11001
11246
|
} catch (e) {
|
|
11002
11247
|
if (opts.signal?.aborted) {
|
|
11003
|
-
void this.notify("notifications/cancelled", { requestId: id, reason: String(opts.signal.reason?.message ?? "cancelled") }).catch((err2) =>
|
|
11248
|
+
void this.notify("notifications/cancelled", { requestId: id, reason: String(opts.signal.reason?.message ?? "cancelled") }).catch((err2) => log22.debug("cancel notify failed", err2));
|
|
11004
11249
|
throw abortError(opts.signal);
|
|
11005
11250
|
}
|
|
11006
11251
|
throw e;
|
|
@@ -11043,7 +11288,7 @@ function sseMessage(line) {
|
|
|
11043
11288
|
try {
|
|
11044
11289
|
return JSON.parse(trimmed.slice(5).trim());
|
|
11045
11290
|
} catch (e) {
|
|
11046
|
-
|
|
11291
|
+
log22.debug("skipping unparseable SSE data line", e);
|
|
11047
11292
|
return void 0;
|
|
11048
11293
|
}
|
|
11049
11294
|
}
|
|
@@ -11053,7 +11298,7 @@ async function readSseResponse(resp, id, onProgress) {
|
|
|
11053
11298
|
try {
|
|
11054
11299
|
onProgress?.(obj.params ?? {});
|
|
11055
11300
|
} catch (e) {
|
|
11056
|
-
|
|
11301
|
+
log22.debug("onProgress handler threw", e);
|
|
11057
11302
|
}
|
|
11058
11303
|
return void 0;
|
|
11059
11304
|
}
|
|
@@ -11152,7 +11397,7 @@ async function mountWithDeadline(name, cfg, mountTimeoutMs) {
|
|
|
11152
11397
|
return { name, client, tools, specs, serverInfo: init?.serverInfo, config: cfg };
|
|
11153
11398
|
})(), mountTimeoutMs, name);
|
|
11154
11399
|
} catch (e) {
|
|
11155
|
-
await client.close().catch((err2) =>
|
|
11400
|
+
await client.close().catch((err2) => log22.debug(`close after failed mount of "${name}": ${err2}`));
|
|
11156
11401
|
throw e;
|
|
11157
11402
|
}
|
|
11158
11403
|
}
|
|
@@ -11163,15 +11408,15 @@ function validEntries(servers) {
|
|
|
11163
11408
|
return Object.entries(servers).filter(([name, cfg]) => {
|
|
11164
11409
|
if (!cfg || cfg.disabled) return false;
|
|
11165
11410
|
if (!cfg.command && !cfg.url) {
|
|
11166
|
-
|
|
11411
|
+
log22.warn(`MCP server "${name}" needs a command (stdio) or url (http) \u2014 skipping`);
|
|
11167
11412
|
return false;
|
|
11168
11413
|
}
|
|
11169
11414
|
return true;
|
|
11170
11415
|
});
|
|
11171
11416
|
}
|
|
11172
11417
|
function logMountFailure(name, e) {
|
|
11173
|
-
if (e instanceof McpAuthError)
|
|
11174
|
-
else
|
|
11418
|
+
if (e instanceof McpAuthError) log22.warn(`MCP "${name}" needs-auth: HTTP ${e.status} \u2014 set bearerToken or headers in its config; skipping`);
|
|
11419
|
+
else log22.error(`MCP server "${name}" failed to mount: ${e?.message ?? e}`);
|
|
11175
11420
|
}
|
|
11176
11421
|
async function mountMcpServers(servers = {}, opts = {}) {
|
|
11177
11422
|
const entries = validEntries(servers);
|
|
@@ -11181,7 +11426,7 @@ async function mountMcpServers(servers = {}, opts = {}) {
|
|
|
11181
11426
|
const name = entries[i][0];
|
|
11182
11427
|
if (r.status === "fulfilled") {
|
|
11183
11428
|
out.push(r.value);
|
|
11184
|
-
|
|
11429
|
+
log22.debug(`MCP "${name}" mounted \u2014 ${r.value.tools.length} tool(s)${r.value.serverInfo?.name ? ` from ${r.value.serverInfo.name}` : ""}`);
|
|
11185
11430
|
} else logMountFailure(name, r.reason);
|
|
11186
11431
|
});
|
|
11187
11432
|
return out;
|
|
@@ -11221,7 +11466,7 @@ var McpPool = class {
|
|
|
11221
11466
|
const prev = this.warm.get(key);
|
|
11222
11467
|
if (prev) {
|
|
11223
11468
|
clearTimeout(prev.timer);
|
|
11224
|
-
if (prev.client !== client) void prev.client.close().catch((err2) =>
|
|
11469
|
+
if (prev.client !== client) void prev.client.close().catch((err2) => log22.debug(`warm-pool replace close failed: ${err2}`));
|
|
11225
11470
|
}
|
|
11226
11471
|
const e = { client, timer: void 0 };
|
|
11227
11472
|
this.warm.set(key, e);
|
|
@@ -11238,7 +11483,7 @@ var McpPool = class {
|
|
|
11238
11483
|
const e = this.warm.get(key);
|
|
11239
11484
|
if (!e) return;
|
|
11240
11485
|
this.warm.delete(key);
|
|
11241
|
-
await e.client.close().catch((err2) =>
|
|
11486
|
+
await e.client.close().catch((err2) => log22.debug(`warm-pool evict close failed: ${err2}`));
|
|
11242
11487
|
}
|
|
11243
11488
|
async closeAll() {
|
|
11244
11489
|
for (const e of this.warm.values()) {
|
|
@@ -11456,7 +11701,7 @@ init_tools_shell();
|
|
|
11456
11701
|
// src/tools.notify.ts
|
|
11457
11702
|
init_logging();
|
|
11458
11703
|
import { execFile } from "child_process";
|
|
11459
|
-
var
|
|
11704
|
+
var log24 = forComponent("notify");
|
|
11460
11705
|
function makeNotifyTool(opts = {}) {
|
|
11461
11706
|
const platform2 = opts.platform ?? process.platform;
|
|
11462
11707
|
const run = opts.exec ?? execFile;
|
|
@@ -11480,7 +11725,7 @@ function makeNotifyTool(opts = {}) {
|
|
|
11480
11725
|
return new Promise((resolve5) => {
|
|
11481
11726
|
run(argv[0], argv[1], { timeout: 5e3 }, (e) => {
|
|
11482
11727
|
if (e) {
|
|
11483
|
-
|
|
11728
|
+
log24.debug("notification failed", e);
|
|
11484
11729
|
resolve5(`Notification failed: ${e.message}`);
|
|
11485
11730
|
} else resolve5("Notification shown.");
|
|
11486
11731
|
});
|
|
@@ -11496,7 +11741,7 @@ import { BodDB as BodDB2 } from "@bod.ee/db";
|
|
|
11496
11741
|
init_logging();
|
|
11497
11742
|
import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
|
|
11498
11743
|
import { homedir } from "os";
|
|
11499
|
-
var
|
|
11744
|
+
var log25 = forComponent("cli-util");
|
|
11500
11745
|
function dotDirs(base, sub, opts = {}) {
|
|
11501
11746
|
const home = opts.home ?? homedir();
|
|
11502
11747
|
const dirs = [`${base}/.agent/${sub}`, `${base}/.claude/${sub}`, `${home}/.agent/${sub}`, `${home}/.claude/${sub}`];
|
|
@@ -11513,7 +11758,7 @@ function parseJson(text, fallback, what = "json") {
|
|
|
11513
11758
|
try {
|
|
11514
11759
|
return JSON.parse(text);
|
|
11515
11760
|
} catch (e) {
|
|
11516
|
-
|
|
11761
|
+
log25.debug(`parseJson(${what}) failed: ${e.message}`);
|
|
11517
11762
|
return fallback;
|
|
11518
11763
|
}
|
|
11519
11764
|
}
|
|
@@ -11523,7 +11768,7 @@ function readJsonFile(path, fallback) {
|
|
|
11523
11768
|
try {
|
|
11524
11769
|
text = readFileSync4(path, "utf8");
|
|
11525
11770
|
} catch (e) {
|
|
11526
|
-
|
|
11771
|
+
log25.debug(`readJsonFile(${path}) unreadable: ${e.message}`);
|
|
11527
11772
|
return fallback;
|
|
11528
11773
|
}
|
|
11529
11774
|
return parseJson(text, fallback, path);
|
|
@@ -11822,7 +12067,7 @@ import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as rea
|
|
|
11822
12067
|
import { homedir as homedir3 } from "os";
|
|
11823
12068
|
import { dirname as dirname3, join as join6 } from "path";
|
|
11824
12069
|
import { fileURLToPath } from "url";
|
|
11825
|
-
var
|
|
12070
|
+
var log26 = forComponent("VoiceIO");
|
|
11826
12071
|
var now3 = () => performance.now();
|
|
11827
12072
|
var Player = class {
|
|
11828
12073
|
proc = null;
|
|
@@ -11836,7 +12081,7 @@ var Player = class {
|
|
|
11836
12081
|
["-loglevel", "quiet", "-nodisp", "-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-f", "s16le", "-ar", String(TTS_SAMPLE_RATE), "-ch_layout", "mono", "-i", "-"],
|
|
11837
12082
|
{ stdio: ["pipe", "ignore", "ignore"] }
|
|
11838
12083
|
);
|
|
11839
|
-
this.proc.on("error", (e) =>
|
|
12084
|
+
this.proc.on("error", (e) => log26.warn(`ffplay error: ${e.message}`));
|
|
11840
12085
|
this.proc.stdin.on("error", () => {
|
|
11841
12086
|
});
|
|
11842
12087
|
this.bytesWritten = 0;
|
|
@@ -11874,7 +12119,7 @@ function detectFfmpegMic() {
|
|
|
11874
12119
|
const devices = [...audio.matchAll(/\[(\d+)\] (.+)/g)].map(([, idx, name]) => ({ idx, name: name.trim() }));
|
|
11875
12120
|
const mic = devices.find((d) => /microphone|built-in/i.test(d.name) && !/teams|blackhole|loopback/i.test(d.name)) ?? devices[0];
|
|
11876
12121
|
if (!mic) throw new Error("no audio input device found");
|
|
11877
|
-
|
|
12122
|
+
log26.debug(`ffmpeg mic: [${mic.idx}] ${mic.name}`);
|
|
11878
12123
|
return `:${mic.idx}`;
|
|
11879
12124
|
}
|
|
11880
12125
|
function detectedInputDevice() {
|
|
@@ -11910,15 +12155,15 @@ function resolveAecBinary() {
|
|
|
11910
12155
|
if (existsSync4(bin) && statSync4(bin).mtimeMs >= statSync4(src).mtimeMs) return bin;
|
|
11911
12156
|
if (spawnSync2("which", ["swiftc"]).status !== 0) return null;
|
|
11912
12157
|
mkdirSync5(cacheDir, { recursive: true });
|
|
11913
|
-
|
|
12158
|
+
log26.info("compiling AEC mic helper (first run)\u2026");
|
|
11914
12159
|
const build = spawnSync2("swiftc", ["-O", "-o", bin, src, "-Xlinker", "-sectcreate", "-Xlinker", "__TEXT", "-Xlinker", "__info_plist", "-Xlinker", plist], { encoding: "utf8" });
|
|
11915
12160
|
if (build.status !== 0) {
|
|
11916
|
-
|
|
12161
|
+
log26.warn(`AEC build failed: ${build.stderr?.slice(0, 400)}`);
|
|
11917
12162
|
return null;
|
|
11918
12163
|
}
|
|
11919
12164
|
const sign = spawnSync2("codesign", ["-fs", "-", bin], { encoding: "utf8" });
|
|
11920
12165
|
if (sign.status !== 0) {
|
|
11921
|
-
|
|
12166
|
+
log26.warn(`codesign failed: ${sign.stderr?.slice(0, 200)}`);
|
|
11922
12167
|
return null;
|
|
11923
12168
|
}
|
|
11924
12169
|
return bin;
|
|
@@ -11960,16 +12205,16 @@ var NodeMicSource = class {
|
|
|
11960
12205
|
this.proc = spawn2(this.bin, [], { stdio: ["ignore", "pipe", "ignore"] });
|
|
11961
12206
|
} else {
|
|
11962
12207
|
if (spawnSync2("which", ["ffmpeg"]).status !== 0) throw new Error("voice I/O unavailable: no AEC helper and no ffmpeg on PATH");
|
|
11963
|
-
|
|
12208
|
+
log26.info("mic: raw capture (no AEC) \u2014 echo handled heuristically; headphones recommended");
|
|
11964
12209
|
this.proc = spawn2(
|
|
11965
12210
|
"ffmpeg",
|
|
11966
12211
|
["-loglevel", "error", "-f", "avfoundation", "-i", detectFfmpegMic(), "-ar", String(STT_SAMPLE_RATE), "-ac", "1", "-f", "s16le", "-"],
|
|
11967
12212
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
11968
12213
|
);
|
|
11969
|
-
this.proc.stderr.on("data", (d) =>
|
|
12214
|
+
this.proc.stderr.on("data", (d) => log26.warn(`ffmpeg: ${String(d).trim()}`));
|
|
11970
12215
|
}
|
|
11971
12216
|
this.proc.on("exit", (c) => {
|
|
11972
|
-
if (c && !this.stopped)
|
|
12217
|
+
if (c && !this.stopped) log26.error(`mic capture exited (${c}) \u2014 check mic permission / MIC_DEVICE / MIC_AEC=0`);
|
|
11973
12218
|
});
|
|
11974
12219
|
this.proc.stdout.on("data", (chunk) => onChunk(chunk));
|
|
11975
12220
|
}
|
|
@@ -12035,7 +12280,7 @@ var AecDuplexAudio = class {
|
|
|
12035
12280
|
this.proc.stdin.on("error", () => {
|
|
12036
12281
|
});
|
|
12037
12282
|
this.proc.on("exit", (c) => {
|
|
12038
|
-
if (c && !this.stopped)
|
|
12283
|
+
if (c && !this.stopped) log26.error(`aec duplex audio exited (${c}) \u2014 check mic permission / MIC_AEC=0`);
|
|
12039
12284
|
});
|
|
12040
12285
|
this.proc.stdout.on("data", (chunk) => {
|
|
12041
12286
|
this.gotChunk = true;
|
|
@@ -12051,7 +12296,7 @@ var AecDuplexAudio = class {
|
|
|
12051
12296
|
openMicSettings();
|
|
12052
12297
|
this.onFatal?.("microphone permission denied \u2014 enable it in System Settings \u2192 Privacy & Security \u2192 Microphone for your terminal, then restart it");
|
|
12053
12298
|
}
|
|
12054
|
-
} else
|
|
12299
|
+
} else log26.debug(`mic-aec: ${s}`);
|
|
12055
12300
|
}
|
|
12056
12301
|
});
|
|
12057
12302
|
if (!this.noVpio && !this.triedFallback) {
|
|
@@ -12060,7 +12305,7 @@ var AecDuplexAudio = class {
|
|
|
12060
12305
|
this.triedFallback = true;
|
|
12061
12306
|
this.noVpio = true;
|
|
12062
12307
|
this._aec = false;
|
|
12063
|
-
|
|
12308
|
+
log26.warn("mic-aec: VPIO delivered no audio in 2.5s \u2014 falling back to non-VPIO capture (no AEC \u2192 half-duplex, no barge-in)");
|
|
12064
12309
|
this.onDegrade?.();
|
|
12065
12310
|
this.killProc();
|
|
12066
12311
|
this.spawnHelper();
|
|
@@ -12231,7 +12476,7 @@ function bindAckInstinct(v, instinct) {
|
|
|
12231
12476
|
if (ev.kind === "ack_fired") instinct.ackOutcome(String(ev.phrase));
|
|
12232
12477
|
else if (ev.kind === "ack_skipped" || ev.kind === "ack_cancelled") instinct.ackOutcome(null);
|
|
12233
12478
|
} catch (e) {
|
|
12234
|
-
|
|
12479
|
+
log26.warn(`ack outcome tap failed: ${e instanceof Error ? e.message : e}`);
|
|
12235
12480
|
}
|
|
12236
12481
|
onDiag(ev);
|
|
12237
12482
|
};
|
|
@@ -12352,7 +12597,7 @@ function fakeVoiceParts(uttFile) {
|
|
|
12352
12597
|
init_logging();
|
|
12353
12598
|
import { appendFile, mkdirSync as mkdirSync6 } from "fs";
|
|
12354
12599
|
import { dirname as dirname4 } from "path";
|
|
12355
|
-
var
|
|
12600
|
+
var log27 = forComponent("VoiceDiag");
|
|
12356
12601
|
var JsonlDiagSink = class {
|
|
12357
12602
|
constructor(path) {
|
|
12358
12603
|
this.path = path;
|
|
@@ -12393,7 +12638,7 @@ var JsonlDiagSink = class {
|
|
|
12393
12638
|
disable(e) {
|
|
12394
12639
|
this.disabled = true;
|
|
12395
12640
|
this.queue.length = 0;
|
|
12396
|
-
|
|
12641
|
+
log27.debug(`voice diag sink disabled (${this.path}): ${e instanceof Error ? e.message : e}`);
|
|
12397
12642
|
}
|
|
12398
12643
|
/** True once a failure permanently disabled the sink (tests/inspection). */
|
|
12399
12644
|
get isDisabled() {
|
|
@@ -12463,7 +12708,7 @@ async function loadConfig(cwd) {
|
|
|
12463
12708
|
|
|
12464
12709
|
// cli/hooks-config.ts
|
|
12465
12710
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
12466
|
-
var
|
|
12711
|
+
var log28 = forComponent("hooks");
|
|
12467
12712
|
var escapeRegex = (s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
12468
12713
|
function ruleMatches(rule, toolName) {
|
|
12469
12714
|
if (!rule.tool || rule.tool === "*") return true;
|
|
@@ -12480,7 +12725,7 @@ function runCmd(rule, env) {
|
|
|
12480
12725
|
});
|
|
12481
12726
|
return { code: r.status ?? 1, out: ((r.stdout ?? "") + (r.stderr ?? "")).trim() };
|
|
12482
12727
|
} catch (e) {
|
|
12483
|
-
|
|
12728
|
+
log28.debug(`hook command failed: ${rule.command}`, e);
|
|
12484
12729
|
return { code: 1, out: String(e?.message ?? e) };
|
|
12485
12730
|
}
|
|
12486
12731
|
}
|
|
@@ -12587,7 +12832,7 @@ function formatDiff(ops, opts = {}) {
|
|
|
12587
12832
|
import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4, readdirSync, renameSync, symlinkSync as symlinkSync2, unlinkSync, readlinkSync, statSync as statSync5 } from "fs";
|
|
12588
12833
|
import { homedir as homedir5 } from "os";
|
|
12589
12834
|
import { join as join8 } from "path";
|
|
12590
|
-
var
|
|
12835
|
+
var log29 = forComponent("session");
|
|
12591
12836
|
var globalDir = () => join8(homedir5(), ".agent", "sessions");
|
|
12592
12837
|
var SessionStore = class {
|
|
12593
12838
|
dir;
|
|
@@ -12632,7 +12877,7 @@ var SessionStore = class {
|
|
|
12632
12877
|
}
|
|
12633
12878
|
load(id) {
|
|
12634
12879
|
if (!this.safeId(id)) {
|
|
12635
|
-
|
|
12880
|
+
log29.debug(`rejecting unsafe session id: ${id}`);
|
|
12636
12881
|
return void 0;
|
|
12637
12882
|
}
|
|
12638
12883
|
const path = join8(this.dir, `${id}.json`);
|
|
@@ -12640,7 +12885,7 @@ var SessionStore = class {
|
|
|
12640
12885
|
try {
|
|
12641
12886
|
return JSON.parse(readFileSync7(path, "utf8"));
|
|
12642
12887
|
} catch (e) {
|
|
12643
|
-
|
|
12888
|
+
log29.debug(`unreadable session ${id} \u2014 ignoring`, e);
|
|
12644
12889
|
return void 0;
|
|
12645
12890
|
}
|
|
12646
12891
|
}
|
|
@@ -12653,7 +12898,7 @@ var SessionStore = class {
|
|
|
12653
12898
|
try {
|
|
12654
12899
|
metas.push(JSON.parse(readFileSync7(join8(this.dir, f), "utf8")).meta);
|
|
12655
12900
|
} catch (e) {
|
|
12656
|
-
|
|
12901
|
+
log29.debug(`skipping unreadable session file ${f}`, e);
|
|
12657
12902
|
}
|
|
12658
12903
|
}
|
|
12659
12904
|
return metas.sort((a, b) => b.updated - a.updated);
|
|
@@ -12892,7 +13137,7 @@ import { promisify } from "util";
|
|
|
12892
13137
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync8 } from "fs";
|
|
12893
13138
|
import { homedir as homedir6 } from "os";
|
|
12894
13139
|
import { join as join9, resolve as resolve3, sep as sep3, parse as parsePath } from "path";
|
|
12895
|
-
var
|
|
13140
|
+
var log30 = forComponent("checkpoints");
|
|
12896
13141
|
var exec = promisify(execFile3);
|
|
12897
13142
|
var DEFAULT_EXCLUDE = [".agent/", ".git/", "node_modules/", "dist/", "build/", ".next/", "target/", ".venv/", "__pycache__/", "*.log"];
|
|
12898
13143
|
function isBroadRoot(p) {
|
|
@@ -12938,7 +13183,7 @@ var ShadowRepo = class {
|
|
|
12938
13183
|
writeFileSync5(join9(this.gitDir, "info", "exclude"), this.exclude.join("\n") + "\n");
|
|
12939
13184
|
this.ready = true;
|
|
12940
13185
|
} catch (e) {
|
|
12941
|
-
|
|
13186
|
+
log30.debug(`git checkpoints unavailable for ${this.workTree}`, e);
|
|
12942
13187
|
this.ready = false;
|
|
12943
13188
|
}
|
|
12944
13189
|
return this.ready;
|
|
@@ -12949,7 +13194,7 @@ var ShadowRepo = class {
|
|
|
12949
13194
|
}
|
|
12950
13195
|
async commit(label, forced = []) {
|
|
12951
13196
|
await this.run("add", "-A");
|
|
12952
|
-
for (const p of forced) await this.run("add", "-f", "--", p).catch((e) =>
|
|
13197
|
+
for (const p of forced) await this.run("add", "-f", "--", p).catch((e) => log30.debug(`force-add failed: ${p}`, e));
|
|
12953
13198
|
await this.run("commit", "--allow-empty", "-q", "-m", label);
|
|
12954
13199
|
}
|
|
12955
13200
|
/** Inject the CURRENT (pre-edit) content of `paths` into the turn-open restore point by amending it.
|
|
@@ -12957,8 +13202,8 @@ var ShadowRepo = class {
|
|
|
12957
13202
|
* turn-boundary `add -A` would never have captured it. Amend (vs a new commit) keeps one restore
|
|
12958
13203
|
* point per turn, so the REPL's turn↔frame mapping stays intact. */
|
|
12959
13204
|
async amendForced(paths) {
|
|
12960
|
-
for (const p of paths) await this.run("add", "-f", "--", p).catch((e) =>
|
|
12961
|
-
await this.run("commit", "--amend", "--no-edit", "-q", "--allow-empty").catch((e) =>
|
|
13205
|
+
for (const p of paths) await this.run("add", "-f", "--", p).catch((e) => log30.debug(`force-capture failed: ${p}`, e));
|
|
13206
|
+
await this.run("commit", "--amend", "--no-edit", "-q", "--allow-empty").catch((e) => log30.debug("amend failed", e));
|
|
12962
13207
|
}
|
|
12963
13208
|
/** Commits on `ref`, oldest-first (canonical index space). */
|
|
12964
13209
|
async log(ref) {
|
|
@@ -13018,7 +13263,7 @@ var ShadowRepo = class {
|
|
|
13018
13263
|
await this.run("gc", "--auto", "-q").catch(() => {
|
|
13019
13264
|
});
|
|
13020
13265
|
} catch (e) {
|
|
13021
|
-
|
|
13266
|
+
log30.debug("checkpoint prune failed", e);
|
|
13022
13267
|
}
|
|
13023
13268
|
}
|
|
13024
13269
|
};
|
|
@@ -13086,7 +13331,7 @@ var GitCheckpoints = class {
|
|
|
13086
13331
|
use(sessionId) {
|
|
13087
13332
|
if (sessionId === this.session) return;
|
|
13088
13333
|
this.session = sessionId;
|
|
13089
|
-
if (this.started) for (const r of this.repos) void r.point(this.ref()).catch((e) =>
|
|
13334
|
+
if (this.started) for (const r of this.repos) void r.point(this.ref()).catch((e) => log30.debug("re-point failed", e));
|
|
13090
13335
|
}
|
|
13091
13336
|
async begin(label) {
|
|
13092
13337
|
if (!await this.start()) return;
|
|
@@ -13106,7 +13351,7 @@ var GitCheckpoints = class {
|
|
|
13106
13351
|
process.stderr.write(`\x1B[2m checkpoints: '${this.repos[i].root}' too large to snapshot in ${Math.round(this.options.opTimeoutMs / 1e3)}s \u2014 file rewind disabled here\x1B[0m
|
|
13107
13352
|
`);
|
|
13108
13353
|
} else {
|
|
13109
|
-
|
|
13354
|
+
log30.debug("checkpoint commit failed", e);
|
|
13110
13355
|
survivors.push(this.repos[i]);
|
|
13111
13356
|
survivorCaches.push(this.caches[i] ?? []);
|
|
13112
13357
|
}
|
|
@@ -13141,7 +13386,7 @@ var GitCheckpoints = class {
|
|
|
13141
13386
|
if (this.forced.has(abs)) continue;
|
|
13142
13387
|
this.forced.add(abs);
|
|
13143
13388
|
const i = this.repoIndexFor(abs);
|
|
13144
|
-
if (i >= 0) await this.repos[i].amendForced([abs]).catch((e) =>
|
|
13389
|
+
if (i >= 0) await this.repos[i].amendForced([abs]).catch((e) => log30.debug("amendForced failed", e));
|
|
13145
13390
|
}
|
|
13146
13391
|
}
|
|
13147
13392
|
};
|
|
@@ -14994,7 +15239,7 @@ import { spawnSync as spawnSync5 } from "child_process";
|
|
|
14994
15239
|
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync3, chmodSync, existsSync as existsSync7 } from "fs";
|
|
14995
15240
|
import { homedir as homedir8 } from "os";
|
|
14996
15241
|
import { join as join12 } from "path";
|
|
14997
|
-
var
|
|
15242
|
+
var log31 = forComponent("os-sched");
|
|
14998
15243
|
var OsScheduler = class {
|
|
14999
15244
|
options;
|
|
15000
15245
|
constructor(options) {
|
|
@@ -15056,7 +15301,7 @@ var OsScheduler = class {
|
|
|
15056
15301
|
}
|
|
15057
15302
|
}
|
|
15058
15303
|
} catch (e) {
|
|
15059
|
-
|
|
15304
|
+
log31.debug(`cancel ${id}`, e);
|
|
15060
15305
|
}
|
|
15061
15306
|
for (const f of [`${id}.json`, `${id}.sh`]) {
|
|
15062
15307
|
try {
|
|
@@ -15173,7 +15418,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
15173
15418
|
import { existsSync as existsSync8, mkdirSync as mkdirSync11, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
15174
15419
|
import { homedir as homedir9 } from "os";
|
|
15175
15420
|
import { join as join13 } from "path";
|
|
15176
|
-
var
|
|
15421
|
+
var log32 = forComponent("remote-trigger");
|
|
15177
15422
|
var TRIGGER_DIR = () => join13(homedir9(), ".agent", "triggers");
|
|
15178
15423
|
var sockPath = (sessionId, dir = TRIGGER_DIR()) => join13(dir, `${sessionId}.sock`);
|
|
15179
15424
|
var TriggerServer = class {
|
|
@@ -15211,13 +15456,13 @@ var TriggerServer = class {
|
|
|
15211
15456
|
conn.end(JSON.stringify({ ok: false, error: String(e) }) + "\n");
|
|
15212
15457
|
}
|
|
15213
15458
|
});
|
|
15214
|
-
conn.on("error", (e) =>
|
|
15459
|
+
conn.on("error", (e) => log32.debug("trigger conn error", e));
|
|
15215
15460
|
});
|
|
15216
|
-
this.server.on("error", (e) =>
|
|
15461
|
+
this.server.on("error", (e) => log32.debug("trigger server error", e));
|
|
15217
15462
|
this.server.listen(p);
|
|
15218
15463
|
this.path = p;
|
|
15219
15464
|
} catch (e) {
|
|
15220
|
-
|
|
15465
|
+
log32.debug("trigger server unavailable", e);
|
|
15221
15466
|
}
|
|
15222
15467
|
}
|
|
15223
15468
|
/** Re-bind on /resume (the session id changed). */
|
|
@@ -15339,7 +15584,7 @@ var strike = C("9");
|
|
|
15339
15584
|
var link = (text, url) => useColor ? `\x1B]8;;${url}\x1B\\${cyan(text)}\x1B]8;;\x1B\\` : `${text} (${url})`;
|
|
15340
15585
|
var mdPalette = { bold, dim, cyan, italic, strike, green, link };
|
|
15341
15586
|
var err = (s) => process.stderr.write(s);
|
|
15342
|
-
var
|
|
15587
|
+
var log33 = forComponent("cli");
|
|
15343
15588
|
var VERSION = (() => {
|
|
15344
15589
|
try {
|
|
15345
15590
|
return JSON.parse(readFileSync9(new URL("../package.json", import.meta.url), "utf8")).version ?? "?";
|
|
@@ -15446,6 +15691,10 @@ function parseArgs(argv) {
|
|
|
15446
15691
|
a.listModels = true;
|
|
15447
15692
|
if (nxt === "list" || nxt === "ls" || nxt === "?") i++;
|
|
15448
15693
|
} else a.model = argv[++i];
|
|
15694
|
+
if (a.model === "auto") {
|
|
15695
|
+
a.autoRoute = true;
|
|
15696
|
+
a.model = autoModels().standard;
|
|
15697
|
+
}
|
|
15449
15698
|
} else if (x === "-C" || x === "--cwd") a.cwd = val(++i, x);
|
|
15450
15699
|
else if (x === "-p" || x === "--print") {
|
|
15451
15700
|
const nxt = argv[i + 1];
|
|
@@ -15524,7 +15773,7 @@ var HELP = `agentx \u2014 agent runtime CLI
|
|
|
15524
15773
|
agentx -c "<task>" continue the most recent session
|
|
15525
15774
|
|
|
15526
15775
|
Flags:
|
|
15527
|
-
-m, --model <id> model (default anthropic/claude-sonnet-4-6); bare -m or -m list = list all models
|
|
15776
|
+
-m, --model <id> model (default auto: per-turn haiku/sonnet + opus offload when Jev is configured, else anthropic/claude-sonnet-4-6); bare -m or -m list = list all models
|
|
15528
15777
|
-C, --cwd <dir> working dir / project root (default .)
|
|
15529
15778
|
-c, --continue resume the most recent session in this dir
|
|
15530
15779
|
-r, --resume [id] resume a session \u2014 with an id, or bare for an interactive picker
|
|
@@ -16092,10 +16341,25 @@ function costOf(pricing, promptTokens = 0, completionTokens = 0, cacheCreationTo
|
|
|
16092
16341
|
const fresh = Math.max(0, promptTokens - cacheCreationTokens - cacheReadTokens);
|
|
16093
16342
|
return fresh / 1e3 * pricing.inputCostPer1K + cacheCreationTokens / 1e3 * pricing.inputCostPer1K * mult.write + cacheReadTokens / 1e3 * pricing.inputCostPer1K * mult.read + completionTokens / 1e3 * pricing.outputCostPer1K;
|
|
16094
16343
|
}
|
|
16344
|
+
var autoModels = () => ({ ...new ModelRouterOptions().models, ...JSON.parse(process.env.AGENTX_AUTO_MODELS || "{}") });
|
|
16345
|
+
function autoRouteSend(args, agent, session, pof) {
|
|
16346
|
+
if (!args.autoRoute) return void 0;
|
|
16347
|
+
const router = new ModelRouter({ costOf: turnCost, models: autoModels(), providerOptionsFor: pof });
|
|
16348
|
+
return async (c) => {
|
|
16349
|
+
const s = session();
|
|
16350
|
+
router.state = s.meta.router ?? {};
|
|
16351
|
+
try {
|
|
16352
|
+
return await router.send(agent, c);
|
|
16353
|
+
} finally {
|
|
16354
|
+
s.meta.router = router.state;
|
|
16355
|
+
}
|
|
16356
|
+
};
|
|
16357
|
+
}
|
|
16095
16358
|
function turnCost(model, usage) {
|
|
16096
|
-
|
|
16359
|
+
const priced = model.startsWith("claude-code/") ? `anthropic/${resolveModelAlias(model.slice("claude-code/".length))}` : model;
|
|
16360
|
+
return costOf(getModelInfo(priced)?.pricing, usage?.promptTokens ?? 0, usage?.completionTokens ?? 0, usage?.cacheCreationTokens ?? 0, usage?.cacheReadTokens ?? 0, priced);
|
|
16097
16361
|
}
|
|
16098
|
-
async function evaluateGoal(ai, condition, transcript,
|
|
16362
|
+
async function evaluateGoal(ai, condition, transcript, log34) {
|
|
16099
16363
|
const recent = transcript.filter((m) => m.role === "assistant").slice(-8).map((m) => {
|
|
16100
16364
|
const text = typeof m.content === "string" ? m.content : m.content.filter((p) => p.type === "text").map((p) => p.text).join(" ");
|
|
16101
16365
|
return text.slice(0, 600);
|
|
@@ -16115,7 +16379,7 @@ ${recent}` }
|
|
|
16115
16379
|
const match = r.content.match(/\{[\s\S]*\}/);
|
|
16116
16380
|
if (match) return JSON.parse(match[0]);
|
|
16117
16381
|
} catch (e) {
|
|
16118
|
-
|
|
16382
|
+
log34(dim(` (goal evaluator error: ${e?.message ?? e})
|
|
16119
16383
|
`));
|
|
16120
16384
|
}
|
|
16121
16385
|
return { met: false, reason: "evaluation unclear" };
|
|
@@ -16336,7 +16600,7 @@ function mcpAgentTools(mounted, opts) {
|
|
|
16336
16600
|
return tools;
|
|
16337
16601
|
}
|
|
16338
16602
|
async function closeMcp(mounted) {
|
|
16339
|
-
await Promise.all(mounted.map((m) => m.client.close().catch((e) =>
|
|
16603
|
+
await Promise.all(mounted.map((m) => m.client.close().catch((e) => log33.debug("mcp close failed", e))));
|
|
16340
16604
|
}
|
|
16341
16605
|
var IMG_EXT = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp" };
|
|
16342
16606
|
function mentionRefs(line) {
|
|
@@ -16388,7 +16652,7 @@ async function expandMentions(fs, line) {
|
|
|
16388
16652
|
if (loaded.includes(ref) || missing.includes(ref)) continue;
|
|
16389
16653
|
if (ref.includes(":") && mcpMentionResolver) {
|
|
16390
16654
|
const body = await mcpMentionResolver(ref).catch((e) => {
|
|
16391
|
-
|
|
16655
|
+
log33.debug("mcp mention resolve failed", e);
|
|
16392
16656
|
return null;
|
|
16393
16657
|
});
|
|
16394
16658
|
if (body != null) {
|
|
@@ -16423,6 +16687,8 @@ function jsonResult(res, session) {
|
|
|
16423
16687
|
steps: res.steps,
|
|
16424
16688
|
tools: res.messages.slice(lastUser).filter((m) => m.role === "tool").length,
|
|
16425
16689
|
usage: res.usage,
|
|
16690
|
+
...res.routing ? { costUsd: res.costUsd, routing: res.routing } : {},
|
|
16691
|
+
// cast: tsup dts hoists a modelRouter import above the shebang
|
|
16426
16692
|
sessionId: session.meta.id,
|
|
16427
16693
|
// The parked question, machine-readable — the caller answers it and resumes `sessionId`.
|
|
16428
16694
|
...res.finishReason === "needs_input" && res.question ? { question: res.question } : {},
|
|
@@ -16475,7 +16741,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
|
|
|
16475
16741
|
try {
|
|
16476
16742
|
store.save(session);
|
|
16477
16743
|
} catch (ex) {
|
|
16478
|
-
|
|
16744
|
+
log33.debug("mid-turn session flush failed", ex);
|
|
16479
16745
|
}
|
|
16480
16746
|
}
|
|
16481
16747
|
return origNotify(e);
|
|
@@ -16503,7 +16769,7 @@ async function runTurn(agent, store, session, task, cp, cwd = process.cwd(), sen
|
|
|
16503
16769
|
agent.options.host?.flushText?.();
|
|
16504
16770
|
flushLookupGroup();
|
|
16505
16771
|
const secs2 = ((Date.now() - t0) / 1e3).toFixed(1);
|
|
16506
|
-
const cost = turnCost(agent.options.model, res.usage);
|
|
16772
|
+
const cost = res.costUsd ?? turnCost(agent.options.model, res.usage);
|
|
16507
16773
|
const m = res.usageEstimated ? "~" : "";
|
|
16508
16774
|
const tok = res.usage?.totalTokens ? `${m}${(res.usage.totalTokens / 1e3).toFixed(1)}k tok \xB7 ${cost > 0 ? m + fmtUsd(cost) + " \xB7 " : ""}` : "";
|
|
16509
16775
|
agent.options.host?.takeToolCount?.();
|
|
@@ -16624,14 +16890,14 @@ var isCancelTeardown = (e) => {
|
|
|
16624
16890
|
function installCancelGuards(mounted) {
|
|
16625
16891
|
process.on("unhandledRejection", (e) => {
|
|
16626
16892
|
if (isCancelTeardown(e)) {
|
|
16627
|
-
|
|
16893
|
+
log33.debug("suppressed unhandledRejection (cursor stream cancel)", e);
|
|
16628
16894
|
return;
|
|
16629
16895
|
}
|
|
16630
|
-
|
|
16896
|
+
log33.error("unhandledRejection", e);
|
|
16631
16897
|
});
|
|
16632
16898
|
process.on("uncaughtException", (e) => {
|
|
16633
16899
|
if (isCancelTeardown(e)) {
|
|
16634
|
-
|
|
16900
|
+
log33.debug("suppressed uncaughtException (cursor stream cancel)", e);
|
|
16635
16901
|
return;
|
|
16636
16902
|
}
|
|
16637
16903
|
console.error(e);
|
|
@@ -16948,6 +17214,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
16948
17214
|
const face = dx ? dx.voice : agent;
|
|
16949
17215
|
const work = workerOptions ?? agent.options;
|
|
16950
17216
|
const sendVia = dx ? (c, o) => dx.send(c, o) : void 0;
|
|
17217
|
+
const routeVia = autoRouteSend(args, agent, () => session, (m) => providerOptionsFor(m, cwd, cfg.mcpServers, mounted.map((x) => x.name)));
|
|
16951
17218
|
const baseRules = () => [
|
|
16952
17219
|
...parsePermRules({ deny: args.disallowedTools }),
|
|
16953
17220
|
...parsePermRules({ allow: args.allowedTools }),
|
|
@@ -17052,7 +17319,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
17052
17319
|
try {
|
|
17053
17320
|
mkdirSync12(dir, { recursive: true });
|
|
17054
17321
|
} catch (e) {
|
|
17055
|
-
|
|
17322
|
+
log33.debug("paste image dir create failed", e);
|
|
17056
17323
|
}
|
|
17057
17324
|
const img = grabClipboardImage(dir, String(Date.now()));
|
|
17058
17325
|
return img ? { display: "Image", ref: "@" + img.path, path: img.path } : null;
|
|
@@ -17165,7 +17432,7 @@ Added entries are loadable now via the Skill/SlashCommand tools; removed ones ar
|
|
|
17165
17432
|
mkdirSync12(join14(cwd, ".agent"), { recursive: true });
|
|
17166
17433
|
appendFileSync(histPath, line + "\n");
|
|
17167
17434
|
} catch (e) {
|
|
17168
|
-
|
|
17435
|
+
log33.debug("history write failed", e);
|
|
17169
17436
|
}
|
|
17170
17437
|
};
|
|
17171
17438
|
const ago = (t) => {
|
|
@@ -17237,7 +17504,7 @@ Added entries are loadable now via the Skill/SlashCommand tools; removed ones ar
|
|
|
17237
17504
|
try {
|
|
17238
17505
|
store.save(session);
|
|
17239
17506
|
} catch (e) {
|
|
17240
|
-
|
|
17507
|
+
log33.debug("session save after rewind failed", e);
|
|
17241
17508
|
}
|
|
17242
17509
|
err(green(" \u27F2 jumped back") + dim(` \u2014 ${face.transcript.length} message(s) kept; edit + resend
|
|
17243
17510
|
`));
|
|
@@ -17272,14 +17539,14 @@ ${task}`;
|
|
|
17272
17539
|
bangContext.length = 0;
|
|
17273
17540
|
}
|
|
17274
17541
|
const delta = await refreshCatalogs().catch((e) => {
|
|
17275
|
-
|
|
17542
|
+
log33.debug("catalog refresh failed", e);
|
|
17276
17543
|
return "";
|
|
17277
17544
|
});
|
|
17278
17545
|
if (delta) {
|
|
17279
17546
|
err(dim(" \u27F3 skill/command catalog changed \u2014 delta attached to this turn\n"));
|
|
17280
17547
|
task += "\n\n" + delta;
|
|
17281
17548
|
}
|
|
17282
|
-
const r = await runTurn(face, store, session, task, duplex ? void 0 : checkpoints, cwd, sendVia
|
|
17549
|
+
const r = await runTurn(face, store, session, task, duplex ? void 0 : checkpoints, cwd, sendVia ? (c) => sendVia(c, opts) : routeVia);
|
|
17283
17550
|
if (voiceIO) {
|
|
17284
17551
|
voiceReasonEnd();
|
|
17285
17552
|
voiceEchoEnd();
|
|
@@ -17536,7 +17803,7 @@ ${task}`;
|
|
|
17536
17803
|
desc: "rescan skills/commands dirs and rebuild the system prompt (one cache miss) \u2014 picks up entries created mid-session",
|
|
17537
17804
|
run: async () => {
|
|
17538
17805
|
await refreshCatalogs().catch((e) => {
|
|
17539
|
-
|
|
17806
|
+
log33.debug("catalog refresh failed", e);
|
|
17540
17807
|
});
|
|
17541
17808
|
face.reprepare();
|
|
17542
17809
|
err(green(` \u2713 reloaded \u2014 ${skills.length} skill(s), ${cmds.length} command(s); system prompt rebuilds on next message
|
|
@@ -18038,7 +18305,7 @@ ${task}`;
|
|
|
18038
18305
|
try {
|
|
18039
18306
|
for (const def of (await loadAgents(fs2, d)).agents) if (!seen.has(def.name)) seen.set(def.name, { def, from: d });
|
|
18040
18307
|
} catch (e) {
|
|
18041
|
-
|
|
18308
|
+
log33.debug(`loadAgents(${d}) failed`, e);
|
|
18042
18309
|
}
|
|
18043
18310
|
}
|
|
18044
18311
|
if (!seen.size) {
|
|
@@ -18126,7 +18393,7 @@ ${task}`;
|
|
|
18126
18393
|
}
|
|
18127
18394
|
if (idx >= 0) {
|
|
18128
18395
|
const old = mounted.splice(idx, 1)[0];
|
|
18129
|
-
await old.client.close().catch((e) =>
|
|
18396
|
+
await old.client.close().catch((e) => log33.debug("mcp close failed", e));
|
|
18130
18397
|
}
|
|
18131
18398
|
try {
|
|
18132
18399
|
const m = await mountMcpServer(name, conf);
|
|
@@ -18154,7 +18421,7 @@ ${task}`;
|
|
|
18154
18421
|
}
|
|
18155
18422
|
const m = mounted.splice(idx, 1)[0];
|
|
18156
18423
|
remountMcpTools();
|
|
18157
|
-
await m.client.close().catch((e) =>
|
|
18424
|
+
await m.client.close().catch((e) => log33.debug("mcp close failed", e));
|
|
18158
18425
|
err(dim(` removed "${name}"
|
|
18159
18426
|
`));
|
|
18160
18427
|
return;
|
|
@@ -18357,7 +18624,7 @@ ${task}`;
|
|
|
18357
18624
|
try {
|
|
18358
18625
|
return readdirSync4(join14(cwd, absDir.replace(/^\/+/, "")), { withFileTypes: true }).map((d) => ({ name: d.name, dir: d.isDirectory() }));
|
|
18359
18626
|
} catch (e) {
|
|
18360
|
-
|
|
18627
|
+
log33.debug("completion readdir failed", absDir, e);
|
|
18361
18628
|
return null;
|
|
18362
18629
|
}
|
|
18363
18630
|
};
|
|
@@ -18494,7 +18761,7 @@ ${out}
|
|
|
18494
18761
|
return;
|
|
18495
18762
|
}
|
|
18496
18763
|
await refreshCatalogs().catch((e) => {
|
|
18497
|
-
|
|
18764
|
+
log33.debug("catalog refresh failed", e);
|
|
18498
18765
|
});
|
|
18499
18766
|
const sk = skills.find((x) => x.name === name);
|
|
18500
18767
|
if (sk) {
|
|
@@ -18605,7 +18872,7 @@ ${out}
|
|
|
18605
18872
|
if (delivery || cut) dx?.parkCutDelivery(delivery, !!cut, heard);
|
|
18606
18873
|
const cutReply = cut && cut.full.length - cut.heard.length > 40 ? cut : null;
|
|
18607
18874
|
const noteP = replaces ? replaces.note : !cutReply ? Promise.resolve("") : (instinct ? instinct.bargeIntent(text).catch((e) => {
|
|
18608
|
-
|
|
18875
|
+
log33.warn(`barge intent failed \u2014 model decides: ${e.message}`);
|
|
18609
18876
|
return void 0;
|
|
18610
18877
|
}) : Promise.resolve(void 0)).then(async (intent) => interruptionNote(cutReply, intent) + ackedNote(await instinct?.ackFor(text)));
|
|
18611
18878
|
const cutIn = replaces ? replaces.cutIn : interjectNote;
|
|
@@ -18994,6 +19261,10 @@ async function main() {
|
|
|
18994
19261
|
}
|
|
18995
19262
|
const cwd = resolve4(args.cwd ?? process.cwd());
|
|
18996
19263
|
const cfg = await loadConfig(cwd);
|
|
19264
|
+
if (!args.autoRoute && !args.model && (cfg.model === "auto" || !cfg.model && await jevAvailable())) {
|
|
19265
|
+
args.autoRoute = true;
|
|
19266
|
+
args.model = autoModels().standard;
|
|
19267
|
+
}
|
|
18997
19268
|
cfg.permissions = mergePerms(loadClaudeSettings(cwd), mergePerms(loadPersistedRules(cwd), cfg.permissions));
|
|
18998
19269
|
if (canPrompt && !args.yes && !isTrusted(cwd)) {
|
|
18999
19270
|
const ok = await makeHost().confirm?.(`Trust this directory? agent.libx will read and edit files in:
|
|
@@ -19043,7 +19314,7 @@ async function main() {
|
|
|
19043
19314
|
const store = new SessionStore(cwd);
|
|
19044
19315
|
const session = startSession(args, store, agent, cwd);
|
|
19045
19316
|
process.once("SIGINT", () => activeTurn?.abort());
|
|
19046
|
-
const { ok, res } = await runTurn(agent, store, session, args.task, void 0, cwd);
|
|
19317
|
+
const { ok, res } = await runTurn(agent, store, session, args.task, void 0, cwd, autoRouteSend(args, agent, () => session, (m) => providerOptionsFor(m, cwd, cfg.mcpServers, mounted.map((x) => x.name))));
|
|
19047
19318
|
if (cfg.reflectOnFailure && !ok && res?.finishReason !== "needs_input" && res && agent.options.memoryDir) {
|
|
19048
19319
|
const _fsBase = agent.options.fs.getCwd() === "/" ? "" : agent.options.fs.getCwd();
|
|
19049
19320
|
const slug2 = await reflectOnRun({ ai, model: agent.options.model, fs: agent.options.fs, dir: primaryMemDir(agent.options.memoryDir, `${_fsBase}/.agent/memory`), result: res });
|
|
@@ -19090,6 +19361,7 @@ export {
|
|
|
19090
19361
|
runShellLine,
|
|
19091
19362
|
runTurn,
|
|
19092
19363
|
setMcpMentionResolver,
|
|
19093
|
-
summarizeResult
|
|
19364
|
+
summarizeResult,
|
|
19365
|
+
turnCost
|
|
19094
19366
|
};
|
|
19095
19367
|
//# sourceMappingURL=cli.js.map
|