agent.libx.js 0.93.26 → 0.93.28
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 +89 -80
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +159 -57
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1466,7 +1466,7 @@ function makeRealShellTool(options) {
|
|
|
1466
1466
|
proc.stderr?.on("data", collect);
|
|
1467
1467
|
proc.on("error", (err2) => {
|
|
1468
1468
|
if (err2?.name === "AbortError" || ctl.signal.aborted) return finish(reasonFor(timedOut, timeoutMs, clean(out)));
|
|
1469
|
-
|
|
1469
|
+
log12.debug("shell spawn error", err2);
|
|
1470
1470
|
finish(`[exit 1] ${err2?.message ?? err2}${out ? "\n" + clean(out) : ""}`);
|
|
1471
1471
|
});
|
|
1472
1472
|
proc.on("close", (code) => {
|
|
@@ -1528,14 +1528,14 @@ ${clean(out) || "(no output yet)"}`;
|
|
|
1528
1528
|
}
|
|
1529
1529
|
];
|
|
1530
1530
|
}
|
|
1531
|
-
var
|
|
1531
|
+
var log12, clean, SECRET_ENV_RE, _spawn, ShellJobRegistry, NO_JOB2;
|
|
1532
1532
|
var init_tools_shell = __esm({
|
|
1533
1533
|
"src/tools.shell.ts"() {
|
|
1534
1534
|
"use strict";
|
|
1535
1535
|
init_tools();
|
|
1536
1536
|
init_redact();
|
|
1537
1537
|
init_logging();
|
|
1538
|
-
|
|
1538
|
+
log12 = forComponent("shell");
|
|
1539
1539
|
clean = (s) => truncateOutput(redactSecrets(s.replace(/\n+$/, "")));
|
|
1540
1540
|
SECRET_ENV_RE = /(_API_KEY|_TOKEN|_SECRET|_PASSWORD|_PRIVATE_KEY|^AWS_|^GITHUB_TOKEN$|^OPENAI_|^ANTHROPIC_|^GOOGLE_|^GEMINI_|^GROQ_|^NPM_TOKEN$)/i;
|
|
1541
1541
|
ShellJobRegistry = class {
|
|
@@ -3468,9 +3468,15 @@ init_tools_structured();
|
|
|
3468
3468
|
init_todo();
|
|
3469
3469
|
init_tools_web();
|
|
3470
3470
|
|
|
3471
|
+
// src/scratch.ts
|
|
3472
|
+
init_tools();
|
|
3473
|
+
init_tools_structured();
|
|
3474
|
+
init_logging();
|
|
3475
|
+
var log4 = forComponent("scratch");
|
|
3476
|
+
|
|
3471
3477
|
// src/lessons.ts
|
|
3472
3478
|
init_logging();
|
|
3473
|
-
var
|
|
3479
|
+
var log5 = forComponent("Lessons");
|
|
3474
3480
|
var LessonOptionsDefaults = class {
|
|
3475
3481
|
minRepeats = 2;
|
|
3476
3482
|
};
|
|
@@ -3495,15 +3501,15 @@ function lessonCapture(options) {
|
|
|
3495
3501
|
counts.set(lesson.slug, n);
|
|
3496
3502
|
if (n < o.minRepeats) return;
|
|
3497
3503
|
written.add(lesson.slug);
|
|
3498
|
-
await writeFact(o.fs, o.dir, lesson.slug, lesson.body).catch((e) =>
|
|
3499
|
-
|
|
3504
|
+
await writeFact(o.fs, o.dir, lesson.slug, lesson.body).catch((e) => log5.warn(`could not persist ${lesson.slug}: ${e?.message ?? e}`));
|
|
3505
|
+
log5.debug(`captured lesson ${lesson.slug} (recurred ${n}\xD7)`);
|
|
3500
3506
|
}
|
|
3501
3507
|
};
|
|
3502
3508
|
}
|
|
3503
3509
|
|
|
3504
3510
|
// src/reflect.ts
|
|
3505
3511
|
init_logging();
|
|
3506
|
-
var
|
|
3512
|
+
var log6 = forComponent("Reflect");
|
|
3507
3513
|
async function reflectOnRun(o) {
|
|
3508
3514
|
const digest = digestRun(o.result.messages, o.maxDigestChars ?? 6e3);
|
|
3509
3515
|
if (!digest.trim()) return null;
|
|
@@ -3519,7 +3525,7 @@ If the run was fine or the issue was purely task-specific (not generalizable), r
|
|
|
3519
3525
|
const r = await o.ai.chat({ model: o.model, messages: [{ role: "user", content: prompt }], stream: false });
|
|
3520
3526
|
text = r?.content ?? "";
|
|
3521
3527
|
} catch (e) {
|
|
3522
|
-
|
|
3528
|
+
log6.warn(`reflection call failed: ${e?.message ?? e}`);
|
|
3523
3529
|
return null;
|
|
3524
3530
|
}
|
|
3525
3531
|
const m = text.match(/LESSON:\s*(.+)/i);
|
|
@@ -3529,10 +3535,10 @@ If the run was fine or the issue was purely task-specific (not generalizable), r
|
|
|
3529
3535
|
try {
|
|
3530
3536
|
await writeFact(o.fs, o.dir, slug, lesson);
|
|
3531
3537
|
} catch (e) {
|
|
3532
|
-
|
|
3538
|
+
log6.warn(`could not persist lesson: ${e?.message ?? e}`);
|
|
3533
3539
|
return null;
|
|
3534
3540
|
}
|
|
3535
|
-
|
|
3541
|
+
log6.debug(`reflection persisted ${slug}`);
|
|
3536
3542
|
return slug;
|
|
3537
3543
|
}
|
|
3538
3544
|
function digestRun(messages, maxChars) {
|
|
@@ -3549,7 +3555,7 @@ function digestRun(messages, maxChars) {
|
|
|
3549
3555
|
// src/duplex.ts
|
|
3550
3556
|
import { MemFilesystem as MemFilesystem2 } from "@livx.cc/wcli/core";
|
|
3551
3557
|
init_logging();
|
|
3552
|
-
var
|
|
3558
|
+
var log7 = forComponent("DuplexAgent");
|
|
3553
3559
|
function describeCall(call) {
|
|
3554
3560
|
const v = call.args && Object.values(call.args).find((x) => typeof x === "string" && x.trim());
|
|
3555
3561
|
const hint = v ? ` (${String(v).replace(/\s+/g, " ").trim().slice(0, 48)})` : "";
|
|
@@ -3603,7 +3609,7 @@ var DuplexAgentOptions = class {
|
|
|
3603
3609
|
/** User-scope memory dir for global facts (type=user/feedback). Forwarded to Remember's routing. */
|
|
3604
3610
|
memoryUserDir;
|
|
3605
3611
|
};
|
|
3606
|
-
var VOICE_SYSTEM_PROMPT = 'You are a spoken voice assistant \u2014 the user HEARS everything you say. Use short sentences. One idea per sentence. No markdown, no bullet lists, no code blocks, no headings, no emoji.\nKeep turns SHORT \u2014 one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\nYou have three cognitive tiers \u2014 like a human brain:\n\u2022 YOU (reflex) \u2014 instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\n\u2022 `Act` \u2014 your hands. A background worker with its own configured tools and access to the user\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building \u2014 any real work.\n{{THINK_SLOT}}\nWhen you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant \u2014 it lists your worker\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\'t. To actually DO real work, call `Act`. When the user mentions their project, folder, files, or environment ("this project", "the current folder", "my code"), call `Act` IMMEDIATELY \u2014 do not ask for paths or details the worker can discover itself. Never pretend to have done the work or invent results \u2014 the worker\'s report is your only source.\nALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do ("got it \u2014 opening that now", "sure, let me pull it up", "okay, checking"). NEVER call a tool (Act, Think, QuickLook) silently \u2014 the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn \u2014 end it and do not wait for the result.\nResults arrive later as events like "[task t1 completed] \u2026" or "[task t1 failed] \u2026". When one arrives,
|
|
3612
|
+
var VOICE_SYSTEM_PROMPT = 'You are a spoken voice assistant \u2014 the user HEARS everything you say. Use short sentences. One idea per sentence. No markdown, no bullet lists, no code blocks, no headings, no emoji.\nKeep turns SHORT \u2014 one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\nYou have three cognitive tiers \u2014 like a human brain:\n\u2022 YOU (reflex) \u2014 instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\n\u2022 `Act` \u2014 your hands. A background worker with its own configured tools and access to the user\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building \u2014 any real work.\n{{THINK_SLOT}}\nWhen you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant \u2014 it lists your worker\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\'t. To actually DO real work, call `Act`. When the user mentions their project, folder, files, or environment ("this project", "the current folder", "my code"), call `Act` IMMEDIATELY \u2014 do not ask for paths or details the worker can discover itself. Never pretend to have done the work or invent results \u2014 the worker\'s report is your only source.\nALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do ("got it \u2014 opening that now", "sure, let me pull it up", "okay, checking"). NEVER call a tool (Act, Think, QuickLook) silently \u2014 the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn \u2014 end it and do not wait for the result.\nResults arrive later as events like "[task t1 completed] \u2026" or "[task t1 failed] \u2026". When one arrives, speak the USEFUL gist in one or two short sentences \u2014 the actual answer the user wanted (the headline finding, the key numbers), not the thinnest possible "it\'s done". A forecast \u2192 say it\'s calm AND that it\'s good for swimming but not surf; a count \u2192 say the number. Be brief, but do not drop the substance. If the result is a LIST (search results, multiple files/matches), the user CANNOT see it \u2014 there is no screen and no numbered menu to point at. Speak the gist: say what you found and name the top one or two by NAME (the source, not "the first one" or a number), then ask plainly if they want more. Never ask them to "pick which one" or reference items by position. The completed result stays in YOUR context \u2014 it is yours to draw on. When the user follows up ("tell me more", "what else", "and?"), answer FROM that result first: you already have the detail, so elaborate on what you have. Do NOT spawn a fresh worker to re-search or re-gather what you were just handed. Re-dispatch ONLY when genuinely new information is needed \u2014 e.g. the user wants the full contents of a SPECIFIC source, which is one WebFetch of that URL, not a brand-new search. "[task t1 progress] \u2026" events are interim status, NOT results \u2014 give at most a half-sentence aside ("still on it \u2014 running tests now") and end your turn. Never present progress as a finished result.\nCRITICAL: while a task is still running you have NO answer yet \u2014 never state a specific result of any kind (a number, size, count, name, path, or value). The real answer arrives ONLY in the "[task \u2026 completed]" event; inventing one meanwhile (a made-up disk size, commit count, etc.) is a serious error. Until then, only acknowledge and wait.\nNever read raw file paths, diffs, or code aloud verbatim.\n"[task t1 asks] \u2026" events are QUESTIONS from a background task \u2014 relay to the user in your own words, short, then end your turn. When the user answers, call `AnswerTask` with that id and their answer. NEVER answer on the user\'s behalf for permissions or risky operations; if their reply is ambiguous, confirm first.\nIf the user\'s message sounds INCOMPLETE \u2014 trailing off mid-sentence, a fragment that needs more context ("and then we", "but the problem is"), hesitation fillers ("uh", "um") \u2014 call `Hold` instead of answering. This keeps listening for the rest of their thought. Only respond with substance when you have a complete question or request.\nDispatch discipline: send ONE self-contained task per request \u2014 a single worker with the full brief beats several workers with fragments (each worker starts fresh and re-discovers context). NEVER dispatch a worker just to read files or gather information \u2014 workers explore and discover context themselves; pass on what you already know and let one worker do the whole job. Split into parallel tasks only when the user asks for genuinely independent things. When a task completes, report its result and stop \u2014 do NOT dispatch follow-up work (verification, polish, extras) the user did not ask for, unless the report itself signals failure or doubt.\nDo not fire a second Act/Think for work already in flight, and NEVER spawn a second task to re-count, cross-check, or verify a result a worker already gave you \u2014 trust its answer; a single question gets ONE task. Call `TaskStatus` at most ONCE per turn; if a task is still running, just say "still on it" and end the turn \u2014 never poll it again and again in a loop. Use `CancelTask` when the user asks to stop something.\nPRIORITY: when the user says goodbye or wants to end/finish/wrap up the session ("ok bye", "that\'s all", "let\'s finish", "let\'s end", "goodnight", "exit", "wrap up"), call `ExitSession` IMMEDIATELY \u2014 do not act, do not check status, just exit.\nFor TRIVIAL instant lookups only \u2014 current time, git branch, listing a folder, peeking at a small file, or checking your own `capabilities`/tools \u2014 use `QuickLook` (instant, no task). Whenever the user asks what you can do or whether you have some ability, QuickLook `capabilities` and answer from that \u2014 never guess. Anything requiring searching, reasoning, running commands, or editing goes through `Act`.\n{{MEMORY_SLOT}}\nUser messages may arrive via speech-to-text and can carry transcription artifacts \u2014 odd words, cut-offs, homophones ("for you" vs "folder"). Read for INTENT, not surface text. If a message seems garbled or surprising, briefly confirm what they meant ("did you mean\u2026?") instead of answering the literal words.';
|
|
3607
3613
|
var THINK_GUIDANCE = "\u2022 `Think` \u2014 your brain. A premium reasoning model, FAR more expensive than Act. Reserve it for open-ended architecture/design questions, or a problem Act already FAILED at. ALL implementation work \u2014 coding, refactoring, debugging, edge cases, tests \u2014 goes to Act; Act is highly capable. Never send the same work to both.";
|
|
3608
3614
|
var THINK_DISABLED_GUIDANCE = "(Think tier is not available \u2014 use Act for all escalations.)";
|
|
3609
3615
|
var VOICE_STYLE_CONVERSATIONAL = `Speak like a person in a live conversation, not an assistant reading a script. React first, then deliver: a quick impulsive beat ("oh nice", "hmm, hold on", "ah, got it") before the substance. Use contractions always. Vary sentence length \u2014 some very short. Light fillers and backchannels are fine ("mm-hm", "right", "let's see") but at most one per reply \u2014 never stack them. When you escalate to Act or Think, say it like a human would ("hang on, let me actually dig into that \u2014 gimme a minute") instead of announcing a task. When a result comes back, react to it like you just found out ("okay so \u2014 turns out\u2026"). Match the user's energy: a quick question gets a quick answer \u2014 a few words is a perfectly good turn. Prefer a short answer plus an offer ("want the details?") over covering everything. Never narrate your own mechanics (no "I will now act", no task ids out loud).`;
|
|
@@ -3726,7 +3732,7 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
|
|
|
3726
3732
|
try {
|
|
3727
3733
|
await this.voice.send("[reminder] You dispatched a task but said nothing to the user. Say ONE short spoken acknowledgement now \u2014 no tools.");
|
|
3728
3734
|
} catch (e) {
|
|
3729
|
-
|
|
3735
|
+
log7.warn(`ack nudge failed: ${e instanceof Error ? e.message : e}`);
|
|
3730
3736
|
} finally {
|
|
3731
3737
|
this.nudging = false;
|
|
3732
3738
|
}
|
|
@@ -3849,7 +3855,7 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
3849
3855
|
this.notify("task_verify", `task ${id}: verifying`, { id });
|
|
3850
3856
|
const cres = await new Agent(agentOpts).run(checkBrief);
|
|
3851
3857
|
if (cres.finishReason !== "stop") {
|
|
3852
|
-
|
|
3858
|
+
log7.warn(`task ${id}: verify inconclusive (${cres.finishReason})`);
|
|
3853
3859
|
this.notify("task_verify", `task ${id}: verify inconclusive (${cres.finishReason})`, { id, finishReason: cres.finishReason });
|
|
3854
3860
|
}
|
|
3855
3861
|
const sum = (a = 0, b = 0) => a + b;
|
|
@@ -3951,7 +3957,7 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
3951
3957
|
return this.failTask(rec, msg);
|
|
3952
3958
|
}
|
|
3953
3959
|
rec.status = "done";
|
|
3954
|
-
|
|
3960
|
+
log7.verbose(`task ${id} done (${res.steps} steps)`);
|
|
3955
3961
|
this.notify("task_done", `task ${id} (${rec.label}) completed`, {
|
|
3956
3962
|
id,
|
|
3957
3963
|
text: res.text,
|
|
@@ -3968,7 +3974,7 @@ Another agent just implemented the above. Independently check the CURRENT state
|
|
|
3968
3974
|
failTask(rec, msg) {
|
|
3969
3975
|
this.dropAsk(rec.id);
|
|
3970
3976
|
rec.status = "error";
|
|
3971
|
-
|
|
3977
|
+
log7.warn(`task ${rec.id} failed: ${msg}`);
|
|
3972
3978
|
this.notify("task_error", `task ${rec.id} (${rec.label}) failed: ${msg}`);
|
|
3973
3979
|
this.queueRevoice(`[task ${rec.id} failed] ${msg}`);
|
|
3974
3980
|
}
|
|
@@ -4207,7 +4213,7 @@ init_logging();
|
|
|
4207
4213
|
|
|
4208
4214
|
// src/voice/engine.ts
|
|
4209
4215
|
init_logging();
|
|
4210
|
-
var
|
|
4216
|
+
var log8 = forComponent("VoiceEngine");
|
|
4211
4217
|
var now = () => performance.now();
|
|
4212
4218
|
var VoiceEngineOptions = class {
|
|
4213
4219
|
stt;
|
|
@@ -4314,7 +4320,7 @@ var VoiceEngine = class _VoiceEngine {
|
|
|
4314
4320
|
this.stt.onLevel = (rms) => this.handleLevel(rms);
|
|
4315
4321
|
await Promise.all([this.tts.connect(), this.stt.start()]);
|
|
4316
4322
|
this.setState("listening");
|
|
4317
|
-
|
|
4323
|
+
log8.debug(`voice I/O up (${this.stt.usingAec ? "AEC" : "heuristic echo"} capture)`);
|
|
4318
4324
|
}
|
|
4319
4325
|
get usingAec() {
|
|
4320
4326
|
return this.stt.usingAec;
|
|
@@ -4366,7 +4372,7 @@ var VoiceEngine = class _VoiceEngine {
|
|
|
4366
4372
|
this.reply += text;
|
|
4367
4373
|
for (const w of this.words(this.reply)) this.echoWords.add(w);
|
|
4368
4374
|
this.tts.speak(text, true);
|
|
4369
|
-
if (!this.spokeDeltas && this.turnStartAt)
|
|
4375
|
+
if (!this.spokeDeltas && this.turnStartAt) log8.debug(`ttft: ${Math.round(now() - this.turnStartAt)}ms`);
|
|
4370
4376
|
this.spokeDeltas = true;
|
|
4371
4377
|
this.setState("speaking");
|
|
4372
4378
|
}
|
|
@@ -4387,7 +4393,7 @@ var VoiceEngine = class _VoiceEngine {
|
|
|
4387
4393
|
}
|
|
4388
4394
|
this.drainTimer = null;
|
|
4389
4395
|
this.speaking = false;
|
|
4390
|
-
if (this.turnStartAt)
|
|
4396
|
+
if (this.turnStartAt) log8.debug(`turn: ${Math.round(now() - this.turnStartAt)}ms (incl. playback)`);
|
|
4391
4397
|
this.echoUntil = now() + 2500;
|
|
4392
4398
|
if (!this.usingAec) this.stt.reset();
|
|
4393
4399
|
this.setState("listening");
|
|
@@ -4528,7 +4534,7 @@ var VoiceEngine = class _VoiceEngine {
|
|
|
4528
4534
|
this.pendingUtt = this.pendingUtt ? `${this.pendingUtt} ${text}` : text;
|
|
4529
4535
|
if (this.pendingTimer) clearTimeout(this.pendingTimer);
|
|
4530
4536
|
if (this.options.incompleteMergeMs && this.looksIncomplete(this.pendingUtt)) {
|
|
4531
|
-
|
|
4537
|
+
log8.verbose(`hold: incomplete utterance "${this.pendingUtt.slice(-40)}"`);
|
|
4532
4538
|
this.options.onHold();
|
|
4533
4539
|
if (this.options.holdFiller && !this.speaking) {
|
|
4534
4540
|
this.beginSpeech();
|
|
@@ -4626,7 +4632,7 @@ async function resolveAuth(auth) {
|
|
|
4626
4632
|
}
|
|
4627
4633
|
|
|
4628
4634
|
// src/voice/soniox.ts
|
|
4629
|
-
var
|
|
4635
|
+
var log9 = forComponent("SonioxSTT");
|
|
4630
4636
|
var now2 = () => performance.now();
|
|
4631
4637
|
var SonioxSTTOptions = class {
|
|
4632
4638
|
auth = "";
|
|
@@ -4683,9 +4689,9 @@ var SonioxSTT = class {
|
|
|
4683
4689
|
this.ws.onmessage = (ev) => this.handle(JSON.parse(String(ev.data)));
|
|
4684
4690
|
this.ws.onclose = (ev) => {
|
|
4685
4691
|
if (this.stopped) return;
|
|
4686
|
-
|
|
4692
|
+
log9.warn(`soniox ws closed (${ev.code} ${ev.reason || ""}) \u2014 reconnecting`);
|
|
4687
4693
|
this.reset();
|
|
4688
|
-
this.connectWs().catch((e) =>
|
|
4694
|
+
this.connectWs().catch((e) => log9.error(`soniox reconnect failed: ${e.message}`));
|
|
4689
4695
|
};
|
|
4690
4696
|
}
|
|
4691
4697
|
async start() {
|
|
@@ -4695,7 +4701,7 @@ var SonioxSTT = class {
|
|
|
4695
4701
|
this.endpointTimer = setInterval(() => {
|
|
4696
4702
|
const combined = (this.finalText + this.partialText).trim();
|
|
4697
4703
|
if (!combined || now2() - this.lastChangeAt < this.options.silenceEndpointMs) return;
|
|
4698
|
-
if (this.firstTokenAt)
|
|
4704
|
+
if (this.firstTokenAt) log9.debug(`stt: ${Math.round(now2() - this.firstTokenAt)}ms first-token\u2192silence-endpoint, "${combined.slice(0, 60)}"`);
|
|
4699
4705
|
this.reset();
|
|
4700
4706
|
this.onUtterance(combined, now2());
|
|
4701
4707
|
}, 120);
|
|
@@ -4712,7 +4718,7 @@ var SonioxSTT = class {
|
|
|
4712
4718
|
});
|
|
4713
4719
|
}
|
|
4714
4720
|
handle(m) {
|
|
4715
|
-
if (m.error_message) return
|
|
4721
|
+
if (m.error_message) return log9.error(`soniox: ${m.error_message}`);
|
|
4716
4722
|
let endpoint = false;
|
|
4717
4723
|
for (const t of m.tokens ?? []) {
|
|
4718
4724
|
if (t.text === "<end>") endpoint = true;
|
|
@@ -4728,7 +4734,7 @@ var SonioxSTT = class {
|
|
|
4728
4734
|
this.onPartial(combined);
|
|
4729
4735
|
if (endpoint && this.finalText.trim()) {
|
|
4730
4736
|
const utterance = this.finalText.trim();
|
|
4731
|
-
if (this.firstTokenAt)
|
|
4737
|
+
if (this.firstTokenAt) log9.debug(`stt: ${Math.round(now2() - this.firstTokenAt)}ms first-token\u2192endpoint, "${utterance.slice(0, 60)}"`);
|
|
4732
4738
|
this.reset();
|
|
4733
4739
|
this.onUtterance(utterance, now2());
|
|
4734
4740
|
}
|
|
@@ -4750,7 +4756,7 @@ var SonioxSTT = class {
|
|
|
4750
4756
|
|
|
4751
4757
|
// src/voice/cartesia.ts
|
|
4752
4758
|
init_logging();
|
|
4753
|
-
var
|
|
4759
|
+
var log10 = forComponent("CartesiaTTS");
|
|
4754
4760
|
var now3 = () => performance.now();
|
|
4755
4761
|
var CartesiaTTSOptions = class {
|
|
4756
4762
|
auth = "";
|
|
@@ -4795,9 +4801,9 @@ var CartesiaTTS = class _CartesiaTTS {
|
|
|
4795
4801
|
this.ws.onerror = (e) => rej(new Error(`cartesia ws: ${e.message || "connect failed"}`));
|
|
4796
4802
|
});
|
|
4797
4803
|
this.ws.onclose = (ev) => {
|
|
4798
|
-
|
|
4804
|
+
log10.warn(`cartesia ws closed (${ev.code} ${ev.reason || ""})`);
|
|
4799
4805
|
if (!this.closed) {
|
|
4800
|
-
this.connecting = this.doConnect().catch((e) =>
|
|
4806
|
+
this.connecting = this.doConnect().catch((e) => log10.error(`cartesia reconnect failed: ${e.message}`));
|
|
4801
4807
|
}
|
|
4802
4808
|
};
|
|
4803
4809
|
this.ws.onmessage = (ev) => {
|
|
@@ -4807,7 +4813,7 @@ var CartesiaTTS = class _CartesiaTTS {
|
|
|
4807
4813
|
this.consecutiveErrors = 0;
|
|
4808
4814
|
if (this.down) {
|
|
4809
4815
|
this.down = false;
|
|
4810
|
-
|
|
4816
|
+
log10.info("TTS recovered");
|
|
4811
4817
|
this.stopProbe();
|
|
4812
4818
|
}
|
|
4813
4819
|
if (!this.firstAudioAt) this.firstAudioAt = now3();
|
|
@@ -4816,7 +4822,7 @@ var CartesiaTTS = class _CartesiaTTS {
|
|
|
4816
4822
|
this.consecutiveErrors = 0;
|
|
4817
4823
|
if (this.down) {
|
|
4818
4824
|
this.down = false;
|
|
4819
|
-
|
|
4825
|
+
log10.info("TTS recovered");
|
|
4820
4826
|
this.stopProbe();
|
|
4821
4827
|
}
|
|
4822
4828
|
this.onDone();
|
|
@@ -4825,11 +4831,11 @@ var CartesiaTTS = class _CartesiaTTS {
|
|
|
4825
4831
|
this.consecutiveErrors++;
|
|
4826
4832
|
if (!this.down && this.consecutiveErrors >= _CartesiaTTS.CB_THRESHOLD) {
|
|
4827
4833
|
this.down = true;
|
|
4828
|
-
|
|
4834
|
+
log10.warn(`TTS circuit breaker open \u2014 ${this.consecutiveErrors} consecutive errors, switching to text-only`);
|
|
4829
4835
|
this.onDone();
|
|
4830
4836
|
this.startProbe();
|
|
4831
4837
|
} else if (!this.down) {
|
|
4832
|
-
|
|
4838
|
+
log10.warn(`cartesia: ${JSON.stringify(m)}`);
|
|
4833
4839
|
}
|
|
4834
4840
|
}
|
|
4835
4841
|
};
|
|
@@ -4910,7 +4916,7 @@ import { MemFilesystem as MemFilesystem3, IndexedDbFilesystem, CommandExecutor a
|
|
|
4910
4916
|
init_logging();
|
|
4911
4917
|
import { spawn } from "child_process";
|
|
4912
4918
|
import { createHash } from "crypto";
|
|
4913
|
-
var
|
|
4919
|
+
var log11 = forComponent("mcp");
|
|
4914
4920
|
var PROTOCOL_VERSION = "2025-06-18";
|
|
4915
4921
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
4916
4922
|
var StdioTransport = class {
|
|
@@ -4929,7 +4935,7 @@ var StdioTransport = class {
|
|
|
4929
4935
|
proc.stdout.setEncoding("utf8");
|
|
4930
4936
|
proc.stdout.on("data", (chunk) => this.onData(chunk));
|
|
4931
4937
|
proc.stderr.setEncoding("utf8");
|
|
4932
|
-
proc.stderr.on("data", (chunk) =>
|
|
4938
|
+
proc.stderr.on("data", (chunk) => log11.debug(`[${command}] stderr:`, chunk.trimEnd()));
|
|
4933
4939
|
proc.on("exit", (code) => this.failAll(new Error(`MCP server "${command}" exited (code ${code})`)));
|
|
4934
4940
|
proc.on("error", (e) => this.failAll(e instanceof Error ? e : new Error(String(e))));
|
|
4935
4941
|
}
|
|
@@ -4943,7 +4949,7 @@ var StdioTransport = class {
|
|
|
4943
4949
|
try {
|
|
4944
4950
|
this.dispatch(JSON.parse(line));
|
|
4945
4951
|
} catch (e) {
|
|
4946
|
-
|
|
4952
|
+
log11.debug("dropping non-JSON line from MCP server:", line, e);
|
|
4947
4953
|
}
|
|
4948
4954
|
}
|
|
4949
4955
|
}
|
|
@@ -4992,7 +4998,7 @@ var StdioTransport = class {
|
|
|
4992
4998
|
try {
|
|
4993
4999
|
this.proc?.stdin?.end();
|
|
4994
5000
|
} catch (e) {
|
|
4995
|
-
|
|
5001
|
+
log11.debug("stdin end failed", e);
|
|
4996
5002
|
}
|
|
4997
5003
|
this.proc?.kill();
|
|
4998
5004
|
}
|
|
@@ -5061,7 +5067,7 @@ function parseSseResponse(body) {
|
|
|
5061
5067
|
const obj = JSON.parse(trimmed.slice(5).trim());
|
|
5062
5068
|
if (obj && (obj.result !== void 0 || obj.error !== void 0)) return obj;
|
|
5063
5069
|
} catch (e) {
|
|
5064
|
-
|
|
5070
|
+
log11.debug("skipping unparseable SSE data line", e);
|
|
5065
5071
|
}
|
|
5066
5072
|
}
|
|
5067
5073
|
return {};
|
|
@@ -5129,7 +5135,7 @@ async function mountWithDeadline(name, cfg, mountTimeoutMs) {
|
|
|
5129
5135
|
return { name, client, tools, specs, serverInfo: init?.serverInfo };
|
|
5130
5136
|
})(), mountTimeoutMs, name);
|
|
5131
5137
|
} catch (e) {
|
|
5132
|
-
await client.close().catch((err2) =>
|
|
5138
|
+
await client.close().catch((err2) => log11.debug(`close after failed mount of "${name}": ${err2}`));
|
|
5133
5139
|
throw e;
|
|
5134
5140
|
}
|
|
5135
5141
|
}
|
|
@@ -5140,15 +5146,15 @@ function validEntries(servers) {
|
|
|
5140
5146
|
return Object.entries(servers).filter(([name, cfg]) => {
|
|
5141
5147
|
if (!cfg || cfg.disabled) return false;
|
|
5142
5148
|
if (!cfg.command && !cfg.url) {
|
|
5143
|
-
|
|
5149
|
+
log11.warn(`MCP server "${name}" needs a command (stdio) or url (http) \u2014 skipping`);
|
|
5144
5150
|
return false;
|
|
5145
5151
|
}
|
|
5146
5152
|
return true;
|
|
5147
5153
|
});
|
|
5148
5154
|
}
|
|
5149
5155
|
function logMountFailure(name, e) {
|
|
5150
|
-
if (e instanceof McpAuthError)
|
|
5151
|
-
else
|
|
5156
|
+
if (e instanceof McpAuthError) log11.warn(`MCP "${name}" needs-auth: HTTP ${e.status} \u2014 set bearerToken or headers in its config; skipping`);
|
|
5157
|
+
else log11.error(`MCP server "${name}" failed to mount: ${e?.message ?? e}`);
|
|
5152
5158
|
}
|
|
5153
5159
|
async function mountMcpServers(servers = {}, opts = {}) {
|
|
5154
5160
|
const entries = validEntries(servers);
|
|
@@ -5158,7 +5164,7 @@ async function mountMcpServers(servers = {}, opts = {}) {
|
|
|
5158
5164
|
const name = entries[i][0];
|
|
5159
5165
|
if (r.status === "fulfilled") {
|
|
5160
5166
|
out.push(r.value);
|
|
5161
|
-
|
|
5167
|
+
log11.info(`MCP "${name}" mounted \u2014 ${r.value.tools.length} tool(s)${r.value.serverInfo?.name ? ` from ${r.value.serverInfo.name}` : ""}`);
|
|
5162
5168
|
} else logMountFailure(name, r.reason);
|
|
5163
5169
|
});
|
|
5164
5170
|
return out;
|
|
@@ -5198,7 +5204,7 @@ var McpPool = class {
|
|
|
5198
5204
|
const prev = this.warm.get(key);
|
|
5199
5205
|
if (prev) {
|
|
5200
5206
|
clearTimeout(prev.timer);
|
|
5201
|
-
if (prev.client !== client) void prev.client.close().catch((err2) =>
|
|
5207
|
+
if (prev.client !== client) void prev.client.close().catch((err2) => log11.debug(`warm-pool replace close failed: ${err2}`));
|
|
5202
5208
|
}
|
|
5203
5209
|
const e = { client, timer: void 0 };
|
|
5204
5210
|
this.warm.set(key, e);
|
|
@@ -5215,7 +5221,7 @@ var McpPool = class {
|
|
|
5215
5221
|
const e = this.warm.get(key);
|
|
5216
5222
|
if (!e) return;
|
|
5217
5223
|
this.warm.delete(key);
|
|
5218
|
-
await e.client.close().catch((err2) =>
|
|
5224
|
+
await e.client.close().catch((err2) => log11.debug(`warm-pool evict close failed: ${err2}`));
|
|
5219
5225
|
}
|
|
5220
5226
|
async closeAll() {
|
|
5221
5227
|
for (const e of this.warm.values()) {
|
|
@@ -5423,6 +5429,7 @@ function defaultOpenBrowser(url) {
|
|
|
5423
5429
|
}
|
|
5424
5430
|
|
|
5425
5431
|
// cli/core.ts
|
|
5432
|
+
import { randomUUID } from "crypto";
|
|
5426
5433
|
import { resolve, basename, join as join3 } from "path";
|
|
5427
5434
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
5428
5435
|
import { platform, arch, release, userInfo, homedir } from "os";
|
|
@@ -5567,7 +5574,9 @@ Reference files in them by their mount path (the left side).`;
|
|
|
5567
5574
|
// host's MCP servers so the delegated cursor agent runs in the same environment. Gated to cursor:
|
|
5568
5575
|
// openai/google adapters Object.assign providerOptions into the request body, so a blanket cwd
|
|
5569
5576
|
// would corrupt those calls.
|
|
5570
|
-
|
|
5577
|
+
// Warm cursor session (default on; CURSOR_WARM=0 to disable): one long-lived agent reused across
|
|
5578
|
+
// turns, amortising the ~2s Agent.create + h2 handshake. Keyed per agentx launch.
|
|
5579
|
+
...isCursor ? { providerOptions: { cwd, ...toCursorMcp(o.mcpServers) ?? {}, ...process.env.CURSOR_WARM === "0" ? {} : { cursorSession: randomUUID() } } } : {},
|
|
5571
5580
|
...(() => {
|
|
5572
5581
|
const now5 = /* @__PURE__ */ new Date();
|
|
5573
5582
|
const platformNames = { darwin: "macOS", linux: "Linux", win32: "Windows" };
|
|
@@ -5644,7 +5653,7 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync3, statSync as statSyn
|
|
|
5644
5653
|
import { homedir as homedir2 } from "os";
|
|
5645
5654
|
import { dirname as dirname3, join as join4 } from "path";
|
|
5646
5655
|
import { fileURLToPath } from "url";
|
|
5647
|
-
var
|
|
5656
|
+
var log13 = forComponent("VoiceIO");
|
|
5648
5657
|
var now4 = () => performance.now();
|
|
5649
5658
|
var Player = class {
|
|
5650
5659
|
proc = null;
|
|
@@ -5658,7 +5667,7 @@ var Player = class {
|
|
|
5658
5667
|
["-loglevel", "quiet", "-nodisp", "-fflags", "nobuffer", "-flags", "low_delay", "-probesize", "32", "-f", "s16le", "-ar", String(TTS_SAMPLE_RATE), "-ch_layout", "mono", "-i", "-"],
|
|
5659
5668
|
{ stdio: ["pipe", "ignore", "ignore"] }
|
|
5660
5669
|
);
|
|
5661
|
-
this.proc.on("error", (e) =>
|
|
5670
|
+
this.proc.on("error", (e) => log13.warn(`ffplay error: ${e.message}`));
|
|
5662
5671
|
this.proc.stdin.on("error", () => {
|
|
5663
5672
|
});
|
|
5664
5673
|
this.bytesWritten = 0;
|
|
@@ -5693,7 +5702,7 @@ function detectFfmpegMic() {
|
|
|
5693
5702
|
const devices = [...audio.matchAll(/\[(\d+)\] (.+)/g)].map(([, idx, name]) => ({ idx, name: name.trim() }));
|
|
5694
5703
|
const mic = devices.find((d) => /microphone|built-in/i.test(d.name) && !/teams|blackhole|loopback/i.test(d.name)) ?? devices[0];
|
|
5695
5704
|
if (!mic) throw new Error("no audio input device found");
|
|
5696
|
-
|
|
5705
|
+
log13.debug(`ffmpeg mic: [${mic.idx}] ${mic.name}`);
|
|
5697
5706
|
return `:${mic.idx}`;
|
|
5698
5707
|
}
|
|
5699
5708
|
function resolveAecBinary() {
|
|
@@ -5706,15 +5715,15 @@ function resolveAecBinary() {
|
|
|
5706
5715
|
if (existsSync3(bin) && statSync2(bin).mtimeMs >= statSync2(src).mtimeMs) return bin;
|
|
5707
5716
|
if (spawnSync("which", ["swiftc"]).status !== 0) return null;
|
|
5708
5717
|
mkdirSync3(cacheDir, { recursive: true });
|
|
5709
|
-
|
|
5718
|
+
log13.info("compiling AEC mic helper (first run)\u2026");
|
|
5710
5719
|
const build = spawnSync("swiftc", ["-O", "-o", bin, src, "-Xlinker", "-sectcreate", "-Xlinker", "__TEXT", "-Xlinker", "__info_plist", "-Xlinker", plist], { encoding: "utf8" });
|
|
5711
5720
|
if (build.status !== 0) {
|
|
5712
|
-
|
|
5721
|
+
log13.warn(`AEC build failed: ${build.stderr?.slice(0, 400)}`);
|
|
5713
5722
|
return null;
|
|
5714
5723
|
}
|
|
5715
5724
|
const sign = spawnSync("codesign", ["-fs", "-", bin], { encoding: "utf8" });
|
|
5716
5725
|
if (sign.status !== 0) {
|
|
5717
|
-
|
|
5726
|
+
log13.warn(`codesign failed: ${sign.stderr?.slice(0, 200)}`);
|
|
5718
5727
|
return null;
|
|
5719
5728
|
}
|
|
5720
5729
|
return bin;
|
|
@@ -5733,16 +5742,16 @@ var NodeMicSource = class {
|
|
|
5733
5742
|
this.proc = spawn2(this.bin, [], { stdio: ["ignore", "pipe", "ignore"] });
|
|
5734
5743
|
} else {
|
|
5735
5744
|
if (spawnSync("which", ["ffmpeg"]).status !== 0) throw new Error("voice I/O unavailable: no AEC helper and no ffmpeg on PATH");
|
|
5736
|
-
|
|
5745
|
+
log13.info("mic: raw capture (no AEC) \u2014 echo handled heuristically; headphones recommended");
|
|
5737
5746
|
this.proc = spawn2(
|
|
5738
5747
|
"ffmpeg",
|
|
5739
5748
|
["-loglevel", "error", "-f", "avfoundation", "-i", detectFfmpegMic(), "-ar", String(STT_SAMPLE_RATE), "-ac", "1", "-f", "s16le", "-"],
|
|
5740
5749
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
5741
5750
|
);
|
|
5742
|
-
this.proc.stderr.on("data", (d) =>
|
|
5751
|
+
this.proc.stderr.on("data", (d) => log13.warn(`ffmpeg: ${String(d).trim()}`));
|
|
5743
5752
|
}
|
|
5744
5753
|
this.proc.on("exit", (c) => {
|
|
5745
|
-
if (c && !this.stopped)
|
|
5754
|
+
if (c && !this.stopped) log13.error(`mic capture exited (${c}) \u2014 check mic permission / MIC_DEVICE / MIC_AEC=0`);
|
|
5746
5755
|
});
|
|
5747
5756
|
this.proc.stdout.on("data", (chunk) => onChunk(chunk));
|
|
5748
5757
|
}
|
|
@@ -5776,11 +5785,11 @@ var AecDuplexAudio = class {
|
|
|
5776
5785
|
this.proc.stdin.on("error", () => {
|
|
5777
5786
|
});
|
|
5778
5787
|
this.proc.on("exit", (c) => {
|
|
5779
|
-
if (c && !this.stopped)
|
|
5788
|
+
if (c && !this.stopped) log13.error(`aec duplex audio exited (${c}) \u2014 check mic permission / MIC_AEC=0`);
|
|
5780
5789
|
});
|
|
5781
5790
|
this.proc.stdout.on("data", (chunk) => onChunk(chunk));
|
|
5782
5791
|
this.proc.stderr.on("data", (d) => {
|
|
5783
|
-
for (const ln of String(d).split("\n")) if (ln.trim())
|
|
5792
|
+
for (const ln of String(d).split("\n")) if (ln.trim()) log13.debug(`mic-aec: ${ln.trim()}`);
|
|
5784
5793
|
});
|
|
5785
5794
|
}
|
|
5786
5795
|
stop() {
|
|
@@ -5953,7 +5962,7 @@ async function loadConfig(cwd) {
|
|
|
5953
5962
|
|
|
5954
5963
|
// cli/hooks-config.ts
|
|
5955
5964
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
5956
|
-
var
|
|
5965
|
+
var log14 = forComponent("hooks");
|
|
5957
5966
|
var escapeRegex = (s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
5958
5967
|
function ruleMatches(rule, toolName) {
|
|
5959
5968
|
if (!rule.tool || rule.tool === "*") return true;
|
|
@@ -5970,7 +5979,7 @@ function runCmd(rule, env) {
|
|
|
5970
5979
|
});
|
|
5971
5980
|
return { code: r.status ?? 1, out: ((r.stdout ?? "") + (r.stderr ?? "")).trim() };
|
|
5972
5981
|
} catch (e) {
|
|
5973
|
-
|
|
5982
|
+
log14.debug(`hook command failed: ${rule.command}`, e);
|
|
5974
5983
|
return { code: 1, out: String(e?.message ?? e) };
|
|
5975
5984
|
}
|
|
5976
5985
|
}
|
|
@@ -6076,7 +6085,7 @@ function formatDiff(ops, opts = {}) {
|
|
|
6076
6085
|
// cli/session.ts
|
|
6077
6086
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3, readdirSync, renameSync } from "fs";
|
|
6078
6087
|
import { join as join6 } from "path";
|
|
6079
|
-
var
|
|
6088
|
+
var log15 = forComponent("session");
|
|
6080
6089
|
var SessionStore = class {
|
|
6081
6090
|
dir;
|
|
6082
6091
|
constructor(cwd) {
|
|
@@ -6102,7 +6111,7 @@ var SessionStore = class {
|
|
|
6102
6111
|
}
|
|
6103
6112
|
load(id) {
|
|
6104
6113
|
if (!this.safeId(id)) {
|
|
6105
|
-
|
|
6114
|
+
log15.debug(`rejecting unsafe session id: ${id}`);
|
|
6106
6115
|
return void 0;
|
|
6107
6116
|
}
|
|
6108
6117
|
const path = join6(this.dir, `${id}.json`);
|
|
@@ -6110,7 +6119,7 @@ var SessionStore = class {
|
|
|
6110
6119
|
try {
|
|
6111
6120
|
return JSON.parse(readFileSync3(path, "utf8"));
|
|
6112
6121
|
} catch (e) {
|
|
6113
|
-
|
|
6122
|
+
log15.debug(`unreadable session ${id} \u2014 ignoring`, e);
|
|
6114
6123
|
return void 0;
|
|
6115
6124
|
}
|
|
6116
6125
|
}
|
|
@@ -6123,7 +6132,7 @@ var SessionStore = class {
|
|
|
6123
6132
|
try {
|
|
6124
6133
|
metas.push(JSON.parse(readFileSync3(join6(this.dir, f), "utf8")).meta);
|
|
6125
6134
|
} catch (e) {
|
|
6126
|
-
|
|
6135
|
+
log15.debug(`skipping unreadable session file ${f}`, e);
|
|
6127
6136
|
}
|
|
6128
6137
|
}
|
|
6129
6138
|
return metas.sort((a, b) => b.updated - a.updated);
|
|
@@ -6217,7 +6226,7 @@ import { execFile } from "child_process";
|
|
|
6217
6226
|
import { promisify } from "util";
|
|
6218
6227
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync6 } from "fs";
|
|
6219
6228
|
import { join as join7, resolve as resolve2, sep as sep2 } from "path";
|
|
6220
|
-
var
|
|
6229
|
+
var log16 = forComponent("checkpoints");
|
|
6221
6230
|
var exec = promisify(execFile);
|
|
6222
6231
|
var DEFAULT_EXCLUDE = [".agent/", ".git/", "node_modules/", "dist/", "build/", ".next/", "target/", ".venv/", "__pycache__/", "*.log"];
|
|
6223
6232
|
var ShadowRepo = class {
|
|
@@ -6251,7 +6260,7 @@ var ShadowRepo = class {
|
|
|
6251
6260
|
writeFileSync4(join7(this.gitDir, "info", "exclude"), this.exclude.join("\n") + "\n");
|
|
6252
6261
|
this.ready = true;
|
|
6253
6262
|
} catch (e) {
|
|
6254
|
-
|
|
6263
|
+
log16.debug(`git checkpoints unavailable for ${this.workTree}`, e);
|
|
6255
6264
|
this.ready = false;
|
|
6256
6265
|
}
|
|
6257
6266
|
return this.ready;
|
|
@@ -6314,7 +6323,7 @@ var ShadowRepo = class {
|
|
|
6314
6323
|
await this.run("gc", "--auto", "-q").catch(() => {
|
|
6315
6324
|
});
|
|
6316
6325
|
} catch (e) {
|
|
6317
|
-
|
|
6326
|
+
log16.debug("checkpoint prune failed", e);
|
|
6318
6327
|
}
|
|
6319
6328
|
}
|
|
6320
6329
|
};
|
|
@@ -6371,7 +6380,7 @@ var GitCheckpoints = class {
|
|
|
6371
6380
|
use(sessionId) {
|
|
6372
6381
|
if (sessionId === this.session) return;
|
|
6373
6382
|
this.session = sessionId;
|
|
6374
|
-
if (this.started) for (const r of this.repos) void r.point(this.ref()).catch((e) =>
|
|
6383
|
+
if (this.started) for (const r of this.repos) void r.point(this.ref()).catch((e) => log16.debug("re-point failed", e));
|
|
6375
6384
|
}
|
|
6376
6385
|
async begin(label) {
|
|
6377
6386
|
if (!await this.start()) return;
|
|
@@ -6382,7 +6391,7 @@ var GitCheckpoints = class {
|
|
|
6382
6391
|
try {
|
|
6383
6392
|
await r.commit(msg);
|
|
6384
6393
|
} catch (e) {
|
|
6385
|
-
|
|
6394
|
+
log16.debug("checkpoint commit failed", e);
|
|
6386
6395
|
}
|
|
6387
6396
|
}
|
|
6388
6397
|
if (slow) clearTimeout(slow);
|
|
@@ -7759,7 +7768,7 @@ var red = C("31");
|
|
|
7759
7768
|
var bold = C("1");
|
|
7760
7769
|
var yellow = C("33");
|
|
7761
7770
|
var err = (s) => process.stderr.write(s);
|
|
7762
|
-
var
|
|
7771
|
+
var log17 = forComponent("cli");
|
|
7763
7772
|
var VERSION = (() => {
|
|
7764
7773
|
try {
|
|
7765
7774
|
return JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8")).version ?? "?";
|
|
@@ -8193,7 +8202,7 @@ function costOf(pricing, promptTokens = 0, completionTokens = 0, cacheCreationTo
|
|
|
8193
8202
|
function turnCost(model, usage) {
|
|
8194
8203
|
return costOf(getModelInfo(model)?.pricing, usage?.promptTokens ?? 0, usage?.completionTokens ?? 0, usage?.cacheCreationTokens ?? 0, usage?.cacheReadTokens ?? 0, model);
|
|
8195
8204
|
}
|
|
8196
|
-
async function evaluateGoal(ai, condition, transcript,
|
|
8205
|
+
async function evaluateGoal(ai, condition, transcript, log18) {
|
|
8197
8206
|
const recent = transcript.filter((m) => m.role === "assistant").slice(-8).map((m) => {
|
|
8198
8207
|
const text = typeof m.content === "string" ? m.content : m.content.filter((p) => p.type === "text").map((p) => p.text).join(" ");
|
|
8199
8208
|
return text.slice(0, 600);
|
|
@@ -8213,7 +8222,7 @@ ${recent}` }
|
|
|
8213
8222
|
const match = r.content.match(/\{[\s\S]*\}/);
|
|
8214
8223
|
if (match) return JSON.parse(match[0]);
|
|
8215
8224
|
} catch (e) {
|
|
8216
|
-
|
|
8225
|
+
log18(dim(` (goal evaluator error: ${e?.message ?? e})
|
|
8217
8226
|
`));
|
|
8218
8227
|
}
|
|
8219
8228
|
return { met: false, reason: "evaluation unclear" };
|
|
@@ -8396,7 +8405,7 @@ async function mountMcp(cfg, oauth) {
|
|
|
8396
8405
|
return mounted;
|
|
8397
8406
|
}
|
|
8398
8407
|
async function closeMcp(mounted) {
|
|
8399
|
-
await Promise.all(mounted.map((m) => m.client.close().catch((e) =>
|
|
8408
|
+
await Promise.all(mounted.map((m) => m.client.close().catch((e) => log17.debug("mcp close failed", e))));
|
|
8400
8409
|
}
|
|
8401
8410
|
var IMG_EXT = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp" };
|
|
8402
8411
|
function readImageParts(cwd, line) {
|
|
@@ -8628,14 +8637,14 @@ var isCancelTeardown = (e) => {
|
|
|
8628
8637
|
function installCancelGuards(mounted) {
|
|
8629
8638
|
process.on("unhandledRejection", (e) => {
|
|
8630
8639
|
if (isCancelTeardown(e)) {
|
|
8631
|
-
|
|
8640
|
+
log17.debug("suppressed unhandledRejection (cursor stream cancel)", e);
|
|
8632
8641
|
return;
|
|
8633
8642
|
}
|
|
8634
|
-
|
|
8643
|
+
log17.error("unhandledRejection", e);
|
|
8635
8644
|
});
|
|
8636
8645
|
process.on("uncaughtException", (e) => {
|
|
8637
8646
|
if (isCancelTeardown(e)) {
|
|
8638
|
-
|
|
8647
|
+
log17.debug("suppressed uncaughtException (cursor stream cancel)", e);
|
|
8639
8648
|
return;
|
|
8640
8649
|
}
|
|
8641
8650
|
console.error(e);
|
|
@@ -8928,7 +8937,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
8928
8937
|
mkdirSync7(join9(cwd, ".agent"), { recursive: true });
|
|
8929
8938
|
appendFileSync(histPath, line + "\n");
|
|
8930
8939
|
} catch (e) {
|
|
8931
|
-
|
|
8940
|
+
log17.debug("history write failed", e);
|
|
8932
8941
|
}
|
|
8933
8942
|
};
|
|
8934
8943
|
const ago = (t) => {
|
|
@@ -8993,7 +9002,7 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
8993
9002
|
try {
|
|
8994
9003
|
store.save(session);
|
|
8995
9004
|
} catch (e) {
|
|
8996
|
-
|
|
9005
|
+
log17.debug("session save after rewind failed", e);
|
|
8997
9006
|
}
|
|
8998
9007
|
err(green(" \u27F2 jumped back") + dim(` \u2014 ${face.transcript.length} message(s) kept; edit + resend
|
|
8999
9008
|
`));
|
|
@@ -9540,7 +9549,7 @@ ${extra}` : body);
|
|
|
9540
9549
|
}
|
|
9541
9550
|
const m = mounted.splice(idx, 1)[0];
|
|
9542
9551
|
removeWorkTools(m.tools.map((t) => t.name));
|
|
9543
|
-
await m.client.close().catch((e) =>
|
|
9552
|
+
await m.client.close().catch((e) => log17.debug("mcp close failed", e));
|
|
9544
9553
|
err(dim(` removed "${name}"
|
|
9545
9554
|
`));
|
|
9546
9555
|
return;
|
|
@@ -9724,7 +9733,7 @@ ${extra}` : body);
|
|
|
9724
9733
|
try {
|
|
9725
9734
|
return readdirSync2(join9(cwd, absDir.replace(/^\/+/, "")), { withFileTypes: true }).map((d) => ({ name: d.name, dir: d.isDirectory() }));
|
|
9726
9735
|
} catch (e) {
|
|
9727
|
-
|
|
9736
|
+
log17.debug("completion readdir failed", absDir, e);
|
|
9728
9737
|
return null;
|
|
9729
9738
|
}
|
|
9730
9739
|
};
|