@modeloslab/modelcode 0.1.3 → 0.1.5
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.mjs
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
searchFacts,
|
|
57
57
|
searchSessions,
|
|
58
58
|
shellInvocation,
|
|
59
|
+
shellName,
|
|
59
60
|
snapshot,
|
|
60
61
|
spawnProc,
|
|
61
62
|
toolSchemas,
|
|
@@ -63,7 +64,7 @@ import {
|
|
|
63
64
|
validateMnemonic,
|
|
64
65
|
walletFromMnemonic,
|
|
65
66
|
which
|
|
66
|
-
} from "./main-
|
|
67
|
+
} from "./main-t9m4v4fc.mjs";
|
|
67
68
|
import"./main-p2xnn95s.mjs";
|
|
68
69
|
import {
|
|
69
70
|
__require
|
|
@@ -141,7 +142,7 @@ function inside(cwd, p) {
|
|
|
141
142
|
}
|
|
142
143
|
var bash = {
|
|
143
144
|
name: "bash",
|
|
144
|
-
description:
|
|
145
|
+
description: `Run a shell command in the working directory (shell: ${shellName()}); returns combined stdout+stderr. Use for builds, tests, git, file ops.${shellName() === "powershell" || shellName() === "pwsh" ? " NOTE: this is Windows PowerShell — use PowerShell syntax (Get-ChildItem/ls, Get-Content/cat, 2>$null, Select-Object -First N)." : shellName() === "cmd" ? " NOTE: this is Windows cmd.exe — use cmd syntax." : ""}`,
|
|
145
146
|
permission: "ask",
|
|
146
147
|
parameters: {
|
|
147
148
|
type: "object",
|
|
@@ -331,7 +332,9 @@ function registerAgentTool(cfg, onProgress) {
|
|
|
331
332
|
if (!agent)
|
|
332
333
|
return `error: unknown subagent '${args.subagent_type}'. available: ${names.join(", ")}`;
|
|
333
334
|
const { text, feeGrains } = await runSubagent(cfg, agent, String(args.prompt ?? ""), ctx, onProgress);
|
|
334
|
-
|
|
335
|
+
ctx.onCost?.(feeGrains);
|
|
336
|
+
onProgress?.(` ↳ ${agent.name} done · ${(feeGrains / 1e8).toFixed(4)} MDL`);
|
|
337
|
+
return `[${agent.name} · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
335
338
|
${text}`;
|
|
336
339
|
}
|
|
337
340
|
};
|
|
@@ -352,7 +355,8 @@ ${text}`;
|
|
|
352
355
|
async run(args, ctx) {
|
|
353
356
|
const members = Array.isArray(args.members) ? args.members.map(String) : [];
|
|
354
357
|
const { transcript, feeGrains } = await runTeam(cfg, members, String(args.prompt ?? ""), ctx, Number(args.rounds) || 2, onProgress);
|
|
355
|
-
|
|
358
|
+
ctx.onCost?.(feeGrains);
|
|
359
|
+
return `[team · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
356
360
|
${transcript}`;
|
|
357
361
|
}
|
|
358
362
|
};
|
|
@@ -407,6 +411,16 @@ class Agent {
|
|
|
407
411
|
note(text) {
|
|
408
412
|
this.history.push({ role: "system", content: `User steering note (apply going forward): ${text}` });
|
|
409
413
|
}
|
|
414
|
+
async sideQuestion(question, onDelta) {
|
|
415
|
+
const forked = [
|
|
416
|
+
...this.history,
|
|
417
|
+
{ role: "system", content: "The user has a quick side question. Answer it concisely using the conversation so far. This does NOT change the current task." },
|
|
418
|
+
{ role: "user", content: question }
|
|
419
|
+
];
|
|
420
|
+
const res = await chat(this.cfg, forked, [], onDelta ?? (() => {}), this.modelFor(question));
|
|
421
|
+
this.h.onCost(res.feeGrains);
|
|
422
|
+
return res.content || "(no answer)";
|
|
423
|
+
}
|
|
410
424
|
get messages() {
|
|
411
425
|
return [...this.history];
|
|
412
426
|
}
|
|
@@ -592,7 +606,7 @@ ${tail}`;
|
|
|
592
606
|
} else {
|
|
593
607
|
if (MUTATING_TOOLS.has(tool.name) && typeof args.path === "string")
|
|
594
608
|
snapshot(this.ctx.cwd, args.path);
|
|
595
|
-
const runCtx = { ...this.ctx, onStream: (c) => this.h.onToolStream?.(c) };
|
|
609
|
+
const runCtx = { ...this.ctx, onStream: (c) => this.h.onToolStream?.(c), onCost: (g) => this.h.onCost(g) };
|
|
596
610
|
try {
|
|
597
611
|
result = await tool.run(args, runCtx);
|
|
598
612
|
} catch (e) {
|
|
@@ -1585,8 +1599,17 @@ async function main() {
|
|
|
1585
1599
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
1586
1600
|
await interactiveLogin(rl, cfg);
|
|
1587
1601
|
rl.close();
|
|
1602
|
+
const s = stdin;
|
|
1603
|
+
s.removeAllListeners("data");
|
|
1604
|
+
s.removeAllListeners("keypress");
|
|
1605
|
+
try {
|
|
1606
|
+
if (s.isTTY)
|
|
1607
|
+
s.setRawMode(false);
|
|
1608
|
+
} catch {}
|
|
1609
|
+
s.resume();
|
|
1610
|
+
await new Promise((r) => setImmediate(r));
|
|
1588
1611
|
}
|
|
1589
|
-
const { runTui } = await import("./tui-
|
|
1612
|
+
const { runTui } = await import("./tui-rxaw95g7.mjs");
|
|
1590
1613
|
return runTui(cfg, resume);
|
|
1591
1614
|
}
|
|
1592
1615
|
if (cmd === "tui")
|
|
@@ -7966,7 +7966,19 @@ var isWin = process.platform === "win32";
|
|
|
7966
7966
|
function shellInvocation(cmd) {
|
|
7967
7967
|
if (!isWin)
|
|
7968
7968
|
return ["bash", "-lc", cmd];
|
|
7969
|
-
|
|
7969
|
+
if (hasBash())
|
|
7970
|
+
return ["bash", "-c", cmd];
|
|
7971
|
+
const ps = powershellBin();
|
|
7972
|
+
if (ps)
|
|
7973
|
+
return [ps, "-NoProfile", "-NonInteractive", "-Command", cmd];
|
|
7974
|
+
return ["cmd", "/c", cmd];
|
|
7975
|
+
}
|
|
7976
|
+
function shellName() {
|
|
7977
|
+
if (!isWin)
|
|
7978
|
+
return "bash";
|
|
7979
|
+
if (hasBash())
|
|
7980
|
+
return "bash";
|
|
7981
|
+
return powershellBin() ?? "cmd";
|
|
7970
7982
|
}
|
|
7971
7983
|
var _bash = null;
|
|
7972
7984
|
function hasBash() {
|
|
@@ -7979,6 +7991,19 @@ function hasBash() {
|
|
|
7979
7991
|
}
|
|
7980
7992
|
return _bash;
|
|
7981
7993
|
}
|
|
7994
|
+
var _ps;
|
|
7995
|
+
function powershellBin() {
|
|
7996
|
+
if (_ps !== undefined)
|
|
7997
|
+
return _ps;
|
|
7998
|
+
for (const bin of ["pwsh", "powershell"]) {
|
|
7999
|
+
try {
|
|
8000
|
+
if (spawnSync(bin, ["-NoProfile", "-Command", "exit 0"], { stdio: "ignore" }).status === 0) {
|
|
8001
|
+
return _ps = bin;
|
|
8002
|
+
}
|
|
8003
|
+
} catch {}
|
|
8004
|
+
}
|
|
8005
|
+
return _ps = null;
|
|
8006
|
+
}
|
|
7982
8007
|
function packageRoot(startDir) {
|
|
7983
8008
|
let dir = startDir;
|
|
7984
8009
|
for (let i = 0;i < 12; i++) {
|
|
@@ -8048,15 +8073,40 @@ function extsFromGlob(glob) {
|
|
|
8048
8073
|
function runProc(cmd, opts = {}) {
|
|
8049
8074
|
return new Promise((resolve) => {
|
|
8050
8075
|
const [bin, ...args] = cmd;
|
|
8051
|
-
const so = { cwd: opts.cwd, env: { ...process.env, ...opts.env }, stdio: ["ignore", "pipe", "pipe"] };
|
|
8076
|
+
const so = { cwd: opts.cwd, env: { ...process.env, ...opts.env }, stdio: ["ignore", "pipe", "pipe"], detached: !isWin };
|
|
8052
8077
|
const p = spawn(bin, args, so);
|
|
8053
|
-
let stdout = "", stderr = "";
|
|
8078
|
+
let stdout = "", stderr = "", done = false;
|
|
8054
8079
|
const dOut = new StringDecoder("utf8"), dErr = new StringDecoder("utf8");
|
|
8080
|
+
const finish = (code) => {
|
|
8081
|
+
if (done)
|
|
8082
|
+
return;
|
|
8083
|
+
done = true;
|
|
8084
|
+
if (killer)
|
|
8085
|
+
clearTimeout(killer);
|
|
8086
|
+
resolve({ code, stdout: stdout + dOut.end(), stderr: stderr + dErr.end() });
|
|
8087
|
+
};
|
|
8088
|
+
const killTree = (signal) => {
|
|
8089
|
+
try {
|
|
8090
|
+
if (isWin)
|
|
8091
|
+
spawnSync("taskkill", ["/pid", String(p.pid), "/T", "/F"], { stdio: "ignore" });
|
|
8092
|
+
else if (p.pid)
|
|
8093
|
+
process.kill(-p.pid, signal);
|
|
8094
|
+
else
|
|
8095
|
+
p.kill(signal);
|
|
8096
|
+
} catch {
|
|
8097
|
+
try {
|
|
8098
|
+
p.kill(signal);
|
|
8099
|
+
} catch {}
|
|
8100
|
+
}
|
|
8101
|
+
};
|
|
8055
8102
|
let killer = null;
|
|
8056
8103
|
if (opts.timeoutMs)
|
|
8057
8104
|
killer = setTimeout(() => {
|
|
8058
|
-
|
|
8059
|
-
setTimeout(() =>
|
|
8105
|
+
killTree("SIGTERM");
|
|
8106
|
+
setTimeout(() => {
|
|
8107
|
+
killTree("SIGKILL");
|
|
8108
|
+
finish(124);
|
|
8109
|
+
}, 2000);
|
|
8060
8110
|
}, opts.timeoutMs);
|
|
8061
8111
|
p.stdout?.on("data", (d) => {
|
|
8062
8112
|
const s = dOut.write(d);
|
|
@@ -8068,15 +8118,10 @@ function runProc(cmd, opts = {}) {
|
|
|
8068
8118
|
stderr += s;
|
|
8069
8119
|
opts.onChunk?.(s, true);
|
|
8070
8120
|
});
|
|
8071
|
-
p.on("close", (code) =>
|
|
8072
|
-
if (killer)
|
|
8073
|
-
clearTimeout(killer);
|
|
8074
|
-
resolve({ code: code ?? 0, stdout: stdout + dOut.end(), stderr: stderr + dErr.end() });
|
|
8075
|
-
});
|
|
8121
|
+
p.on("close", (code) => finish(code ?? 0));
|
|
8076
8122
|
p.on("error", (e) => {
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
resolve({ code: 1, stdout, stderr: stderr + String(e) });
|
|
8123
|
+
stderr += String(e);
|
|
8124
|
+
finish(1);
|
|
8080
8125
|
});
|
|
8081
8126
|
});
|
|
8082
8127
|
}
|
|
@@ -21025,6 +21070,7 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21025
21070
|
messages,
|
|
21026
21071
|
max_tokens: cfg.maxTokens,
|
|
21027
21072
|
stream: true,
|
|
21073
|
+
stream_options: { include_usage: true },
|
|
21028
21074
|
...tools.length ? { tools, tool_choice: "auto" } : {}
|
|
21029
21075
|
};
|
|
21030
21076
|
const attempt = async (live) => {
|
|
@@ -21032,7 +21078,13 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21032
21078
|
let content = "";
|
|
21033
21079
|
let finishReason = null;
|
|
21034
21080
|
let feeGrains = 0;
|
|
21081
|
+
let promptTokens = 0, completionTokens = 0;
|
|
21035
21082
|
const calls = {};
|
|
21083
|
+
const readFee = (o) => {
|
|
21084
|
+
const x = o;
|
|
21085
|
+
const v = x?.x_modelos?.fee_grains ?? x?.fee_grains ?? x?.cost_grains;
|
|
21086
|
+
return v != null ? Number(v) || 0 : 0;
|
|
21087
|
+
};
|
|
21036
21088
|
for await (const chunk of stream) {
|
|
21037
21089
|
const choice = chunk.choices?.[0];
|
|
21038
21090
|
const delta = choice?.delta;
|
|
@@ -21053,22 +21105,33 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21053
21105
|
}
|
|
21054
21106
|
if (choice?.finish_reason)
|
|
21055
21107
|
finishReason = choice.finish_reason;
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21108
|
+
feeGrains = readFee(chunk) || readFee(chunk.usage) || feeGrains;
|
|
21109
|
+
const usage = chunk.usage;
|
|
21110
|
+
if (usage) {
|
|
21111
|
+
promptTokens = usage.prompt_tokens ?? promptTokens;
|
|
21112
|
+
completionTokens = usage.completion_tokens ?? completionTokens;
|
|
21113
|
+
}
|
|
21059
21114
|
}
|
|
21060
|
-
return { content, toolCalls: Object.values(calls), finishReason, feeGrains };
|
|
21115
|
+
return { content, toolCalls: Object.values(calls), finishReason, feeGrains, promptTokens, completionTokens };
|
|
21061
21116
|
};
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
} catch (e) {
|
|
21065
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
21117
|
+
let lastErr;
|
|
21118
|
+
for (let i = 0;i < 3; i++) {
|
|
21066
21119
|
try {
|
|
21067
21120
|
return await attempt(true);
|
|
21068
|
-
} catch {
|
|
21069
|
-
|
|
21121
|
+
} catch (e) {
|
|
21122
|
+
lastErr = e;
|
|
21123
|
+
const status = e.status;
|
|
21124
|
+
if (status && status >= 400 && status < 500)
|
|
21125
|
+
break;
|
|
21126
|
+
if (i < 2)
|
|
21127
|
+
await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
|
|
21070
21128
|
}
|
|
21071
21129
|
}
|
|
21130
|
+
const err = lastErr;
|
|
21131
|
+
const reachable = err?.status !== undefined;
|
|
21132
|
+
if (!reachable)
|
|
21133
|
+
throw new Error(`inference API not reachable (${cfg.baseUrl}) — check your connection. ${err?.message ?? err?.code ?? ""}`.trim());
|
|
21134
|
+
throw new Error(`inference API error${err.status ? ` (HTTP ${err.status})` : ""}: ${err.message ?? "request rejected"}`);
|
|
21072
21135
|
}
|
|
21073
21136
|
|
|
21074
21137
|
// src/router/router.ts
|
|
@@ -21387,21 +21450,39 @@ async function runSubagent(cfg2, agent, task, ctx, onProgress, extraTools = [])
|
|
|
21387
21450
|
const granted = base ? [...base, ...extraTools] : extraTools.length ? [...allTools(), ...extraTools] : null;
|
|
21388
21451
|
const tools = granted ? granted.map((t) => ({ type: "function", function: { name: t.name, description: t.description, parameters: t.parameters } })) : toolSchemas();
|
|
21389
21452
|
const lookup = (name) => granted ? granted.find((t) => t.name === name) : getTool(name);
|
|
21390
|
-
const
|
|
21453
|
+
const env = `Working directory: ${ctx.cwd}
|
|
21454
|
+
Platform: ${process.platform}
|
|
21455
|
+
Today: ${new Date().toISOString().slice(0, 10)}`;
|
|
21456
|
+
const projSlice = loadProjectContext(ctx.cwd).slice(0, 4000);
|
|
21457
|
+
const turnCtx = (buildTurnContext(task, ctx.cwd, {}) || "").slice(0, 4000);
|
|
21458
|
+
const sys = [agent.systemPrompt, env, projSlice, turnCtx].filter(Boolean).join(`
|
|
21459
|
+
|
|
21460
|
+
`);
|
|
21391
21461
|
const history = [
|
|
21392
|
-
{ role: "system", content:
|
|
21393
|
-
...turnCtx ? [{ role: "system", content: turnCtx }] : [],
|
|
21462
|
+
{ role: "system", content: sys },
|
|
21394
21463
|
{ role: "user", content: task }
|
|
21395
21464
|
];
|
|
21396
21465
|
let feeGrains = 0;
|
|
21397
21466
|
const routed = cfg2.autoRoute ? route(task)?.model : undefined;
|
|
21398
21467
|
const subModel = cfg2.subagentModel || routed || agent.model || cfg2.model;
|
|
21468
|
+
onProgress?.(` ↳ ${agent.name} on ${subModel}`);
|
|
21469
|
+
const RESULT_CAP = Number(process.env.MODELCODE_MAX_TOOL_RESULT || "40000");
|
|
21470
|
+
const capResult = (s) => s.length <= RESULT_CAP ? s : `${s.slice(0, Math.floor(RESULT_CAP * 0.7))}
|
|
21471
|
+
|
|
21472
|
+
…[truncated ${s.length - RESULT_CAP} chars]…
|
|
21473
|
+
|
|
21474
|
+
${s.slice(-Math.floor(RESULT_CAP * 0.2))}`;
|
|
21399
21475
|
const finish = (text) => {
|
|
21400
21476
|
fireEvent("subagentStop", ctx.cwd, { AGENT: agent.name, RESULT: text.slice(0, 4000) }).catch(() => {});
|
|
21401
21477
|
return { text, feeGrains };
|
|
21402
21478
|
};
|
|
21403
21479
|
for (let step = 0;step < MAX_STEPS; step++) {
|
|
21404
|
-
|
|
21480
|
+
let res;
|
|
21481
|
+
try {
|
|
21482
|
+
res = await chat2(cfg2, history, tools, () => {}, subModel, 120000);
|
|
21483
|
+
} catch (e) {
|
|
21484
|
+
return finish(`error: ${agent.name} (${subModel}) — ${e.message}`);
|
|
21485
|
+
}
|
|
21405
21486
|
feeGrains += res.feeGrains;
|
|
21406
21487
|
history.push({ role: "assistant", content: res.content || null, ...res.toolCalls.length ? { tool_calls: res.toolCalls } : {} });
|
|
21407
21488
|
if (!res.toolCalls.length)
|
|
@@ -21423,7 +21504,7 @@ async function runSubagent(cfg2, agent, task, ctx, onProgress, extraTools = [])
|
|
|
21423
21504
|
result = `error: ${e.message}`;
|
|
21424
21505
|
}
|
|
21425
21506
|
}
|
|
21426
|
-
history.push({ role: "tool", tool_call_id: call.id, name: call.function.name, content: result });
|
|
21507
|
+
history.push({ role: "tool", tool_call_id: call.id, name: call.function.name, content: capResult(result) });
|
|
21427
21508
|
}
|
|
21428
21509
|
}
|
|
21429
21510
|
return finish("(subagent hit the step limit without finishing)");
|
|
@@ -24254,4 +24335,4 @@ async function decryptWallet(enc, password, network = MAINNET) {
|
|
|
24254
24335
|
}
|
|
24255
24336
|
return w;
|
|
24256
24337
|
}
|
|
24257
|
-
export { exports_external, register, getTool, toolSchemas, renderDiff, shellInvocation, globMatch, runProc, which, spawnProc, globalDir, loadConfig, saveConfig, rememberFact, allFacts, searchFacts, deleteFact, recordTurn, searchSessions, parseFrontmatter, loadSubagents, chat2 as chat, route, loadProjectContext, addEntity, addRelation, query, indexFile, indexCodebaseIncremental, indexCodebase, loadSkills, buildTurnContext, preToolUse, postToolUse, userPromptSubmit, fireEvent, runSubagent, runTeam, isImagePath, imageToDataUrl, estimateTokens, contextStatus, compactionThreshold, findCompactionCut, newTurn, snapshot, undo, depth, MUTATING_TOOLS, isProtectedBuiltin, recordUse, recordPatch, recordCreate, getUsage, allUsage, activityCount, analyzeImpact, impactSummary, lspFor, closeAllLsp, COLUMNS, addCard, moveCard, removeCard, renderBoard, addJob, listJobs, removeJob, startScheduler, MAINNET, generateMnemonic2 as generateMnemonic, validateMnemonic2 as validateMnemonic, walletFromMnemonic, importWalletHex, encryptWallet, decryptWallet, createTransfer };
|
|
24338
|
+
export { exports_external, register, getTool, toolSchemas, renderDiff, shellInvocation, shellName, globMatch, runProc, which, spawnProc, globalDir, loadConfig, saveConfig, rememberFact, allFacts, searchFacts, deleteFact, recordTurn, searchSessions, parseFrontmatter, loadSubagents, chat2 as chat, route, loadProjectContext, addEntity, addRelation, query, indexFile, indexCodebaseIncremental, indexCodebase, loadSkills, buildTurnContext, preToolUse, postToolUse, userPromptSubmit, fireEvent, runSubagent, runTeam, isImagePath, imageToDataUrl, estimateTokens, contextStatus, compactionThreshold, findCompactionCut, newTurn, snapshot, undo, depth, MUTATING_TOOLS, isProtectedBuiltin, recordUse, recordPatch, recordCreate, getUsage, allUsage, activityCount, analyzeImpact, impactSummary, lspFor, closeAllLsp, COLUMNS, addCard, moveCard, removeCard, renderBoard, addJob, listJobs, removeJob, startScheduler, MAINNET, generateMnemonic2 as generateMnemonic, validateMnemonic2 as validateMnemonic, walletFromMnemonic, importWalletHex, encryptWallet, decryptWallet, createTransfer };
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
searchFacts,
|
|
61
61
|
searchSessions,
|
|
62
62
|
shellInvocation,
|
|
63
|
+
shellName,
|
|
63
64
|
snapshot,
|
|
64
65
|
spawnProc,
|
|
65
66
|
startScheduler,
|
|
@@ -67,7 +68,7 @@ import {
|
|
|
67
68
|
undo,
|
|
68
69
|
userPromptSubmit,
|
|
69
70
|
which
|
|
70
|
-
} from "./main-
|
|
71
|
+
} from "./main-t9m4v4fc.mjs";
|
|
71
72
|
import"./main-p2xnn95s.mjs";
|
|
72
73
|
import {
|
|
73
74
|
__commonJS,
|
|
@@ -21382,7 +21383,8 @@ var COMMAND_GROUPS = [
|
|
|
21382
21383
|
{ cmd: "/summary", desc: "recap the session (also /recap); auto-runs after heavy tasks — /summary disable to turn off" },
|
|
21383
21384
|
{ cmd: "/compact <summary>", desc: "collapse history to a summary (free context)" },
|
|
21384
21385
|
{ cmd: "/fork", desc: "save a snapshot of the current conversation" },
|
|
21385
|
-
{ cmd: "/btw <
|
|
21386
|
+
{ cmd: "/btw <question>", desc: "quick side question — answered without changing the current task" },
|
|
21387
|
+
{ cmd: "/steer <note>", desc: "steer the ongoing task (applied going forward)" },
|
|
21386
21388
|
{ cmd: "@<path>", desc: "mention a file — its contents are attached to your message" },
|
|
21387
21389
|
{ cmd: "/exit", desc: "quit" }
|
|
21388
21390
|
] },
|
|
@@ -21566,6 +21568,54 @@ function randomVerb() {
|
|
|
21566
21568
|
return SPINNER_VERBS[Math.floor(Math.random() * SPINNER_VERBS.length)];
|
|
21567
21569
|
}
|
|
21568
21570
|
|
|
21571
|
+
// src/ui/markdown.ts
|
|
21572
|
+
var B = "\x1B[1m";
|
|
21573
|
+
var _B = "\x1B[22m";
|
|
21574
|
+
var I = "\x1B[3m";
|
|
21575
|
+
var _I = "\x1B[23m";
|
|
21576
|
+
var U = "\x1B[4m";
|
|
21577
|
+
var _U = "\x1B[24m";
|
|
21578
|
+
var DIM = "\x1B[2m";
|
|
21579
|
+
var _DIM = "\x1B[22m";
|
|
21580
|
+
var CY = "\x1B[36m";
|
|
21581
|
+
var _CY = "\x1B[39m";
|
|
21582
|
+
function inline(s) {
|
|
21583
|
+
return s.replace(/`([^`]+)`/g, `${CY}$1${_CY}`).replace(/\*\*([^*]+)\*\*/g, `${B}$1${_B}`).replace(/__([^_]+)__/g, `${B}$1${_B}`).replace(/(^|[^*])\*([^*\n]+)\*/g, `$1${I}$2${_I}`).replace(/(^|[^_])_([^_\n]+)_/g, `$1${I}$2${_I}`);
|
|
21584
|
+
}
|
|
21585
|
+
function formatMarkdown(src) {
|
|
21586
|
+
const out = [];
|
|
21587
|
+
let inFence = false;
|
|
21588
|
+
for (const raw of src.split(`
|
|
21589
|
+
`)) {
|
|
21590
|
+
const line = raw.replace(/\s+$/, "");
|
|
21591
|
+
if (/^\s*```/.test(line)) {
|
|
21592
|
+
inFence = !inFence;
|
|
21593
|
+
continue;
|
|
21594
|
+
}
|
|
21595
|
+
if (inFence) {
|
|
21596
|
+
out.push(`${DIM} ${line}${_DIM}`);
|
|
21597
|
+
continue;
|
|
21598
|
+
}
|
|
21599
|
+
const h = line.match(/^(#{1,6})\s+(.*)$/);
|
|
21600
|
+
if (h) {
|
|
21601
|
+
out.push(h[1].length === 1 ? `${B}${U}${h[2]}${_U}${_B}` : `${B}${inline(h[2])}${_B}`);
|
|
21602
|
+
continue;
|
|
21603
|
+
}
|
|
21604
|
+
if (/^\s*([-*_])\1{2,}\s*$/.test(line)) {
|
|
21605
|
+
out.push(`${DIM}────────${_DIM}`);
|
|
21606
|
+
continue;
|
|
21607
|
+
}
|
|
21608
|
+
const b = line.match(/^(\s*)[-*+]\s+(.*)$/);
|
|
21609
|
+
if (b) {
|
|
21610
|
+
out.push(`${b[1]}${CY}•${_CY} ${inline(b[2])}`);
|
|
21611
|
+
continue;
|
|
21612
|
+
}
|
|
21613
|
+
out.push(inline(line));
|
|
21614
|
+
}
|
|
21615
|
+
return out.join(`
|
|
21616
|
+
`);
|
|
21617
|
+
}
|
|
21618
|
+
|
|
21569
21619
|
// src/ui/themes.ts
|
|
21570
21620
|
var THEMES = {
|
|
21571
21621
|
amber: { accent: "yellow", user: "green", tool: "cyan", dim: "gray", ok: "green", warn: "yellow" },
|
|
@@ -21703,8 +21753,6 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21703
21753
|
onInterrupt();
|
|
21704
21754
|
return;
|
|
21705
21755
|
}
|
|
21706
|
-
if (busy)
|
|
21707
|
-
return;
|
|
21708
21756
|
if (key.upArrow) {
|
|
21709
21757
|
if (history.length) {
|
|
21710
21758
|
const i = histIdx < 0 ? history.length - 1 : Math.max(0, histIdx - 1);
|
|
@@ -21752,6 +21800,7 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21752
21800
|
const renderLine = (l, i) => {
|
|
21753
21801
|
if (l.kind === "user")
|
|
21754
21802
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21803
|
+
flexDirection: "column",
|
|
21755
21804
|
marginTop: 1,
|
|
21756
21805
|
children: [
|
|
21757
21806
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Chip, {
|
|
@@ -21759,39 +21808,60 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21759
21808
|
color: t.user
|
|
21760
21809
|
}, undefined, false, undefined, this),
|
|
21761
21810
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21762
|
-
children:
|
|
21763
|
-
|
|
21764
|
-
l.text
|
|
21765
|
-
]
|
|
21766
|
-
}, undefined, true, undefined, this)
|
|
21811
|
+
children: l.text
|
|
21812
|
+
}, undefined, false, undefined, this)
|
|
21767
21813
|
]
|
|
21768
21814
|
}, i, true, undefined, this);
|
|
21769
21815
|
if (l.kind === "assistant")
|
|
21770
21816
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21817
|
+
flexDirection: "column",
|
|
21771
21818
|
marginTop: 1,
|
|
21772
21819
|
children: [
|
|
21773
|
-
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(
|
|
21774
|
-
|
|
21775
|
-
|
|
21820
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21821
|
+
color: t.accent,
|
|
21822
|
+
bold: true,
|
|
21823
|
+
children: "◆ modelcode"
|
|
21776
21824
|
}, undefined, false, undefined, this),
|
|
21777
21825
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21778
|
-
children:
|
|
21779
|
-
|
|
21780
|
-
l.text
|
|
21781
|
-
]
|
|
21782
|
-
}, undefined, true, undefined, this)
|
|
21826
|
+
children: formatMarkdown(l.text)
|
|
21827
|
+
}, undefined, false, undefined, this)
|
|
21783
21828
|
]
|
|
21784
21829
|
}, i, true, undefined, this);
|
|
21785
21830
|
if (l.kind === "tool")
|
|
21786
21831
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21787
|
-
color: t.tool,
|
|
21788
21832
|
children: [
|
|
21789
|
-
|
|
21790
|
-
|
|
21833
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21834
|
+
color: t.tool,
|
|
21835
|
+
children: "⏺ "
|
|
21836
|
+
}, undefined, false, undefined, this),
|
|
21837
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21838
|
+
children: l.text
|
|
21839
|
+
}, undefined, false, undefined, this)
|
|
21840
|
+
]
|
|
21841
|
+
}, i, true, undefined, this);
|
|
21842
|
+
if (l.kind === "result")
|
|
21843
|
+
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21844
|
+
flexDirection: "row",
|
|
21845
|
+
children: [
|
|
21846
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21847
|
+
color: t.dim,
|
|
21848
|
+
children: " ⎿ "
|
|
21849
|
+
}, undefined, false, undefined, this),
|
|
21850
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21851
|
+
flexShrink: 1,
|
|
21852
|
+
flexGrow: 1,
|
|
21853
|
+
children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21854
|
+
color: t.dim,
|
|
21855
|
+
children: l.text.split(`
|
|
21856
|
+
`).join(`
|
|
21857
|
+
`)
|
|
21858
|
+
}, undefined, false, undefined, this)
|
|
21859
|
+
}, undefined, false, undefined, this)
|
|
21791
21860
|
]
|
|
21792
21861
|
}, i, true, undefined, this);
|
|
21793
21862
|
if (l.kind === "error")
|
|
21794
21863
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21864
|
+
flexDirection: "column",
|
|
21795
21865
|
marginTop: 1,
|
|
21796
21866
|
children: [
|
|
21797
21867
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Chip, {
|
|
@@ -21800,11 +21870,8 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21800
21870
|
}, undefined, false, undefined, this),
|
|
21801
21871
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21802
21872
|
color: t.warn,
|
|
21803
|
-
children:
|
|
21804
|
-
|
|
21805
|
-
l.text
|
|
21806
|
-
]
|
|
21807
|
-
}, undefined, true, undefined, this)
|
|
21873
|
+
children: l.text
|
|
21874
|
+
}, undefined, false, undefined, this)
|
|
21808
21875
|
]
|
|
21809
21876
|
}, i, true, undefined, this);
|
|
21810
21877
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -21846,18 +21913,17 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21846
21913
|
flexDirection: "column",
|
|
21847
21914
|
children: [
|
|
21848
21915
|
streaming ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21916
|
+
flexDirection: "column",
|
|
21849
21917
|
marginTop: 1,
|
|
21850
21918
|
children: [
|
|
21851
|
-
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(
|
|
21852
|
-
|
|
21853
|
-
|
|
21919
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21920
|
+
color: t.accent,
|
|
21921
|
+
bold: true,
|
|
21922
|
+
children: "◆ modelcode"
|
|
21854
21923
|
}, undefined, false, undefined, this),
|
|
21855
21924
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21856
|
-
children:
|
|
21857
|
-
|
|
21858
|
-
streaming
|
|
21859
|
-
]
|
|
21860
|
-
}, undefined, true, undefined, this)
|
|
21925
|
+
children: formatMarkdown(streaming)
|
|
21926
|
+
}, undefined, false, undefined, this)
|
|
21861
21927
|
]
|
|
21862
21928
|
}, undefined, true, undefined, this) : null,
|
|
21863
21929
|
toolStream ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -21931,26 +21997,27 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21931
21997
|
]
|
|
21932
21998
|
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21933
21999
|
borderStyle: "round",
|
|
21934
|
-
borderColor:
|
|
22000
|
+
borderColor: t.user,
|
|
21935
22001
|
paddingX: 1,
|
|
21936
22002
|
marginTop: 1,
|
|
21937
22003
|
children: [
|
|
21938
22004
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21939
|
-
color:
|
|
21940
|
-
children:
|
|
21941
|
-
|
|
21942
|
-
" "
|
|
21943
|
-
]
|
|
21944
|
-
}, undefined, true, undefined, this),
|
|
22005
|
+
color: t.user,
|
|
22006
|
+
children: "› "
|
|
22007
|
+
}, undefined, false, undefined, this),
|
|
21945
22008
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21946
|
-
children: input
|
|
22009
|
+
children: input
|
|
21947
22010
|
}, undefined, false, undefined, this),
|
|
21948
|
-
|
|
22011
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21949
22012
|
color: t.accent,
|
|
21950
22013
|
children: "▋"
|
|
21951
|
-
}, undefined, false, undefined, this)
|
|
22014
|
+
}, undefined, false, undefined, this)
|
|
21952
22015
|
]
|
|
21953
22016
|
}, undefined, true, undefined, this),
|
|
22017
|
+
busy && input ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
22018
|
+
color: t.dim,
|
|
22019
|
+
children: " ↵ to queue this for after the current turn"
|
|
22020
|
+
}, undefined, false, undefined, this) : null,
|
|
21954
22021
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21955
22022
|
justifyContent: "space-between",
|
|
21956
22023
|
paddingX: 1,
|
|
@@ -22051,6 +22118,16 @@ class Agent {
|
|
|
22051
22118
|
note(text) {
|
|
22052
22119
|
this.history.push({ role: "system", content: `User steering note (apply going forward): ${text}` });
|
|
22053
22120
|
}
|
|
22121
|
+
async sideQuestion(question, onDelta) {
|
|
22122
|
+
const forked = [
|
|
22123
|
+
...this.history,
|
|
22124
|
+
{ role: "system", content: "The user has a quick side question. Answer it concisely using the conversation so far. This does NOT change the current task." },
|
|
22125
|
+
{ role: "user", content: question }
|
|
22126
|
+
];
|
|
22127
|
+
const res = await chat(this.cfg, forked, [], onDelta ?? (() => {}), this.modelFor(question));
|
|
22128
|
+
this.h.onCost(res.feeGrains);
|
|
22129
|
+
return res.content || "(no answer)";
|
|
22130
|
+
}
|
|
22054
22131
|
get messages() {
|
|
22055
22132
|
return [...this.history];
|
|
22056
22133
|
}
|
|
@@ -22236,7 +22313,7 @@ ${tail2}`;
|
|
|
22236
22313
|
} else {
|
|
22237
22314
|
if (MUTATING_TOOLS.has(tool.name) && typeof args.path === "string")
|
|
22238
22315
|
snapshot(this.ctx.cwd, args.path);
|
|
22239
|
-
const runCtx = { ...this.ctx, onStream: (c2) => this.h.onToolStream?.(c2) };
|
|
22316
|
+
const runCtx = { ...this.ctx, onStream: (c2) => this.h.onToolStream?.(c2), onCost: (g) => this.h.onCost(g) };
|
|
22240
22317
|
try {
|
|
22241
22318
|
result2 = await tool.run(args, runCtx);
|
|
22242
22319
|
} catch (e) {
|
|
@@ -22888,7 +22965,9 @@ ${typeof m.content === "string" ? m.content : JSON.stringify(m.content)}`).join(
|
|
|
22888
22965
|
`) : "no saved sessions" };
|
|
22889
22966
|
}
|
|
22890
22967
|
case "/btw":
|
|
22891
|
-
return arg ? {
|
|
22968
|
+
return arg ? { sideQuestion: arg } : { output: "usage: /btw <quick question> — answered without changing the current task" };
|
|
22969
|
+
case "/steer":
|
|
22970
|
+
return arg ? { note: arg, output: "noted — will apply going forward" } : { output: "usage: /steer <note> — steer the ongoing task" };
|
|
22892
22971
|
case "/web":
|
|
22893
22972
|
case "/fetch":
|
|
22894
22973
|
case "/browse":
|
|
@@ -22947,7 +23026,7 @@ function inside(cwd2, p) {
|
|
|
22947
23026
|
}
|
|
22948
23027
|
var bash = {
|
|
22949
23028
|
name: "bash",
|
|
22950
|
-
description:
|
|
23029
|
+
description: `Run a shell command in the working directory (shell: ${shellName()}); returns combined stdout+stderr. Use for builds, tests, git, file ops.${shellName() === "powershell" || shellName() === "pwsh" ? " NOTE: this is Windows PowerShell — use PowerShell syntax (Get-ChildItem/ls, Get-Content/cat, 2>$null, Select-Object -First N)." : shellName() === "cmd" ? " NOTE: this is Windows cmd.exe — use cmd syntax." : ""}`,
|
|
22951
23030
|
permission: "ask",
|
|
22952
23031
|
parameters: {
|
|
22953
23032
|
type: "object",
|
|
@@ -23137,7 +23216,9 @@ function registerAgentTool(cfg, onProgress) {
|
|
|
23137
23216
|
if (!agent)
|
|
23138
23217
|
return `error: unknown subagent '${args.subagent_type}'. available: ${names.join(", ")}`;
|
|
23139
23218
|
const { text, feeGrains } = await runSubagent(cfg, agent, String(args.prompt ?? ""), ctx, onProgress);
|
|
23140
|
-
|
|
23219
|
+
ctx.onCost?.(feeGrains);
|
|
23220
|
+
onProgress?.(` ↳ ${agent.name} done · ${(feeGrains / 1e8).toFixed(4)} MDL`);
|
|
23221
|
+
return `[${agent.name} · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
23141
23222
|
${text}`;
|
|
23142
23223
|
}
|
|
23143
23224
|
};
|
|
@@ -23158,7 +23239,8 @@ ${text}`;
|
|
|
23158
23239
|
async run(args, ctx) {
|
|
23159
23240
|
const members = Array.isArray(args.members) ? args.members.map(String) : [];
|
|
23160
23241
|
const { transcript, feeGrains } = await runTeam(cfg, members, String(args.prompt ?? ""), ctx, Number(args.rounds) || 2, onProgress);
|
|
23161
|
-
|
|
23242
|
+
ctx.onCost?.(feeGrains);
|
|
23243
|
+
return `[team · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
23162
23244
|
${transcript}`;
|
|
23163
23245
|
}
|
|
23164
23246
|
};
|
|
@@ -23761,6 +23843,26 @@ function imageMentions(line, cwd2) {
|
|
|
23761
23843
|
|
|
23762
23844
|
// src/ui/tui.tsx
|
|
23763
23845
|
var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
|
|
23846
|
+
function toolUseLabel(name, args) {
|
|
23847
|
+
const cap = (s, n = 160) => s.length > n ? s.slice(0, n).trim() + "…" : s;
|
|
23848
|
+
if (name === "bash")
|
|
23849
|
+
return cap(String(args.command ?? "").split(`
|
|
23850
|
+
`)[0] ?? "");
|
|
23851
|
+
if (name === "edit" || name === "write" || name === "read")
|
|
23852
|
+
return `${name} ${cap(String(args.path ?? ""), 80)}`;
|
|
23853
|
+
const keys2 = Object.entries(args).map(([k, v]) => `${k}=${cap(String(v), 40)}`).join(" ");
|
|
23854
|
+
return cap(`${name} ${keys2}`);
|
|
23855
|
+
}
|
|
23856
|
+
function capLines(s, max2) {
|
|
23857
|
+
const lines = s.replace(/\s+$/, "").split(`
|
|
23858
|
+
`);
|
|
23859
|
+
if (lines.length <= max2)
|
|
23860
|
+
return lines.join(`
|
|
23861
|
+
`);
|
|
23862
|
+
return lines.slice(0, max2).join(`
|
|
23863
|
+
`) + `
|
|
23864
|
+
… +${lines.length - max2} lines`;
|
|
23865
|
+
}
|
|
23764
23866
|
function Root({ cfg, resume, mcpCount }) {
|
|
23765
23867
|
const [lines, setLines] = import_react35.useState([
|
|
23766
23868
|
{ kind: "system", text: `ready · model ${cfg.model} — ask me anything, or /help` },
|
|
@@ -23779,7 +23881,11 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23779
23881
|
const [turnTokens, setTurnTokens] = import_react35.useState(0);
|
|
23780
23882
|
const mdlUsd = import_react35.useRef(null);
|
|
23781
23883
|
const streamBuf = import_react35.useRef("");
|
|
23884
|
+
const toolStreamRef = import_react35.useRef("");
|
|
23782
23885
|
const tokensRef = import_react35.useRef(0);
|
|
23886
|
+
const pumpRef = import_react35.useRef(null);
|
|
23887
|
+
const busyRef = import_react35.useRef(false);
|
|
23888
|
+
const queueRef = import_react35.useRef([]);
|
|
23783
23889
|
const confirmResolve = import_react35.useRef(null);
|
|
23784
23890
|
const sessionIdRef = import_react35.useRef(newSessionId());
|
|
23785
23891
|
const sessionMdlRef = import_react35.useRef(0);
|
|
@@ -23812,20 +23918,22 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23812
23918
|
const agent = import_react35.useRef(new Agent(cfg, { cwd: cwd2 }, {
|
|
23813
23919
|
onAssistantDelta: (txt) => {
|
|
23814
23920
|
streamBuf.current += txt;
|
|
23815
|
-
setStreaming(streamBuf.current);
|
|
23816
23921
|
tokensRef.current += Math.max(1, Math.round(txt.length / 4));
|
|
23817
|
-
setTurnTokens(tokensRef.current);
|
|
23818
23922
|
},
|
|
23819
23923
|
onToolStart: (name, args) => {
|
|
23820
23924
|
flushAssistant();
|
|
23925
|
+
toolStreamRef.current = "";
|
|
23821
23926
|
setToolStream("");
|
|
23822
|
-
add2({ kind: "tool", text:
|
|
23927
|
+
add2({ kind: "tool", text: toolUseLabel(name, args) });
|
|
23823
23928
|
},
|
|
23824
23929
|
onToolResult: (_n, r) => {
|
|
23930
|
+
toolStreamRef.current = "";
|
|
23825
23931
|
setToolStream("");
|
|
23826
|
-
add2({ kind: "
|
|
23932
|
+
add2({ kind: "result", text: capLines(r, 8) });
|
|
23933
|
+
},
|
|
23934
|
+
onToolStream: (chunk2) => {
|
|
23935
|
+
toolStreamRef.current = (toolStreamRef.current + chunk2).slice(-2000);
|
|
23827
23936
|
},
|
|
23828
|
-
onToolStream: (chunk2) => setToolStream((s) => (s + chunk2).slice(-2000)),
|
|
23829
23937
|
onCost: (g) => setSessionMdl((s) => {
|
|
23830
23938
|
const v = s + g / 1e8;
|
|
23831
23939
|
sessionMdlRef.current = v;
|
|
@@ -23872,12 +23980,21 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23872
23980
|
return;
|
|
23873
23981
|
}
|
|
23874
23982
|
streamBuf.current = "";
|
|
23983
|
+
toolStreamRef.current = "";
|
|
23875
23984
|
setStreaming("");
|
|
23876
23985
|
setToolStream("");
|
|
23877
23986
|
tokensRef.current = 0;
|
|
23878
23987
|
setTurnTokens(0);
|
|
23879
23988
|
setTurnStart(Date.now());
|
|
23989
|
+
busyRef.current = true;
|
|
23880
23990
|
setBusy(true);
|
|
23991
|
+
if (pumpRef.current)
|
|
23992
|
+
clearInterval(pumpRef.current);
|
|
23993
|
+
pumpRef.current = setInterval(() => {
|
|
23994
|
+
setStreaming(streamBuf.current);
|
|
23995
|
+
setToolStream(toolStreamRef.current);
|
|
23996
|
+
setTurnTokens(tokensRef.current);
|
|
23997
|
+
}, 80);
|
|
23881
23998
|
try {
|
|
23882
23999
|
await agent.send(expandFileMentions(prompt, cwd2), imageMentions(prompt, cwd2));
|
|
23883
24000
|
flushAssistant();
|
|
@@ -23894,21 +24011,28 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23894
24011
|
flushAssistant();
|
|
23895
24012
|
add2({ kind: "error", text: e.message });
|
|
23896
24013
|
} finally {
|
|
24014
|
+
if (pumpRef.current) {
|
|
24015
|
+
clearInterval(pumpRef.current);
|
|
24016
|
+
pumpRef.current = null;
|
|
24017
|
+
}
|
|
23897
24018
|
setStreaming("");
|
|
23898
24019
|
setToolStream("");
|
|
23899
24020
|
streamBuf.current = "";
|
|
24021
|
+
toolStreamRef.current = "";
|
|
24022
|
+
busyRef.current = false;
|
|
23900
24023
|
setBusy(false);
|
|
23901
24024
|
setContextPct(agent.contextStatus().pct);
|
|
23902
24025
|
setMode(agent.mode);
|
|
23903
24026
|
refreshWallet();
|
|
24027
|
+
const next = queueRef.current.shift();
|
|
24028
|
+
if (next !== undefined)
|
|
24029
|
+
runInput(next);
|
|
23904
24030
|
}
|
|
23905
24031
|
}, [agent, add2, refreshWallet, cfg, cwd2, flushAssistant]);
|
|
23906
24032
|
const onInterrupt = import_react35.useCallback(() => {
|
|
23907
24033
|
agent.abort();
|
|
23908
24034
|
}, [agent]);
|
|
23909
|
-
const
|
|
23910
|
-
add2({ kind: "user", text: input });
|
|
23911
|
-
setHistory((h) => (h[h.length - 1] === input ? h : [...h, input]).slice(-100));
|
|
24035
|
+
const runInput = import_react35.useCallback(async (input) => {
|
|
23912
24036
|
if (input.startsWith("/")) {
|
|
23913
24037
|
const r = await handleSlash(input, { agent, cfg, cwd: cwd2, sessionMdl: sessionMdlRef.current, mcpCount: mcpCountRef.current });
|
|
23914
24038
|
if (r) {
|
|
@@ -23933,6 +24057,28 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23933
24057
|
setMode(agent.mode);
|
|
23934
24058
|
if (r.output)
|
|
23935
24059
|
add2({ kind: "system", text: r.output });
|
|
24060
|
+
if (r.sideQuestion) {
|
|
24061
|
+
busyRef.current = true;
|
|
24062
|
+
setBusy(true);
|
|
24063
|
+
setTurnStart(Date.now());
|
|
24064
|
+
streamBuf.current = "";
|
|
24065
|
+
setStreaming("");
|
|
24066
|
+
try {
|
|
24067
|
+
const ans = await agent.sideQuestion(r.sideQuestion, (t) => {
|
|
24068
|
+
streamBuf.current += t;
|
|
24069
|
+
setStreaming(streamBuf.current);
|
|
24070
|
+
});
|
|
24071
|
+
add2({ kind: "system", text: `btw › ${ans}` });
|
|
24072
|
+
} catch (e) {
|
|
24073
|
+
add2({ kind: "error", text: e.message });
|
|
24074
|
+
} finally {
|
|
24075
|
+
streamBuf.current = "";
|
|
24076
|
+
setStreaming("");
|
|
24077
|
+
busyRef.current = false;
|
|
24078
|
+
setBusy(false);
|
|
24079
|
+
refreshWallet();
|
|
24080
|
+
}
|
|
24081
|
+
}
|
|
23936
24082
|
if (r.agentPrompt)
|
|
23937
24083
|
await runTurn(r.agentPrompt);
|
|
23938
24084
|
return;
|
|
@@ -23940,6 +24086,17 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23940
24086
|
}
|
|
23941
24087
|
await runTurn(input);
|
|
23942
24088
|
}, [agent, add2, cfg, cwd2, onExit, runTurn]);
|
|
24089
|
+
const onSubmit = import_react35.useCallback((input) => {
|
|
24090
|
+
setHistory((h) => (h[h.length - 1] === input ? h : [...h, input]).slice(-100));
|
|
24091
|
+
if (busyRef.current) {
|
|
24092
|
+
queueRef.current.push(input);
|
|
24093
|
+
add2({ kind: "user", text: input });
|
|
24094
|
+
add2({ kind: "system", text: "↳ queued (runs after the current turn)" });
|
|
24095
|
+
return;
|
|
24096
|
+
}
|
|
24097
|
+
add2({ kind: "user", text: input });
|
|
24098
|
+
runInput(input);
|
|
24099
|
+
}, [add2, runInput]);
|
|
23943
24100
|
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(App2, {
|
|
23944
24101
|
theme: cfg.theme,
|
|
23945
24102
|
model: cfg.model,
|
|
@@ -23962,12 +24119,25 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23962
24119
|
onExit
|
|
23963
24120
|
}, undefined, false, undefined, this);
|
|
23964
24121
|
}
|
|
23965
|
-
|
|
23966
|
-
if (
|
|
23967
|
-
|
|
23968
|
-
|
|
23969
|
-
|
|
24122
|
+
function getRenderStdin() {
|
|
24123
|
+
if (process.stdin.isTTY)
|
|
24124
|
+
return;
|
|
24125
|
+
if (process.env.CI)
|
|
24126
|
+
return;
|
|
24127
|
+
if (process.platform === "win32")
|
|
24128
|
+
return;
|
|
24129
|
+
try {
|
|
24130
|
+
const { openSync } = __require("fs");
|
|
24131
|
+
const { ReadStream } = __require("tty");
|
|
24132
|
+
const s = new ReadStream(openSync("/dev/tty", "r"));
|
|
24133
|
+
s.isTTY = true;
|
|
24134
|
+
return s;
|
|
24135
|
+
} catch {
|
|
24136
|
+
return;
|
|
23970
24137
|
}
|
|
24138
|
+
}
|
|
24139
|
+
async function runTui(cfg, resume = "none") {
|
|
24140
|
+
const renderStdin = getRenderStdin();
|
|
23971
24141
|
registerCoreTools();
|
|
23972
24142
|
registerMemoryTools();
|
|
23973
24143
|
registerAgentTool(cfg, (line) => emitProgress(line));
|
|
@@ -23975,7 +24145,12 @@ async function runTui(cfg, resume = "none") {
|
|
|
23975
24145
|
registerMoreTools();
|
|
23976
24146
|
registerBrowserTool();
|
|
23977
24147
|
registerTaskTools();
|
|
23978
|
-
|
|
24148
|
+
let mcpCount = 0;
|
|
24149
|
+
registerMcpTools(process.cwd()).then((n) => {
|
|
24150
|
+
mcpCount = n;
|
|
24151
|
+
if (n)
|
|
24152
|
+
emitProgress(`✓ ${n} MCP tool(s) connected`);
|
|
24153
|
+
}).catch(() => {});
|
|
23979
24154
|
startScheduler(async (prompt, jobCwd) => {
|
|
23980
24155
|
emitProgress(`⏰ running scheduled job…`);
|
|
23981
24156
|
const a = new Agent(cfg, { cwd: jobCwd }, { onAssistantDelta: () => {}, onToolStart: () => {}, onToolResult: () => {}, onCost: () => {}, confirm: async () => true });
|
|
@@ -23984,11 +24159,26 @@ async function runTui(cfg, resume = "none") {
|
|
|
23984
24159
|
});
|
|
23985
24160
|
pullTeamMemory().catch(() => {});
|
|
23986
24161
|
indexCodebaseIncremental(process.cwd()).catch(() => {});
|
|
24162
|
+
const restore = () => {
|
|
24163
|
+
try {
|
|
24164
|
+
if (process.stdin.isTTY)
|
|
24165
|
+
process.stdin.setRawMode(false);
|
|
24166
|
+
} catch {}
|
|
24167
|
+
};
|
|
24168
|
+
process.on("exit", restore);
|
|
24169
|
+
process.on("SIGINT", () => {
|
|
24170
|
+
restore();
|
|
24171
|
+
process.exit(0);
|
|
24172
|
+
});
|
|
24173
|
+
process.on("SIGTERM", () => {
|
|
24174
|
+
restore();
|
|
24175
|
+
process.exit(0);
|
|
24176
|
+
});
|
|
23987
24177
|
render_default(/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Root, {
|
|
23988
24178
|
cfg,
|
|
23989
24179
|
resume,
|
|
23990
24180
|
mcpCount
|
|
23991
|
-
}, undefined, false, undefined, this));
|
|
24181
|
+
}, undefined, false, undefined, this), { exitOnCtrlC: false, ...renderStdin ? { stdin: renderStdin } : {} });
|
|
23992
24182
|
}
|
|
23993
24183
|
export {
|
|
23994
24184
|
runTui
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modeloslab/modelcode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "modelOS-native AI coding agent CLI — remembers like Hermes, codes like Claude Code, runs on modelOS (pay-per-use in MDL, no rate limits). Knowledge-graph memory, subagents, MCP, vision, spend caps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|