miii-agent 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -247
- package/dist/cli.js +1138 -124
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -34,7 +34,8 @@ function migrate(raw) {
|
|
|
34
34
|
model: raw.model,
|
|
35
35
|
provider: raw.provider,
|
|
36
36
|
effort: raw.effort,
|
|
37
|
-
providers
|
|
37
|
+
providers,
|
|
38
|
+
modelContexts: raw.modelContexts
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
function readRawConfig() {
|
|
@@ -79,6 +80,10 @@ function setEffort(effort) {
|
|
|
79
80
|
function setProvider(provider) {
|
|
80
81
|
saveConfig({ ...readRawConfig(), provider });
|
|
81
82
|
}
|
|
83
|
+
function setModelContexts(contexts) {
|
|
84
|
+
const raw = readRawConfig();
|
|
85
|
+
saveConfig({ ...raw, modelContexts: { ...raw.modelContexts, ...contexts } });
|
|
86
|
+
}
|
|
82
87
|
var EFFORT_OPTIONS, CONFIG_DIR, CONFIG_PATH;
|
|
83
88
|
var init_config = __esm({
|
|
84
89
|
"src/config.ts"() {
|
|
@@ -158,6 +163,30 @@ async function modelContext(entry, model) {
|
|
|
158
163
|
throw err;
|
|
159
164
|
}
|
|
160
165
|
}
|
|
166
|
+
async function paramCountB(entry, model) {
|
|
167
|
+
try {
|
|
168
|
+
const info = await makeClient(entry).show({ model });
|
|
169
|
+
const details = info.details;
|
|
170
|
+
if (details?.parameter_size) {
|
|
171
|
+
const m = details.parameter_size.match(/([\d.]+)\s*([BM])/i);
|
|
172
|
+
if (m) {
|
|
173
|
+
const n = parseFloat(m[1]);
|
|
174
|
+
if (!isNaN(n)) return m[2].toUpperCase() === "M" ? n / 1e3 : n;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const modelInfo = info.model_info;
|
|
178
|
+
if (modelInfo) {
|
|
179
|
+
const key = Object.keys(modelInfo).find((k) => k.endsWith("parameter_count"));
|
|
180
|
+
if (key) {
|
|
181
|
+
const val = Number(modelInfo[key]);
|
|
182
|
+
if (!isNaN(val) && val > 0) return val / 1e9;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
161
190
|
async function* chat(entry, model, messages, tools, opts) {
|
|
162
191
|
if (opts?.signal?.aborted) return;
|
|
163
192
|
const signal = opts?.signal;
|
|
@@ -177,15 +206,31 @@ async function* chat(entry, model, messages, tools, opts) {
|
|
|
177
206
|
num_ctx: opts?.num_ctx ?? 8192
|
|
178
207
|
};
|
|
179
208
|
if (numPredict !== void 0 && numPredict > 0) options.num_predict = numPredict;
|
|
180
|
-
|
|
209
|
+
const req = {
|
|
181
210
|
model,
|
|
182
211
|
messages,
|
|
183
|
-
tools,
|
|
184
212
|
stream: true,
|
|
185
213
|
think: true,
|
|
186
214
|
keep_alive: opts?.keep_alive ?? "10m",
|
|
187
215
|
options
|
|
188
|
-
}
|
|
216
|
+
};
|
|
217
|
+
if (opts?.format) req.format = opts.format;
|
|
218
|
+
else if (tools) req.tools = tools;
|
|
219
|
+
try {
|
|
220
|
+
stream = await client.chat(
|
|
221
|
+
req
|
|
222
|
+
);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
225
|
+
if (!signal?.aborted && msg.toLowerCase().includes("does not support thinking")) {
|
|
226
|
+
delete req.think;
|
|
227
|
+
stream = await client.chat(
|
|
228
|
+
req
|
|
229
|
+
);
|
|
230
|
+
} else {
|
|
231
|
+
throw err;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
189
234
|
} catch (err) {
|
|
190
235
|
if (signal?.aborted) return;
|
|
191
236
|
if (isConnectionError(err)) {
|
|
@@ -215,6 +260,11 @@ async function* chat(entry, model, messages, tools, opts) {
|
|
|
215
260
|
if (isConnectionError(err)) {
|
|
216
261
|
throw new Error(NOT_RUNNING);
|
|
217
262
|
}
|
|
263
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
264
|
+
if (msg.includes("Did not receive done or success response in stream")) {
|
|
265
|
+
yield { content: "", done: true, prompt_eval_count: 0, eval_count: 0 };
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
218
268
|
throw err;
|
|
219
269
|
} finally {
|
|
220
270
|
if (opts?.signal) opts.signal.removeEventListener("abort", onAbort);
|
|
@@ -452,6 +502,9 @@ var init_openai = __esm({
|
|
|
452
502
|
function active() {
|
|
453
503
|
return resolveProvider();
|
|
454
504
|
}
|
|
505
|
+
function providerName() {
|
|
506
|
+
return active().name;
|
|
507
|
+
}
|
|
455
508
|
function isAvailable3() {
|
|
456
509
|
const { entry } = active();
|
|
457
510
|
return entry.type === "ollama" ? isAvailable(entry) : isAvailable2(entry);
|
|
@@ -468,6 +521,16 @@ async function modelContext3(model) {
|
|
|
468
521
|
const { entry } = active();
|
|
469
522
|
return entry.type === "ollama" ? modelContext(entry, model) : modelContext2(entry, model);
|
|
470
523
|
}
|
|
524
|
+
async function modelParamCountB(model) {
|
|
525
|
+
const { entry } = active();
|
|
526
|
+
if (entry.type !== "ollama") return null;
|
|
527
|
+
const key = `${entry.baseUrl}:${model}`;
|
|
528
|
+
const cached = paramCountCache.get(key);
|
|
529
|
+
if (cached !== void 0) return cached;
|
|
530
|
+
const params = await paramCountB(entry, model);
|
|
531
|
+
paramCountCache.set(key, params);
|
|
532
|
+
return params;
|
|
533
|
+
}
|
|
471
534
|
async function* chat3(model, messages, tools, opts) {
|
|
472
535
|
const { entry } = active();
|
|
473
536
|
if (entry.type === "ollama") {
|
|
@@ -476,12 +539,70 @@ async function* chat3(model, messages, tools, opts) {
|
|
|
476
539
|
yield* chat2(entry, model, messages, tools, opts);
|
|
477
540
|
}
|
|
478
541
|
}
|
|
542
|
+
var paramCountCache;
|
|
479
543
|
var init_client = __esm({
|
|
480
544
|
"src/llm/client.ts"() {
|
|
481
545
|
"use strict";
|
|
482
546
|
init_config();
|
|
483
547
|
init_ollama();
|
|
484
548
|
init_openai();
|
|
549
|
+
paramCountCache = /* @__PURE__ */ new Map();
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// src/llm/grammar.ts
|
|
554
|
+
function argProperties(props) {
|
|
555
|
+
const out = {};
|
|
556
|
+
for (const [key, spec] of Object.entries(props)) {
|
|
557
|
+
const node = { type: spec.type };
|
|
558
|
+
if (spec.enum && spec.enum.length) node.enum = spec.enum;
|
|
559
|
+
out[key] = node;
|
|
560
|
+
}
|
|
561
|
+
return out;
|
|
562
|
+
}
|
|
563
|
+
function toolBranch(tool) {
|
|
564
|
+
const args2 = {
|
|
565
|
+
type: "object",
|
|
566
|
+
additionalProperties: false,
|
|
567
|
+
properties: argProperties(tool.input_schema.properties)
|
|
568
|
+
};
|
|
569
|
+
if (tool.input_schema.required && tool.input_schema.required.length) {
|
|
570
|
+
args2.required = tool.input_schema.required;
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
type: "object",
|
|
574
|
+
additionalProperties: false,
|
|
575
|
+
required: ["name", "arguments"],
|
|
576
|
+
properties: {
|
|
577
|
+
name: { const: tool.name },
|
|
578
|
+
arguments: args2
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
function respondBranch() {
|
|
583
|
+
return {
|
|
584
|
+
type: "object",
|
|
585
|
+
additionalProperties: false,
|
|
586
|
+
required: ["name", "arguments"],
|
|
587
|
+
properties: {
|
|
588
|
+
name: { const: RESPOND_ACTION },
|
|
589
|
+
arguments: {
|
|
590
|
+
type: "object",
|
|
591
|
+
additionalProperties: false,
|
|
592
|
+
required: ["message"],
|
|
593
|
+
properties: { message: { type: "string" } }
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function buildToolGrammar(tools) {
|
|
599
|
+
return { oneOf: [...tools.map(toolBranch), respondBranch()] };
|
|
600
|
+
}
|
|
601
|
+
var RESPOND_ACTION;
|
|
602
|
+
var init_grammar = __esm({
|
|
603
|
+
"src/llm/grammar.ts"() {
|
|
604
|
+
"use strict";
|
|
605
|
+
RESPOND_ACTION = "respond";
|
|
485
606
|
}
|
|
486
607
|
});
|
|
487
608
|
|
|
@@ -1149,8 +1270,15 @@ var init_context = __esm({
|
|
|
1149
1270
|
});
|
|
1150
1271
|
|
|
1151
1272
|
// src/prompt/system.ts
|
|
1152
|
-
function buildSystemPrompt(tools, cwd, project) {
|
|
1273
|
+
function buildSystemPrompt(tools, cwd, project, grammarMode = false) {
|
|
1153
1274
|
const toolLines = tools.map((t) => `- ${t.name}: ${t.description}`).join("\n");
|
|
1275
|
+
const actionProtocol = grammarMode ? `
|
|
1276
|
+
# Action protocol (strict)
|
|
1277
|
+
Every reply is exactly ONE JSON action object, nothing else \u2014 no prose outside it, no markdown, no fences. Decoding is grammar-constrained, so malformed output is impossible; your only job is to choose the right action.
|
|
1278
|
+
To use a tool: {"name": "<tool_name>", "arguments": { ...that tool's args }}
|
|
1279
|
+
To give your final answer to the user: {"name": "respond", "arguments": {"message": "<your full answer here>"}}
|
|
1280
|
+
Call tools until the GOAL is met, then emit a single "respond" action with the complete answer. The "respond" action is the ONLY way to end the turn and talk to the user \u2014 never put your final answer in a tool call.
|
|
1281
|
+
` : "";
|
|
1154
1282
|
const projectSection = project && project.content.trim() ? `
|
|
1155
1283
|
# ${CONTEXT_FILENAME} \u2014 project instructions (authoritative, read first)
|
|
1156
1284
|
The user maintains ${CONTEXT_FILENAME} at ${project.source} to steer how you work in this project: conventions, commands, architecture, do's and don'ts. Treat it as direct instruction from the user, higher priority than your defaults. When it conflicts with a default rule below, ${CONTEXT_FILENAME} wins (except permissions and safety, which you never override).${project.truncated ? `
|
|
@@ -1175,6 +1303,17 @@ If GAPS is non-empty, ask the minimum questions needed to fill them \u2014 one m
|
|
|
1175
1303
|
|
|
1176
1304
|
Re-read GOAL before every tool call. If a tool call does not move toward GOAL, skip it.
|
|
1177
1305
|
|
|
1306
|
+
# Plan summary before acting (conditional)
|
|
1307
|
+
Write a brief plan BEFORE the first tool call ONLY when the work is non-trivial:
|
|
1308
|
+
- Multi-step, OR touches multiple files, OR is destructive/hard to reverse, OR mixes investigation + change.
|
|
1309
|
+
SKIP the plan for trivial work \u2014 a single read, one small edit, a quick search, a direct question. Just act.
|
|
1310
|
+
When you do write one:
|
|
1311
|
+
- One or two plain-text sentences naming what you will do and in what order.
|
|
1312
|
+
- State the intent (the bug/feature/fix and the steps), not a tool-by-tool narration.
|
|
1313
|
+
- Keep it short \u2014 the user reads this to follow along, not a spec.
|
|
1314
|
+
Then begin immediately with the first tool call. Do not wait for approval unless GAPS was non-empty or the work is destructive.
|
|
1315
|
+
This summary is the ONE allowed preamble. It does not override the Tool calls rule below: after this plan, emit tool calls directly with no further narration between them.
|
|
1316
|
+
|
|
1178
1317
|
# Attention: re-attend to goal at each step
|
|
1179
1318
|
After each tool result, answer silently: "Does this result move me toward GOAL?"
|
|
1180
1319
|
YES \u2192 continue
|
|
@@ -1183,9 +1322,9 @@ After each tool result, answer silently: "Does this result move me toward GOAL?"
|
|
|
1183
1322
|
This prevents drift. Each step attends to the original goal, not just the previous step.
|
|
1184
1323
|
|
|
1185
1324
|
# Output format
|
|
1186
|
-
-
|
|
1187
|
-
-
|
|
1188
|
-
-
|
|
1325
|
+
- Your reply is rendered as Markdown in the terminal. You may use the Markdown the renderer supports: \`#\` headings, \`**bold**\` / \`*italic*\`, \`-\` bullet and numbered lists, fenced \`\`\` code blocks (with a language tag for syntax highlighting), inline backticks, blockquotes, links, and tables.
|
|
1326
|
+
- Use it sparingly and only where it aids clarity. Wrap code, paths, commands, and identifiers in inline backticks; put multi-line code in fenced blocks with a language tag. Keep prose plain \u2014 no decorative formatting.
|
|
1327
|
+
- This does NOT apply to your reasoning/thinking. Write internal thoughts in plain text \u2014 no Markdown headings, bold, lists, or code fences there.
|
|
1189
1328
|
- Keep prose terse.
|
|
1190
1329
|
|
|
1191
1330
|
# Tone and voice
|
|
@@ -1224,7 +1363,7 @@ Ask in a numbered list. One round of questions per turn. Then wait.
|
|
|
1224
1363
|
# Tools
|
|
1225
1364
|
You have access to the following tools. Call them via the function-calling interface.
|
|
1226
1365
|
${toolLines}
|
|
1227
|
-
|
|
1366
|
+
${actionProtocol}
|
|
1228
1367
|
# Loop semantics
|
|
1229
1368
|
- When you need to act on the filesystem or run a command, emit a tool call.
|
|
1230
1369
|
- After each tool result, decide: more tool calls, or a final plain-text answer.
|
|
@@ -1289,6 +1428,17 @@ function subjectFor(toolName, input) {
|
|
|
1289
1428
|
if (typeof obj.path === "string") return obj.path;
|
|
1290
1429
|
return "";
|
|
1291
1430
|
}
|
|
1431
|
+
function generalizeCommand(command) {
|
|
1432
|
+
const tokens = command.trim().split(/\s+/);
|
|
1433
|
+
if (tokens.length === 0 || tokens[0] === "") return command;
|
|
1434
|
+
const prog = tokens[0];
|
|
1435
|
+
const prefixLen = WRAPPER_PROGRAMS.has(prog) && tokens.length > 1 ? 2 : 1;
|
|
1436
|
+
const prefix = tokens.slice(0, prefixLen).join(" ");
|
|
1437
|
+
return `${prefix} *`;
|
|
1438
|
+
}
|
|
1439
|
+
function patternToPersist(toolName, subject) {
|
|
1440
|
+
return toolName === "run_bash" ? generalizeCommand(subject) : subject;
|
|
1441
|
+
}
|
|
1292
1442
|
function globToRegExp(glob2) {
|
|
1293
1443
|
const escaped = glob2.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
1294
1444
|
const pattern = escaped.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
@@ -1309,15 +1459,28 @@ async function check(toolName, input, ctx) {
|
|
|
1309
1459
|
if (rules.some((r) => matches(r, toolName, subject))) return "allow";
|
|
1310
1460
|
const answer = await ctx.ask(toolName, input);
|
|
1311
1461
|
if (answer === "no") return "deny";
|
|
1312
|
-
if (answer === "always") addRule(toolName, subject);
|
|
1462
|
+
if (answer === "always") addRule(toolName, patternToPersist(toolName, subject));
|
|
1313
1463
|
return "allow";
|
|
1314
1464
|
}
|
|
1315
|
-
var RULES_DIR, RULES_PATH, ALWAYS_ALLOW;
|
|
1465
|
+
var RULES_DIR, RULES_PATH, WRAPPER_PROGRAMS, ALWAYS_ALLOW;
|
|
1316
1466
|
var init_policy = __esm({
|
|
1317
1467
|
"src/permissions/policy.ts"() {
|
|
1318
1468
|
"use strict";
|
|
1319
1469
|
RULES_DIR = join7(homedir5(), ".miii");
|
|
1320
1470
|
RULES_PATH = join7(RULES_DIR, "permissions.json");
|
|
1471
|
+
WRAPPER_PROGRAMS = /* @__PURE__ */ new Set([
|
|
1472
|
+
"npm",
|
|
1473
|
+
"npx",
|
|
1474
|
+
"pnpm",
|
|
1475
|
+
"yarn",
|
|
1476
|
+
"brew",
|
|
1477
|
+
"pip",
|
|
1478
|
+
"pip3",
|
|
1479
|
+
"cargo",
|
|
1480
|
+
"docker",
|
|
1481
|
+
"kubectl",
|
|
1482
|
+
"go"
|
|
1483
|
+
]);
|
|
1321
1484
|
ALWAYS_ALLOW = /* @__PURE__ */ new Set(["read_file", "grep", "glob"]);
|
|
1322
1485
|
}
|
|
1323
1486
|
});
|
|
@@ -1430,6 +1593,75 @@ function extractFirstJsonObject(s) {
|
|
|
1430
1593
|
}
|
|
1431
1594
|
return null;
|
|
1432
1595
|
}
|
|
1596
|
+
function parseGrammarAction(content, knownToolNames) {
|
|
1597
|
+
if (!content) return null;
|
|
1598
|
+
let raw = content.trim();
|
|
1599
|
+
if (!raw.startsWith("{")) {
|
|
1600
|
+
const found = extractFirstJsonObject(raw);
|
|
1601
|
+
if (!found) return null;
|
|
1602
|
+
raw = found.json;
|
|
1603
|
+
}
|
|
1604
|
+
let obj;
|
|
1605
|
+
try {
|
|
1606
|
+
obj = JSON.parse(raw);
|
|
1607
|
+
} catch {
|
|
1608
|
+
const found = extractFirstJsonObject(raw);
|
|
1609
|
+
if (!found) return null;
|
|
1610
|
+
try {
|
|
1611
|
+
obj = JSON.parse(found.json);
|
|
1612
|
+
} catch {
|
|
1613
|
+
return null;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
const name = typeof obj.name === "string" ? obj.name : void 0;
|
|
1617
|
+
const args2 = obj.arguments ?? {};
|
|
1618
|
+
if (!name) return null;
|
|
1619
|
+
if (name === "respond") {
|
|
1620
|
+
const message = typeof args2.message === "string" ? args2.message : "";
|
|
1621
|
+
return { kind: "respond", message };
|
|
1622
|
+
}
|
|
1623
|
+
if (!knownToolNames.includes(name)) return null;
|
|
1624
|
+
return { kind: "tool", name, arguments: args2 };
|
|
1625
|
+
}
|
|
1626
|
+
function streamRespondMessage(text) {
|
|
1627
|
+
if (!/"name"\s*:\s*"respond"/.test(text)) return null;
|
|
1628
|
+
const m = text.match(/"message"\s*:\s*"/);
|
|
1629
|
+
if (!m || m.index == null) return null;
|
|
1630
|
+
const start = m.index + m[0].length;
|
|
1631
|
+
const escapes = {
|
|
1632
|
+
n: "\n",
|
|
1633
|
+
t: " ",
|
|
1634
|
+
r: "\r",
|
|
1635
|
+
b: "\b",
|
|
1636
|
+
f: "\f",
|
|
1637
|
+
'"': '"',
|
|
1638
|
+
"\\": "\\",
|
|
1639
|
+
"/": "/"
|
|
1640
|
+
};
|
|
1641
|
+
let out = "";
|
|
1642
|
+
let i = start;
|
|
1643
|
+
while (i < text.length) {
|
|
1644
|
+
const ch = text[i];
|
|
1645
|
+
if (ch === '"') return { message: out, complete: true };
|
|
1646
|
+
if (ch === "\\") {
|
|
1647
|
+
const nx = text[i + 1];
|
|
1648
|
+
if (nx === void 0) break;
|
|
1649
|
+
if (nx === "u") {
|
|
1650
|
+
const hex = text.slice(i + 2, i + 6);
|
|
1651
|
+
if (hex.length < 4) break;
|
|
1652
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
1653
|
+
i += 6;
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
out += escapes[nx] ?? nx;
|
|
1657
|
+
i += 2;
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
out += ch;
|
|
1661
|
+
i++;
|
|
1662
|
+
}
|
|
1663
|
+
return { message: out, complete: false };
|
|
1664
|
+
}
|
|
1433
1665
|
function blocksFromOllama(text, tool_calls, knownToolNames = []) {
|
|
1434
1666
|
const blocks = [];
|
|
1435
1667
|
let finalText = text;
|
|
@@ -1487,8 +1719,15 @@ function markSeen(name, input, seen) {
|
|
|
1487
1719
|
async function* runAgent(opts) {
|
|
1488
1720
|
const { model, cwd, permissions, hooks, signal, num_ctx } = opts;
|
|
1489
1721
|
const startTime = Date.now();
|
|
1490
|
-
|
|
1722
|
+
let useGrammar = false;
|
|
1723
|
+
if (providerName() === "ollama") {
|
|
1724
|
+
const params = await modelParamCountB(model);
|
|
1725
|
+
useGrammar = params == null || params <= GRAMMAR_MAX_PARAMS_B;
|
|
1726
|
+
}
|
|
1727
|
+
const system = buildSystemPrompt(TOOLS, cwd, loadProjectContext(cwd), useGrammar);
|
|
1728
|
+
const grammar = useGrammar ? buildToolGrammar(TOOLS) : void 0;
|
|
1491
1729
|
const ollamaTools = toOllamaTools(TOOLS);
|
|
1730
|
+
const toolNames = TOOLS.map((t) => t.name);
|
|
1492
1731
|
const effort = EFFORT_OPTIONS[loadConfig().effort ?? "medium"];
|
|
1493
1732
|
const history = [
|
|
1494
1733
|
...opts.history,
|
|
@@ -1502,6 +1741,8 @@ async function* runAgent(opts) {
|
|
|
1502
1741
|
for (let turn = 0; turn < MAX_TURNS; turn++) {
|
|
1503
1742
|
let text = "";
|
|
1504
1743
|
let tool_calls;
|
|
1744
|
+
let respondEmitted = 0;
|
|
1745
|
+
let streamedRespond = false;
|
|
1505
1746
|
let lastTail = "";
|
|
1506
1747
|
let tailRepeats = 0;
|
|
1507
1748
|
let streamLooped = false;
|
|
@@ -1509,11 +1750,22 @@ async function* runAgent(opts) {
|
|
|
1509
1750
|
const composedSignal = signal ? AbortSignal.any ? AbortSignal.any([signal, ac.signal]) : ac.signal : ac.signal;
|
|
1510
1751
|
if (signal) signal.addEventListener("abort", () => ac.abort(), { once: true });
|
|
1511
1752
|
try {
|
|
1512
|
-
for await (const chunk of chat3(model, toOllamaMessages(history, system), ollamaTools, { signal: composedSignal, num_ctx, num_predict: effort.num_predict, temperature: effort.temperature })) {
|
|
1753
|
+
for await (const chunk of chat3(model, toOllamaMessages(history, system), useGrammar ? void 0 : ollamaTools, { signal: composedSignal, num_ctx, num_predict: effort.num_predict, temperature: effort.temperature, format: grammar })) {
|
|
1513
1754
|
if (signal?.aborted) break;
|
|
1514
1755
|
if (chunk.content) {
|
|
1515
1756
|
text += chunk.content;
|
|
1516
|
-
|
|
1757
|
+
if (!useGrammar) {
|
|
1758
|
+
yield { type: "text-delta", text: chunk.content };
|
|
1759
|
+
} else {
|
|
1760
|
+
const r = streamRespondMessage(text);
|
|
1761
|
+
if (r) {
|
|
1762
|
+
streamedRespond = true;
|
|
1763
|
+
if (r.message.length > respondEmitted) {
|
|
1764
|
+
yield { type: "text-delta", text: r.message.slice(respondEmitted) };
|
|
1765
|
+
respondEmitted = r.message.length;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1517
1769
|
if (text.length >= REPEAT_TAIL) {
|
|
1518
1770
|
const tail = text.slice(-REPEAT_TAIL);
|
|
1519
1771
|
if (tail === lastTail) {
|
|
@@ -1561,7 +1813,19 @@ async function* runAgent(opts) {
|
|
|
1561
1813
|
};
|
|
1562
1814
|
return history;
|
|
1563
1815
|
}
|
|
1564
|
-
|
|
1816
|
+
let blocks;
|
|
1817
|
+
if (useGrammar) {
|
|
1818
|
+
const action = parseGrammarAction(text, toolNames);
|
|
1819
|
+
if (action?.kind === "tool") {
|
|
1820
|
+
blocks = [{ type: "tool_use", id: mintToolUseId(), name: action.name, input: action.arguments }];
|
|
1821
|
+
} else {
|
|
1822
|
+
const message = action?.kind === "respond" ? action.message : text.trim();
|
|
1823
|
+
if (message && !streamedRespond) yield { type: "text-delta", text: message };
|
|
1824
|
+
blocks = message ? [{ type: "text", text: message }] : [];
|
|
1825
|
+
}
|
|
1826
|
+
} else {
|
|
1827
|
+
blocks = blocksFromOllama(text, tool_calls, toolNames);
|
|
1828
|
+
}
|
|
1565
1829
|
const tool_uses = blocks.filter((b) => b.type === "tool_use");
|
|
1566
1830
|
history.push({ role: "assistant", content: blocks });
|
|
1567
1831
|
if (tool_uses.length === 0) {
|
|
@@ -1670,11 +1934,12 @@ async function* runAgent(opts) {
|
|
|
1670
1934
|
yield { type: "done", prompt_tokens: promptTokens, eval_tokens: evalTokens };
|
|
1671
1935
|
return history;
|
|
1672
1936
|
}
|
|
1673
|
-
var MAX_TURNS, REPEAT_TAIL, REPEAT_KILL;
|
|
1937
|
+
var MAX_TURNS, REPEAT_TAIL, REPEAT_KILL, GRAMMAR_MAX_PARAMS_B;
|
|
1674
1938
|
var init_loop = __esm({
|
|
1675
1939
|
"src/agent/loop.ts"() {
|
|
1676
1940
|
"use strict";
|
|
1677
1941
|
init_client();
|
|
1942
|
+
init_grammar();
|
|
1678
1943
|
init_paths();
|
|
1679
1944
|
init_registry();
|
|
1680
1945
|
init_validate();
|
|
@@ -1686,6 +1951,7 @@ var init_loop = __esm({
|
|
|
1686
1951
|
MAX_TURNS = 25;
|
|
1687
1952
|
REPEAT_TAIL = 120;
|
|
1688
1953
|
REPEAT_KILL = 4;
|
|
1954
|
+
GRAMMAR_MAX_PARAMS_B = 14;
|
|
1689
1955
|
}
|
|
1690
1956
|
});
|
|
1691
1957
|
|
|
@@ -1915,7 +2181,7 @@ import { createElement } from "react";
|
|
|
1915
2181
|
init_client();
|
|
1916
2182
|
init_config();
|
|
1917
2183
|
import { useState as useState5, useEffect as useEffect4, useRef as useRef2 } from "react";
|
|
1918
|
-
import { Box as
|
|
2184
|
+
import { Box as Box13, Text as Text13, useApp } from "ink";
|
|
1919
2185
|
import { homedir as homedir6 } from "os";
|
|
1920
2186
|
import { sep as sep2 } from "path";
|
|
1921
2187
|
|
|
@@ -1957,7 +2223,7 @@ import { memo, useEffect, useState } from "react";
|
|
|
1957
2223
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
1958
2224
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1959
2225
|
var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1960
|
-
var InputBar = memo(function InputBar2({ input, disabled, processingLabel }) {
|
|
2226
|
+
var InputBar = memo(function InputBar2({ input, caret, disabled, processingLabel }) {
|
|
1961
2227
|
const [frame, setFrame] = useState(0);
|
|
1962
2228
|
useEffect(() => {
|
|
1963
2229
|
if (!disabled) return;
|
|
@@ -1980,8 +2246,17 @@ var InputBar = memo(function InputBar2({ input, disabled, processingLabel }) {
|
|
|
1980
2246
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " (esc to cancel)" })
|
|
1981
2247
|
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1982
2248
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "> " }),
|
|
1983
|
-
|
|
1984
|
-
|
|
2249
|
+
(() => {
|
|
2250
|
+
const pos = Math.max(0, Math.min(caret ?? input.length, input.length));
|
|
2251
|
+
const before = input.slice(0, pos);
|
|
2252
|
+
const at = input.slice(pos, pos + 1) || " ";
|
|
2253
|
+
const after = input.slice(pos + 1);
|
|
2254
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2255
|
+
/* @__PURE__ */ jsx2(Text2, { children: before }),
|
|
2256
|
+
/* @__PURE__ */ jsx2(Text2, { inverse: true, children: at }),
|
|
2257
|
+
/* @__PURE__ */ jsx2(Text2, { children: after })
|
|
2258
|
+
] });
|
|
2259
|
+
})()
|
|
1985
2260
|
] })
|
|
1986
2261
|
}
|
|
1987
2262
|
);
|
|
@@ -2390,10 +2665,566 @@ function FilePicker({ matches: matches2, cursor }) {
|
|
|
2390
2665
|
}
|
|
2391
2666
|
|
|
2392
2667
|
// src/ui/ChatView.tsx
|
|
2393
|
-
import {
|
|
2394
|
-
|
|
2668
|
+
import { Box as Box12, Text as Text12, Static } from "ink";
|
|
2669
|
+
|
|
2670
|
+
// src/ui/markdown.ts
|
|
2671
|
+
import { Marked } from "marked";
|
|
2672
|
+
import { markedTerminal } from "marked-terminal";
|
|
2395
2673
|
import { highlight } from "cli-highlight";
|
|
2396
2674
|
|
|
2675
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
2676
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
2677
|
+
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
2678
|
+
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
2679
|
+
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
2680
|
+
var styles = {
|
|
2681
|
+
modifier: {
|
|
2682
|
+
reset: [0, 0],
|
|
2683
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
2684
|
+
bold: [1, 22],
|
|
2685
|
+
dim: [2, 22],
|
|
2686
|
+
italic: [3, 23],
|
|
2687
|
+
underline: [4, 24],
|
|
2688
|
+
overline: [53, 55],
|
|
2689
|
+
inverse: [7, 27],
|
|
2690
|
+
hidden: [8, 28],
|
|
2691
|
+
strikethrough: [9, 29]
|
|
2692
|
+
},
|
|
2693
|
+
color: {
|
|
2694
|
+
black: [30, 39],
|
|
2695
|
+
red: [31, 39],
|
|
2696
|
+
green: [32, 39],
|
|
2697
|
+
yellow: [33, 39],
|
|
2698
|
+
blue: [34, 39],
|
|
2699
|
+
magenta: [35, 39],
|
|
2700
|
+
cyan: [36, 39],
|
|
2701
|
+
white: [37, 39],
|
|
2702
|
+
// Bright color
|
|
2703
|
+
blackBright: [90, 39],
|
|
2704
|
+
gray: [90, 39],
|
|
2705
|
+
// Alias of `blackBright`
|
|
2706
|
+
grey: [90, 39],
|
|
2707
|
+
// Alias of `blackBright`
|
|
2708
|
+
redBright: [91, 39],
|
|
2709
|
+
greenBright: [92, 39],
|
|
2710
|
+
yellowBright: [93, 39],
|
|
2711
|
+
blueBright: [94, 39],
|
|
2712
|
+
magentaBright: [95, 39],
|
|
2713
|
+
cyanBright: [96, 39],
|
|
2714
|
+
whiteBright: [97, 39]
|
|
2715
|
+
},
|
|
2716
|
+
bgColor: {
|
|
2717
|
+
bgBlack: [40, 49],
|
|
2718
|
+
bgRed: [41, 49],
|
|
2719
|
+
bgGreen: [42, 49],
|
|
2720
|
+
bgYellow: [43, 49],
|
|
2721
|
+
bgBlue: [44, 49],
|
|
2722
|
+
bgMagenta: [45, 49],
|
|
2723
|
+
bgCyan: [46, 49],
|
|
2724
|
+
bgWhite: [47, 49],
|
|
2725
|
+
// Bright color
|
|
2726
|
+
bgBlackBright: [100, 49],
|
|
2727
|
+
bgGray: [100, 49],
|
|
2728
|
+
// Alias of `bgBlackBright`
|
|
2729
|
+
bgGrey: [100, 49],
|
|
2730
|
+
// Alias of `bgBlackBright`
|
|
2731
|
+
bgRedBright: [101, 49],
|
|
2732
|
+
bgGreenBright: [102, 49],
|
|
2733
|
+
bgYellowBright: [103, 49],
|
|
2734
|
+
bgBlueBright: [104, 49],
|
|
2735
|
+
bgMagentaBright: [105, 49],
|
|
2736
|
+
bgCyanBright: [106, 49],
|
|
2737
|
+
bgWhiteBright: [107, 49]
|
|
2738
|
+
}
|
|
2739
|
+
};
|
|
2740
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
2741
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
2742
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
2743
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
2744
|
+
function assembleStyles() {
|
|
2745
|
+
const codes = /* @__PURE__ */ new Map();
|
|
2746
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
2747
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
2748
|
+
styles[styleName] = {
|
|
2749
|
+
open: `\x1B[${style[0]}m`,
|
|
2750
|
+
close: `\x1B[${style[1]}m`
|
|
2751
|
+
};
|
|
2752
|
+
group[styleName] = styles[styleName];
|
|
2753
|
+
codes.set(style[0], style[1]);
|
|
2754
|
+
}
|
|
2755
|
+
Object.defineProperty(styles, groupName, {
|
|
2756
|
+
value: group,
|
|
2757
|
+
enumerable: false
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
Object.defineProperty(styles, "codes", {
|
|
2761
|
+
value: codes,
|
|
2762
|
+
enumerable: false
|
|
2763
|
+
});
|
|
2764
|
+
styles.color.close = "\x1B[39m";
|
|
2765
|
+
styles.bgColor.close = "\x1B[49m";
|
|
2766
|
+
styles.color.ansi = wrapAnsi16();
|
|
2767
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
2768
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
2769
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
2770
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
2771
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
2772
|
+
Object.defineProperties(styles, {
|
|
2773
|
+
rgbToAnsi256: {
|
|
2774
|
+
value(red, green, blue) {
|
|
2775
|
+
if (red === green && green === blue) {
|
|
2776
|
+
if (red < 8) {
|
|
2777
|
+
return 16;
|
|
2778
|
+
}
|
|
2779
|
+
if (red > 248) {
|
|
2780
|
+
return 231;
|
|
2781
|
+
}
|
|
2782
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
2783
|
+
}
|
|
2784
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
2785
|
+
},
|
|
2786
|
+
enumerable: false
|
|
2787
|
+
},
|
|
2788
|
+
hexToRgb: {
|
|
2789
|
+
value(hex) {
|
|
2790
|
+
const matches2 = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
2791
|
+
if (!matches2) {
|
|
2792
|
+
return [0, 0, 0];
|
|
2793
|
+
}
|
|
2794
|
+
let [colorString] = matches2;
|
|
2795
|
+
if (colorString.length === 3) {
|
|
2796
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
2797
|
+
}
|
|
2798
|
+
const integer = Number.parseInt(colorString, 16);
|
|
2799
|
+
return [
|
|
2800
|
+
/* eslint-disable no-bitwise */
|
|
2801
|
+
integer >> 16 & 255,
|
|
2802
|
+
integer >> 8 & 255,
|
|
2803
|
+
integer & 255
|
|
2804
|
+
/* eslint-enable no-bitwise */
|
|
2805
|
+
];
|
|
2806
|
+
},
|
|
2807
|
+
enumerable: false
|
|
2808
|
+
},
|
|
2809
|
+
hexToAnsi256: {
|
|
2810
|
+
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
2811
|
+
enumerable: false
|
|
2812
|
+
},
|
|
2813
|
+
ansi256ToAnsi: {
|
|
2814
|
+
value(code) {
|
|
2815
|
+
if (code < 8) {
|
|
2816
|
+
return 30 + code;
|
|
2817
|
+
}
|
|
2818
|
+
if (code < 16) {
|
|
2819
|
+
return 90 + (code - 8);
|
|
2820
|
+
}
|
|
2821
|
+
let red;
|
|
2822
|
+
let green;
|
|
2823
|
+
let blue;
|
|
2824
|
+
if (code >= 232) {
|
|
2825
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
2826
|
+
green = red;
|
|
2827
|
+
blue = red;
|
|
2828
|
+
} else {
|
|
2829
|
+
code -= 16;
|
|
2830
|
+
const remainder = code % 36;
|
|
2831
|
+
red = Math.floor(code / 36) / 5;
|
|
2832
|
+
green = Math.floor(remainder / 6) / 5;
|
|
2833
|
+
blue = remainder % 6 / 5;
|
|
2834
|
+
}
|
|
2835
|
+
const value = Math.max(red, green, blue) * 2;
|
|
2836
|
+
if (value === 0) {
|
|
2837
|
+
return 30;
|
|
2838
|
+
}
|
|
2839
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
2840
|
+
if (value === 2) {
|
|
2841
|
+
result += 60;
|
|
2842
|
+
}
|
|
2843
|
+
return result;
|
|
2844
|
+
},
|
|
2845
|
+
enumerable: false
|
|
2846
|
+
},
|
|
2847
|
+
rgbToAnsi: {
|
|
2848
|
+
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
2849
|
+
enumerable: false
|
|
2850
|
+
},
|
|
2851
|
+
hexToAnsi: {
|
|
2852
|
+
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
2853
|
+
enumerable: false
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
return styles;
|
|
2857
|
+
}
|
|
2858
|
+
var ansiStyles = assembleStyles();
|
|
2859
|
+
var ansi_styles_default = ansiStyles;
|
|
2860
|
+
|
|
2861
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
2862
|
+
import process2 from "process";
|
|
2863
|
+
import os from "os";
|
|
2864
|
+
import tty from "tty";
|
|
2865
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
2866
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
2867
|
+
const position = argv.indexOf(prefix + flag);
|
|
2868
|
+
const terminatorPosition = argv.indexOf("--");
|
|
2869
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
2870
|
+
}
|
|
2871
|
+
var { env } = process2;
|
|
2872
|
+
var flagForceColor;
|
|
2873
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
2874
|
+
flagForceColor = 0;
|
|
2875
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
2876
|
+
flagForceColor = 1;
|
|
2877
|
+
}
|
|
2878
|
+
function envForceColor() {
|
|
2879
|
+
if ("FORCE_COLOR" in env) {
|
|
2880
|
+
if (env.FORCE_COLOR === "true") {
|
|
2881
|
+
return 1;
|
|
2882
|
+
}
|
|
2883
|
+
if (env.FORCE_COLOR === "false") {
|
|
2884
|
+
return 0;
|
|
2885
|
+
}
|
|
2886
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
function translateLevel(level) {
|
|
2890
|
+
if (level === 0) {
|
|
2891
|
+
return false;
|
|
2892
|
+
}
|
|
2893
|
+
return {
|
|
2894
|
+
level,
|
|
2895
|
+
hasBasic: true,
|
|
2896
|
+
has256: level >= 2,
|
|
2897
|
+
has16m: level >= 3
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
2901
|
+
const noFlagForceColor = envForceColor();
|
|
2902
|
+
if (noFlagForceColor !== void 0) {
|
|
2903
|
+
flagForceColor = noFlagForceColor;
|
|
2904
|
+
}
|
|
2905
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
2906
|
+
if (forceColor === 0) {
|
|
2907
|
+
return 0;
|
|
2908
|
+
}
|
|
2909
|
+
if (sniffFlags) {
|
|
2910
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
2911
|
+
return 3;
|
|
2912
|
+
}
|
|
2913
|
+
if (hasFlag("color=256")) {
|
|
2914
|
+
return 2;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
2918
|
+
return 1;
|
|
2919
|
+
}
|
|
2920
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
2921
|
+
return 0;
|
|
2922
|
+
}
|
|
2923
|
+
const min = forceColor || 0;
|
|
2924
|
+
if (env.TERM === "dumb") {
|
|
2925
|
+
return min;
|
|
2926
|
+
}
|
|
2927
|
+
if (process2.platform === "win32") {
|
|
2928
|
+
const osRelease = os.release().split(".");
|
|
2929
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
2930
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
2931
|
+
}
|
|
2932
|
+
return 1;
|
|
2933
|
+
}
|
|
2934
|
+
if ("CI" in env) {
|
|
2935
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
2936
|
+
return 3;
|
|
2937
|
+
}
|
|
2938
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
2939
|
+
return 1;
|
|
2940
|
+
}
|
|
2941
|
+
return min;
|
|
2942
|
+
}
|
|
2943
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
2944
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
2945
|
+
}
|
|
2946
|
+
if (env.COLORTERM === "truecolor") {
|
|
2947
|
+
return 3;
|
|
2948
|
+
}
|
|
2949
|
+
if (env.TERM === "xterm-kitty") {
|
|
2950
|
+
return 3;
|
|
2951
|
+
}
|
|
2952
|
+
if (env.TERM === "xterm-ghostty") {
|
|
2953
|
+
return 3;
|
|
2954
|
+
}
|
|
2955
|
+
if (env.TERM === "wezterm") {
|
|
2956
|
+
return 3;
|
|
2957
|
+
}
|
|
2958
|
+
if ("TERM_PROGRAM" in env) {
|
|
2959
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
2960
|
+
switch (env.TERM_PROGRAM) {
|
|
2961
|
+
case "iTerm.app": {
|
|
2962
|
+
return version >= 3 ? 3 : 2;
|
|
2963
|
+
}
|
|
2964
|
+
case "Apple_Terminal": {
|
|
2965
|
+
return 2;
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
2970
|
+
return 2;
|
|
2971
|
+
}
|
|
2972
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
2973
|
+
return 1;
|
|
2974
|
+
}
|
|
2975
|
+
if ("COLORTERM" in env) {
|
|
2976
|
+
return 1;
|
|
2977
|
+
}
|
|
2978
|
+
return min;
|
|
2979
|
+
}
|
|
2980
|
+
function createSupportsColor(stream, options = {}) {
|
|
2981
|
+
const level = _supportsColor(stream, {
|
|
2982
|
+
streamIsTTY: stream && stream.isTTY,
|
|
2983
|
+
...options
|
|
2984
|
+
});
|
|
2985
|
+
return translateLevel(level);
|
|
2986
|
+
}
|
|
2987
|
+
var supportsColor = {
|
|
2988
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
2989
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
2990
|
+
};
|
|
2991
|
+
var supports_color_default = supportsColor;
|
|
2992
|
+
|
|
2993
|
+
// node_modules/chalk/source/utilities.js
|
|
2994
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
2995
|
+
let index = string.indexOf(substring);
|
|
2996
|
+
if (index === -1) {
|
|
2997
|
+
return string;
|
|
2998
|
+
}
|
|
2999
|
+
const substringLength = substring.length;
|
|
3000
|
+
let endIndex = 0;
|
|
3001
|
+
let returnValue = "";
|
|
3002
|
+
do {
|
|
3003
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
3004
|
+
endIndex = index + substringLength;
|
|
3005
|
+
index = string.indexOf(substring, endIndex);
|
|
3006
|
+
} while (index !== -1);
|
|
3007
|
+
returnValue += string.slice(endIndex);
|
|
3008
|
+
return returnValue;
|
|
3009
|
+
}
|
|
3010
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
3011
|
+
let endIndex = 0;
|
|
3012
|
+
let returnValue = "";
|
|
3013
|
+
do {
|
|
3014
|
+
const gotCR = string[index - 1] === "\r";
|
|
3015
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
3016
|
+
endIndex = index + 1;
|
|
3017
|
+
index = string.indexOf("\n", endIndex);
|
|
3018
|
+
} while (index !== -1);
|
|
3019
|
+
returnValue += string.slice(endIndex);
|
|
3020
|
+
return returnValue;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
// node_modules/chalk/source/index.js
|
|
3024
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
3025
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
3026
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
3027
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
3028
|
+
var levelMapping = [
|
|
3029
|
+
"ansi",
|
|
3030
|
+
"ansi",
|
|
3031
|
+
"ansi256",
|
|
3032
|
+
"ansi16m"
|
|
3033
|
+
];
|
|
3034
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
3035
|
+
var applyOptions = (object, options = {}) => {
|
|
3036
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
3037
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
3038
|
+
}
|
|
3039
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
3040
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
3041
|
+
};
|
|
3042
|
+
var chalkFactory = (options) => {
|
|
3043
|
+
const chalk2 = (...strings) => strings.join(" ");
|
|
3044
|
+
applyOptions(chalk2, options);
|
|
3045
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
3046
|
+
return chalk2;
|
|
3047
|
+
};
|
|
3048
|
+
function createChalk(options) {
|
|
3049
|
+
return chalkFactory(options);
|
|
3050
|
+
}
|
|
3051
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
3052
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
3053
|
+
styles2[styleName] = {
|
|
3054
|
+
get() {
|
|
3055
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
3056
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
3057
|
+
return builder;
|
|
3058
|
+
}
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
styles2.visible = {
|
|
3062
|
+
get() {
|
|
3063
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
3064
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
3065
|
+
return builder;
|
|
3066
|
+
}
|
|
3067
|
+
};
|
|
3068
|
+
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
3069
|
+
if (model === "rgb") {
|
|
3070
|
+
if (level === "ansi16m") {
|
|
3071
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
3072
|
+
}
|
|
3073
|
+
if (level === "ansi256") {
|
|
3074
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
3075
|
+
}
|
|
3076
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
3077
|
+
}
|
|
3078
|
+
if (model === "hex") {
|
|
3079
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
3080
|
+
}
|
|
3081
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
3082
|
+
};
|
|
3083
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
3084
|
+
for (const model of usedModels) {
|
|
3085
|
+
styles2[model] = {
|
|
3086
|
+
get() {
|
|
3087
|
+
const { level } = this;
|
|
3088
|
+
return function(...arguments_) {
|
|
3089
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
3090
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
3091
|
+
};
|
|
3092
|
+
}
|
|
3093
|
+
};
|
|
3094
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
3095
|
+
styles2[bgModel] = {
|
|
3096
|
+
get() {
|
|
3097
|
+
const { level } = this;
|
|
3098
|
+
return function(...arguments_) {
|
|
3099
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
3100
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
var proto = Object.defineProperties(() => {
|
|
3106
|
+
}, {
|
|
3107
|
+
...styles2,
|
|
3108
|
+
level: {
|
|
3109
|
+
enumerable: true,
|
|
3110
|
+
get() {
|
|
3111
|
+
return this[GENERATOR].level;
|
|
3112
|
+
},
|
|
3113
|
+
set(level) {
|
|
3114
|
+
this[GENERATOR].level = level;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
});
|
|
3118
|
+
var createStyler = (open, close, parent) => {
|
|
3119
|
+
let openAll;
|
|
3120
|
+
let closeAll;
|
|
3121
|
+
if (parent === void 0) {
|
|
3122
|
+
openAll = open;
|
|
3123
|
+
closeAll = close;
|
|
3124
|
+
} else {
|
|
3125
|
+
openAll = parent.openAll + open;
|
|
3126
|
+
closeAll = close + parent.closeAll;
|
|
3127
|
+
}
|
|
3128
|
+
return {
|
|
3129
|
+
open,
|
|
3130
|
+
close,
|
|
3131
|
+
openAll,
|
|
3132
|
+
closeAll,
|
|
3133
|
+
parent
|
|
3134
|
+
};
|
|
3135
|
+
};
|
|
3136
|
+
var createBuilder = (self, _styler, _isEmpty) => {
|
|
3137
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
3138
|
+
Object.setPrototypeOf(builder, proto);
|
|
3139
|
+
builder[GENERATOR] = self;
|
|
3140
|
+
builder[STYLER] = _styler;
|
|
3141
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
3142
|
+
return builder;
|
|
3143
|
+
};
|
|
3144
|
+
var applyStyle = (self, string) => {
|
|
3145
|
+
if (self.level <= 0 || !string) {
|
|
3146
|
+
return self[IS_EMPTY] ? "" : string;
|
|
3147
|
+
}
|
|
3148
|
+
let styler = self[STYLER];
|
|
3149
|
+
if (styler === void 0) {
|
|
3150
|
+
return string;
|
|
3151
|
+
}
|
|
3152
|
+
const { openAll, closeAll } = styler;
|
|
3153
|
+
if (string.includes("\x1B")) {
|
|
3154
|
+
while (styler !== void 0) {
|
|
3155
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
3156
|
+
styler = styler.parent;
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
const lfIndex = string.indexOf("\n");
|
|
3160
|
+
if (lfIndex !== -1) {
|
|
3161
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
3162
|
+
}
|
|
3163
|
+
return openAll + string + closeAll;
|
|
3164
|
+
};
|
|
3165
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
3166
|
+
var chalk = createChalk();
|
|
3167
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
3168
|
+
var source_default = chalk;
|
|
3169
|
+
|
|
3170
|
+
// src/ui/markdown.ts
|
|
3171
|
+
var theme = {
|
|
3172
|
+
heading: source_default.hex("#7fa8d4").bold,
|
|
3173
|
+
// dusty blue
|
|
3174
|
+
firstHeading: source_default.hex("#9ab8de").bold,
|
|
3175
|
+
// slightly lighter for h1
|
|
3176
|
+
strong: source_default.hex("#d6c9a8").bold,
|
|
3177
|
+
// warm sand
|
|
3178
|
+
em: source_default.hex("#b59ec4").italic,
|
|
3179
|
+
// soft mauve
|
|
3180
|
+
del: source_default.hex("#6b7280").strikethrough,
|
|
3181
|
+
// dim gray
|
|
3182
|
+
codespan: source_default.hex("#c8a98a"),
|
|
3183
|
+
// muted clay
|
|
3184
|
+
link: source_default.hex("#83b3a6").underline,
|
|
3185
|
+
// sage teal
|
|
3186
|
+
href: source_default.hex("#83b3a6").underline,
|
|
3187
|
+
blockquote: source_default.hex("#8a9aa8").italic,
|
|
3188
|
+
// slate
|
|
3189
|
+
listitem: source_default.hex("#c4c9cf"),
|
|
3190
|
+
// off-white
|
|
3191
|
+
paragraph: source_default.hex("#c4c9cf"),
|
|
3192
|
+
// off-white body text
|
|
3193
|
+
hr: source_default.hex("#4b5563")
|
|
3194
|
+
// faint rule
|
|
3195
|
+
};
|
|
3196
|
+
function highlightCode(code, lang) {
|
|
3197
|
+
if (!lang) return code;
|
|
3198
|
+
try {
|
|
3199
|
+
return highlight(code, { language: lang, ignoreIllegals: true });
|
|
3200
|
+
} catch {
|
|
3201
|
+
return code;
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
var md = new Marked();
|
|
3205
|
+
md.use(
|
|
3206
|
+
markedTerminal({
|
|
3207
|
+
// Drop the literal `#` prefix on headings; render them styled instead.
|
|
3208
|
+
showSectionPrefix: false,
|
|
3209
|
+
// marked-terminal calls this for ``` blocks; fall back to plain on unknown lang.
|
|
3210
|
+
code: (code, lang) => highlightCode(code, lang),
|
|
3211
|
+
...theme
|
|
3212
|
+
})
|
|
3213
|
+
);
|
|
3214
|
+
function renderMarkdown(content) {
|
|
3215
|
+
try {
|
|
3216
|
+
const out = md.parse(content, { async: false });
|
|
3217
|
+
return out.replace(/\n+$/, "");
|
|
3218
|
+
} catch {
|
|
3219
|
+
return content;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
function renderMarkdownStreaming(content) {
|
|
3223
|
+
const fences = (content.match(/^```/gm) ?? []).length;
|
|
3224
|
+
const balanced = fences % 2 === 1 ? content + "\n```" : content;
|
|
3225
|
+
return renderMarkdown(balanced);
|
|
3226
|
+
}
|
|
3227
|
+
|
|
2397
3228
|
// src/ui/ThinkingBlock.tsx
|
|
2398
3229
|
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
2399
3230
|
import { Box as Box8, Text as Text8 } from "ink";
|
|
@@ -2436,7 +3267,12 @@ function ThinkingBlock({ content }) {
|
|
|
2436
3267
|
" thoughts"
|
|
2437
3268
|
] })
|
|
2438
3269
|
] }),
|
|
2439
|
-
visible && content ?
|
|
3270
|
+
visible && content ? (() => {
|
|
3271
|
+
const max = Math.max(4, (process.stdout.rows ?? 24) - 10);
|
|
3272
|
+
const lines = content.split("\n");
|
|
3273
|
+
const shown = lines.length > max ? lines.slice(-max) : lines;
|
|
3274
|
+
return /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, italic: true, children: shown.join("\n") }) });
|
|
3275
|
+
})() : null
|
|
2440
3276
|
] });
|
|
2441
3277
|
}
|
|
2442
3278
|
|
|
@@ -2450,9 +3286,16 @@ var EMPTY_STATE_HINTS = [
|
|
|
2450
3286
|
];
|
|
2451
3287
|
var EMPTY_STATE_TITLE = "Ask anything, or try:";
|
|
2452
3288
|
|
|
2453
|
-
// src/ui/
|
|
2454
|
-
import {
|
|
2455
|
-
|
|
3289
|
+
// src/ui/Message.tsx
|
|
3290
|
+
import { memo as memo2 } from "react";
|
|
3291
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
3292
|
+
|
|
3293
|
+
// src/ui/ToolBlock.tsx
|
|
3294
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
3295
|
+
import { highlight as highlight2 } from "cli-highlight";
|
|
3296
|
+
|
|
3297
|
+
// src/ui/toolExpand.ts
|
|
3298
|
+
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
2456
3299
|
var globalToolExpanded = false;
|
|
2457
3300
|
var toolExpandListeners = /* @__PURE__ */ new Set();
|
|
2458
3301
|
function toggleToolExpanded() {
|
|
@@ -2470,6 +3313,8 @@ function useToolExpanded() {
|
|
|
2470
3313
|
}, []);
|
|
2471
3314
|
return expanded;
|
|
2472
3315
|
}
|
|
3316
|
+
|
|
3317
|
+
// src/ui/layout.ts
|
|
2473
3318
|
function formatTokens(n) {
|
|
2474
3319
|
if (n >= 1e3) return (n / 1e3).toFixed(n >= 1e4 ? 0 : 1) + "k";
|
|
2475
3320
|
return String(n);
|
|
@@ -2485,6 +3330,61 @@ function countLines(s) {
|
|
|
2485
3330
|
if (!s) return 0;
|
|
2486
3331
|
return s.split("\n").length;
|
|
2487
3332
|
}
|
|
3333
|
+
function truncate2(s, max) {
|
|
3334
|
+
if (s.length <= max) return s;
|
|
3335
|
+
return s.slice(0, max - 1) + "\u2026";
|
|
3336
|
+
}
|
|
3337
|
+
function clipTail(rendered, max) {
|
|
3338
|
+
const lines = rendered.split("\n");
|
|
3339
|
+
if (lines.length <= max) return { text: rendered, clipped: 0 };
|
|
3340
|
+
return { text: lines.slice(-max).join("\n"), clipped: lines.length - max };
|
|
3341
|
+
}
|
|
3342
|
+
function liveFrameRows() {
|
|
3343
|
+
const rows = process.stdout.rows ?? 24;
|
|
3344
|
+
return Math.max(6, rows - 8);
|
|
3345
|
+
}
|
|
3346
|
+
var COLLAPSED_LINES = 3;
|
|
3347
|
+
function estimateToolRows(use, result) {
|
|
3348
|
+
const input = use.input ?? {};
|
|
3349
|
+
const noErr = !result?.is_error;
|
|
3350
|
+
if (use.name === "write_file" && noErr) {
|
|
3351
|
+
const total = countLines(String(input.content ?? ""));
|
|
3352
|
+
const shown = Math.min(total, COLLAPSED_LINES);
|
|
3353
|
+
return 2 + shown + (total > shown ? 1 : 0);
|
|
3354
|
+
}
|
|
3355
|
+
if (use.name === "edit_file" && noErr) {
|
|
3356
|
+
const total = countLines(String(input.old_str ?? "")) + countLines(String(input.new_str ?? ""));
|
|
3357
|
+
const shown = Math.min(total, COLLAPSED_LINES);
|
|
3358
|
+
return 2 + shown + (total > shown ? 1 : 0);
|
|
3359
|
+
}
|
|
3360
|
+
let rows = 1;
|
|
3361
|
+
if (result) {
|
|
3362
|
+
const lines = (result.content ?? "").split("\n");
|
|
3363
|
+
const multi = (use.name === "run_bash" || use.name === "grep" || use.name === "glob" || result.is_error) && lines.length > 1;
|
|
3364
|
+
if (multi) {
|
|
3365
|
+
const shown = Math.min(lines.length, COLLAPSED_LINES);
|
|
3366
|
+
rows += 1 + shown + (lines.length > shown ? 1 : 0);
|
|
3367
|
+
} else {
|
|
3368
|
+
rows += 1;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
return rows;
|
|
3372
|
+
}
|
|
3373
|
+
function contentWidth() {
|
|
3374
|
+
return Math.max(20, (process.stdout.columns ?? 80) - 4);
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
// src/ui/ToolBlock.tsx
|
|
3378
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3379
|
+
var COLLAPSED_LINES2 = 3;
|
|
3380
|
+
var TOOL_LABEL = {
|
|
3381
|
+
write_file: "Write",
|
|
3382
|
+
edit_file: "Update",
|
|
3383
|
+
read_file: "Read",
|
|
3384
|
+
run_bash: "Bash",
|
|
3385
|
+
glob: "Glob",
|
|
3386
|
+
grep: "Grep"
|
|
3387
|
+
};
|
|
2488
3388
|
var EXT_LANG = {
|
|
2489
3389
|
ts: "typescript",
|
|
2490
3390
|
tsx: "typescript",
|
|
@@ -2529,7 +3429,7 @@ function langFromPath(path) {
|
|
|
2529
3429
|
function highlightLine(text, lang) {
|
|
2530
3430
|
if (!lang) return text;
|
|
2531
3431
|
try {
|
|
2532
|
-
return
|
|
3432
|
+
return highlight2(text, { language: lang, ignoreIllegals: true });
|
|
2533
3433
|
} catch {
|
|
2534
3434
|
return text;
|
|
2535
3435
|
}
|
|
@@ -2542,7 +3442,7 @@ function FileEditBlock({
|
|
|
2542
3442
|
previewLines
|
|
2543
3443
|
}) {
|
|
2544
3444
|
const expanded = useToolExpanded();
|
|
2545
|
-
const shown = expanded ? previewLines : previewLines.slice(0,
|
|
3445
|
+
const shown = expanded ? previewLines : previewLines.slice(0, COLLAPSED_LINES2);
|
|
2546
3446
|
const extra = previewLines.length - shown.length;
|
|
2547
3447
|
const lang = langFromPath(path);
|
|
2548
3448
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginLeft: 2, children: [
|
|
@@ -2585,18 +3485,6 @@ function FileEditBlock({
|
|
|
2585
3485
|
] }) })
|
|
2586
3486
|
] });
|
|
2587
3487
|
}
|
|
2588
|
-
var TOOL_LABEL = {
|
|
2589
|
-
write_file: "Write",
|
|
2590
|
-
edit_file: "Update",
|
|
2591
|
-
read_file: "Read",
|
|
2592
|
-
run_bash: "Bash",
|
|
2593
|
-
glob: "Glob",
|
|
2594
|
-
grep: "Grep"
|
|
2595
|
-
};
|
|
2596
|
-
function truncate2(s, max) {
|
|
2597
|
-
if (s.length <= max) return s;
|
|
2598
|
-
return s.slice(0, max - 1) + "\u2026";
|
|
2599
|
-
}
|
|
2600
3488
|
function toolHeader(use) {
|
|
2601
3489
|
const label = TOOL_LABEL[use.name] ?? use.name;
|
|
2602
3490
|
const input = use.input ?? {};
|
|
@@ -2658,7 +3546,7 @@ function ToolResultBlock({ result, toolName }) {
|
|
|
2658
3546
|
] }) });
|
|
2659
3547
|
}
|
|
2660
3548
|
const MAX_LINE_WIDTH = 200;
|
|
2661
|
-
const visible = expanded ? lines : lines.slice(0,
|
|
3549
|
+
const visible = expanded ? lines : lines.slice(0, COLLAPSED_LINES2);
|
|
2662
3550
|
const shown = visible.map((l) => truncate2(l, MAX_LINE_WIDTH));
|
|
2663
3551
|
const extra = lines.length - shown.length;
|
|
2664
3552
|
const header = toolName === "grep" || toolName === "glob" ? summarizeResult(result, toolName) : `${lines.length} line${lines.length === 1 ? "" : "s"}`;
|
|
@@ -2710,28 +3598,35 @@ function ToolUseLine({ use, result }) {
|
|
|
2710
3598
|
result && /* @__PURE__ */ jsx9(ToolResultBlock, { result, toolName: use.name })
|
|
2711
3599
|
] });
|
|
2712
3600
|
}
|
|
3601
|
+
|
|
3602
|
+
// src/ui/Message.tsx
|
|
3603
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2713
3604
|
var UserMessage = memo2(function UserMessage2({ msg }) {
|
|
2714
|
-
return /* @__PURE__ */
|
|
2715
|
-
/* @__PURE__ */
|
|
2716
|
-
/* @__PURE__ */
|
|
3605
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", marginBottom: 1, children: [
|
|
3606
|
+
/* @__PURE__ */ jsx10(Text10, { color: "gray", children: "\u276F " }),
|
|
3607
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, children: /* @__PURE__ */ jsx10(Text10, { children: msg.content }) })
|
|
2717
3608
|
] });
|
|
2718
3609
|
});
|
|
2719
3610
|
var AssistantMessage = memo2(function AssistantMessage2({ msg }) {
|
|
2720
|
-
return /* @__PURE__ */
|
|
2721
|
-
msg.content && /* @__PURE__ */
|
|
2722
|
-
/* @__PURE__ */
|
|
2723
|
-
/* @__PURE__ */
|
|
3611
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
|
|
3612
|
+
msg.content && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
3613
|
+
/* @__PURE__ */ jsx10(Text10, { color: "blue", children: "\u25CF " }),
|
|
3614
|
+
/* @__PURE__ */ jsx10(Box10, { width: contentWidth(), children: /* @__PURE__ */ jsx10(Text10, { wrap: "wrap", children: renderMarkdown(msg.content) }) })
|
|
2724
3615
|
] }),
|
|
2725
3616
|
msg.tool_uses?.map((u) => {
|
|
2726
3617
|
const r = msg.tool_results?.find((x) => x.tool_use_id === u.id);
|
|
2727
|
-
return /* @__PURE__ */
|
|
3618
|
+
return /* @__PURE__ */ jsx10(ToolUseLine, { use: u, result: r }, u.id);
|
|
2728
3619
|
}),
|
|
2729
|
-
msg.tokens && /* @__PURE__ */
|
|
3620
|
+
msg.tokens && /* @__PURE__ */ jsx10(Box10, { marginLeft: 2, children: /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
2730
3621
|
`\u21B3 Completed \xB7 ${formatTokens(msg.tokens.prompt_eval + msg.tokens.eval)} tokens`,
|
|
2731
3622
|
msg.duration != null ? ` \xB7 ${formatDuration(msg.duration)}` : ""
|
|
2732
3623
|
] }) })
|
|
2733
3624
|
] });
|
|
2734
3625
|
});
|
|
3626
|
+
|
|
3627
|
+
// src/ui/PermissionPrompt.tsx
|
|
3628
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
3629
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2735
3630
|
function summarizeInput(input) {
|
|
2736
3631
|
if (!input || typeof input !== "object") return "";
|
|
2737
3632
|
const obj = input;
|
|
@@ -2758,15 +3653,15 @@ function PermissionPrompt({ req, cursor }) {
|
|
|
2758
3653
|
{ label: "No", key: "no" }
|
|
2759
3654
|
];
|
|
2760
3655
|
const summary = summarizeInput(req.input);
|
|
2761
|
-
return /* @__PURE__ */
|
|
2762
|
-
/* @__PURE__ */
|
|
2763
|
-
/* @__PURE__ */
|
|
3656
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
|
|
3657
|
+
/* @__PURE__ */ jsx11(Text11, { color: "blue", bold: true, children: "Tool use" }),
|
|
3658
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { children: [
|
|
2764
3659
|
"Allow ",
|
|
2765
|
-
/* @__PURE__ */
|
|
3660
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, children: label }),
|
|
2766
3661
|
"?"
|
|
2767
3662
|
] }) }),
|
|
2768
|
-
summary && /* @__PURE__ */
|
|
2769
|
-
/* @__PURE__ */
|
|
3663
|
+
summary && /* @__PURE__ */ jsx11(Box11, { marginLeft: 2, children: /* @__PURE__ */ jsx11(Text11, { wrap: "truncate", dimColor: true, children: summary }) }),
|
|
3664
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", marginTop: 1, children: options.map((opt, i) => /* @__PURE__ */ jsxs11(Text11, { color: i === cursor ? "blue" : void 0, children: [
|
|
2770
3665
|
i === cursor ? "\u276F " : " ",
|
|
2771
3666
|
i + 1,
|
|
2772
3667
|
". ",
|
|
@@ -2774,6 +3669,9 @@ function PermissionPrompt({ req, cursor }) {
|
|
|
2774
3669
|
] }, opt.key)) })
|
|
2775
3670
|
] });
|
|
2776
3671
|
}
|
|
3672
|
+
|
|
3673
|
+
// src/ui/ChatView.tsx
|
|
3674
|
+
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2777
3675
|
function ChatView({
|
|
2778
3676
|
messages,
|
|
2779
3677
|
streaming,
|
|
@@ -2784,33 +3682,70 @@ function ChatView({
|
|
|
2784
3682
|
pendingPermission,
|
|
2785
3683
|
permissionCursor = 0,
|
|
2786
3684
|
activeToolUses,
|
|
2787
|
-
activeToolResults
|
|
3685
|
+
activeToolResults,
|
|
3686
|
+
header
|
|
2788
3687
|
}) {
|
|
2789
3688
|
const empty = messages.length === 0 && !streaming && !thinking && !pendingPermission && !error;
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
3689
|
+
const log = [];
|
|
3690
|
+
if (header) log.push({ key: "header", node: header });
|
|
3691
|
+
messages.forEach((msg, i) => {
|
|
3692
|
+
log.push({
|
|
3693
|
+
key: `msg-${i}`,
|
|
3694
|
+
node: msg.role === "user" ? /* @__PURE__ */ jsx12(UserMessage, { msg }) : /* @__PURE__ */ jsx12(AssistantMessage, { msg })
|
|
3695
|
+
});
|
|
3696
|
+
});
|
|
3697
|
+
const liveBudget = liveFrameRows();
|
|
3698
|
+
let streamNode = null;
|
|
3699
|
+
let streamRows = 0;
|
|
3700
|
+
if (streaming && streamingContent) {
|
|
3701
|
+
const { text, clipped } = clipTail(renderMarkdownStreaming(streamingContent), liveBudget);
|
|
3702
|
+
streamRows = text.split("\n").length + (clipped > 0 ? 1 : 0);
|
|
3703
|
+
streamNode = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
|
|
3704
|
+
clipped > 0 && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2191 ${clipped} more line${clipped === 1 ? "" : "s"} above \u2014 streaming\u2026` }),
|
|
3705
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
3706
|
+
/* @__PURE__ */ jsx12(Text12, { color: "blue", children: "\u25CF " }),
|
|
3707
|
+
/* @__PURE__ */ jsx12(Box12, { width: contentWidth(), children: /* @__PURE__ */ jsx12(Text12, { wrap: "wrap", children: text }) })
|
|
3708
|
+
] })
|
|
3709
|
+
] });
|
|
3710
|
+
}
|
|
3711
|
+
let toolNode = null;
|
|
3712
|
+
if (activeToolUses?.length) {
|
|
3713
|
+
const remaining = Math.max(4, liveBudget - streamRows);
|
|
3714
|
+
const resultById = new Map(activeToolResults?.map((r) => [r.tool_use_id, r]));
|
|
3715
|
+
const kept = [];
|
|
3716
|
+
let rows = 0;
|
|
3717
|
+
for (let i = activeToolUses.length - 1; i >= 0; i--) {
|
|
3718
|
+
const u = activeToolUses[i];
|
|
3719
|
+
const r = resultById.get(u.id);
|
|
3720
|
+
const h = estimateToolRows(u, r);
|
|
3721
|
+
if (rows + h > remaining && kept.length) break;
|
|
3722
|
+
rows += h;
|
|
3723
|
+
kept.unshift({ u, r });
|
|
3724
|
+
}
|
|
3725
|
+
const hidden = activeToolUses.length - kept.length;
|
|
3726
|
+
toolNode = /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
3727
|
+
hidden > 0 && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2191 ${hidden} earlier tool call${hidden === 1 ? "" : "s"} above` }),
|
|
3728
|
+
kept.map(({ u, r }) => /* @__PURE__ */ jsx12(ToolUseLine, { use: u, result: r }, u.id))
|
|
3729
|
+
] });
|
|
3730
|
+
}
|
|
3731
|
+
return /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
3732
|
+
/* @__PURE__ */ jsx12(Static, { items: log, children: (item) => item.key === "header" ? /* @__PURE__ */ jsx12(Box12, { children: item.node }, item.key) : /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: item.node }, item.key) }),
|
|
3733
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
|
|
3734
|
+
empty && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
|
|
3735
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: EMPTY_STATE_TITLE }),
|
|
3736
|
+
EMPTY_STATE_HINTS.map((h, i) => /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
3737
|
+
" ",
|
|
3738
|
+
h
|
|
3739
|
+
] }, i))
|
|
3740
|
+
] }),
|
|
3741
|
+
thinking && /* @__PURE__ */ jsx12(ThinkingBlock, { content: thinkingContent }),
|
|
3742
|
+
streamNode,
|
|
3743
|
+
toolNode,
|
|
3744
|
+
pendingPermission && /* @__PURE__ */ jsx12(PermissionPrompt, { req: pendingPermission, cursor: permissionCursor }),
|
|
3745
|
+
error && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", marginBottom: 1, children: [
|
|
3746
|
+
/* @__PURE__ */ jsx12(Text12, { color: "red", children: "\u25CF " }),
|
|
3747
|
+
/* @__PURE__ */ jsx12(Text12, { color: "red", children: error })
|
|
3748
|
+
] })
|
|
2814
3749
|
] })
|
|
2815
3750
|
] });
|
|
2816
3751
|
}
|
|
@@ -3050,6 +3985,14 @@ function clearPasteStore() {
|
|
|
3050
3985
|
pasteStore.clear();
|
|
3051
3986
|
pasteCounter = 0;
|
|
3052
3987
|
}
|
|
3988
|
+
var inputHistory = [];
|
|
3989
|
+
var historyIndex = -1;
|
|
3990
|
+
var historyDraft = "";
|
|
3991
|
+
function pushHistory(line) {
|
|
3992
|
+
if (!line) return;
|
|
3993
|
+
if (inputHistory[inputHistory.length - 1] === line) return;
|
|
3994
|
+
inputHistory.push(line);
|
|
3995
|
+
}
|
|
3053
3996
|
function expandPastes(text) {
|
|
3054
3997
|
let out = text;
|
|
3055
3998
|
for (const [chip, full] of pasteStore) out = out.split(chip).join(full);
|
|
@@ -3087,6 +4030,8 @@ function useKeyboard(opts) {
|
|
|
3087
4030
|
agent,
|
|
3088
4031
|
input,
|
|
3089
4032
|
setInput,
|
|
4033
|
+
caret,
|
|
4034
|
+
setCaret,
|
|
3090
4035
|
paletteCursor,
|
|
3091
4036
|
setPaletteCursor,
|
|
3092
4037
|
filePickerCursor,
|
|
@@ -3294,36 +4239,43 @@ function useKeyboard(opts) {
|
|
|
3294
4239
|
const mention = !paletteOpen ? parseMention(input) : null;
|
|
3295
4240
|
const fileMatches = mention ? searchFiles(process.cwd(), mention.query) : [];
|
|
3296
4241
|
const fileOpen = mention !== null && fileMatches.length > 0;
|
|
3297
|
-
if (paletteOpen && key.upArrow) {
|
|
4242
|
+
if (paletteOpen && historyIndex === -1 && key.upArrow) {
|
|
3298
4243
|
setPaletteCursor((i) => Math.max(0, i - 1));
|
|
3299
4244
|
return;
|
|
3300
4245
|
}
|
|
3301
|
-
if (paletteOpen && key.downArrow) {
|
|
4246
|
+
if (paletteOpen && historyIndex === -1 && key.downArrow) {
|
|
3302
4247
|
setPaletteCursor((i) => Math.min(matches2.length - 1, i + 1));
|
|
3303
4248
|
return;
|
|
3304
4249
|
}
|
|
3305
4250
|
if (paletteOpen && (key.tab || key.return) && matches2[paletteCursor] && input !== matches2[paletteCursor].name) {
|
|
3306
|
-
|
|
4251
|
+
const name = matches2[paletteCursor].name;
|
|
4252
|
+
setInput(() => name);
|
|
4253
|
+
setCaret(() => name.length);
|
|
3307
4254
|
setPaletteCursor(() => 0);
|
|
3308
4255
|
return;
|
|
3309
4256
|
}
|
|
3310
4257
|
if (paletteOpen && key.escape) {
|
|
3311
4258
|
clearPasteStore();
|
|
3312
4259
|
setInput(() => "");
|
|
4260
|
+
setCaret(() => 0);
|
|
3313
4261
|
setPaletteCursor(() => 0);
|
|
3314
4262
|
return;
|
|
3315
4263
|
}
|
|
3316
|
-
if (fileOpen && key.upArrow) {
|
|
4264
|
+
if (fileOpen && historyIndex === -1 && key.upArrow) {
|
|
3317
4265
|
setFilePickerCursor((i) => Math.max(0, i - 1));
|
|
3318
4266
|
return;
|
|
3319
4267
|
}
|
|
3320
|
-
if (fileOpen && key.downArrow) {
|
|
4268
|
+
if (fileOpen && historyIndex === -1 && key.downArrow) {
|
|
3321
4269
|
setFilePickerCursor((i) => Math.min(fileMatches.length - 1, i + 1));
|
|
3322
4270
|
return;
|
|
3323
4271
|
}
|
|
3324
4272
|
if (fileOpen && key.tab && fileMatches[filePickerCursor]) {
|
|
3325
4273
|
const picked = fileMatches[filePickerCursor];
|
|
3326
|
-
setInput((s) =>
|
|
4274
|
+
setInput((s) => {
|
|
4275
|
+
const next = s.slice(0, mention.start) + "@" + picked + " ";
|
|
4276
|
+
setCaret(() => next.length);
|
|
4277
|
+
return next;
|
|
4278
|
+
});
|
|
3327
4279
|
setFilePickerCursor(() => 0);
|
|
3328
4280
|
return;
|
|
3329
4281
|
}
|
|
@@ -3331,8 +4283,36 @@ function useKeyboard(opts) {
|
|
|
3331
4283
|
setFilePickerCursor(() => 0);
|
|
3332
4284
|
return;
|
|
3333
4285
|
}
|
|
4286
|
+
if ((historyIndex !== -1 || !paletteOpen && !fileOpen) && key.upArrow) {
|
|
4287
|
+
if (inputHistory.length === 0) return;
|
|
4288
|
+
if (historyIndex === -1) {
|
|
4289
|
+
historyDraft = input;
|
|
4290
|
+
historyIndex = inputHistory.length - 1;
|
|
4291
|
+
} else if (historyIndex > 0) historyIndex--;
|
|
4292
|
+
const val = inputHistory[historyIndex];
|
|
4293
|
+
setInput(() => val);
|
|
4294
|
+
setCaret(() => val.length);
|
|
4295
|
+
return;
|
|
4296
|
+
}
|
|
4297
|
+
if ((historyIndex !== -1 || !paletteOpen && !fileOpen) && key.downArrow) {
|
|
4298
|
+
if (historyIndex === -1) return;
|
|
4299
|
+
if (historyIndex < inputHistory.length - 1) {
|
|
4300
|
+
historyIndex++;
|
|
4301
|
+
const val = inputHistory[historyIndex];
|
|
4302
|
+
setInput(() => val);
|
|
4303
|
+
setCaret(() => val.length);
|
|
4304
|
+
} else {
|
|
4305
|
+
historyIndex = -1;
|
|
4306
|
+
setInput(() => historyDraft);
|
|
4307
|
+
setCaret(() => historyDraft.length);
|
|
4308
|
+
}
|
|
4309
|
+
return;
|
|
4310
|
+
}
|
|
3334
4311
|
if (key.return) {
|
|
3335
4312
|
const trimmed = input.trim();
|
|
4313
|
+
pushHistory(trimmed);
|
|
4314
|
+
historyIndex = -1;
|
|
4315
|
+
historyDraft = "";
|
|
3336
4316
|
if (trimmed === "/models") {
|
|
3337
4317
|
setPickerQuery("");
|
|
3338
4318
|
setCursor(() => Math.max(0, models.findIndex((m) => m === cfg.model)));
|
|
@@ -3369,30 +4349,49 @@ function useKeyboard(opts) {
|
|
|
3369
4349
|
}
|
|
3370
4350
|
clearPasteStore();
|
|
3371
4351
|
setInput(() => "");
|
|
4352
|
+
setCaret(() => 0);
|
|
3372
4353
|
setPaletteCursor(() => 0);
|
|
3373
4354
|
return;
|
|
3374
4355
|
}
|
|
4356
|
+
if (key.leftArrow) {
|
|
4357
|
+
setCaret((i) => Math.max(0, i - 1));
|
|
4358
|
+
return;
|
|
4359
|
+
}
|
|
4360
|
+
if (key.rightArrow) {
|
|
4361
|
+
setCaret((i) => Math.min(input.length, i + 1));
|
|
4362
|
+
return;
|
|
4363
|
+
}
|
|
4364
|
+
if (key.ctrl && char === "a") {
|
|
4365
|
+
setCaret(() => 0);
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4368
|
+
if (key.ctrl && char === "e") {
|
|
4369
|
+
setCaret(() => input.length);
|
|
4370
|
+
return;
|
|
4371
|
+
}
|
|
3375
4372
|
if (key.backspace || key.delete) {
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
if (match)
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
4373
|
+
historyIndex = -1;
|
|
4374
|
+
setPaletteCursor(() => 0);
|
|
4375
|
+
setFilePickerCursor(() => 0);
|
|
4376
|
+
if (caret <= 0) return;
|
|
4377
|
+
const before = input.slice(0, caret);
|
|
4378
|
+
let match = "";
|
|
4379
|
+
for (const chip of pasteStore.keys()) {
|
|
4380
|
+
if (before.endsWith(chip) && chip.length > match.length) match = chip;
|
|
4381
|
+
}
|
|
4382
|
+
const cut = match ? match.length : 1;
|
|
4383
|
+
if (match) pasteStore.delete(match);
|
|
4384
|
+
setInput((s) => s.slice(0, caret - cut) + s.slice(caret));
|
|
4385
|
+
setCaret((i) => Math.max(0, i - cut));
|
|
3389
4386
|
} else if (char && !key.ctrl && !key.meta && !key.tab) {
|
|
3390
4387
|
const text = sanitizePaste(char);
|
|
3391
|
-
if (text)
|
|
4388
|
+
if (text) {
|
|
4389
|
+
historyIndex = -1;
|
|
3392
4390
|
setPaletteCursor(() => 0);
|
|
3393
4391
|
setFilePickerCursor(() => 0);
|
|
3394
|
-
|
|
3395
|
-
|
|
4392
|
+
setInput((s) => s.slice(0, caret) + text + s.slice(caret));
|
|
4393
|
+
setCaret((i) => i + text.length);
|
|
4394
|
+
}
|
|
3396
4395
|
}
|
|
3397
4396
|
}
|
|
3398
4397
|
});
|
|
@@ -3434,14 +4433,16 @@ async function checkForUpdate() {
|
|
|
3434
4433
|
}
|
|
3435
4434
|
|
|
3436
4435
|
// src/ui/App.tsx
|
|
3437
|
-
import { Fragment as
|
|
4436
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3438
4437
|
function App() {
|
|
3439
4438
|
const { exit } = useApp();
|
|
3440
4439
|
const cwd = process.cwd().replace(homedir6(), "~").split(sep2).join("/");
|
|
3441
4440
|
const [cfg, setCfg] = useState5(loadConfig());
|
|
3442
4441
|
const [models, setModels] = useState5([]);
|
|
3443
|
-
const [contexts, setContexts] = useState5({});
|
|
3444
|
-
const [activeCtx, setActiveCtx] = useState5(
|
|
4442
|
+
const [contexts, setContexts] = useState5(() => cfg.modelContexts ?? {});
|
|
4443
|
+
const [activeCtx, setActiveCtx] = useState5(
|
|
4444
|
+
() => cfg.model ? cfg.modelContexts?.[cfg.model] ?? null : null
|
|
4445
|
+
);
|
|
3445
4446
|
const [state, setState] = useState5("loading");
|
|
3446
4447
|
const [cursor, setCursor] = useState5(0);
|
|
3447
4448
|
const [pickerQuery, setPickerQuery] = useState5("");
|
|
@@ -3451,6 +4452,7 @@ function App() {
|
|
|
3451
4452
|
const [sessions, setSessions] = useState5([]);
|
|
3452
4453
|
const [notice, setNotice] = useState5(null);
|
|
3453
4454
|
const [input, setInput] = useState5("");
|
|
4455
|
+
const [caret, setCaret] = useState5(0);
|
|
3454
4456
|
const [paletteCursor, setPaletteCursor] = useState5(0);
|
|
3455
4457
|
const [filePickerCursor, setFilePickerCursor] = useState5(0);
|
|
3456
4458
|
const agent = useAgentRunner(cfg.model, activeCtx);
|
|
@@ -3492,12 +4494,20 @@ function App() {
|
|
|
3492
4494
|
} else {
|
|
3493
4495
|
setState(hasModel ? "ready" : "select-model");
|
|
3494
4496
|
}
|
|
3495
|
-
Promise.all(
|
|
4497
|
+
Promise.all(
|
|
4498
|
+
m.map(
|
|
4499
|
+
(name) => modelContext3(name).then((ctx) => [name, ctx]).catch(() => [name, null])
|
|
4500
|
+
)
|
|
4501
|
+
).then((pairs) => {
|
|
3496
4502
|
if (stale()) return;
|
|
3497
4503
|
const map = Object.fromEntries(pairs);
|
|
3498
4504
|
setContexts(map);
|
|
4505
|
+
const resolved = Object.fromEntries(
|
|
4506
|
+
pairs.filter((p) => p[1] != null)
|
|
4507
|
+
);
|
|
4508
|
+
if (Object.keys(resolved).length) setModelContexts(resolved);
|
|
3499
4509
|
const active2 = (hasModel ? cfg.model : void 0) ?? m[0];
|
|
3500
|
-
if (active2 && map[active2]) setActiveCtx(map[active2]);
|
|
4510
|
+
if (active2 && map[active2] != null) setActiveCtx(map[active2]);
|
|
3501
4511
|
}).catch(() => {
|
|
3502
4512
|
});
|
|
3503
4513
|
}).catch((err) => {
|
|
@@ -3542,6 +4552,8 @@ function App() {
|
|
|
3542
4552
|
agent,
|
|
3543
4553
|
input,
|
|
3544
4554
|
setInput,
|
|
4555
|
+
caret,
|
|
4556
|
+
setCaret,
|
|
3545
4557
|
paletteCursor,
|
|
3546
4558
|
setPaletteCursor,
|
|
3547
4559
|
filePickerCursor,
|
|
@@ -3562,10 +4574,10 @@ function App() {
|
|
|
3562
4574
|
if (used < activeCtx * 0.7) return null;
|
|
3563
4575
|
return Math.round(used / activeCtx * 100);
|
|
3564
4576
|
})();
|
|
3565
|
-
return /* @__PURE__ */
|
|
3566
|
-
/* @__PURE__ */
|
|
3567
|
-
state === "loading" && !agent.error && /* @__PURE__ */
|
|
3568
|
-
agent.error && state !== "ready" && /* @__PURE__ */
|
|
4577
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingX: 1, children: [
|
|
4578
|
+
state !== "ready" && /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd, error: agent.error, updateAvailable }),
|
|
4579
|
+
state === "loading" && !agent.error && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: `connecting to ${provName}\u2026` }) }),
|
|
4580
|
+
agent.error && state !== "ready" && /* @__PURE__ */ jsx13(
|
|
3569
4581
|
ChatView,
|
|
3570
4582
|
{
|
|
3571
4583
|
messages: [],
|
|
@@ -3575,7 +4587,7 @@ function App() {
|
|
|
3575
4587
|
error: agent.error
|
|
3576
4588
|
}
|
|
3577
4589
|
),
|
|
3578
|
-
(state === "select-model" || state === "models") && /* @__PURE__ */
|
|
4590
|
+
(state === "select-model" || state === "models") && /* @__PURE__ */ jsx13(
|
|
3579
4591
|
ModelsView,
|
|
3580
4592
|
{
|
|
3581
4593
|
models: filteredModels,
|
|
@@ -3588,7 +4600,7 @@ function App() {
|
|
|
3588
4600
|
requireSelection: state === "select-model"
|
|
3589
4601
|
}
|
|
3590
4602
|
),
|
|
3591
|
-
state === "providers" && /* @__PURE__ */
|
|
4603
|
+
state === "providers" && /* @__PURE__ */ jsx13(
|
|
3592
4604
|
ProviderPicker,
|
|
3593
4605
|
{
|
|
3594
4606
|
entries: filteredProviders,
|
|
@@ -3597,10 +4609,10 @@ function App() {
|
|
|
3597
4609
|
query: pickerQuery
|
|
3598
4610
|
}
|
|
3599
4611
|
),
|
|
3600
|
-
state === "sessions" && /* @__PURE__ */
|
|
3601
|
-
state === "ready" && /* @__PURE__ */
|
|
3602
|
-
notice && /* @__PURE__ */
|
|
3603
|
-
/* @__PURE__ */
|
|
4612
|
+
state === "sessions" && /* @__PURE__ */ jsx13(SessionsView, { sessions, cursor }),
|
|
4613
|
+
state === "ready" && /* @__PURE__ */ jsxs13(Fragment3, { children: [
|
|
4614
|
+
notice && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "green", children: `\u2713 ${notice}` }) }),
|
|
4615
|
+
/* @__PURE__ */ jsx13(
|
|
3604
4616
|
ChatView,
|
|
3605
4617
|
{
|
|
3606
4618
|
messages: agent.messages,
|
|
@@ -3612,18 +4624,20 @@ function App() {
|
|
|
3612
4624
|
pendingPermission: agent.pendingPermission,
|
|
3613
4625
|
permissionCursor: agent.permissionCursor,
|
|
3614
4626
|
activeToolUses: agent.activeToolUses,
|
|
3615
|
-
activeToolResults: agent.activeToolResults
|
|
4627
|
+
activeToolResults: agent.activeToolResults,
|
|
4628
|
+
header: /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd })
|
|
3616
4629
|
}
|
|
3617
4630
|
),
|
|
3618
|
-
|
|
3619
|
-
|
|
4631
|
+
updateAvailable && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u2191 update available: v${updateAvailable} \u2014 run: miii --update` }) }),
|
|
4632
|
+
input.startsWith("/") && /* @__PURE__ */ jsx13(CommandPalette, { filter: input, cursor: paletteCursor }),
|
|
4633
|
+
contextWarning !== null && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u26A0 context ${contextWarning}% full \u2014 run /clear and start fresh` }) }),
|
|
3620
4634
|
!input.startsWith("/") && (() => {
|
|
3621
4635
|
const m = parseMention(input);
|
|
3622
4636
|
if (!m) return null;
|
|
3623
|
-
return /* @__PURE__ */
|
|
4637
|
+
return /* @__PURE__ */ jsx13(FilePicker, { matches: searchFiles(process.cwd(), m.query), cursor: filePickerCursor });
|
|
3624
4638
|
})(),
|
|
3625
|
-
/* @__PURE__ */
|
|
3626
|
-
!agent.busy && /* @__PURE__ */
|
|
4639
|
+
/* @__PURE__ */ jsx13(InputBar, { input, caret, disabled: agent.busy, processingLabel: agent.processingLabel }),
|
|
4640
|
+
!agent.busy && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: providerDown ? "provider unavailable \u2014 /provider to switch \xB7 /models to pick a model" : "type / to see commands" }) })
|
|
3627
4641
|
] })
|
|
3628
4642
|
] });
|
|
3629
4643
|
}
|