kimiflare 0.13.1 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +62 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -87,6 +87,8 @@ async function* readSSE(stream, signal) {
|
|
|
87
87
|
const reader = stream.getReader();
|
|
88
88
|
const decoder = new TextDecoder("utf-8");
|
|
89
89
|
let buffer = "";
|
|
90
|
+
const onAbort = () => reader.cancel(new DOMException("aborted", "AbortError"));
|
|
91
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
90
92
|
try {
|
|
91
93
|
while (true) {
|
|
92
94
|
if (signal?.aborted) throw new DOMException("aborted", "AbortError");
|
|
@@ -106,6 +108,7 @@ async function* readSSE(stream, signal) {
|
|
|
106
108
|
const tail = extractData(buffer.trim());
|
|
107
109
|
if (tail !== null) yield tail;
|
|
108
110
|
} finally {
|
|
111
|
+
signal?.removeEventListener("abort", onAbort);
|
|
109
112
|
reader.releaseLock();
|
|
110
113
|
}
|
|
111
114
|
}
|
|
@@ -782,7 +785,7 @@ How to work:
|
|
|
782
785
|
- You have a 262k-token context window. Read as much of a file as needed rather than guessing.
|
|
783
786
|
- If a request is ambiguous, ask one focused question instead of making large assumptions.
|
|
784
787
|
- When you finish a task, stop. Do not add a closing summary.
|
|
785
|
-
- When creating git commits, you
|
|
788
|
+
- When creating git commits, you must include \`Co-authored-by: kimiflare <kimiflare@proton.me>\` in the commit message so kimiflare is credited as a contributor. The bash tool will also auto-append this trailer when it detects git commit-creating commands.`;
|
|
786
789
|
const ctx = loadContextFile(opts2.cwd);
|
|
787
790
|
const contextBlock = ctx ? `
|
|
788
791
|
|
|
@@ -977,6 +980,8 @@ var init_edit = __esm({
|
|
|
977
980
|
|
|
978
981
|
// src/tools/bash.ts
|
|
979
982
|
import { spawn } from "child_process";
|
|
983
|
+
import { tmpdir } from "os";
|
|
984
|
+
import { join as join3 } from "path";
|
|
980
985
|
function formatBashTitle(raw) {
|
|
981
986
|
let cmd = (raw ?? "").trim();
|
|
982
987
|
const m = cmd.match(/^cd\s+([^\s&;]+)\s*(?:&&|;)\s*(.*)$/);
|
|
@@ -987,13 +992,28 @@ function injectCoauthor(command, coauthor) {
|
|
|
987
992
|
if (!coauthor) return command;
|
|
988
993
|
const trailer = `Co-authored-by: ${coauthor.name} <${coauthor.email}>`;
|
|
989
994
|
const trimmed = command.trim();
|
|
990
|
-
if (!/\bgit\s+commit\b/.test(trimmed)) return command;
|
|
991
995
|
if (command.includes(trailer)) return command;
|
|
992
|
-
|
|
993
|
-
const
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
996
|
+
const createsCommit = /\bgit\s+(commit|merge|revert|cherry-pick)\b/.test(trimmed);
|
|
997
|
+
const isRebaseContinue = /\bgit\s+rebase\b/.test(trimmed) && !/\b--abort\b|\b--skip\b/.test(trimmed);
|
|
998
|
+
const mentionsGit = /\bgit\b/.test(trimmed);
|
|
999
|
+
if (!createsCommit && !isRebaseContinue && !mentionsGit) return command;
|
|
1000
|
+
const tmpFile = join3(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
1001
|
+
const amendBlock = `
|
|
1002
|
+
if ! git log -1 --pretty=%B 2>/dev/null | grep -qF "${trailer}"; then
|
|
1003
|
+
git log -1 --pretty=%B | git interpret-trailers --trailer "${trailer}" > "${tmpFile}" && git commit --amend -F "${tmpFile}" --no-edit && rm -f "${tmpFile}"
|
|
1004
|
+
fi
|
|
1005
|
+
`.trim();
|
|
1006
|
+
if (createsCommit || isRebaseContinue) {
|
|
1007
|
+
return `(${command}) && { ${amendBlock}; }`;
|
|
1008
|
+
}
|
|
1009
|
+
const beforeHead = `git rev-parse HEAD 2>/dev/null || echo "NO_HEAD"`;
|
|
1010
|
+
const afterCheck = `
|
|
1011
|
+
_KF_AFTER_HEAD=$(git rev-parse HEAD 2>/dev/null || echo "NO_HEAD")
|
|
1012
|
+
if [ "$_KF_BEFORE_HEAD" != "$_KF_AFTER_HEAD" ] && [ "$_KF_AFTER_HEAD" != "NO_HEAD" ]; then
|
|
1013
|
+
${amendBlock}
|
|
1014
|
+
fi
|
|
1015
|
+
`.trim();
|
|
1016
|
+
return `_KF_BEFORE_HEAD=$(${beforeHead}); (${command}); _KF_EXIT=$?; [ $_KF_EXIT -eq 0 ] && { ${afterCheck}; }; exit $_KF_EXIT`;
|
|
997
1017
|
}
|
|
998
1018
|
function runBash(args, ctx) {
|
|
999
1019
|
const timeout = Math.min(Math.max(1e3, args.timeout_ms ?? DEFAULT_TIMEOUT), MAX_TIMEOUT);
|
|
@@ -1437,16 +1457,16 @@ var init_executor = __esm({
|
|
|
1437
1457
|
// src/util/update-check.ts
|
|
1438
1458
|
import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir3, access } from "fs/promises";
|
|
1439
1459
|
import { homedir as homedir4 } from "os";
|
|
1440
|
-
import { join as
|
|
1460
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
1441
1461
|
import { fileURLToPath } from "url";
|
|
1442
1462
|
function cachePath() {
|
|
1443
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
1444
|
-
return
|
|
1463
|
+
const xdg = process.env.XDG_CONFIG_HOME || join4(homedir4(), ".config");
|
|
1464
|
+
return join4(xdg, "kimiflare", "update-check.json");
|
|
1445
1465
|
}
|
|
1446
1466
|
async function findPackageJson(startDir) {
|
|
1447
1467
|
let dir = startDir;
|
|
1448
1468
|
while (true) {
|
|
1449
|
-
const candidate =
|
|
1469
|
+
const candidate = join4(dir, "package.json");
|
|
1450
1470
|
try {
|
|
1451
1471
|
const raw = await readFile6(candidate, "utf8");
|
|
1452
1472
|
const parsed = JSON.parse(raw);
|
|
@@ -1530,7 +1550,7 @@ async function isGitRepo() {
|
|
|
1530
1550
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
1531
1551
|
while (true) {
|
|
1532
1552
|
try {
|
|
1533
|
-
await access(
|
|
1553
|
+
await access(join4(dir, ".git"));
|
|
1534
1554
|
return true;
|
|
1535
1555
|
} catch {
|
|
1536
1556
|
}
|
|
@@ -3481,10 +3501,10 @@ var init_theme = __esm({
|
|
|
3481
3501
|
// src/sessions.ts
|
|
3482
3502
|
import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir4, readdir, stat as stat2 } from "fs/promises";
|
|
3483
3503
|
import { homedir as homedir5 } from "os";
|
|
3484
|
-
import { join as
|
|
3504
|
+
import { join as join5 } from "path";
|
|
3485
3505
|
function sessionsDir() {
|
|
3486
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
3487
|
-
return
|
|
3506
|
+
const xdg = process.env.XDG_DATA_HOME || join5(homedir5(), ".local", "share");
|
|
3507
|
+
return join5(xdg, "kimiflare", "sessions");
|
|
3488
3508
|
}
|
|
3489
3509
|
function sanitize(text) {
|
|
3490
3510
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -3497,7 +3517,7 @@ function makeSessionId(firstPrompt) {
|
|
|
3497
3517
|
async function saveSession(file) {
|
|
3498
3518
|
const dir = sessionsDir();
|
|
3499
3519
|
await mkdir4(dir, { recursive: true });
|
|
3500
|
-
const path =
|
|
3520
|
+
const path = join5(dir, `${file.id}.json`);
|
|
3501
3521
|
await writeFile5(path, JSON.stringify(file, null, 2), "utf8");
|
|
3502
3522
|
return path;
|
|
3503
3523
|
}
|
|
@@ -3512,7 +3532,7 @@ async function listSessions(limit = 30) {
|
|
|
3512
3532
|
const summaries = [];
|
|
3513
3533
|
for (const name of entries) {
|
|
3514
3534
|
if (!name.endsWith(".json")) continue;
|
|
3515
|
-
const path =
|
|
3535
|
+
const path = join5(dir, name);
|
|
3516
3536
|
try {
|
|
3517
3537
|
const [s, raw] = await Promise.all([stat2(path), readFile7(path, "utf8")]);
|
|
3518
3538
|
const parsed = JSON.parse(raw);
|
|
@@ -3589,7 +3609,7 @@ __export(app_exports, {
|
|
|
3589
3609
|
import { useState as useState6, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
|
|
3590
3610
|
import { Box as Box12, Text as Text13, useApp, useInput as useInput2, render } from "ink";
|
|
3591
3611
|
import { existsSync } from "fs";
|
|
3592
|
-
import { join as
|
|
3612
|
+
import { join as join6 } from "path";
|
|
3593
3613
|
import { unlink } from "fs/promises";
|
|
3594
3614
|
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3595
3615
|
function capEvents(prev) {
|
|
@@ -3720,6 +3740,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3720
3740
|
const updateCheckedRef = useRef3(false);
|
|
3721
3741
|
const updateNudgedRef = useRef3(false);
|
|
3722
3742
|
const compactSuggestedRef = useRef3(false);
|
|
3743
|
+
const interruptRequestedRef = useRef3(false);
|
|
3723
3744
|
useEffect4(() => {
|
|
3724
3745
|
if (!cfg || updateCheckedRef.current) return;
|
|
3725
3746
|
updateCheckedRef.current = true;
|
|
@@ -3854,6 +3875,10 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3854
3875
|
useInput2((inputChar, key) => {
|
|
3855
3876
|
if (key.ctrl && inputChar === "c") {
|
|
3856
3877
|
if (busy) {
|
|
3878
|
+
if (interruptRequestedRef.current) {
|
|
3879
|
+
process.exit(0);
|
|
3880
|
+
}
|
|
3881
|
+
interruptRequestedRef.current = true;
|
|
3857
3882
|
activeControllerRef.current?.abort();
|
|
3858
3883
|
permResolveRef.current?.("deny");
|
|
3859
3884
|
permResolveRef.current = null;
|
|
@@ -3949,6 +3974,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3949
3974
|
setBusy(false);
|
|
3950
3975
|
setTurnStartedAt(null);
|
|
3951
3976
|
activeControllerRef.current = null;
|
|
3977
|
+
interruptRequestedRef.current = false;
|
|
3952
3978
|
}
|
|
3953
3979
|
}, [cfg, busy, saveSessionSafe]);
|
|
3954
3980
|
const openResumePicker = useCallback(async () => {
|
|
@@ -3963,13 +3989,13 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3963
3989
|
}
|
|
3964
3990
|
const cwd = process.cwd();
|
|
3965
3991
|
for (const name of ["KIMI.md", "KIMIFLARE.md", "AGENT.md"]) {
|
|
3966
|
-
if (existsSync(
|
|
3992
|
+
if (existsSync(join6(cwd, name))) {
|
|
3967
3993
|
setEvents((e) => [
|
|
3968
3994
|
...e,
|
|
3969
3995
|
{
|
|
3970
3996
|
kind: "info",
|
|
3971
3997
|
key: mkKey(),
|
|
3972
|
-
text: `${name} already exists at ${
|
|
3998
|
+
text: `${name} already exists at ${join6(cwd, name)} \u2014 delete it first if you want to regenerate`
|
|
3973
3999
|
}
|
|
3974
4000
|
]);
|
|
3975
4001
|
return;
|
|
@@ -4094,7 +4120,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4094
4120
|
cfg,
|
|
4095
4121
|
(text) => setEvents((es) => [...es, { kind: "info", key: mkKey(), text }])
|
|
4096
4122
|
);
|
|
4097
|
-
if (existsSync(
|
|
4123
|
+
if (existsSync(join6(cwd, "KIMI.md"))) {
|
|
4098
4124
|
messagesRef.current[0] = {
|
|
4099
4125
|
role: "system",
|
|
4100
4126
|
content: buildSystemPrompt({
|
|
@@ -4129,6 +4155,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4129
4155
|
activeAsstIdRef.current = null;
|
|
4130
4156
|
activeControllerRef.current = null;
|
|
4131
4157
|
permResolveRef.current = null;
|
|
4158
|
+
interruptRequestedRef.current = false;
|
|
4132
4159
|
}
|
|
4133
4160
|
}, [cfg, busy, updateAssistant, updateTool]);
|
|
4134
4161
|
const handleResumePick = useCallback(
|
|
@@ -4589,10 +4616,18 @@ use: /thinking low | medium | high`
|
|
|
4589
4616
|
activeAsstIdRef.current = null;
|
|
4590
4617
|
activeControllerRef.current = null;
|
|
4591
4618
|
permResolveRef.current = null;
|
|
4619
|
+
interruptRequestedRef.current = false;
|
|
4592
4620
|
}
|
|
4593
4621
|
},
|
|
4594
4622
|
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe]
|
|
4595
4623
|
);
|
|
4624
|
+
useEffect4(() => {
|
|
4625
|
+
const onSigint = () => exit();
|
|
4626
|
+
process.on("SIGINT", onSigint);
|
|
4627
|
+
return () => {
|
|
4628
|
+
process.off("SIGINT", onSigint);
|
|
4629
|
+
};
|
|
4630
|
+
}, [exit]);
|
|
4596
4631
|
useEffect4(() => {
|
|
4597
4632
|
if (!busy && queue.length > 0) {
|
|
4598
4633
|
const next = queue[0];
|
|
@@ -4802,11 +4837,11 @@ init_update_check();
|
|
|
4802
4837
|
import { Command } from "commander";
|
|
4803
4838
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4804
4839
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4805
|
-
import { dirname as dirname3, join as
|
|
4840
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
4806
4841
|
function readPackageVersion() {
|
|
4807
4842
|
try {
|
|
4808
4843
|
const here = dirname3(fileURLToPath2(import.meta.url));
|
|
4809
|
-
const pkg = JSON.parse(readFileSync2(
|
|
4844
|
+
const pkg = JSON.parse(readFileSync2(join7(here, "..", "package.json"), "utf8"));
|
|
4810
4845
|
return pkg.version ?? "0.0.0";
|
|
4811
4846
|
} catch {
|
|
4812
4847
|
return "0.0.0";
|
|
@@ -4867,7 +4902,10 @@ async function runPrintMode(opts2) {
|
|
|
4867
4902
|
{ role: "user", content: opts2.prompt }
|
|
4868
4903
|
];
|
|
4869
4904
|
const controller = new AbortController();
|
|
4870
|
-
process.
|
|
4905
|
+
process.once("SIGINT", () => {
|
|
4906
|
+
controller.abort();
|
|
4907
|
+
setTimeout(() => process.exit(1), 500);
|
|
4908
|
+
});
|
|
4871
4909
|
let printedReasoningHeader = false;
|
|
4872
4910
|
let printedAnswerHeader = false;
|
|
4873
4911
|
await runAgentTurn({
|