kimiflare 0.2.2 → 0.3.0
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 +5 -0
- package/dist/index.js +579 -195
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -80,10 +80,10 @@ async function* readSSE(stream, signal) {
|
|
|
80
80
|
if (done) break;
|
|
81
81
|
buffer += decoder.decode(value, { stream: true });
|
|
82
82
|
buffer = buffer.replace(/\r\n/g, "\n");
|
|
83
|
-
let
|
|
84
|
-
while ((
|
|
85
|
-
const event = buffer.slice(0,
|
|
86
|
-
buffer = buffer.slice(
|
|
83
|
+
let sep2;
|
|
84
|
+
while ((sep2 = buffer.indexOf("\n\n")) !== -1) {
|
|
85
|
+
const event = buffer.slice(0, sep2);
|
|
86
|
+
buffer = buffer.slice(sep2 + 2);
|
|
87
87
|
const data = extractData(event);
|
|
88
88
|
if (data !== null) yield data;
|
|
89
89
|
}
|
|
@@ -407,7 +407,21 @@ var init_mode = __esm({
|
|
|
407
407
|
|
|
408
408
|
// src/agent/system-prompt.ts
|
|
409
409
|
import { platform, release, homedir as homedir2 } from "os";
|
|
410
|
-
import { basename } from "path";
|
|
410
|
+
import { basename, join as join2 } from "path";
|
|
411
|
+
import { readFileSync, statSync } from "fs";
|
|
412
|
+
function loadContextFile(cwd) {
|
|
413
|
+
for (const name of CONTEXT_FILENAMES) {
|
|
414
|
+
const path = join2(cwd, name);
|
|
415
|
+
try {
|
|
416
|
+
const s = statSync(path);
|
|
417
|
+
if (!s.isFile() || s.size > MAX_CONTEXT_BYTES) continue;
|
|
418
|
+
const content = readFileSync(path, "utf8");
|
|
419
|
+
return { name, path, content, lineCount: content.split("\n").length };
|
|
420
|
+
} catch {
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
411
425
|
function buildSystemPrompt(opts2) {
|
|
412
426
|
const now = opts2.now ?? /* @__PURE__ */ new Date();
|
|
413
427
|
const date = now.toISOString().slice(0, 10);
|
|
@@ -416,7 +430,7 @@ function buildSystemPrompt(opts2) {
|
|
|
416
430
|
const perm = t.needsPermission ? " [needs user permission]" : "";
|
|
417
431
|
return `- \`${t.name}\`${perm}: ${t.description.split("\n")[0]}`;
|
|
418
432
|
}).join("\n");
|
|
419
|
-
|
|
433
|
+
const base = `You are kimiflare, an interactive coding assistant running in the user's terminal. You act on the user's local filesystem through the tools listed below. You are powered by the ${opts2.model} model on Cloudflare Workers AI.
|
|
420
434
|
|
|
421
435
|
Environment:
|
|
422
436
|
- Working directory: ${opts2.cwd}
|
|
@@ -437,17 +451,27 @@ How to work:
|
|
|
437
451
|
- If a tool returns an error, read it carefully and adjust; do not retry the same call blindly.
|
|
438
452
|
- You have a 262k-token context window. Read as much of a file as needed rather than guessing.
|
|
439
453
|
- If a request is ambiguous, ask one focused question instead of making large assumptions.
|
|
440
|
-
- When you finish a task, stop. Do not add a closing summary
|
|
454
|
+
- When you finish a task, stop. Do not add a closing summary.`;
|
|
455
|
+
const ctx = loadContextFile(opts2.cwd);
|
|
456
|
+
const contextBlock = ctx ? `
|
|
457
|
+
|
|
458
|
+
Project context from ${ctx.name} (${ctx.lineCount} lines, treat as authoritative):
|
|
459
|
+
${ctx.content.trim()}` : "";
|
|
460
|
+
const modeBlock = opts2.mode ? systemPromptForMode(opts2.mode) : "";
|
|
461
|
+
return base + contextBlock + modeBlock;
|
|
441
462
|
}
|
|
463
|
+
var CONTEXT_FILENAMES, MAX_CONTEXT_BYTES;
|
|
442
464
|
var init_system_prompt = __esm({
|
|
443
465
|
"src/agent/system-prompt.ts"() {
|
|
444
466
|
"use strict";
|
|
445
467
|
init_mode();
|
|
468
|
+
CONTEXT_FILENAMES = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"];
|
|
469
|
+
MAX_CONTEXT_BYTES = 20 * 1024;
|
|
446
470
|
}
|
|
447
471
|
});
|
|
448
472
|
|
|
449
473
|
// src/util/paths.ts
|
|
450
|
-
import { resolve, isAbsolute } from "path";
|
|
474
|
+
import { resolve, isAbsolute, relative, sep } from "path";
|
|
451
475
|
import { homedir as homedir3 } from "os";
|
|
452
476
|
function resolvePath(cwd, input) {
|
|
453
477
|
if (input.startsWith("~/") || input === "~") {
|
|
@@ -460,6 +484,26 @@ function truncate(s, n) {
|
|
|
460
484
|
return s.slice(0, n) + `
|
|
461
485
|
... [truncated, ${s.length - n} chars omitted]`;
|
|
462
486
|
}
|
|
487
|
+
function collapsePath(input, cwd, maxLen = 40) {
|
|
488
|
+
if (!input) return input;
|
|
489
|
+
let abs;
|
|
490
|
+
try {
|
|
491
|
+
abs = resolvePath(cwd, input);
|
|
492
|
+
} catch {
|
|
493
|
+
return input;
|
|
494
|
+
}
|
|
495
|
+
const rel = relative(cwd, abs);
|
|
496
|
+
if (rel && !rel.startsWith("..") && !isAbsolute(rel)) {
|
|
497
|
+
return rel === "" ? "." : rel;
|
|
498
|
+
}
|
|
499
|
+
if (input.length <= maxLen) return input;
|
|
500
|
+
const parts = input.split(sep).filter(Boolean);
|
|
501
|
+
if (parts.length <= 2) return input;
|
|
502
|
+
return `\u2026/${parts.slice(-2).join(sep)}`;
|
|
503
|
+
}
|
|
504
|
+
function collapsePathsInText(s, cwd, maxLen = 40) {
|
|
505
|
+
return s.replace(/([~/][^\s"',)}\]]+)/g, (match) => collapsePath(match, cwd, maxLen));
|
|
506
|
+
}
|
|
463
507
|
var init_paths = __esm({
|
|
464
508
|
"src/util/paths.ts"() {
|
|
465
509
|
"use strict";
|
|
@@ -488,7 +532,7 @@ var init_read = __esm({
|
|
|
488
532
|
additionalProperties: false
|
|
489
533
|
},
|
|
490
534
|
needsPermission: false,
|
|
491
|
-
render: ({ path }) => ({ title: `read ${path}` }),
|
|
535
|
+
render: ({ path }) => ({ title: `read ${collapsePath(path, process.cwd())}` }),
|
|
492
536
|
async run(args, ctx) {
|
|
493
537
|
const abs = resolvePath(ctx.cwd, args.path);
|
|
494
538
|
const st = await stat(abs);
|
|
@@ -526,7 +570,7 @@ var init_write = __esm({
|
|
|
526
570
|
},
|
|
527
571
|
needsPermission: true,
|
|
528
572
|
render: (args) => ({
|
|
529
|
-
title: `write ${args.path} (${args.content.length} chars)`,
|
|
573
|
+
title: `write ${collapsePath(args.path, process.cwd())} (${args.content.length} chars)`,
|
|
530
574
|
diff: { path: args.path, before: "", after: args.content }
|
|
531
575
|
}),
|
|
532
576
|
async run(args, ctx) {
|
|
@@ -579,7 +623,7 @@ var init_edit = __esm({
|
|
|
579
623
|
},
|
|
580
624
|
needsPermission: true,
|
|
581
625
|
render: (args) => ({
|
|
582
|
-
title: `edit ${args.path}${args.replace_all ? " (replace_all)" : ""}`,
|
|
626
|
+
title: `edit ${collapsePath(args.path, process.cwd())}${args.replace_all ? " (replace_all)" : ""}`,
|
|
583
627
|
diff: { path: args.path, before: args.old_string, after: args.new_string }
|
|
584
628
|
}),
|
|
585
629
|
async run(args, ctx) {
|
|
@@ -602,6 +646,49 @@ var init_edit = __esm({
|
|
|
602
646
|
|
|
603
647
|
// src/tools/bash.ts
|
|
604
648
|
import { spawn } from "child_process";
|
|
649
|
+
function formatBashTitle(raw) {
|
|
650
|
+
let cmd = (raw ?? "").trim();
|
|
651
|
+
const m = cmd.match(/^cd\s+([^\s&;]+)\s*(?:&&|;)\s*(.*)$/);
|
|
652
|
+
if (m) cmd = m[2].trim();
|
|
653
|
+
return `$ ${cmd}`.slice(0, 120);
|
|
654
|
+
}
|
|
655
|
+
function runBash(args, ctx) {
|
|
656
|
+
const timeout = Math.min(Math.max(1e3, args.timeout_ms ?? DEFAULT_TIMEOUT), MAX_TIMEOUT);
|
|
657
|
+
return new Promise((resolve2, reject) => {
|
|
658
|
+
const child = spawn("bash", ["-lc", args.command], {
|
|
659
|
+
cwd: ctx.cwd,
|
|
660
|
+
signal: ctx.signal
|
|
661
|
+
});
|
|
662
|
+
let stdout = "";
|
|
663
|
+
let stderr = "";
|
|
664
|
+
let killedByTimeout = false;
|
|
665
|
+
const timer = setTimeout(() => {
|
|
666
|
+
killedByTimeout = true;
|
|
667
|
+
child.kill("SIGKILL");
|
|
668
|
+
}, timeout);
|
|
669
|
+
child.stdout.on("data", (d) => {
|
|
670
|
+
stdout += d.toString("utf8");
|
|
671
|
+
});
|
|
672
|
+
child.stderr.on("data", (d) => {
|
|
673
|
+
stderr += d.toString("utf8");
|
|
674
|
+
});
|
|
675
|
+
child.on("error", (e) => {
|
|
676
|
+
clearTimeout(timer);
|
|
677
|
+
reject(e);
|
|
678
|
+
});
|
|
679
|
+
child.on("close", (code, signal) => {
|
|
680
|
+
clearTimeout(timer);
|
|
681
|
+
const header = killedByTimeout ? `(timed out after ${timeout}ms)` : `exit=${code ?? "?"}${signal ? ` signal=${signal}` : ""}`;
|
|
682
|
+
const parts = [header];
|
|
683
|
+
if (stdout) parts.push(`--- stdout ---
|
|
684
|
+
${stdout.trimEnd()}`);
|
|
685
|
+
if (stderr) parts.push(`--- stderr ---
|
|
686
|
+
${stderr.trimEnd()}`);
|
|
687
|
+
if (!stdout && !stderr) parts.push("(no output)");
|
|
688
|
+
resolve2(truncate(parts.join("\n"), OUTPUT_CAP));
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
}
|
|
605
692
|
var DEFAULT_TIMEOUT, MAX_TIMEOUT, OUTPUT_CAP, bashTool;
|
|
606
693
|
var init_bash = __esm({
|
|
607
694
|
"src/tools/bash.ts"() {
|
|
@@ -628,44 +715,8 @@ var init_bash = __esm({
|
|
|
628
715
|
additionalProperties: false
|
|
629
716
|
},
|
|
630
717
|
needsPermission: true,
|
|
631
|
-
render: (args) => ({ title:
|
|
632
|
-
run(args, ctx)
|
|
633
|
-
const timeout = Math.min(Math.max(1e3, args.timeout_ms ?? DEFAULT_TIMEOUT), MAX_TIMEOUT);
|
|
634
|
-
return new Promise((resolve2, reject) => {
|
|
635
|
-
const child = spawn("bash", ["-lc", args.command], {
|
|
636
|
-
cwd: ctx.cwd,
|
|
637
|
-
signal: ctx.signal
|
|
638
|
-
});
|
|
639
|
-
let stdout = "";
|
|
640
|
-
let stderr = "";
|
|
641
|
-
let killedByTimeout = false;
|
|
642
|
-
const timer = setTimeout(() => {
|
|
643
|
-
killedByTimeout = true;
|
|
644
|
-
child.kill("SIGKILL");
|
|
645
|
-
}, timeout);
|
|
646
|
-
child.stdout.on("data", (d) => {
|
|
647
|
-
stdout += d.toString("utf8");
|
|
648
|
-
});
|
|
649
|
-
child.stderr.on("data", (d) => {
|
|
650
|
-
stderr += d.toString("utf8");
|
|
651
|
-
});
|
|
652
|
-
child.on("error", (e) => {
|
|
653
|
-
clearTimeout(timer);
|
|
654
|
-
reject(e);
|
|
655
|
-
});
|
|
656
|
-
child.on("close", (code, signal) => {
|
|
657
|
-
clearTimeout(timer);
|
|
658
|
-
const header = killedByTimeout ? `(timed out after ${timeout}ms)` : `exit=${code ?? "?"}${signal ? ` signal=${signal}` : ""}`;
|
|
659
|
-
const parts = [header];
|
|
660
|
-
if (stdout) parts.push(`--- stdout ---
|
|
661
|
-
${stdout.trimEnd()}`);
|
|
662
|
-
if (stderr) parts.push(`--- stderr ---
|
|
663
|
-
${stderr.trimEnd()}`);
|
|
664
|
-
if (!stdout && !stderr) parts.push("(no output)");
|
|
665
|
-
resolve2(truncate(parts.join("\n"), OUTPUT_CAP));
|
|
666
|
-
});
|
|
667
|
-
});
|
|
668
|
-
}
|
|
718
|
+
render: (args) => ({ title: formatBashTitle(args.command) }),
|
|
719
|
+
run: (args, ctx) => runBash(args, ctx)
|
|
669
720
|
};
|
|
670
721
|
}
|
|
671
722
|
});
|
|
@@ -690,7 +741,7 @@ var init_glob = __esm({
|
|
|
690
741
|
additionalProperties: false
|
|
691
742
|
},
|
|
692
743
|
needsPermission: false,
|
|
693
|
-
render: (args) => ({ title: `glob ${args.pattern}${args.path ? ` in ${args.path}` : ""}` }),
|
|
744
|
+
render: (args) => ({ title: `glob ${args.pattern}${args.path ? ` in ${collapsePath(args.path, process.cwd())}` : ""}` }),
|
|
694
745
|
async run(args, ctx) {
|
|
695
746
|
const root = args.path ? resolvePath(ctx.cwd, args.path) : ctx.cwd;
|
|
696
747
|
const entries = await fg(args.pattern, {
|
|
@@ -1124,27 +1175,40 @@ import { createTwoFilesPatch } from "diff";
|
|
|
1124
1175
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1125
1176
|
function DiffView({ path, before, after, maxLines = 40 }) {
|
|
1126
1177
|
const patch = createTwoFilesPatch(path, path, before, after, "", "", { context: 2 });
|
|
1127
|
-
const
|
|
1128
|
-
const
|
|
1178
|
+
const raw = patch.split("\n").slice(4);
|
|
1179
|
+
const lines = raw.filter((l) => {
|
|
1180
|
+
if (l.startsWith("--- ") || l.startsWith("+++ ")) return false;
|
|
1181
|
+
if (l.startsWith("\")) return false;
|
|
1182
|
+
return true;
|
|
1183
|
+
});
|
|
1184
|
+
const diffStats = countChanges(lines);
|
|
1185
|
+
const hideHeader = diffStats.changed <= 3 && diffStats.context <= 3 && diffStats.hunks <= 1;
|
|
1186
|
+
const filtered = hideHeader ? lines.filter((l) => !l.startsWith("@@")) : lines;
|
|
1187
|
+
const truncated = filtered.length > maxLines ? filtered.slice(0, maxLines) : filtered;
|
|
1129
1188
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1130
1189
|
truncated.map((line, i) => /* @__PURE__ */ jsx(DiffLine, { line }, i)),
|
|
1131
|
-
|
|
1190
|
+
filtered.length > maxLines && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
1132
1191
|
"... (",
|
|
1133
|
-
|
|
1192
|
+
filtered.length - maxLines,
|
|
1134
1193
|
" more lines)"
|
|
1135
1194
|
] })
|
|
1136
1195
|
] });
|
|
1137
1196
|
}
|
|
1138
|
-
function
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
return /* @__PURE__ */ jsx(Text, { color: "cyan", children: line });
|
|
1197
|
+
function countChanges(lines) {
|
|
1198
|
+
let changed = 0;
|
|
1199
|
+
let context = 0;
|
|
1200
|
+
let hunks = 0;
|
|
1201
|
+
for (const l of lines) {
|
|
1202
|
+
if (l.startsWith("@@")) hunks++;
|
|
1203
|
+
else if (l.startsWith("+") || l.startsWith("-")) changed++;
|
|
1204
|
+
else if (l.trim().length > 0) context++;
|
|
1147
1205
|
}
|
|
1206
|
+
return { changed, context, hunks };
|
|
1207
|
+
}
|
|
1208
|
+
function DiffLine({ line }) {
|
|
1209
|
+
if (line.startsWith("+")) return /* @__PURE__ */ jsx(Text, { color: "green", children: line });
|
|
1210
|
+
if (line.startsWith("-")) return /* @__PURE__ */ jsx(Text, { color: "red", children: line });
|
|
1211
|
+
if (line.startsWith("@@")) return /* @__PURE__ */ jsx(Text, { color: "cyan", children: line });
|
|
1148
1212
|
return /* @__PURE__ */ jsx(Text, { color: "gray", children: line });
|
|
1149
1213
|
}
|
|
1150
1214
|
var init_diff_view = __esm({
|
|
@@ -1185,7 +1249,8 @@ function ToolView({ evt, verbose }) {
|
|
|
1185
1249
|
] });
|
|
1186
1250
|
}
|
|
1187
1251
|
function compactArgs(raw) {
|
|
1188
|
-
const
|
|
1252
|
+
const collapsed = collapsePathsInText(raw, process.cwd());
|
|
1253
|
+
const s = collapsed.replace(/\s+/g, " ");
|
|
1189
1254
|
return s.length <= 80 ? s : s.slice(0, 80) + "\u2026";
|
|
1190
1255
|
}
|
|
1191
1256
|
function firstLine(s) {
|
|
@@ -1196,38 +1261,198 @@ var init_tool_view = __esm({
|
|
|
1196
1261
|
"src/ui/tool-view.tsx"() {
|
|
1197
1262
|
"use strict";
|
|
1198
1263
|
init_diff_view();
|
|
1264
|
+
init_paths();
|
|
1199
1265
|
}
|
|
1200
1266
|
});
|
|
1201
1267
|
|
|
1202
|
-
// src/ui/
|
|
1268
|
+
// src/ui/markdown.tsx
|
|
1203
1269
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
1204
1270
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1271
|
+
function MD({ text, theme }) {
|
|
1272
|
+
const blocks = parseBlocks(text);
|
|
1273
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: blocks.map((b, i) => /* @__PURE__ */ jsx3(Block, { block: b, theme }, i)) });
|
|
1274
|
+
}
|
|
1275
|
+
function parseBlocks(src) {
|
|
1276
|
+
const out = [];
|
|
1277
|
+
const lines = src.split("\n");
|
|
1278
|
+
let i = 0;
|
|
1279
|
+
while (i < lines.length) {
|
|
1280
|
+
const line = lines[i];
|
|
1281
|
+
if (line.trim() === "") {
|
|
1282
|
+
out.push({ kind: "blank" });
|
|
1283
|
+
i++;
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
const fence = line.match(/^```(\w*)\s*$/);
|
|
1287
|
+
if (fence) {
|
|
1288
|
+
const lang = fence[1] || void 0;
|
|
1289
|
+
const start = i + 1;
|
|
1290
|
+
let end = start;
|
|
1291
|
+
while (end < lines.length && !/^```\s*$/.test(lines[end])) end++;
|
|
1292
|
+
out.push({ kind: "code", lang, text: lines.slice(start, end).join("\n") });
|
|
1293
|
+
i = end + 1;
|
|
1294
|
+
continue;
|
|
1295
|
+
}
|
|
1296
|
+
const heading = line.match(/^(#{1,3})\s+(.*)$/);
|
|
1297
|
+
if (heading) {
|
|
1298
|
+
out.push({ kind: "heading", level: heading[1].length, text: heading[2] });
|
|
1299
|
+
i++;
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1302
|
+
if (/^\s*>\s?/.test(line)) {
|
|
1303
|
+
const quoteLines = [];
|
|
1304
|
+
while (i < lines.length && /^\s*>\s?/.test(lines[i])) {
|
|
1305
|
+
quoteLines.push(lines[i].replace(/^\s*>\s?/, ""));
|
|
1306
|
+
i++;
|
|
1307
|
+
}
|
|
1308
|
+
out.push({ kind: "quote", text: quoteLines.join("\n") });
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
if (/^\s*[-*]\s+/.test(line)) {
|
|
1312
|
+
const items = [];
|
|
1313
|
+
while (i < lines.length && /^\s*[-*]\s+/.test(lines[i])) {
|
|
1314
|
+
items.push(lines[i].replace(/^\s*[-*]\s+/, ""));
|
|
1315
|
+
i++;
|
|
1316
|
+
}
|
|
1317
|
+
out.push({ kind: "bullet", items });
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
const paraLines = [line];
|
|
1321
|
+
i++;
|
|
1322
|
+
while (i < lines.length && lines[i].trim() !== "" && !/^(#{1,3})\s+/.test(lines[i]) && !/^\s*[-*]\s+/.test(lines[i]) && !/^\s*>\s?/.test(lines[i]) && !/^```/.test(lines[i])) {
|
|
1323
|
+
paraLines.push(lines[i]);
|
|
1324
|
+
i++;
|
|
1325
|
+
}
|
|
1326
|
+
out.push({ kind: "paragraph", text: paraLines.join("\n") });
|
|
1327
|
+
}
|
|
1328
|
+
return out;
|
|
1329
|
+
}
|
|
1330
|
+
function Block({ block, theme }) {
|
|
1331
|
+
if (block.kind === "blank") return /* @__PURE__ */ jsx3(Text3, { children: " " });
|
|
1332
|
+
if (block.kind === "heading") {
|
|
1333
|
+
return /* @__PURE__ */ jsx3(Box3, { marginTop: block.level === 1 ? 1 : 0, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accent, children: renderInline(block.text, theme) }) });
|
|
1334
|
+
}
|
|
1335
|
+
if (block.kind === "bullet") {
|
|
1336
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: block.items.map((item, i) => /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
1337
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: " \u2022 " }),
|
|
1338
|
+
/* @__PURE__ */ jsx3(Text3, { children: renderInline(item, theme) })
|
|
1339
|
+
] }, i)) });
|
|
1340
|
+
}
|
|
1341
|
+
if (block.kind === "quote") {
|
|
1342
|
+
return /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsx3(Text3, { color: theme.info.color, dimColor: theme.info.dim, italic: true, children: renderInline(block.text, theme) }) });
|
|
1343
|
+
}
|
|
1344
|
+
if (block.kind === "code") {
|
|
1345
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginLeft: 2, children: block.text.split("\n").map((l, i) => /* @__PURE__ */ jsx3(Text3, { color: theme.tool, children: l }, i)) });
|
|
1346
|
+
}
|
|
1347
|
+
return /* @__PURE__ */ jsx3(Text3, { children: renderInline(block.text, theme) });
|
|
1348
|
+
}
|
|
1349
|
+
function renderInline(src, theme) {
|
|
1350
|
+
const segments = parseInline(src);
|
|
1351
|
+
return segments.map((seg, i) => {
|
|
1352
|
+
if (seg.kind === "bold") return /* @__PURE__ */ jsx3(Text3, { bold: true, children: seg.text }, i);
|
|
1353
|
+
if (seg.kind === "italic") return /* @__PURE__ */ jsx3(Text3, { italic: true, children: seg.text }, i);
|
|
1354
|
+
if (seg.kind === "code") return /* @__PURE__ */ jsx3(Text3, { color: theme.tool, children: seg.text }, i);
|
|
1355
|
+
return /* @__PURE__ */ jsx3(Text3, { children: seg.text }, i);
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
function parseInline(src) {
|
|
1359
|
+
const out = [];
|
|
1360
|
+
let i = 0;
|
|
1361
|
+
let buf = "";
|
|
1362
|
+
const flush = () => {
|
|
1363
|
+
if (buf) {
|
|
1364
|
+
out.push({ kind: "plain", text: buf });
|
|
1365
|
+
buf = "";
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
while (i < src.length) {
|
|
1369
|
+
const ch = src[i];
|
|
1370
|
+
if (ch === "`") {
|
|
1371
|
+
const end = src.indexOf("`", i + 1);
|
|
1372
|
+
if (end > i) {
|
|
1373
|
+
flush();
|
|
1374
|
+
out.push({ kind: "code", text: src.slice(i + 1, end) });
|
|
1375
|
+
i = end + 1;
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
if (ch === "*" && src[i + 1] === "*") {
|
|
1380
|
+
const end = src.indexOf("**", i + 2);
|
|
1381
|
+
if (end > i + 1) {
|
|
1382
|
+
flush();
|
|
1383
|
+
out.push({ kind: "bold", text: src.slice(i + 2, end) });
|
|
1384
|
+
i = end + 2;
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (ch === "_" && src[i + 1] === "_") {
|
|
1389
|
+
const end = src.indexOf("__", i + 2);
|
|
1390
|
+
if (end > i + 1) {
|
|
1391
|
+
flush();
|
|
1392
|
+
out.push({ kind: "bold", text: src.slice(i + 2, end) });
|
|
1393
|
+
i = end + 2;
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
if (ch === "*" && src[i + 1] !== "*") {
|
|
1398
|
+
const end = src.indexOf("*", i + 1);
|
|
1399
|
+
if (end > i) {
|
|
1400
|
+
flush();
|
|
1401
|
+
out.push({ kind: "italic", text: src.slice(i + 1, end) });
|
|
1402
|
+
i = end + 1;
|
|
1403
|
+
continue;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (ch === "_" && !/\w/.test(src[i - 1] ?? "") && src[i + 1] !== "_") {
|
|
1407
|
+
const end = src.indexOf("_", i + 1);
|
|
1408
|
+
if (end > i && !/\w/.test(src[end + 1] ?? "")) {
|
|
1409
|
+
flush();
|
|
1410
|
+
out.push({ kind: "italic", text: src.slice(i + 1, end) });
|
|
1411
|
+
i = end + 1;
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
buf += ch;
|
|
1416
|
+
i++;
|
|
1417
|
+
}
|
|
1418
|
+
flush();
|
|
1419
|
+
return out;
|
|
1420
|
+
}
|
|
1421
|
+
var init_markdown = __esm({
|
|
1422
|
+
"src/ui/markdown.tsx"() {
|
|
1423
|
+
"use strict";
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
// src/ui/chat.tsx
|
|
1428
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
1429
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1205
1430
|
function ChatView({ events, showReasoning, theme, verbose }) {
|
|
1206
|
-
return /* @__PURE__ */
|
|
1431
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: events.map((e) => /* @__PURE__ */ jsx4(EventView, { evt: e, showReasoning, theme, verbose }, e.key)) });
|
|
1207
1432
|
}
|
|
1208
1433
|
function EventView({ evt, showReasoning, theme, verbose }) {
|
|
1209
1434
|
if (evt.kind === "user") {
|
|
1210
|
-
return /* @__PURE__ */
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
/* @__PURE__ */
|
|
1435
|
+
return /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
|
|
1436
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.user, children: "\u203A " }),
|
|
1437
|
+
/* @__PURE__ */ jsx4(Text4, { children: evt.text })
|
|
1213
1438
|
] });
|
|
1214
1439
|
}
|
|
1215
1440
|
if (evt.kind === "assistant") {
|
|
1216
|
-
return /* @__PURE__ */
|
|
1217
|
-
showReasoning && evt.reasoning ? /* @__PURE__ */
|
|
1441
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, paddingLeft: 1, children: [
|
|
1442
|
+
showReasoning && evt.reasoning ? /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginLeft: 2, children: /* @__PURE__ */ jsxs4(Text4, { color: theme.reasoning.color, dimColor: theme.reasoning.dim, children: [
|
|
1218
1443
|
"\u2727 thinking: ",
|
|
1219
1444
|
evt.reasoning.length > 400 ? evt.reasoning.slice(0, 400) + "\u2026" : evt.reasoning
|
|
1220
1445
|
] }) }) : null,
|
|
1221
|
-
evt.text ?
|
|
1446
|
+
evt.text ? /* @__PURE__ */ jsx4(MD, { text: evt.text, theme }) : null
|
|
1222
1447
|
] });
|
|
1223
1448
|
}
|
|
1224
1449
|
if (evt.kind === "tool") {
|
|
1225
|
-
return /* @__PURE__ */
|
|
1450
|
+
return /* @__PURE__ */ jsx4(ToolView, { evt, verbose });
|
|
1226
1451
|
}
|
|
1227
1452
|
if (evt.kind === "info") {
|
|
1228
|
-
return /* @__PURE__ */
|
|
1453
|
+
return /* @__PURE__ */ jsx4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: evt.text });
|
|
1229
1454
|
}
|
|
1230
|
-
return /* @__PURE__ */
|
|
1455
|
+
return /* @__PURE__ */ jsxs4(Text4, { color: theme.error, children: [
|
|
1231
1456
|
"! ",
|
|
1232
1457
|
evt.text
|
|
1233
1458
|
] });
|
|
@@ -1236,12 +1461,13 @@ var init_chat = __esm({
|
|
|
1236
1461
|
"src/ui/chat.tsx"() {
|
|
1237
1462
|
"use strict";
|
|
1238
1463
|
init_tool_view();
|
|
1464
|
+
init_markdown();
|
|
1239
1465
|
}
|
|
1240
1466
|
});
|
|
1241
1467
|
|
|
1242
1468
|
// src/ui/status.tsx
|
|
1243
|
-
import { Box as
|
|
1244
|
-
import { jsx as
|
|
1469
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
1470
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1245
1471
|
function StatusBar({ model, usage, thinking, hint, theme, mode, effort, contextLimit }) {
|
|
1246
1472
|
const parts = [`model: ${shortModel(model)}`, `effort: ${effort}`];
|
|
1247
1473
|
if (usage) {
|
|
@@ -1260,15 +1486,15 @@ function StatusBar({ model, usage, thinking, hint, theme, mode, effort, contextL
|
|
|
1260
1486
|
if (hint) parts.push(hint);
|
|
1261
1487
|
const modeColor = mode === "plan" ? theme.modeBadge.plan : mode === "auto" ? theme.modeBadge.auto : theme.modeBadge.edit;
|
|
1262
1488
|
const warn = usage && usage.prompt_tokens / contextLimit >= 0.8;
|
|
1263
|
-
return /* @__PURE__ */
|
|
1264
|
-
/* @__PURE__ */
|
|
1489
|
+
return /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
1490
|
+
/* @__PURE__ */ jsxs5(Text5, { color: modeColor, bold: true, children: [
|
|
1265
1491
|
"[",
|
|
1266
1492
|
mode,
|
|
1267
1493
|
"]"
|
|
1268
1494
|
] }),
|
|
1269
|
-
/* @__PURE__ */
|
|
1270
|
-
/* @__PURE__ */
|
|
1271
|
-
warn ? /* @__PURE__ */
|
|
1495
|
+
/* @__PURE__ */ jsx5(Text5, { children: " " }),
|
|
1496
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.info.color, dimColor: theme.info.dim, children: parts.join(" \xB7 ") }),
|
|
1497
|
+
warn ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
|
|
1272
1498
|
" \xB7 ",
|
|
1273
1499
|
"/compact recommended"
|
|
1274
1500
|
] }) : null
|
|
@@ -1289,9 +1515,9 @@ var init_status = __esm({
|
|
|
1289
1515
|
});
|
|
1290
1516
|
|
|
1291
1517
|
// src/ui/permission.tsx
|
|
1292
|
-
import { Box as
|
|
1518
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
1293
1519
|
import SelectInput from "ink-select-input";
|
|
1294
|
-
import { jsx as
|
|
1520
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1295
1521
|
function PermissionModal({ tool, args, onDecide, theme }) {
|
|
1296
1522
|
const render2 = tool.render?.(args);
|
|
1297
1523
|
const items = [
|
|
@@ -1299,21 +1525,21 @@ function PermissionModal({ tool, args, onDecide, theme }) {
|
|
|
1299
1525
|
{ label: "Allow for this session", value: "allow_session" },
|
|
1300
1526
|
{ label: "Deny", value: "deny" }
|
|
1301
1527
|
];
|
|
1302
|
-
return /* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
1304
|
-
/* @__PURE__ */
|
|
1528
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: theme.permission, paddingX: 1, children: [
|
|
1529
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.permission, bold: true, children: "Permission requested" }),
|
|
1530
|
+
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
1305
1531
|
"tool: ",
|
|
1306
|
-
/* @__PURE__ */
|
|
1532
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.tool, children: tool.name })
|
|
1307
1533
|
] }),
|
|
1308
|
-
render2?.title ? /* @__PURE__ */
|
|
1534
|
+
render2?.title ? /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
1309
1535
|
"action: ",
|
|
1310
1536
|
render2.title
|
|
1311
1537
|
] }) : null,
|
|
1312
|
-
render2?.diff ? /* @__PURE__ */
|
|
1538
|
+
render2?.diff ? /* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx6(DiffView, { ...render2.diff }) }) : /* @__PURE__ */ jsxs6(Text6, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1313
1539
|
"args: ",
|
|
1314
1540
|
JSON.stringify(args)
|
|
1315
1541
|
] }),
|
|
1316
|
-
/* @__PURE__ */
|
|
1542
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(SelectInput, { items, onSelect: (item) => onDecide(item.value) }) })
|
|
1317
1543
|
] });
|
|
1318
1544
|
}
|
|
1319
1545
|
var init_permission = __esm({
|
|
@@ -1324,15 +1550,15 @@ var init_permission = __esm({
|
|
|
1324
1550
|
});
|
|
1325
1551
|
|
|
1326
1552
|
// src/ui/resume-picker.tsx
|
|
1327
|
-
import { Box as
|
|
1553
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
1328
1554
|
import SelectInput2 from "ink-select-input";
|
|
1329
|
-
import { jsx as
|
|
1555
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1330
1556
|
function ResumePicker({ sessions, onPick, theme }) {
|
|
1331
1557
|
if (sessions.length === 0) {
|
|
1332
|
-
return /* @__PURE__ */
|
|
1333
|
-
/* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
1335
|
-
/* @__PURE__ */
|
|
1558
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1559
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
|
|
1560
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.info.color, dimColor: theme.info.dim, children: "No saved sessions yet. Press Enter to dismiss." }),
|
|
1561
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
|
|
1336
1562
|
SelectInput2,
|
|
1337
1563
|
{
|
|
1338
1564
|
items: [{ label: "(back)", value: "__cancel__" }],
|
|
@@ -1346,10 +1572,10 @@ function ResumePicker({ sessions, onPick, theme }) {
|
|
|
1346
1572
|
value: s.id
|
|
1347
1573
|
}));
|
|
1348
1574
|
items.push({ label: "(cancel)", value: "__cancel__" });
|
|
1349
|
-
return /* @__PURE__ */
|
|
1350
|
-
/* @__PURE__ */
|
|
1351
|
-
/* @__PURE__ */
|
|
1352
|
-
/* @__PURE__ */
|
|
1575
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1576
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
|
|
1577
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.info.color, dimColor: theme.info.dim, children: "Arrow keys to select, Enter to confirm." }),
|
|
1578
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
|
|
1353
1579
|
SelectInput2,
|
|
1354
1580
|
{
|
|
1355
1581
|
items,
|
|
@@ -1383,8 +1609,8 @@ var init_resume_picker = __esm({
|
|
|
1383
1609
|
|
|
1384
1610
|
// src/ui/task-list.tsx
|
|
1385
1611
|
import { useEffect, useState } from "react";
|
|
1386
|
-
import { Box as
|
|
1387
|
-
import { jsx as
|
|
1612
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
1613
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1388
1614
|
function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
1389
1615
|
const [now, setNow] = useState(Date.now());
|
|
1390
1616
|
useEffect(() => {
|
|
@@ -1404,22 +1630,22 @@ function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
|
1404
1630
|
const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
|
|
1405
1631
|
const visibleTasks = tasks.slice(0, MAX_VISIBLE);
|
|
1406
1632
|
const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
|
|
1407
|
-
return /* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1633
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
1634
|
+
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
1635
|
+
/* @__PURE__ */ jsxs8(Text8, { color: allDone ? "green" : theme.accent, bold: true, children: [
|
|
1410
1636
|
allDone ? "\u2713" : "\u25B8",
|
|
1411
1637
|
" ",
|
|
1412
1638
|
header
|
|
1413
1639
|
] }),
|
|
1414
|
-
headerStats && /* @__PURE__ */
|
|
1640
|
+
headerStats && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1415
1641
|
" ",
|
|
1416
1642
|
"(",
|
|
1417
1643
|
headerStats,
|
|
1418
1644
|
")"
|
|
1419
1645
|
] })
|
|
1420
1646
|
] }),
|
|
1421
|
-
visibleTasks.map((t) => /* @__PURE__ */
|
|
1422
|
-
hiddenPending > 0 && /* @__PURE__ */
|
|
1647
|
+
visibleTasks.map((t) => /* @__PURE__ */ jsx8(TaskRow, { task: t, theme }, t.id)),
|
|
1648
|
+
hiddenPending > 0 && /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1423
1649
|
" ",
|
|
1424
1650
|
"\u2026 +",
|
|
1425
1651
|
hiddenPending,
|
|
@@ -1429,20 +1655,20 @@ function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
|
1429
1655
|
}
|
|
1430
1656
|
function TaskRow({ task, theme }) {
|
|
1431
1657
|
if (task.status === "completed") {
|
|
1432
|
-
return /* @__PURE__ */
|
|
1658
|
+
return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1433
1659
|
" ",
|
|
1434
1660
|
"\u2713 ",
|
|
1435
|
-
/* @__PURE__ */
|
|
1661
|
+
/* @__PURE__ */ jsx8(Text8, { strikethrough: true, children: task.title })
|
|
1436
1662
|
] });
|
|
1437
1663
|
}
|
|
1438
1664
|
if (task.status === "in_progress") {
|
|
1439
|
-
return /* @__PURE__ */
|
|
1665
|
+
return /* @__PURE__ */ jsxs8(Text8, { color: theme.accent, bold: true, children: [
|
|
1440
1666
|
" ",
|
|
1441
1667
|
"\u25A0 ",
|
|
1442
1668
|
task.title
|
|
1443
1669
|
] });
|
|
1444
1670
|
}
|
|
1445
|
-
return /* @__PURE__ */
|
|
1671
|
+
return /* @__PURE__ */ jsxs8(Text8, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1446
1672
|
" ",
|
|
1447
1673
|
"\u2610 ",
|
|
1448
1674
|
task.title
|
|
@@ -1989,8 +2215,8 @@ var init_source = __esm({
|
|
|
1989
2215
|
|
|
1990
2216
|
// src/ui/text-input.tsx
|
|
1991
2217
|
import { useState as useState2, useEffect as useEffect2, useRef } from "react";
|
|
1992
|
-
import { Text as
|
|
1993
|
-
import { jsx as
|
|
2218
|
+
import { Text as Text9, useInput } from "ink";
|
|
2219
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1994
2220
|
function shouldTreatAsPaste(input) {
|
|
1995
2221
|
if (input.length >= PASTE_CHAR_THRESHOLD) return true;
|
|
1996
2222
|
const newlines = (input.match(/\n/g) ?? []).length;
|
|
@@ -2167,7 +2393,7 @@ function CustomTextInput({
|
|
|
2167
2393
|
} else if (cursorOffset === displayValue.length) {
|
|
2168
2394
|
renderedValue += source_default.inverse(" ");
|
|
2169
2395
|
}
|
|
2170
|
-
return /* @__PURE__ */
|
|
2396
|
+
return /* @__PURE__ */ jsx9(Text9, { children: renderedValue });
|
|
2171
2397
|
}
|
|
2172
2398
|
function findPasteTokenEndingAt(value, pos, pastes) {
|
|
2173
2399
|
if (pos <= 0 || value[pos - 1] !== "]") return -1;
|
|
@@ -2191,15 +2417,15 @@ var init_text_input = __esm({
|
|
|
2191
2417
|
// src/util/update-check.ts
|
|
2192
2418
|
import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir3, access } from "fs/promises";
|
|
2193
2419
|
import { homedir as homedir4 } from "os";
|
|
2194
|
-
import { join as
|
|
2420
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
2195
2421
|
import { fileURLToPath } from "url";
|
|
2196
2422
|
function cachePath() {
|
|
2197
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
2198
|
-
return
|
|
2423
|
+
const xdg = process.env.XDG_CONFIG_HOME || join3(homedir4(), ".config");
|
|
2424
|
+
return join3(xdg, "kimiflare", "update-check.json");
|
|
2199
2425
|
}
|
|
2200
2426
|
function localPackageJsonPath() {
|
|
2201
2427
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2202
|
-
return
|
|
2428
|
+
return join3(here, "..", "..", "package.json");
|
|
2203
2429
|
}
|
|
2204
2430
|
async function readLocalVersion() {
|
|
2205
2431
|
try {
|
|
@@ -2270,7 +2496,7 @@ async function checkForUpdate() {
|
|
|
2270
2496
|
async function isGitRepo() {
|
|
2271
2497
|
try {
|
|
2272
2498
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2273
|
-
await access(
|
|
2499
|
+
await access(join3(here, "..", "..", ".git"));
|
|
2274
2500
|
return true;
|
|
2275
2501
|
} catch {
|
|
2276
2502
|
return false;
|
|
@@ -2287,8 +2513,8 @@ var init_update_check = __esm({
|
|
|
2287
2513
|
|
|
2288
2514
|
// src/ui/onboarding.tsx
|
|
2289
2515
|
import { useState as useState3 } from "react";
|
|
2290
|
-
import { Box as
|
|
2291
|
-
import { Fragment, jsx as
|
|
2516
|
+
import { Box as Box9, Text as Text10 } from "ink";
|
|
2517
|
+
import { Fragment, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2292
2518
|
function Onboarding({ onDone }) {
|
|
2293
2519
|
const [step, setStep] = useState3("accountId");
|
|
2294
2520
|
const [accountId, setAccountId] = useState3("");
|
|
@@ -2322,15 +2548,15 @@ function Onboarding({ onDone }) {
|
|
|
2322
2548
|
setSavedPath(`error: ${e.message}`);
|
|
2323
2549
|
}
|
|
2324
2550
|
};
|
|
2325
|
-
return /* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
step === "accountId" && /* @__PURE__ */
|
|
2330
|
-
/* @__PURE__ */
|
|
2331
|
-
/* @__PURE__ */
|
|
2332
|
-
/* @__PURE__ */
|
|
2333
|
-
/* @__PURE__ */
|
|
2551
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
2552
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: "cyan", children: "Welcome to kimiflare!" }),
|
|
2553
|
+
/* @__PURE__ */ jsx10(Text10, { color: "gray", dimColor: true, children: "Terminal coding agent powered by Kimi-K2.6 on Cloudflare Workers AI." }),
|
|
2554
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
2555
|
+
step === "accountId" && /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2556
|
+
/* @__PURE__ */ jsx10(Text10, { children: "Enter your Cloudflare Account ID:" }),
|
|
2557
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2558
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: "\u203A " }),
|
|
2559
|
+
/* @__PURE__ */ jsx10(
|
|
2334
2560
|
CustomTextInput,
|
|
2335
2561
|
{
|
|
2336
2562
|
value: accountId,
|
|
@@ -2340,12 +2566,12 @@ function Onboarding({ onDone }) {
|
|
|
2340
2566
|
)
|
|
2341
2567
|
] })
|
|
2342
2568
|
] }),
|
|
2343
|
-
step === "apiToken" && /* @__PURE__ */
|
|
2344
|
-
/* @__PURE__ */
|
|
2345
|
-
/* @__PURE__ */
|
|
2346
|
-
/* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2348
|
-
/* @__PURE__ */
|
|
2569
|
+
step === "apiToken" && /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2570
|
+
/* @__PURE__ */ jsx10(Text10, { children: "Enter your Cloudflare API Token:" }),
|
|
2571
|
+
/* @__PURE__ */ jsx10(Text10, { color: "gray", dimColor: true, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
|
|
2572
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2573
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: "\u203A " }),
|
|
2574
|
+
/* @__PURE__ */ jsx10(
|
|
2349
2575
|
CustomTextInput,
|
|
2350
2576
|
{
|
|
2351
2577
|
value: apiToken,
|
|
@@ -2356,15 +2582,15 @@ function Onboarding({ onDone }) {
|
|
|
2356
2582
|
)
|
|
2357
2583
|
] })
|
|
2358
2584
|
] }),
|
|
2359
|
-
step === "model" && /* @__PURE__ */
|
|
2360
|
-
/* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2585
|
+
step === "model" && /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2586
|
+
/* @__PURE__ */ jsx10(Text10, { children: "Model ID (press Enter for default):" }),
|
|
2587
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "gray", dimColor: true, children: [
|
|
2362
2588
|
"default: ",
|
|
2363
2589
|
DEFAULT_MODEL
|
|
2364
2590
|
] }),
|
|
2365
|
-
/* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2367
|
-
/* @__PURE__ */
|
|
2591
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2592
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: "\u203A " }),
|
|
2593
|
+
/* @__PURE__ */ jsx10(
|
|
2368
2594
|
CustomTextInput,
|
|
2369
2595
|
{
|
|
2370
2596
|
value: model,
|
|
@@ -2374,26 +2600,26 @@ function Onboarding({ onDone }) {
|
|
|
2374
2600
|
)
|
|
2375
2601
|
] })
|
|
2376
2602
|
] }),
|
|
2377
|
-
step === "confirm" && /* @__PURE__ */
|
|
2378
|
-
/* @__PURE__ */
|
|
2379
|
-
/* @__PURE__ */
|
|
2380
|
-
/* @__PURE__ */
|
|
2603
|
+
step === "confirm" && /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2604
|
+
/* @__PURE__ */ jsx10(Text10, { children: "Ready to save configuration:" }),
|
|
2605
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginLeft: 2, children: [
|
|
2606
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "gray", children: [
|
|
2381
2607
|
"Account ID: ",
|
|
2382
2608
|
accountId
|
|
2383
2609
|
] }),
|
|
2384
|
-
/* @__PURE__ */
|
|
2610
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "gray", children: [
|
|
2385
2611
|
"API Token: ",
|
|
2386
2612
|
"\u2022".repeat(apiToken.length)
|
|
2387
2613
|
] }),
|
|
2388
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "gray", children: [
|
|
2389
2615
|
"Model: ",
|
|
2390
2616
|
model
|
|
2391
2617
|
] })
|
|
2392
2618
|
] }),
|
|
2393
|
-
/* @__PURE__ */
|
|
2394
|
-
/* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2619
|
+
/* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { children: "Press Enter to confirm, or Ctrl+C to cancel" }) }),
|
|
2620
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2621
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: "\u203A " }),
|
|
2622
|
+
/* @__PURE__ */ jsx10(
|
|
2397
2623
|
CustomTextInput,
|
|
2398
2624
|
{
|
|
2399
2625
|
value: "",
|
|
@@ -2404,7 +2630,7 @@ function Onboarding({ onDone }) {
|
|
|
2404
2630
|
)
|
|
2405
2631
|
] })
|
|
2406
2632
|
] }),
|
|
2407
|
-
savedPath && /* @__PURE__ */
|
|
2633
|
+
savedPath && /* @__PURE__ */ jsxs9(Text10, { color: "green", children: [
|
|
2408
2634
|
"Config saved to ",
|
|
2409
2635
|
savedPath
|
|
2410
2636
|
] })
|
|
@@ -2491,10 +2717,10 @@ var init_theme = __esm({
|
|
|
2491
2717
|
// src/sessions.ts
|
|
2492
2718
|
import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir4, readdir, stat as stat2 } from "fs/promises";
|
|
2493
2719
|
import { homedir as homedir5 } from "os";
|
|
2494
|
-
import { join as
|
|
2720
|
+
import { join as join4 } from "path";
|
|
2495
2721
|
function sessionsDir() {
|
|
2496
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
2497
|
-
return
|
|
2722
|
+
const xdg = process.env.XDG_DATA_HOME || join4(homedir5(), ".local", "share");
|
|
2723
|
+
return join4(xdg, "kimiflare", "sessions");
|
|
2498
2724
|
}
|
|
2499
2725
|
function sanitize(text) {
|
|
2500
2726
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -2507,7 +2733,7 @@ function makeSessionId(firstPrompt) {
|
|
|
2507
2733
|
async function saveSession(file) {
|
|
2508
2734
|
const dir = sessionsDir();
|
|
2509
2735
|
await mkdir4(dir, { recursive: true });
|
|
2510
|
-
const path =
|
|
2736
|
+
const path = join4(dir, `${file.id}.json`);
|
|
2511
2737
|
await writeFile5(path, JSON.stringify(file, null, 2), "utf8");
|
|
2512
2738
|
return path;
|
|
2513
2739
|
}
|
|
@@ -2522,7 +2748,7 @@ async function listSessions(limit = 30) {
|
|
|
2522
2748
|
const summaries = [];
|
|
2523
2749
|
for (const name of entries) {
|
|
2524
2750
|
if (!name.endsWith(".json")) continue;
|
|
2525
|
-
const path =
|
|
2751
|
+
const path = join4(dir, name);
|
|
2526
2752
|
try {
|
|
2527
2753
|
const [s, raw] = await Promise.all([stat2(path), readFile7(path, "utf8")]);
|
|
2528
2754
|
const parsed = JSON.parse(raw);
|
|
@@ -2558,16 +2784,29 @@ __export(app_exports, {
|
|
|
2558
2784
|
renderApp: () => renderApp
|
|
2559
2785
|
});
|
|
2560
2786
|
import { useState as useState4, useRef as useRef2, useEffect as useEffect3, useCallback } from "react";
|
|
2561
|
-
import { Box as
|
|
2787
|
+
import { Box as Box10, Text as Text11, useApp, useInput as useInput2, render } from "ink";
|
|
2562
2788
|
import Spinner2 from "ink-spinner";
|
|
2789
|
+
import { existsSync } from "fs";
|
|
2790
|
+
import { join as join5 } from "path";
|
|
2563
2791
|
import { unlink } from "fs/promises";
|
|
2564
|
-
import { jsx as
|
|
2792
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2565
2793
|
function App({ initialCfg }) {
|
|
2566
2794
|
const { exit } = useApp();
|
|
2567
2795
|
const [cfg, setCfg] = useState4(initialCfg);
|
|
2568
|
-
const [events, setEvents] = useState4(
|
|
2569
|
-
|
|
2570
|
-
|
|
2796
|
+
const [events, setEvents] = useState4(() => {
|
|
2797
|
+
const initial = [
|
|
2798
|
+
{ kind: "info", key: mkKey(), text: "kimiflare \xB7 /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }
|
|
2799
|
+
];
|
|
2800
|
+
const ctxFile = loadContextFile(process.cwd());
|
|
2801
|
+
if (ctxFile) {
|
|
2802
|
+
initial.push({
|
|
2803
|
+
kind: "info",
|
|
2804
|
+
key: mkKey(),
|
|
2805
|
+
text: `loaded project context from ${ctxFile.name} (${ctxFile.lineCount} lines)`
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
return initial;
|
|
2809
|
+
});
|
|
2571
2810
|
const [input, setInput] = useState4("");
|
|
2572
2811
|
const [busy, setBusy] = useState4(false);
|
|
2573
2812
|
const [usage, setUsage] = useState4(null);
|
|
@@ -2605,6 +2844,8 @@ function App({ initialCfg }) {
|
|
|
2605
2844
|
const sessionIdRef = useRef2(null);
|
|
2606
2845
|
const modeRef = useRef2(mode);
|
|
2607
2846
|
const effortRef = useRef2(effort);
|
|
2847
|
+
const tasksRef = useRef2([]);
|
|
2848
|
+
const usageRef = useRef2(null);
|
|
2608
2849
|
useEffect3(() => {
|
|
2609
2850
|
modeRef.current = mode;
|
|
2610
2851
|
messagesRef.current[0] = {
|
|
@@ -2751,6 +2992,141 @@ function App({ initialCfg }) {
|
|
|
2751
2992
|
const sessions = await listSessions(30);
|
|
2752
2993
|
setResumeSessions(sessions);
|
|
2753
2994
|
}, []);
|
|
2995
|
+
const runInit = useCallback(async () => {
|
|
2996
|
+
if (!cfg) return;
|
|
2997
|
+
if (busy) {
|
|
2998
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "can't /init while model is running" }]);
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
3001
|
+
const cwd = process.cwd();
|
|
3002
|
+
for (const name of ["KIMI.md", "KIMIFLARE.md", "AGENT.md"]) {
|
|
3003
|
+
if (existsSync(join5(cwd, name))) {
|
|
3004
|
+
setEvents((e) => [
|
|
3005
|
+
...e,
|
|
3006
|
+
{
|
|
3007
|
+
kind: "info",
|
|
3008
|
+
key: mkKey(),
|
|
3009
|
+
text: `${name} already exists at ${join5(cwd, name)} \u2014 delete it first if you want to regenerate`
|
|
3010
|
+
}
|
|
3011
|
+
]);
|
|
3012
|
+
return;
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
const prompt = [
|
|
3016
|
+
"Generate a KIMI.md at the repository root so future agents have project context.",
|
|
3017
|
+
"",
|
|
3018
|
+
"First, use the `glob`, `read`, and `grep` tools to understand the project: read `package.json`, the top-level `README.md` if present, the tsconfig / build config, and skim the top-level source directory structure.",
|
|
3019
|
+
"",
|
|
3020
|
+
"Then call the `write` tool to create `KIMI.md` at the repo root with these sections, terse (aim \u2264 100 lines total):",
|
|
3021
|
+
"",
|
|
3022
|
+
"- **Project** \u2014 one-line description + primary language/runtime.",
|
|
3023
|
+
"- **Build / test / run** \u2014 exact shell commands an agent should use.",
|
|
3024
|
+
"- **Layout** \u2014 key directories and what lives in each.",
|
|
3025
|
+
"- **Conventions** \u2014 naming, import style, file structure, commit style, anything surprising.",
|
|
3026
|
+
"- **Do / Don't** \u2014 quirks or rules future agents should know.",
|
|
3027
|
+
"",
|
|
3028
|
+
"Do not call `tasks_set` for this. Just read what you need, then write the file."
|
|
3029
|
+
].join("\n");
|
|
3030
|
+
setEvents((e) => [...e, { kind: "user", key: mkKey(), text: "/init" }]);
|
|
3031
|
+
messagesRef.current.push({ role: "user", content: prompt });
|
|
3032
|
+
setBusy(true);
|
|
3033
|
+
const controller = new AbortController();
|
|
3034
|
+
activeControllerRef.current = controller;
|
|
3035
|
+
try {
|
|
3036
|
+
await runAgentTurn({
|
|
3037
|
+
accountId: cfg.accountId,
|
|
3038
|
+
apiToken: cfg.apiToken,
|
|
3039
|
+
model: cfg.model,
|
|
3040
|
+
messages: messagesRef.current,
|
|
3041
|
+
tools: ALL_TOOLS,
|
|
3042
|
+
executor: executorRef.current,
|
|
3043
|
+
cwd,
|
|
3044
|
+
signal: controller.signal,
|
|
3045
|
+
reasoningEffort: effortRef.current,
|
|
3046
|
+
callbacks: {
|
|
3047
|
+
onAssistantStart: () => {
|
|
3048
|
+
const id = nextAssistantId++;
|
|
3049
|
+
activeAsstIdRef.current = id;
|
|
3050
|
+
setEvents((e) => [
|
|
3051
|
+
...e,
|
|
3052
|
+
{ kind: "assistant", key: `asst_${id}`, id, text: "", reasoning: "", streaming: true }
|
|
3053
|
+
]);
|
|
3054
|
+
},
|
|
3055
|
+
onReasoningDelta: (d) => {
|
|
3056
|
+
const id = activeAsstIdRef.current;
|
|
3057
|
+
if (id !== null) updateAssistant(id, (e) => ({ reasoning: e.reasoning + d }));
|
|
3058
|
+
},
|
|
3059
|
+
onTextDelta: (d) => {
|
|
3060
|
+
const id = activeAsstIdRef.current;
|
|
3061
|
+
if (id !== null) updateAssistant(id, (e) => ({ text: e.text + d }));
|
|
3062
|
+
},
|
|
3063
|
+
onAssistantFinal: () => {
|
|
3064
|
+
const id = activeAsstIdRef.current;
|
|
3065
|
+
if (id !== null) updateAssistant(id, () => ({ streaming: false }));
|
|
3066
|
+
},
|
|
3067
|
+
onToolCallFinalized: (call) => {
|
|
3068
|
+
const spec = executorRef.current.list().find((t) => t.name === call.function.name);
|
|
3069
|
+
let renderMeta;
|
|
3070
|
+
try {
|
|
3071
|
+
const args = call.function.arguments ? JSON.parse(call.function.arguments) : {};
|
|
3072
|
+
renderMeta = spec?.render?.(args);
|
|
3073
|
+
} catch {
|
|
3074
|
+
}
|
|
3075
|
+
setEvents((e) => [
|
|
3076
|
+
...e,
|
|
3077
|
+
{
|
|
3078
|
+
kind: "tool",
|
|
3079
|
+
key: `tool_${call.id}`,
|
|
3080
|
+
id: call.id,
|
|
3081
|
+
name: call.function.name,
|
|
3082
|
+
args: call.function.arguments,
|
|
3083
|
+
status: "running",
|
|
3084
|
+
render: renderMeta,
|
|
3085
|
+
expanded: false
|
|
3086
|
+
}
|
|
3087
|
+
]);
|
|
3088
|
+
},
|
|
3089
|
+
onToolResult: (r) => {
|
|
3090
|
+
updateTool(r.tool_call_id, { status: r.ok ? "done" : "error", result: r.content });
|
|
3091
|
+
},
|
|
3092
|
+
onUsage: (u) => {
|
|
3093
|
+
usageRef.current = u;
|
|
3094
|
+
setUsage(u);
|
|
3095
|
+
},
|
|
3096
|
+
askPermission: (req) => new Promise((resolve2) => {
|
|
3097
|
+
if (modeRef.current === "auto") return resolve2("allow");
|
|
3098
|
+
setPerm({ tool: req.tool, args: req.args, resolve: resolve2 });
|
|
3099
|
+
})
|
|
3100
|
+
}
|
|
3101
|
+
});
|
|
3102
|
+
if (existsSync(join5(cwd, "KIMI.md"))) {
|
|
3103
|
+
messagesRef.current[0] = {
|
|
3104
|
+
role: "system",
|
|
3105
|
+
content: buildSystemPrompt({
|
|
3106
|
+
cwd,
|
|
3107
|
+
tools: ALL_TOOLS,
|
|
3108
|
+
model: cfg.model,
|
|
3109
|
+
mode: modeRef.current
|
|
3110
|
+
})
|
|
3111
|
+
};
|
|
3112
|
+
setEvents((e) => [
|
|
3113
|
+
...e,
|
|
3114
|
+
{ kind: "info", key: mkKey(), text: "KIMI.md generated; context loaded for future turns" }
|
|
3115
|
+
]);
|
|
3116
|
+
}
|
|
3117
|
+
} catch (e) {
|
|
3118
|
+
if (e.name !== "AbortError") {
|
|
3119
|
+
setEvents((es) => [
|
|
3120
|
+
...es,
|
|
3121
|
+
{ kind: "error", key: mkKey(), text: `init failed: ${e.message}` }
|
|
3122
|
+
]);
|
|
3123
|
+
}
|
|
3124
|
+
} finally {
|
|
3125
|
+
setBusy(false);
|
|
3126
|
+
activeAsstIdRef.current = null;
|
|
3127
|
+
activeControllerRef.current = null;
|
|
3128
|
+
}
|
|
3129
|
+
}, [cfg, busy, updateAssistant, updateTool]);
|
|
2754
3130
|
const handleResumePick = useCallback(
|
|
2755
3131
|
async (picked) => {
|
|
2756
3132
|
setResumeSessions(null);
|
|
@@ -2935,6 +3311,10 @@ use: /thinking low | medium | high`
|
|
|
2935
3311
|
void runCompact();
|
|
2936
3312
|
return true;
|
|
2937
3313
|
}
|
|
3314
|
+
if (c === "/init") {
|
|
3315
|
+
void runInit();
|
|
3316
|
+
return true;
|
|
3317
|
+
}
|
|
2938
3318
|
if (c === "/update") {
|
|
2939
3319
|
if (updateInfo?.hasUpdate) {
|
|
2940
3320
|
setEvents((e) => [
|
|
@@ -2990,14 +3370,14 @@ use: /thinking low | medium | high`
|
|
|
2990
3370
|
{
|
|
2991
3371
|
kind: "info",
|
|
2992
3372
|
key: mkKey(),
|
|
2993
|
-
text: "commands:\n /mode edit|plan|auto switch mode (or shift+tab to cycle)\n /plan /auto /edit shortcuts for /mode\n /thinking low|med|high set reasoning effort (quality vs speed)\n /theme NAME dark, light, high-contrast\n /resume pick a past conversation\n /compact summarize old turns to free context\n /reasoning toggle show/hide model reasoning\n /clear clear current conversation\n /cost /model /update /logout /help /exit\nkeys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o toggle verbose output \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history"
|
|
3373
|
+
text: "commands:\n /mode edit|plan|auto switch mode (or shift+tab to cycle)\n /plan /auto /edit shortcuts for /mode\n /thinking low|med|high set reasoning effort (quality vs speed)\n /theme NAME dark, light, high-contrast\n /resume pick a past conversation\n /compact summarize old turns to free context\n /init scan this repo and write a KIMI.md for future agents\n /reasoning toggle show/hide model reasoning\n /clear clear current conversation\n /cost /model /update /logout /help /exit\nkeys: ctrl-c interrupt/exit \xB7 ctrl-r toggle reasoning \xB7 ctrl-o toggle verbose output \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history"
|
|
2994
3374
|
}
|
|
2995
3375
|
]);
|
|
2996
3376
|
return true;
|
|
2997
3377
|
}
|
|
2998
3378
|
return false;
|
|
2999
3379
|
},
|
|
3000
|
-
[cfg, exit, usage, updateInfo, effort, theme, mode, openResumePicker, runCompact]
|
|
3380
|
+
[cfg, exit, usage, updateInfo, effort, theme, mode, openResumePicker, runCompact, runInit]
|
|
3001
3381
|
);
|
|
3002
3382
|
const processMessage = useCallback(
|
|
3003
3383
|
async (text, displayText) => {
|
|
@@ -3071,19 +3451,22 @@ use: /thinking low | medium | high`
|
|
|
3071
3451
|
result: r.content
|
|
3072
3452
|
});
|
|
3073
3453
|
},
|
|
3074
|
-
onUsage: (u) =>
|
|
3454
|
+
onUsage: (u) => {
|
|
3455
|
+
usageRef.current = u;
|
|
3456
|
+
setUsage(u);
|
|
3457
|
+
},
|
|
3075
3458
|
onTasks: (nextTasks) => {
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
}
|
|
3459
|
+
const prevEmpty = tasksRef.current.length === 0;
|
|
3460
|
+
tasksRef.current = nextTasks;
|
|
3461
|
+
setTasks(nextTasks);
|
|
3462
|
+
if (prevEmpty && nextTasks.length > 0) {
|
|
3463
|
+
setTasksStartedAt(Date.now());
|
|
3464
|
+
setTasksStartTokens(usageRef.current?.prompt_tokens ?? 0);
|
|
3465
|
+
}
|
|
3466
|
+
if (nextTasks.length === 0) {
|
|
3467
|
+
setTasksStartedAt(null);
|
|
3468
|
+
setTasksStartTokens(0);
|
|
3469
|
+
}
|
|
3087
3470
|
},
|
|
3088
3471
|
askPermission: (req) => new Promise((resolve2) => {
|
|
3089
3472
|
if (modeRef.current === "auto") {
|
|
@@ -3183,7 +3566,7 @@ use: /thinking low | medium | high`
|
|
|
3183
3566
|
}
|
|
3184
3567
|
}, [usage]);
|
|
3185
3568
|
if (!cfg) {
|
|
3186
|
-
return /* @__PURE__ */
|
|
3569
|
+
return /* @__PURE__ */ jsx11(
|
|
3187
3570
|
Onboarding,
|
|
3188
3571
|
{
|
|
3189
3572
|
onDone: (newCfg) => {
|
|
@@ -3197,11 +3580,11 @@ use: /thinking low | medium | high`
|
|
|
3197
3580
|
);
|
|
3198
3581
|
}
|
|
3199
3582
|
if (resumeSessions !== null) {
|
|
3200
|
-
return /* @__PURE__ */
|
|
3583
|
+
return /* @__PURE__ */ jsx11(Box10, { flexDirection: "column", children: /* @__PURE__ */ jsx11(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick, theme }) });
|
|
3201
3584
|
}
|
|
3202
|
-
return /* @__PURE__ */
|
|
3203
|
-
/* @__PURE__ */
|
|
3204
|
-
perm ? /* @__PURE__ */
|
|
3585
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
3586
|
+
/* @__PURE__ */ jsx11(ChatView, { events, showReasoning, theme, verbose }),
|
|
3587
|
+
perm ? /* @__PURE__ */ jsx11(
|
|
3205
3588
|
PermissionModal,
|
|
3206
3589
|
{
|
|
3207
3590
|
tool: perm.tool,
|
|
@@ -3212,8 +3595,8 @@ use: /thinking low | medium | high`
|
|
|
3212
3595
|
setPerm(null);
|
|
3213
3596
|
}
|
|
3214
3597
|
}
|
|
3215
|
-
) : /* @__PURE__ */
|
|
3216
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
3598
|
+
) : /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
3599
|
+
tasks.length > 0 && /* @__PURE__ */ jsx11(
|
|
3217
3600
|
TaskList,
|
|
3218
3601
|
{
|
|
3219
3602
|
tasks,
|
|
@@ -3222,11 +3605,11 @@ use: /thinking low | medium | high`
|
|
|
3222
3605
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
3223
3606
|
}
|
|
3224
3607
|
),
|
|
3225
|
-
queue.length > 0 && /* @__PURE__ */
|
|
3608
|
+
queue.length > 0 && /* @__PURE__ */ jsx11(Box10, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs10(Text11, { color: theme.queue.color, dimColor: theme.queue.dim, children: [
|
|
3226
3609
|
"\u23F3 ",
|
|
3227
3610
|
q.display
|
|
3228
3611
|
] }, `queue_${i}`)) }),
|
|
3229
|
-
/* @__PURE__ */
|
|
3612
|
+
/* @__PURE__ */ jsx11(
|
|
3230
3613
|
StatusBar,
|
|
3231
3614
|
{
|
|
3232
3615
|
model: cfg.model,
|
|
@@ -3239,13 +3622,13 @@ use: /thinking low | medium | high`
|
|
|
3239
3622
|
contextLimit: CONTEXT_LIMIT
|
|
3240
3623
|
}
|
|
3241
3624
|
),
|
|
3242
|
-
busy && /* @__PURE__ */
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3625
|
+
busy && /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
3626
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.spinner, children: /* @__PURE__ */ jsx11(Spinner2, { type: "dots" }) }),
|
|
3627
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.info.color, dimColor: theme.info.dim, children: " working\u2026" })
|
|
3245
3628
|
] }),
|
|
3246
|
-
/* @__PURE__ */
|
|
3247
|
-
/* @__PURE__ */
|
|
3248
|
-
/* @__PURE__ */
|
|
3629
|
+
/* @__PURE__ */ jsxs10(Box10, { children: [
|
|
3630
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.user, children: busy ? "\u23F3 " : "\u203A " }),
|
|
3631
|
+
/* @__PURE__ */ jsx11(
|
|
3249
3632
|
CustomTextInput,
|
|
3250
3633
|
{
|
|
3251
3634
|
value: input,
|
|
@@ -3294,7 +3677,7 @@ use: /thinking low | medium | high`
|
|
|
3294
3677
|
] });
|
|
3295
3678
|
}
|
|
3296
3679
|
async function renderApp(cfg) {
|
|
3297
|
-
const instance = render(/* @__PURE__ */
|
|
3680
|
+
const instance = render(/* @__PURE__ */ jsx11(App, { initialCfg: cfg }));
|
|
3298
3681
|
await instance.waitUntilExit();
|
|
3299
3682
|
}
|
|
3300
3683
|
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, nextAssistantId, nextKey, mkKey, EFFORT_DESCRIPTIONS;
|
|
@@ -3310,6 +3693,7 @@ var init_app = __esm({
|
|
|
3310
3693
|
init_permission();
|
|
3311
3694
|
init_resume_picker();
|
|
3312
3695
|
init_task_list();
|
|
3696
|
+
init_system_prompt();
|
|
3313
3697
|
init_text_input();
|
|
3314
3698
|
init_update_check();
|
|
3315
3699
|
init_onboarding();
|