kimiflare 0.7.0 → 0.8.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/dist/index.js +708 -269
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -142,7 +142,33 @@ var init_errors = __esm({
|
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
+
// src/agent/messages.ts
|
|
146
|
+
function sanitizeString(str) {
|
|
147
|
+
return str.replace(/[\uD800-\uDFFF]/g, "\uFFFD");
|
|
148
|
+
}
|
|
149
|
+
function jsonReplacer(_key, value) {
|
|
150
|
+
if (typeof value === "string") {
|
|
151
|
+
return sanitizeString(value);
|
|
152
|
+
}
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
var init_messages = __esm({
|
|
156
|
+
"src/agent/messages.ts"() {
|
|
157
|
+
"use strict";
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
145
161
|
// src/agent/client.ts
|
|
162
|
+
function cleanErrorMessage(msg) {
|
|
163
|
+
return msg.replace(/^(AiError:\s*)+/, "").trim();
|
|
164
|
+
}
|
|
165
|
+
function isRetryable(err, attempt) {
|
|
166
|
+
if (attempt >= MAX_ATTEMPTS - 1) return false;
|
|
167
|
+
if (err.code !== void 0 && RETRYABLE_CODES.has(err.code)) return true;
|
|
168
|
+
if (err.httpStatus !== void 0 && err.httpStatus >= 500 && err.httpStatus < 600) return true;
|
|
169
|
+
if (err.message.includes("Internal server error")) return true;
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
146
172
|
async function* runKimi(opts2) {
|
|
147
173
|
const url = `https://api.cloudflare.com/client/v4/accounts/${opts2.accountId}/ai/run/${opts2.model}`;
|
|
148
174
|
const body = {
|
|
@@ -156,15 +182,26 @@ async function* runKimi(opts2) {
|
|
|
156
182
|
body.reasoning_effort = opts2.reasoningEffort;
|
|
157
183
|
}
|
|
158
184
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
185
|
+
let res;
|
|
186
|
+
try {
|
|
187
|
+
res = await fetch(url, {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: {
|
|
190
|
+
Authorization: `Bearer ${opts2.apiToken}`,
|
|
191
|
+
"Content-Type": "application/json"
|
|
192
|
+
},
|
|
193
|
+
body: JSON.stringify(body, jsonReplacer),
|
|
194
|
+
signal: opts2.signal
|
|
195
|
+
});
|
|
196
|
+
} catch (fetchErr) {
|
|
197
|
+
const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr);
|
|
198
|
+
if (attempt < MAX_ATTEMPTS - 1) {
|
|
199
|
+
const delay = 500 * 2 ** attempt + Math.random() * 250;
|
|
200
|
+
await sleep(delay, opts2.signal);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
throw new KimiApiError(`kimiflare: network error: ${msg}`, void 0, void 0);
|
|
204
|
+
}
|
|
168
205
|
const contentType = res.headers.get("content-type") ?? "";
|
|
169
206
|
if (!contentType.includes("text/event-stream")) {
|
|
170
207
|
const text = await res.text();
|
|
@@ -174,13 +211,15 @@ async function* runKimi(opts2) {
|
|
|
174
211
|
} catch {
|
|
175
212
|
}
|
|
176
213
|
const err = extractCloudflareError(parsed);
|
|
177
|
-
|
|
214
|
+
const rawMsg = err?.message ?? `HTTP ${res.status}: ${text.slice(0, 300)}`;
|
|
215
|
+
const msg = cleanErrorMessage(rawMsg);
|
|
216
|
+
const apiErr = new KimiApiError(`kimiflare: ${msg}`, err?.code, res.status);
|
|
217
|
+
if (isRetryable(apiErr, attempt)) {
|
|
178
218
|
const delay = 500 * 2 ** attempt + Math.random() * 250;
|
|
179
219
|
await sleep(delay, opts2.signal);
|
|
180
220
|
continue;
|
|
181
221
|
}
|
|
182
|
-
|
|
183
|
-
throw new KimiApiError(`kimiflare: ${msg}`, err?.code, res.status);
|
|
222
|
+
throw apiErr;
|
|
184
223
|
}
|
|
185
224
|
if (!res.body) throw new KimiApiError("kimiflare: empty response body", void 0, res.status);
|
|
186
225
|
yield* parseStream(res.body, opts2.signal);
|
|
@@ -257,9 +296,14 @@ async function* parseStream(body, signal) {
|
|
|
257
296
|
}
|
|
258
297
|
function extractCloudflareError(parsed) {
|
|
259
298
|
if (!parsed || typeof parsed !== "object") return null;
|
|
260
|
-
const
|
|
261
|
-
if (
|
|
262
|
-
return { code:
|
|
299
|
+
const cf = parsed;
|
|
300
|
+
if (cf.success === false && Array.isArray(cf.errors) && cf.errors.length > 0) {
|
|
301
|
+
return { code: cf.errors[0]?.code, message: cf.errors[0]?.message };
|
|
302
|
+
}
|
|
303
|
+
const oai = parsed;
|
|
304
|
+
if (oai.object === "error" && typeof oai.message === "string") {
|
|
305
|
+
const codeNum = typeof oai.code === "number" ? oai.code : void 0;
|
|
306
|
+
return { code: codeNum, message: oai.message };
|
|
263
307
|
}
|
|
264
308
|
return null;
|
|
265
309
|
}
|
|
@@ -277,13 +321,14 @@ function sleep(ms, signal) {
|
|
|
277
321
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
278
322
|
});
|
|
279
323
|
}
|
|
280
|
-
var
|
|
324
|
+
var RETRYABLE_CODES, MAX_ATTEMPTS;
|
|
281
325
|
var init_client = __esm({
|
|
282
326
|
"src/agent/client.ts"() {
|
|
283
327
|
"use strict";
|
|
284
328
|
init_sse();
|
|
285
329
|
init_errors();
|
|
286
|
-
|
|
330
|
+
init_messages();
|
|
331
|
+
RETRYABLE_CODES = /* @__PURE__ */ new Set([3040]);
|
|
287
332
|
MAX_ATTEMPTS = 5;
|
|
288
333
|
}
|
|
289
334
|
});
|
|
@@ -360,9 +405,17 @@ async function runAgentTurn(opts2) {
|
|
|
360
405
|
}
|
|
361
406
|
const assistantMsg = {
|
|
362
407
|
role: "assistant",
|
|
363
|
-
content: content
|
|
364
|
-
...reasoning ? { reasoning_content: reasoning } : {},
|
|
365
|
-
...toolCalls.length ? {
|
|
408
|
+
content: content ? sanitizeString(content) : null,
|
|
409
|
+
...reasoning ? { reasoning_content: sanitizeString(reasoning) } : {},
|
|
410
|
+
...toolCalls.length ? {
|
|
411
|
+
tool_calls: toolCalls.map((tc) => ({
|
|
412
|
+
...tc,
|
|
413
|
+
function: {
|
|
414
|
+
name: tc.function.name,
|
|
415
|
+
arguments: sanitizeString(tc.function.arguments)
|
|
416
|
+
}
|
|
417
|
+
}))
|
|
418
|
+
} : {}
|
|
366
419
|
};
|
|
367
420
|
opts2.messages.push(assistantMsg);
|
|
368
421
|
opts2.callbacks.onAssistantFinal?.(assistantMsg);
|
|
@@ -377,7 +430,7 @@ async function runAgentTurn(opts2) {
|
|
|
377
430
|
opts2.messages.push({
|
|
378
431
|
role: "tool",
|
|
379
432
|
tool_call_id: result.tool_call_id,
|
|
380
|
-
content: result.content,
|
|
433
|
+
content: sanitizeString(result.content),
|
|
381
434
|
name: result.name
|
|
382
435
|
});
|
|
383
436
|
opts2.callbacks.onToolResult?.(result);
|
|
@@ -390,6 +443,7 @@ var init_loop = __esm({
|
|
|
390
443
|
"use strict";
|
|
391
444
|
init_client();
|
|
392
445
|
init_registry();
|
|
446
|
+
init_messages();
|
|
393
447
|
}
|
|
394
448
|
});
|
|
395
449
|
|
|
@@ -1118,6 +1172,120 @@ var init_executor = __esm({
|
|
|
1118
1172
|
}
|
|
1119
1173
|
});
|
|
1120
1174
|
|
|
1175
|
+
// src/util/update-check.ts
|
|
1176
|
+
import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir3, access } from "fs/promises";
|
|
1177
|
+
import { homedir as homedir4 } from "os";
|
|
1178
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
1179
|
+
import { fileURLToPath } from "url";
|
|
1180
|
+
function cachePath() {
|
|
1181
|
+
const xdg = process.env.XDG_CONFIG_HOME || join3(homedir4(), ".config");
|
|
1182
|
+
return join3(xdg, "kimiflare", "update-check.json");
|
|
1183
|
+
}
|
|
1184
|
+
async function findPackageJson(startDir) {
|
|
1185
|
+
let dir = startDir;
|
|
1186
|
+
while (true) {
|
|
1187
|
+
const candidate = join3(dir, "package.json");
|
|
1188
|
+
try {
|
|
1189
|
+
const raw = await readFile6(candidate, "utf8");
|
|
1190
|
+
const parsed = JSON.parse(raw);
|
|
1191
|
+
if (parsed.name === "kimiflare" && parsed.version) {
|
|
1192
|
+
return { path: candidate, version: parsed.version };
|
|
1193
|
+
}
|
|
1194
|
+
} catch {
|
|
1195
|
+
}
|
|
1196
|
+
const parent = dirname2(dir);
|
|
1197
|
+
if (parent === dir) break;
|
|
1198
|
+
dir = parent;
|
|
1199
|
+
}
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
async function readLocalVersion() {
|
|
1203
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
1204
|
+
const found = await findPackageJson(here);
|
|
1205
|
+
return found?.version ?? null;
|
|
1206
|
+
}
|
|
1207
|
+
async function readCache() {
|
|
1208
|
+
try {
|
|
1209
|
+
const raw = await readFile6(cachePath(), "utf8");
|
|
1210
|
+
const parsed = JSON.parse(raw);
|
|
1211
|
+
if (Date.now() - parsed.checkedAt < CACHE_TTL_MS) {
|
|
1212
|
+
return parsed;
|
|
1213
|
+
}
|
|
1214
|
+
} catch {
|
|
1215
|
+
}
|
|
1216
|
+
return null;
|
|
1217
|
+
}
|
|
1218
|
+
async function writeCache(entry) {
|
|
1219
|
+
const p = cachePath();
|
|
1220
|
+
await mkdir3(dirname2(p), { recursive: true });
|
|
1221
|
+
await writeFile4(p, JSON.stringify(entry), "utf8");
|
|
1222
|
+
}
|
|
1223
|
+
async function fetchLatestVersion() {
|
|
1224
|
+
try {
|
|
1225
|
+
const res = await fetch(NPM_REGISTRY, {
|
|
1226
|
+
headers: { "User-Agent": "kimiflare-update-checker", Accept: "application/json" }
|
|
1227
|
+
});
|
|
1228
|
+
if (!res.ok) return null;
|
|
1229
|
+
const data = await res.json();
|
|
1230
|
+
return data.version ?? null;
|
|
1231
|
+
} catch {
|
|
1232
|
+
return null;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
function stripV(v) {
|
|
1236
|
+
return v.startsWith("v") ? v.slice(1) : v;
|
|
1237
|
+
}
|
|
1238
|
+
function isNewer(local, remote) {
|
|
1239
|
+
const a = stripV(local).split(".").map(Number);
|
|
1240
|
+
const b = stripV(remote).split(".").map(Number);
|
|
1241
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
1242
|
+
const av = a[i] ?? 0;
|
|
1243
|
+
const bv = b[i] ?? 0;
|
|
1244
|
+
if (av < bv) return true;
|
|
1245
|
+
if (av > bv) return false;
|
|
1246
|
+
}
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
async function checkForUpdate(force = false) {
|
|
1250
|
+
const localVersion = await readLocalVersion();
|
|
1251
|
+
if (!localVersion) return { hasUpdate: false, localVersion: null, latestVersion: null };
|
|
1252
|
+
if (!force) {
|
|
1253
|
+
const cached = await readCache();
|
|
1254
|
+
if (cached) {
|
|
1255
|
+
return { hasUpdate: cached.hasUpdate, localVersion, latestVersion: cached.latestVersion };
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
const latestVersion = await fetchLatestVersion();
|
|
1259
|
+
if (!latestVersion) {
|
|
1260
|
+
return { hasUpdate: false, localVersion, latestVersion: null };
|
|
1261
|
+
}
|
|
1262
|
+
const hasUpdate = isNewer(localVersion, latestVersion);
|
|
1263
|
+
await writeCache({ checkedAt: Date.now(), latestVersion, hasUpdate });
|
|
1264
|
+
return { hasUpdate, localVersion, latestVersion };
|
|
1265
|
+
}
|
|
1266
|
+
async function isGitRepo() {
|
|
1267
|
+
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
1268
|
+
while (true) {
|
|
1269
|
+
try {
|
|
1270
|
+
await access(join3(dir, ".git"));
|
|
1271
|
+
return true;
|
|
1272
|
+
} catch {
|
|
1273
|
+
}
|
|
1274
|
+
const parent = dirname2(dir);
|
|
1275
|
+
if (parent === dir) break;
|
|
1276
|
+
dir = parent;
|
|
1277
|
+
}
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
var CACHE_TTL_MS, NPM_REGISTRY;
|
|
1281
|
+
var init_update_check = __esm({
|
|
1282
|
+
"src/util/update-check.ts"() {
|
|
1283
|
+
"use strict";
|
|
1284
|
+
CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
1285
|
+
NPM_REGISTRY = "https://registry.npmjs.org/kimiflare/latest";
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1121
1289
|
// src/agent/compact.ts
|
|
1122
1290
|
function indexOfNthUserFromEnd(messages, n) {
|
|
1123
1291
|
let seen = 0;
|
|
@@ -1530,7 +1698,7 @@ import { useEffect, useState } from "react";
|
|
|
1530
1698
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
1531
1699
|
import Spinner3 from "ink-spinner";
|
|
1532
1700
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1533
|
-
function StatusBar({ model, usage, thinking, turnStartedAt, theme, mode, effort, contextLimit }) {
|
|
1701
|
+
function StatusBar({ model, usage, thinking, turnStartedAt, theme, mode, effort, contextLimit, hasUpdate, latestVersion }) {
|
|
1534
1702
|
const [now, setNow] = useState(Date.now());
|
|
1535
1703
|
const modeColor = mode === "plan" ? theme.modeBadge.plan : mode === "auto" ? theme.modeBadge.auto : theme.modeBadge.edit;
|
|
1536
1704
|
const warn = usage && usage.prompt_tokens / contextLimit >= 0.8;
|
|
@@ -1564,6 +1732,12 @@ function StatusBar({ model, usage, thinking, turnStartedAt, theme, mode, effort,
|
|
|
1564
1732
|
warn ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
|
|
1565
1733
|
" \xB7 ",
|
|
1566
1734
|
"/compact recommended"
|
|
1735
|
+
] }) : null,
|
|
1736
|
+
hasUpdate ? /* @__PURE__ */ jsxs5(Text5, { color: theme.warn, bold: true, children: [
|
|
1737
|
+
" \xB7 ",
|
|
1738
|
+
"update available",
|
|
1739
|
+
latestVersion ? ` \u2192 ${latestVersion}` : "",
|
|
1740
|
+
" \xB7 run /update"
|
|
1567
1741
|
] }) : null
|
|
1568
1742
|
] })
|
|
1569
1743
|
] });
|
|
@@ -1637,10 +1811,16 @@ var init_permission = __esm({
|
|
|
1637
1811
|
});
|
|
1638
1812
|
|
|
1639
1813
|
// src/ui/resume-picker.tsx
|
|
1640
|
-
import {
|
|
1814
|
+
import { useState as useState2 } from "react";
|
|
1815
|
+
import { Box as Box7, Text as Text7, useWindowSize } from "ink";
|
|
1641
1816
|
import SelectInput2 from "ink-select-input";
|
|
1642
1817
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1643
1818
|
function ResumePicker({ sessions, onPick, theme }) {
|
|
1819
|
+
const { rows } = useWindowSize();
|
|
1820
|
+
const [page, setPage] = useState2(0);
|
|
1821
|
+
const pageSize = Math.max(MIN_PAGE_SIZE, rows - HEADER_ROWS - FOOTER_ROWS);
|
|
1822
|
+
const totalPages = Math.max(1, Math.ceil(sessions.length / pageSize));
|
|
1823
|
+
const safePage = Math.min(page, totalPages - 1);
|
|
1644
1824
|
if (sessions.length === 0) {
|
|
1645
1825
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1646
1826
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
|
|
@@ -1654,20 +1834,39 @@ function ResumePicker({ sessions, onPick, theme }) {
|
|
|
1654
1834
|
) })
|
|
1655
1835
|
] });
|
|
1656
1836
|
}
|
|
1657
|
-
const
|
|
1837
|
+
const start = safePage * pageSize;
|
|
1838
|
+
const end = Math.min(start + pageSize, sessions.length);
|
|
1839
|
+
const pageSessions = sessions.slice(start, end);
|
|
1840
|
+
const items = pageSessions.map((s) => ({
|
|
1658
1841
|
label: `${formatDate(s.updatedAt)} \xB7 ${s.messageCount} msgs \xB7 ${s.firstPrompt}`,
|
|
1659
1842
|
value: s.id
|
|
1660
1843
|
}));
|
|
1844
|
+
if (safePage > 0) {
|
|
1845
|
+
items.push({ label: "\u2190 previous page", value: "__prev__" });
|
|
1846
|
+
}
|
|
1847
|
+
if (safePage < totalPages - 1) {
|
|
1848
|
+
items.push({ label: "\u2192 next page", value: "__next__" });
|
|
1849
|
+
}
|
|
1661
1850
|
items.push({ label: "(cancel)", value: "__cancel__" });
|
|
1662
1851
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
1663
1852
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: "Resume a session" }),
|
|
1664
|
-
/* @__PURE__ */
|
|
1853
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1854
|
+
"Arrow keys to select, Enter to confirm. Page ",
|
|
1855
|
+
safePage + 1,
|
|
1856
|
+
" of ",
|
|
1857
|
+
totalPages,
|
|
1858
|
+
" (",
|
|
1859
|
+
sessions.length,
|
|
1860
|
+
" total)"
|
|
1861
|
+
] }),
|
|
1665
1862
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(
|
|
1666
1863
|
SelectInput2,
|
|
1667
1864
|
{
|
|
1668
1865
|
items,
|
|
1669
1866
|
onSelect: (item) => {
|
|
1670
1867
|
if (item.value === "__cancel__") return onPick(null);
|
|
1868
|
+
if (item.value === "__prev__") return setPage((p) => Math.max(0, p - 1));
|
|
1869
|
+
if (item.value === "__next__") return setPage((p) => Math.min(totalPages - 1, p + 1));
|
|
1671
1870
|
const picked = sessions.find((s) => s.id === item.value) ?? null;
|
|
1672
1871
|
onPick(picked);
|
|
1673
1872
|
}
|
|
@@ -1688,19 +1887,70 @@ function formatDate(iso) {
|
|
|
1688
1887
|
return iso;
|
|
1689
1888
|
}
|
|
1690
1889
|
}
|
|
1890
|
+
var HEADER_ROWS, FOOTER_ROWS, MIN_PAGE_SIZE;
|
|
1691
1891
|
var init_resume_picker = __esm({
|
|
1692
1892
|
"src/ui/resume-picker.tsx"() {
|
|
1693
1893
|
"use strict";
|
|
1894
|
+
HEADER_ROWS = 5;
|
|
1895
|
+
FOOTER_ROWS = 2;
|
|
1896
|
+
MIN_PAGE_SIZE = 5;
|
|
1694
1897
|
}
|
|
1695
1898
|
});
|
|
1696
1899
|
|
|
1697
|
-
// src/ui/
|
|
1698
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1900
|
+
// src/ui/theme-picker.tsx
|
|
1699
1901
|
import { Box as Box8, Text as Text8 } from "ink";
|
|
1700
|
-
import
|
|
1902
|
+
import SelectInput3 from "ink-select-input";
|
|
1701
1903
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1904
|
+
function ThemePicker({ themes, current, onPick }) {
|
|
1905
|
+
const items = themes.map((t) => ({
|
|
1906
|
+
label: t.label,
|
|
1907
|
+
value: t.name,
|
|
1908
|
+
key: t.name
|
|
1909
|
+
}));
|
|
1910
|
+
items.push({ label: "(cancel)", value: "__cancel__", key: "__cancel__" });
|
|
1911
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
|
|
1912
|
+
/* @__PURE__ */ jsx8(Text8, { color: current.accent, bold: true, children: "Pick a theme" }),
|
|
1913
|
+
/* @__PURE__ */ jsx8(Text8, { color: current.info.color, dimColor: current.info.dim, children: "Arrow keys to preview, Enter to confirm." }),
|
|
1914
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(
|
|
1915
|
+
SelectInput3,
|
|
1916
|
+
{
|
|
1917
|
+
items,
|
|
1918
|
+
onHighlight: (item) => {
|
|
1919
|
+
if (item.value !== "__cancel__") {
|
|
1920
|
+
const highlighted = themes.find((t) => t.name === item.value);
|
|
1921
|
+
if (highlighted) onPick(highlighted);
|
|
1922
|
+
}
|
|
1923
|
+
},
|
|
1924
|
+
onSelect: (item) => {
|
|
1925
|
+
if (item.value === "__cancel__") return onPick(null);
|
|
1926
|
+
const picked = themes.find((t) => t.name === item.value) ?? null;
|
|
1927
|
+
onPick(picked);
|
|
1928
|
+
},
|
|
1929
|
+
itemComponent: ({ label, isSelected }) => {
|
|
1930
|
+
const theme = themes.find((t) => t.label === label);
|
|
1931
|
+
const color = theme?.accent ?? current.accent;
|
|
1932
|
+
return /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { color, bold: isSelected, dimColor: !isSelected, children: [
|
|
1933
|
+
isSelected ? "\u203A " : " ",
|
|
1934
|
+
label
|
|
1935
|
+
] }) });
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
) })
|
|
1939
|
+
] });
|
|
1940
|
+
}
|
|
1941
|
+
var init_theme_picker = __esm({
|
|
1942
|
+
"src/ui/theme-picker.tsx"() {
|
|
1943
|
+
"use strict";
|
|
1944
|
+
}
|
|
1945
|
+
});
|
|
1946
|
+
|
|
1947
|
+
// src/ui/task-list.tsx
|
|
1948
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
1949
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1950
|
+
import Spinner4 from "ink-spinner";
|
|
1951
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1702
1952
|
function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
1703
|
-
const [now, setNow] =
|
|
1953
|
+
const [now, setNow] = useState3(Date.now());
|
|
1704
1954
|
useEffect2(() => {
|
|
1705
1955
|
if (startedAt === null) return;
|
|
1706
1956
|
const allDone2 = tasks.length > 0 && tasks.every((t) => t.status === "completed");
|
|
@@ -1718,18 +1968,18 @@ function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
|
1718
1968
|
const headerStats = [elapsed, tokensDelta > 0 ? `\u2191 ${formatTokens(tokensDelta)} tokens` : null].filter(Boolean).join(" \xB7 ");
|
|
1719
1969
|
const visibleTasks = tasks.slice(0, MAX_VISIBLE);
|
|
1720
1970
|
const hiddenPending = Math.max(0, tasks.length - visibleTasks.length);
|
|
1721
|
-
return /* @__PURE__ */
|
|
1722
|
-
/* @__PURE__ */
|
|
1723
|
-
/* @__PURE__ */
|
|
1724
|
-
headerStats && /* @__PURE__ */
|
|
1971
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
|
|
1972
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
1973
|
+
/* @__PURE__ */ jsx9(Text9, { color: allDone ? "green" : theme.accent, bold: true, children: header }),
|
|
1974
|
+
headerStats && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1725
1975
|
" ",
|
|
1726
1976
|
"(",
|
|
1727
1977
|
headerStats,
|
|
1728
1978
|
")"
|
|
1729
1979
|
] })
|
|
1730
1980
|
] }),
|
|
1731
|
-
visibleTasks.map((t) => /* @__PURE__ */
|
|
1732
|
-
hiddenPending > 0 && /* @__PURE__ */
|
|
1981
|
+
visibleTasks.map((t) => /* @__PURE__ */ jsx9(TaskRow, { task: t, theme }, t.id)),
|
|
1982
|
+
hiddenPending > 0 && /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1733
1983
|
" ",
|
|
1734
1984
|
"\u2026 +",
|
|
1735
1985
|
hiddenPending,
|
|
@@ -1739,21 +1989,21 @@ function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
|
1739
1989
|
}
|
|
1740
1990
|
function TaskRow({ task, theme }) {
|
|
1741
1991
|
if (task.status === "completed") {
|
|
1742
|
-
return /* @__PURE__ */
|
|
1992
|
+
return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1743
1993
|
" ",
|
|
1744
1994
|
"\u2713 ",
|
|
1745
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsx9(Text9, { strikethrough: true, children: task.title })
|
|
1746
1996
|
] });
|
|
1747
1997
|
}
|
|
1748
1998
|
if (task.status === "in_progress") {
|
|
1749
|
-
return /* @__PURE__ */
|
|
1999
|
+
return /* @__PURE__ */ jsxs9(Text9, { color: theme.accent, bold: true, children: [
|
|
1750
2000
|
" ",
|
|
1751
|
-
/* @__PURE__ */
|
|
2001
|
+
/* @__PURE__ */ jsx9(Spinner4, { type: "dots" }),
|
|
1752
2002
|
" ",
|
|
1753
2003
|
task.title
|
|
1754
2004
|
] });
|
|
1755
2005
|
}
|
|
1756
|
-
return /* @__PURE__ */
|
|
2006
|
+
return /* @__PURE__ */ jsxs9(Text9, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
1757
2007
|
" ",
|
|
1758
2008
|
"\u2610 ",
|
|
1759
2009
|
task.title
|
|
@@ -2299,9 +2549,9 @@ var init_source = __esm({
|
|
|
2299
2549
|
});
|
|
2300
2550
|
|
|
2301
2551
|
// src/ui/text-input.tsx
|
|
2302
|
-
import { useState as
|
|
2303
|
-
import { Text as
|
|
2304
|
-
import { jsx as
|
|
2552
|
+
import { useState as useState4, useEffect as useEffect3, useRef } from "react";
|
|
2553
|
+
import { Text as Text10, useInput } from "ink";
|
|
2554
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2305
2555
|
function shouldTreatAsPaste(input) {
|
|
2306
2556
|
if (input.length >= PASTE_CHAR_THRESHOLD) return true;
|
|
2307
2557
|
const newlines = (input.match(/\n/g) ?? []).length;
|
|
@@ -2334,7 +2584,7 @@ function CustomTextInput({
|
|
|
2334
2584
|
mask,
|
|
2335
2585
|
enablePaste = false
|
|
2336
2586
|
}) {
|
|
2337
|
-
const [cursorOffset, setCursorOffset] =
|
|
2587
|
+
const [cursorOffset, setCursorOffset] = useState4(value.length);
|
|
2338
2588
|
const pastesRef = useRef(/* @__PURE__ */ new Map());
|
|
2339
2589
|
useEffect3(() => {
|
|
2340
2590
|
if (!focus) return;
|
|
@@ -2478,7 +2728,7 @@ function CustomTextInput({
|
|
|
2478
2728
|
} else if (cursorOffset === displayValue.length) {
|
|
2479
2729
|
renderedValue += source_default.inverse(" ");
|
|
2480
2730
|
}
|
|
2481
|
-
return /* @__PURE__ */
|
|
2731
|
+
return /* @__PURE__ */ jsx10(Text10, { children: renderedValue });
|
|
2482
2732
|
}
|
|
2483
2733
|
function findPasteTokenEndingAt(value, pos, pastes) {
|
|
2484
2734
|
if (pos <= 0 || value[pos - 1] !== "]") return -1;
|
|
@@ -2499,128 +2749,16 @@ var init_text_input = __esm({
|
|
|
2499
2749
|
}
|
|
2500
2750
|
});
|
|
2501
2751
|
|
|
2502
|
-
// src/util/update-check.ts
|
|
2503
|
-
import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir3, access } from "fs/promises";
|
|
2504
|
-
import { homedir as homedir4 } from "os";
|
|
2505
|
-
import { join as join3, dirname as dirname2 } from "path";
|
|
2506
|
-
import { fileURLToPath } from "url";
|
|
2507
|
-
function cachePath() {
|
|
2508
|
-
const xdg = process.env.XDG_CONFIG_HOME || join3(homedir4(), ".config");
|
|
2509
|
-
return join3(xdg, "kimiflare", "update-check.json");
|
|
2510
|
-
}
|
|
2511
|
-
async function findPackageJson(startDir) {
|
|
2512
|
-
let dir = startDir;
|
|
2513
|
-
while (true) {
|
|
2514
|
-
const candidate = join3(dir, "package.json");
|
|
2515
|
-
try {
|
|
2516
|
-
const raw = await readFile6(candidate, "utf8");
|
|
2517
|
-
const parsed = JSON.parse(raw);
|
|
2518
|
-
if (parsed.name === "kimiflare" && parsed.version) {
|
|
2519
|
-
return { path: candidate, version: parsed.version };
|
|
2520
|
-
}
|
|
2521
|
-
} catch {
|
|
2522
|
-
}
|
|
2523
|
-
const parent = dirname2(dir);
|
|
2524
|
-
if (parent === dir) break;
|
|
2525
|
-
dir = parent;
|
|
2526
|
-
}
|
|
2527
|
-
return null;
|
|
2528
|
-
}
|
|
2529
|
-
async function readLocalVersion() {
|
|
2530
|
-
const here = dirname2(fileURLToPath(import.meta.url));
|
|
2531
|
-
const found = await findPackageJson(here);
|
|
2532
|
-
return found?.version ?? null;
|
|
2533
|
-
}
|
|
2534
|
-
async function readCache() {
|
|
2535
|
-
try {
|
|
2536
|
-
const raw = await readFile6(cachePath(), "utf8");
|
|
2537
|
-
const parsed = JSON.parse(raw);
|
|
2538
|
-
if (Date.now() - parsed.checkedAt < CACHE_TTL_MS) {
|
|
2539
|
-
return parsed;
|
|
2540
|
-
}
|
|
2541
|
-
} catch {
|
|
2542
|
-
}
|
|
2543
|
-
return null;
|
|
2544
|
-
}
|
|
2545
|
-
async function writeCache(entry) {
|
|
2546
|
-
const p = cachePath();
|
|
2547
|
-
await mkdir3(dirname2(p), { recursive: true });
|
|
2548
|
-
await writeFile4(p, JSON.stringify(entry), "utf8");
|
|
2549
|
-
}
|
|
2550
|
-
async function fetchLatestVersion() {
|
|
2551
|
-
try {
|
|
2552
|
-
const res = await fetch(NPM_REGISTRY, {
|
|
2553
|
-
headers: { "User-Agent": "kimiflare-update-checker", Accept: "application/json" }
|
|
2554
|
-
});
|
|
2555
|
-
if (!res.ok) return null;
|
|
2556
|
-
const data = await res.json();
|
|
2557
|
-
return data.version ?? null;
|
|
2558
|
-
} catch {
|
|
2559
|
-
return null;
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
function stripV(v) {
|
|
2563
|
-
return v.startsWith("v") ? v.slice(1) : v;
|
|
2564
|
-
}
|
|
2565
|
-
function isNewer(local, remote) {
|
|
2566
|
-
const a = stripV(local).split(".").map(Number);
|
|
2567
|
-
const b = stripV(remote).split(".").map(Number);
|
|
2568
|
-
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
2569
|
-
const av = a[i] ?? 0;
|
|
2570
|
-
const bv = b[i] ?? 0;
|
|
2571
|
-
if (av < bv) return true;
|
|
2572
|
-
if (av > bv) return false;
|
|
2573
|
-
}
|
|
2574
|
-
return false;
|
|
2575
|
-
}
|
|
2576
|
-
async function checkForUpdate() {
|
|
2577
|
-
const localVersion = await readLocalVersion();
|
|
2578
|
-
if (!localVersion) return { hasUpdate: false, localVersion: null, latestVersion: null };
|
|
2579
|
-
const cached = await readCache();
|
|
2580
|
-
if (cached) {
|
|
2581
|
-
return { hasUpdate: cached.hasUpdate, localVersion, latestVersion: cached.latestVersion };
|
|
2582
|
-
}
|
|
2583
|
-
const latestVersion = await fetchLatestVersion();
|
|
2584
|
-
if (!latestVersion) {
|
|
2585
|
-
return { hasUpdate: false, localVersion, latestVersion: null };
|
|
2586
|
-
}
|
|
2587
|
-
const hasUpdate = isNewer(localVersion, latestVersion);
|
|
2588
|
-
await writeCache({ checkedAt: Date.now(), latestVersion, hasUpdate });
|
|
2589
|
-
return { hasUpdate, localVersion, latestVersion };
|
|
2590
|
-
}
|
|
2591
|
-
async function isGitRepo() {
|
|
2592
|
-
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
2593
|
-
while (true) {
|
|
2594
|
-
try {
|
|
2595
|
-
await access(join3(dir, ".git"));
|
|
2596
|
-
return true;
|
|
2597
|
-
} catch {
|
|
2598
|
-
}
|
|
2599
|
-
const parent = dirname2(dir);
|
|
2600
|
-
if (parent === dir) break;
|
|
2601
|
-
dir = parent;
|
|
2602
|
-
}
|
|
2603
|
-
return false;
|
|
2604
|
-
}
|
|
2605
|
-
var CACHE_TTL_MS, NPM_REGISTRY;
|
|
2606
|
-
var init_update_check = __esm({
|
|
2607
|
-
"src/util/update-check.ts"() {
|
|
2608
|
-
"use strict";
|
|
2609
|
-
CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
2610
|
-
NPM_REGISTRY = "https://registry.npmjs.org/kimiflare/latest";
|
|
2611
|
-
}
|
|
2612
|
-
});
|
|
2613
|
-
|
|
2614
2752
|
// src/ui/onboarding.tsx
|
|
2615
|
-
import { useState as
|
|
2616
|
-
import { Box as
|
|
2617
|
-
import { Fragment, jsx as
|
|
2753
|
+
import { useState as useState5 } from "react";
|
|
2754
|
+
import { Box as Box10, Text as Text11 } from "ink";
|
|
2755
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2618
2756
|
function Onboarding({ onDone }) {
|
|
2619
|
-
const [step, setStep] =
|
|
2620
|
-
const [accountId, setAccountId] =
|
|
2621
|
-
const [apiToken, setApiToken] =
|
|
2622
|
-
const [model, setModel] =
|
|
2623
|
-
const [savedPath, setSavedPath] =
|
|
2757
|
+
const [step, setStep] = useState5("accountId");
|
|
2758
|
+
const [accountId, setAccountId] = useState5("");
|
|
2759
|
+
const [apiToken, setApiToken] = useState5("");
|
|
2760
|
+
const [model, setModel] = useState5(DEFAULT_MODEL);
|
|
2761
|
+
const [savedPath, setSavedPath] = useState5(null);
|
|
2624
2762
|
const stepIndex = STEPS.indexOf(step) + 1;
|
|
2625
2763
|
const handleAccountIdSubmit = (value) => {
|
|
2626
2764
|
const trimmed = value.trim();
|
|
@@ -2649,26 +2787,26 @@ function Onboarding({ onDone }) {
|
|
|
2649
2787
|
setSavedPath(`error: ${e.message}`);
|
|
2650
2788
|
}
|
|
2651
2789
|
};
|
|
2652
|
-
return /* @__PURE__ */
|
|
2653
|
-
/* @__PURE__ */
|
|
2654
|
-
/* @__PURE__ */
|
|
2655
|
-
/* @__PURE__ */
|
|
2790
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
|
|
2791
|
+
/* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
|
|
2792
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, color: "cyan", children: "kimiflare" }),
|
|
2793
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", dimColor: true, children: [
|
|
2656
2794
|
" ",
|
|
2657
2795
|
"Terminal coding agent"
|
|
2658
2796
|
] })
|
|
2659
2797
|
] }),
|
|
2660
|
-
/* @__PURE__ */
|
|
2798
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", dimColor: true, children: [
|
|
2661
2799
|
"Step ",
|
|
2662
2800
|
stepIndex,
|
|
2663
2801
|
" of ",
|
|
2664
2802
|
STEPS.length
|
|
2665
2803
|
] }),
|
|
2666
|
-
/* @__PURE__ */
|
|
2667
|
-
step === "accountId" && /* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
2671
|
-
/* @__PURE__ */
|
|
2804
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
2805
|
+
step === "accountId" && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
2806
|
+
/* @__PURE__ */ jsx11(Text11, { children: "Enter your Cloudflare Account ID" }),
|
|
2807
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2808
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "\u203A " }),
|
|
2809
|
+
/* @__PURE__ */ jsx11(
|
|
2672
2810
|
CustomTextInput,
|
|
2673
2811
|
{
|
|
2674
2812
|
value: accountId,
|
|
@@ -2678,12 +2816,12 @@ function Onboarding({ onDone }) {
|
|
|
2678
2816
|
)
|
|
2679
2817
|
] })
|
|
2680
2818
|
] }),
|
|
2681
|
-
step === "apiToken" && /* @__PURE__ */
|
|
2682
|
-
/* @__PURE__ */
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
/* @__PURE__ */
|
|
2819
|
+
step === "apiToken" && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
2820
|
+
/* @__PURE__ */ jsx11(Text11, { children: "Enter your Cloudflare API Token" }),
|
|
2821
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", dimColor: true, children: "Create one at https://dash.cloudflare.com/profile/api-tokens" }),
|
|
2822
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2823
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "\u203A " }),
|
|
2824
|
+
/* @__PURE__ */ jsx11(
|
|
2687
2825
|
CustomTextInput,
|
|
2688
2826
|
{
|
|
2689
2827
|
value: apiToken,
|
|
@@ -2694,15 +2832,15 @@ function Onboarding({ onDone }) {
|
|
|
2694
2832
|
)
|
|
2695
2833
|
] })
|
|
2696
2834
|
] }),
|
|
2697
|
-
step === "model" && /* @__PURE__ */
|
|
2698
|
-
/* @__PURE__ */
|
|
2699
|
-
/* @__PURE__ */
|
|
2835
|
+
step === "model" && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
2836
|
+
/* @__PURE__ */ jsx11(Text11, { children: "Model ID (press Enter for default)" }),
|
|
2837
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", dimColor: true, children: [
|
|
2700
2838
|
"default: ",
|
|
2701
2839
|
DEFAULT_MODEL
|
|
2702
2840
|
] }),
|
|
2703
|
-
/* @__PURE__ */
|
|
2704
|
-
/* @__PURE__ */
|
|
2705
|
-
/* @__PURE__ */
|
|
2841
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2842
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "\u203A " }),
|
|
2843
|
+
/* @__PURE__ */ jsx11(
|
|
2706
2844
|
CustomTextInput,
|
|
2707
2845
|
{
|
|
2708
2846
|
value: model,
|
|
@@ -2712,10 +2850,10 @@ function Onboarding({ onDone }) {
|
|
|
2712
2850
|
)
|
|
2713
2851
|
] })
|
|
2714
2852
|
] }),
|
|
2715
|
-
step === "confirm" && /* @__PURE__ */
|
|
2716
|
-
/* @__PURE__ */
|
|
2717
|
-
/* @__PURE__ */
|
|
2718
|
-
|
|
2853
|
+
step === "confirm" && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
2854
|
+
/* @__PURE__ */ jsx11(Text11, { children: "Ready to save configuration" }),
|
|
2855
|
+
/* @__PURE__ */ jsxs10(
|
|
2856
|
+
Box10,
|
|
2719
2857
|
{
|
|
2720
2858
|
flexDirection: "column",
|
|
2721
2859
|
marginTop: 1,
|
|
@@ -2724,25 +2862,25 @@ function Onboarding({ onDone }) {
|
|
|
2724
2862
|
borderColor: "gray",
|
|
2725
2863
|
paddingX: 1,
|
|
2726
2864
|
children: [
|
|
2727
|
-
/* @__PURE__ */
|
|
2865
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
|
|
2728
2866
|
"Account ID: ",
|
|
2729
2867
|
accountId
|
|
2730
2868
|
] }),
|
|
2731
|
-
/* @__PURE__ */
|
|
2869
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
|
|
2732
2870
|
"API Token: ",
|
|
2733
2871
|
"\u2022".repeat(apiToken.length)
|
|
2734
2872
|
] }),
|
|
2735
|
-
/* @__PURE__ */
|
|
2873
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
|
|
2736
2874
|
"Model: ",
|
|
2737
2875
|
model
|
|
2738
2876
|
] })
|
|
2739
2877
|
]
|
|
2740
2878
|
}
|
|
2741
2879
|
),
|
|
2742
|
-
/* @__PURE__ */
|
|
2743
|
-
/* @__PURE__ */
|
|
2744
|
-
/* @__PURE__ */
|
|
2745
|
-
/* @__PURE__ */
|
|
2880
|
+
/* @__PURE__ */ jsx11(Text11, { children: "Press Enter to confirm, or Ctrl+C to cancel" }),
|
|
2881
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2882
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "\u203A " }),
|
|
2883
|
+
/* @__PURE__ */ jsx11(
|
|
2746
2884
|
CustomTextInput,
|
|
2747
2885
|
{
|
|
2748
2886
|
value: "",
|
|
@@ -2753,7 +2891,7 @@ function Onboarding({ onDone }) {
|
|
|
2753
2891
|
)
|
|
2754
2892
|
] })
|
|
2755
2893
|
] }),
|
|
2756
|
-
savedPath && /* @__PURE__ */
|
|
2894
|
+
savedPath && /* @__PURE__ */ jsxs10(Text11, { color: "green", children: [
|
|
2757
2895
|
"Config saved to ",
|
|
2758
2896
|
savedPath
|
|
2759
2897
|
] })
|
|
@@ -2771,26 +2909,26 @@ var init_onboarding = __esm({
|
|
|
2771
2909
|
});
|
|
2772
2910
|
|
|
2773
2911
|
// src/ui/welcome.tsx
|
|
2774
|
-
import { Box as
|
|
2775
|
-
import { jsx as
|
|
2912
|
+
import { Box as Box11, Text as Text12 } from "ink";
|
|
2913
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2776
2914
|
function Welcome({ theme }) {
|
|
2777
|
-
return /* @__PURE__ */
|
|
2778
|
-
/* @__PURE__ */
|
|
2779
|
-
/* @__PURE__ */
|
|
2780
|
-
/* @__PURE__ */
|
|
2915
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
|
|
2916
|
+
/* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
|
|
2917
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, color: theme.accent, children: "kimiflare" }),
|
|
2918
|
+
/* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
2781
2919
|
" ",
|
|
2782
2920
|
"Ready when you are."
|
|
2783
2921
|
] })
|
|
2784
2922
|
] }),
|
|
2785
|
-
/* @__PURE__ */
|
|
2786
|
-
/* @__PURE__ */
|
|
2923
|
+
/* @__PURE__ */ jsx12(Box11, { flexDirection: "column", children: SUGGESTIONS.map((s, i) => /* @__PURE__ */ jsxs11(Box11, { children: [
|
|
2924
|
+
/* @__PURE__ */ jsxs11(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
2787
2925
|
" ",
|
|
2788
2926
|
"\u203A",
|
|
2789
2927
|
" "
|
|
2790
2928
|
] }),
|
|
2791
|
-
/* @__PURE__ */
|
|
2929
|
+
/* @__PURE__ */ jsx12(Text12, { color: theme.user, children: s })
|
|
2792
2930
|
] }, i)) }),
|
|
2793
|
-
/* @__PURE__ */
|
|
2931
|
+
/* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { color: theme.info.color, dimColor: theme.info.dim, children: "Type a message or /help for commands \xB7 ctrl-c to exit \xB7 shift+tab to cycle modes" }) })
|
|
2794
2932
|
] });
|
|
2795
2933
|
}
|
|
2796
2934
|
var SUGGESTIONS;
|
|
@@ -2813,7 +2951,10 @@ function resolveTheme(name) {
|
|
|
2813
2951
|
function themeNames() {
|
|
2814
2952
|
return Object.keys(THEMES);
|
|
2815
2953
|
}
|
|
2816
|
-
|
|
2954
|
+
function themeList() {
|
|
2955
|
+
return Object.values(THEMES);
|
|
2956
|
+
}
|
|
2957
|
+
var dark, light, highContrast, dracula, nord, oneDark, monokai, solarizedDark, solarizedLight, tokyoNight, gruvboxDark, gruvboxLight, catppuccinMocha, rosePine, THEMES, DEFAULT_THEME_NAME;
|
|
2817
2958
|
var init_theme = __esm({
|
|
2818
2959
|
"src/ui/theme.ts"() {
|
|
2819
2960
|
"use strict";
|
|
@@ -2865,10 +3006,197 @@ var init_theme = __esm({
|
|
|
2865
3006
|
accent: "cyanBright",
|
|
2866
3007
|
modeBadge: { plan: "blueBright", auto: "greenBright", edit: "cyanBright" }
|
|
2867
3008
|
};
|
|
3009
|
+
dracula = {
|
|
3010
|
+
name: "dracula",
|
|
3011
|
+
label: "dracula (purple & cyan, popular dark)",
|
|
3012
|
+
user: "cyanBright",
|
|
3013
|
+
assistant: void 0,
|
|
3014
|
+
reasoning: { color: "magenta", dim: true },
|
|
3015
|
+
info: { color: "gray", dim: true },
|
|
3016
|
+
error: "redBright",
|
|
3017
|
+
warn: "yellowBright",
|
|
3018
|
+
tool: "magentaBright",
|
|
3019
|
+
spinner: "cyanBright",
|
|
3020
|
+
permission: "yellowBright",
|
|
3021
|
+
queue: { color: "gray", dim: true },
|
|
3022
|
+
accent: "magentaBright",
|
|
3023
|
+
modeBadge: { plan: "blueBright", auto: "greenBright", edit: "magentaBright" }
|
|
3024
|
+
};
|
|
3025
|
+
nord = {
|
|
3026
|
+
name: "nord",
|
|
3027
|
+
label: "nord (arctic blue & frost, calm dark)",
|
|
3028
|
+
user: "cyan",
|
|
3029
|
+
assistant: void 0,
|
|
3030
|
+
reasoning: { color: "blue", dim: true },
|
|
3031
|
+
info: { color: "blue", dim: true },
|
|
3032
|
+
error: "red",
|
|
3033
|
+
warn: "yellow",
|
|
3034
|
+
tool: "cyan",
|
|
3035
|
+
spinner: "cyan",
|
|
3036
|
+
permission: "yellow",
|
|
3037
|
+
queue: { color: "blue", dim: true },
|
|
3038
|
+
accent: "cyan",
|
|
3039
|
+
modeBadge: { plan: "blue", auto: "green", edit: "cyan" }
|
|
3040
|
+
};
|
|
3041
|
+
oneDark = {
|
|
3042
|
+
name: "one-dark",
|
|
3043
|
+
label: "one-dark (Atom's classic dark)",
|
|
3044
|
+
user: "cyan",
|
|
3045
|
+
assistant: void 0,
|
|
3046
|
+
reasoning: { color: "gray", dim: true },
|
|
3047
|
+
info: { color: "gray", dim: true },
|
|
3048
|
+
error: "red",
|
|
3049
|
+
warn: "yellow",
|
|
3050
|
+
tool: "blue",
|
|
3051
|
+
spinner: "cyan",
|
|
3052
|
+
permission: "yellow",
|
|
3053
|
+
queue: { color: "gray", dim: true },
|
|
3054
|
+
accent: "blue",
|
|
3055
|
+
modeBadge: { plan: "blue", auto: "green", edit: "cyan" }
|
|
3056
|
+
};
|
|
3057
|
+
monokai = {
|
|
3058
|
+
name: "monokai",
|
|
3059
|
+
label: "monokai (vibrant magenta & yellow)",
|
|
3060
|
+
user: "magentaBright",
|
|
3061
|
+
assistant: void 0,
|
|
3062
|
+
reasoning: { color: "gray", dim: true },
|
|
3063
|
+
info: { color: "gray", dim: true },
|
|
3064
|
+
error: "redBright",
|
|
3065
|
+
warn: "yellowBright",
|
|
3066
|
+
tool: "cyanBright",
|
|
3067
|
+
spinner: "yellowBright",
|
|
3068
|
+
permission: "yellowBright",
|
|
3069
|
+
queue: { color: "gray", dim: true },
|
|
3070
|
+
accent: "magentaBright",
|
|
3071
|
+
modeBadge: { plan: "blueBright", auto: "greenBright", edit: "magentaBright" }
|
|
3072
|
+
};
|
|
3073
|
+
solarizedDark = {
|
|
3074
|
+
name: "solarized-dark",
|
|
3075
|
+
label: "solarized-dark (muted blue & yellow)",
|
|
3076
|
+
user: "cyan",
|
|
3077
|
+
assistant: void 0,
|
|
3078
|
+
reasoning: { color: "blue", dim: true },
|
|
3079
|
+
info: { color: "blue", dim: true },
|
|
3080
|
+
error: "red",
|
|
3081
|
+
warn: "yellow",
|
|
3082
|
+
tool: "cyan",
|
|
3083
|
+
spinner: "yellow",
|
|
3084
|
+
permission: "yellow",
|
|
3085
|
+
queue: { color: "blue", dim: true },
|
|
3086
|
+
accent: "cyan",
|
|
3087
|
+
modeBadge: { plan: "blue", auto: "green", edit: "cyan" }
|
|
3088
|
+
};
|
|
3089
|
+
solarizedLight = {
|
|
3090
|
+
name: "solarized-light",
|
|
3091
|
+
label: "solarized-light (light beige & cyan)",
|
|
3092
|
+
user: "blue",
|
|
3093
|
+
assistant: void 0,
|
|
3094
|
+
reasoning: { color: "cyan", dim: false },
|
|
3095
|
+
info: { color: "cyan", dim: false },
|
|
3096
|
+
error: "red",
|
|
3097
|
+
warn: "yellow",
|
|
3098
|
+
tool: "blue",
|
|
3099
|
+
spinner: "blue",
|
|
3100
|
+
permission: "yellow",
|
|
3101
|
+
queue: { color: "cyan", dim: false },
|
|
3102
|
+
accent: "blue",
|
|
3103
|
+
modeBadge: { plan: "blue", auto: "green", edit: "blue" }
|
|
3104
|
+
};
|
|
3105
|
+
tokyoNight = {
|
|
3106
|
+
name: "tokyo-night",
|
|
3107
|
+
label: "tokyo-night (deep blue & purple)",
|
|
3108
|
+
user: "cyanBright",
|
|
3109
|
+
assistant: void 0,
|
|
3110
|
+
reasoning: { color: "blue", dim: true },
|
|
3111
|
+
info: { color: "blue", dim: true },
|
|
3112
|
+
error: "redBright",
|
|
3113
|
+
warn: "yellow",
|
|
3114
|
+
tool: "magentaBright",
|
|
3115
|
+
spinner: "cyanBright",
|
|
3116
|
+
permission: "yellow",
|
|
3117
|
+
queue: { color: "blue", dim: true },
|
|
3118
|
+
accent: "magentaBright",
|
|
3119
|
+
modeBadge: { plan: "blueBright", auto: "greenBright", edit: "magentaBright" }
|
|
3120
|
+
};
|
|
3121
|
+
gruvboxDark = {
|
|
3122
|
+
name: "gruvbox-dark",
|
|
3123
|
+
label: "gruvbox-dark (warm retro dark)",
|
|
3124
|
+
user: "yellow",
|
|
3125
|
+
assistant: void 0,
|
|
3126
|
+
reasoning: { color: "gray", dim: true },
|
|
3127
|
+
info: { color: "gray", dim: true },
|
|
3128
|
+
error: "red",
|
|
3129
|
+
warn: "yellowBright",
|
|
3130
|
+
tool: "cyan",
|
|
3131
|
+
spinner: "yellow",
|
|
3132
|
+
permission: "yellowBright",
|
|
3133
|
+
queue: { color: "gray", dim: true },
|
|
3134
|
+
accent: "yellow",
|
|
3135
|
+
modeBadge: { plan: "blue", auto: "green", edit: "yellow" }
|
|
3136
|
+
};
|
|
3137
|
+
gruvboxLight = {
|
|
3138
|
+
name: "gruvbox-light",
|
|
3139
|
+
label: "gruvbox-light (warm retro light)",
|
|
3140
|
+
user: "blue",
|
|
3141
|
+
assistant: void 0,
|
|
3142
|
+
reasoning: { color: "blackBright", dim: false },
|
|
3143
|
+
info: { color: "blackBright", dim: false },
|
|
3144
|
+
error: "red",
|
|
3145
|
+
warn: "yellow",
|
|
3146
|
+
tool: "cyan",
|
|
3147
|
+
spinner: "blue",
|
|
3148
|
+
permission: "yellow",
|
|
3149
|
+
queue: { color: "blackBright", dim: false },
|
|
3150
|
+
accent: "blue",
|
|
3151
|
+
modeBadge: { plan: "blue", auto: "green", edit: "blue" }
|
|
3152
|
+
};
|
|
3153
|
+
catppuccinMocha = {
|
|
3154
|
+
name: "catppuccin-mocha",
|
|
3155
|
+
label: "catppuccin-mocha (pastel pink & lavender)",
|
|
3156
|
+
user: "magentaBright",
|
|
3157
|
+
assistant: void 0,
|
|
3158
|
+
reasoning: { color: "gray", dim: true },
|
|
3159
|
+
info: { color: "gray", dim: true },
|
|
3160
|
+
error: "redBright",
|
|
3161
|
+
warn: "yellow",
|
|
3162
|
+
tool: "cyanBright",
|
|
3163
|
+
spinner: "cyanBright",
|
|
3164
|
+
permission: "yellow",
|
|
3165
|
+
queue: { color: "gray", dim: true },
|
|
3166
|
+
accent: "magentaBright",
|
|
3167
|
+
modeBadge: { plan: "blueBright", auto: "greenBright", edit: "magentaBright" }
|
|
3168
|
+
};
|
|
3169
|
+
rosePine = {
|
|
3170
|
+
name: "rose-pine",
|
|
3171
|
+
label: "rose-pine (soft rose & foam)",
|
|
3172
|
+
user: "magenta",
|
|
3173
|
+
assistant: void 0,
|
|
3174
|
+
reasoning: { color: "gray", dim: true },
|
|
3175
|
+
info: { color: "gray", dim: true },
|
|
3176
|
+
error: "red",
|
|
3177
|
+
warn: "yellow",
|
|
3178
|
+
tool: "cyan",
|
|
3179
|
+
spinner: "magenta",
|
|
3180
|
+
permission: "yellow",
|
|
3181
|
+
queue: { color: "gray", dim: true },
|
|
3182
|
+
accent: "magenta",
|
|
3183
|
+
modeBadge: { plan: "blue", auto: "green", edit: "magenta" }
|
|
3184
|
+
};
|
|
2868
3185
|
THEMES = {
|
|
2869
3186
|
dark,
|
|
2870
3187
|
light,
|
|
2871
|
-
"high-contrast": highContrast
|
|
3188
|
+
"high-contrast": highContrast,
|
|
3189
|
+
dracula,
|
|
3190
|
+
nord,
|
|
3191
|
+
"one-dark": oneDark,
|
|
3192
|
+
monokai,
|
|
3193
|
+
"solarized-dark": solarizedDark,
|
|
3194
|
+
"solarized-light": solarizedLight,
|
|
3195
|
+
"tokyo-night": tokyoNight,
|
|
3196
|
+
"gruvbox-dark": gruvboxDark,
|
|
3197
|
+
"gruvbox-light": gruvboxLight,
|
|
3198
|
+
"catppuccin-mocha": catppuccinMocha,
|
|
3199
|
+
"rose-pine": rosePine
|
|
2872
3200
|
};
|
|
2873
3201
|
DEFAULT_THEME_NAME = "dark";
|
|
2874
3202
|
}
|
|
@@ -2943,36 +3271,40 @@ var app_exports = {};
|
|
|
2943
3271
|
__export(app_exports, {
|
|
2944
3272
|
renderApp: () => renderApp
|
|
2945
3273
|
});
|
|
2946
|
-
import { useState as
|
|
2947
|
-
import { Box as
|
|
3274
|
+
import { useState as useState6, useRef as useRef2, useEffect as useEffect4, useCallback } from "react";
|
|
3275
|
+
import { Box as Box12, Text as Text13, useApp, useInput as useInput2, render } from "ink";
|
|
2948
3276
|
import { existsSync } from "fs";
|
|
2949
3277
|
import { join as join5 } from "path";
|
|
2950
3278
|
import { unlink } from "fs/promises";
|
|
2951
|
-
import { jsx as
|
|
2952
|
-
function App({ initialCfg }) {
|
|
3279
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3280
|
+
function App({ initialCfg, initialUpdateResult }) {
|
|
2953
3281
|
const { exit } = useApp();
|
|
2954
|
-
const [cfg, setCfg] =
|
|
2955
|
-
const [events, setEvents] =
|
|
2956
|
-
const [input, setInput] =
|
|
2957
|
-
const [busy, setBusy] =
|
|
2958
|
-
const [usage, setUsage] =
|
|
2959
|
-
const [showReasoning, setShowReasoning] =
|
|
2960
|
-
const [perm, setPerm] =
|
|
2961
|
-
const [queue, setQueue] =
|
|
2962
|
-
const [history, setHistory] =
|
|
2963
|
-
const [historyIndex, setHistoryIndex] =
|
|
2964
|
-
const [draftInput, setDraftInput] =
|
|
2965
|
-
const [mode, setMode] =
|
|
2966
|
-
const [effort, setEffort] =
|
|
3282
|
+
const [cfg, setCfg] = useState6(initialCfg);
|
|
3283
|
+
const [events, setEvents] = useState6([]);
|
|
3284
|
+
const [input, setInput] = useState6("");
|
|
3285
|
+
const [busy, setBusy] = useState6(false);
|
|
3286
|
+
const [usage, setUsage] = useState6(null);
|
|
3287
|
+
const [showReasoning, setShowReasoning] = useState6(false);
|
|
3288
|
+
const [perm, setPerm] = useState6(null);
|
|
3289
|
+
const [queue, setQueue] = useState6([]);
|
|
3290
|
+
const [history, setHistory] = useState6([]);
|
|
3291
|
+
const [historyIndex, setHistoryIndex] = useState6(-1);
|
|
3292
|
+
const [draftInput, setDraftInput] = useState6("");
|
|
3293
|
+
const [mode, setMode] = useState6("edit");
|
|
3294
|
+
const [effort, setEffort] = useState6(
|
|
2967
3295
|
initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
|
|
2968
3296
|
);
|
|
2969
|
-
const [theme, setTheme] =
|
|
2970
|
-
const [resumeSessions, setResumeSessions] =
|
|
2971
|
-
const [
|
|
2972
|
-
const [
|
|
2973
|
-
const [
|
|
2974
|
-
const [
|
|
2975
|
-
const [
|
|
3297
|
+
const [theme, setTheme] = useState6(resolveTheme(initialCfg?.theme));
|
|
3298
|
+
const [resumeSessions, setResumeSessions] = useState6(null);
|
|
3299
|
+
const [showThemePicker, setShowThemePicker] = useState6(false);
|
|
3300
|
+
const [originalTheme, setOriginalTheme] = useState6(null);
|
|
3301
|
+
const [tasks, setTasks] = useState6([]);
|
|
3302
|
+
const [tasksStartedAt, setTasksStartedAt] = useState6(null);
|
|
3303
|
+
const [tasksStartTokens, setTasksStartTokens] = useState6(0);
|
|
3304
|
+
const [turnStartedAt, setTurnStartedAt] = useState6(null);
|
|
3305
|
+
const [verbose, setVerbose] = useState6(false);
|
|
3306
|
+
const [hasUpdate, setHasUpdate] = useState6(initialUpdateResult?.hasUpdate ?? false);
|
|
3307
|
+
const [latestVersion, setLatestVersion] = useState6(initialUpdateResult?.latestVersion ?? null);
|
|
2976
3308
|
const messagesRef = useRef2([
|
|
2977
3309
|
{
|
|
2978
3310
|
role: "system",
|
|
@@ -2993,12 +3325,42 @@ function App({ initialCfg }) {
|
|
|
2993
3325
|
const tasksRef = useRef2([]);
|
|
2994
3326
|
const usageRef = useRef2(null);
|
|
2995
3327
|
const updateCheckedRef = useRef2(false);
|
|
3328
|
+
const updateNudgedRef = useRef2(false);
|
|
2996
3329
|
const compactSuggestedRef = useRef2(false);
|
|
2997
3330
|
useEffect4(() => {
|
|
2998
3331
|
if (!cfg || updateCheckedRef.current) return;
|
|
2999
3332
|
updateCheckedRef.current = true;
|
|
3333
|
+
if (initialUpdateResult) {
|
|
3334
|
+
if (initialUpdateResult.hasUpdate && !updateNudgedRef.current) {
|
|
3335
|
+
updateNudgedRef.current = true;
|
|
3336
|
+
setHasUpdate(true);
|
|
3337
|
+
setLatestVersion(initialUpdateResult.latestVersion);
|
|
3338
|
+
setEvents((e) => [
|
|
3339
|
+
...e,
|
|
3340
|
+
{
|
|
3341
|
+
kind: "info",
|
|
3342
|
+
key: mkKey(),
|
|
3343
|
+
text: `update available: ${initialUpdateResult.localVersion} \u2192 ${initialUpdateResult.latestVersion}`
|
|
3344
|
+
}
|
|
3345
|
+
]);
|
|
3346
|
+
void isGitRepo().then((git) => {
|
|
3347
|
+
setEvents((e) => [
|
|
3348
|
+
...e,
|
|
3349
|
+
{
|
|
3350
|
+
kind: "info",
|
|
3351
|
+
key: mkKey(),
|
|
3352
|
+
text: git ? "run: git pull && npm install && npm run build then restart kimiflare" : "run: npm update -g kimiflare then restart"
|
|
3353
|
+
}
|
|
3354
|
+
]);
|
|
3355
|
+
});
|
|
3356
|
+
}
|
|
3357
|
+
return;
|
|
3358
|
+
}
|
|
3000
3359
|
void checkForUpdate().then((result) => {
|
|
3001
|
-
if (result.hasUpdate) {
|
|
3360
|
+
if (result.hasUpdate && !updateNudgedRef.current) {
|
|
3361
|
+
updateNudgedRef.current = true;
|
|
3362
|
+
setHasUpdate(true);
|
|
3363
|
+
setLatestVersion(result.latestVersion);
|
|
3002
3364
|
setEvents((e) => [
|
|
3003
3365
|
...e,
|
|
3004
3366
|
{
|
|
@@ -3019,7 +3381,7 @@ function App({ initialCfg }) {
|
|
|
3019
3381
|
});
|
|
3020
3382
|
}
|
|
3021
3383
|
});
|
|
3022
|
-
}, [cfg]);
|
|
3384
|
+
}, [cfg, initialUpdateResult]);
|
|
3023
3385
|
useEffect4(() => {
|
|
3024
3386
|
modeRef.current = mode;
|
|
3025
3387
|
messagesRef.current[0] = {
|
|
@@ -3038,6 +3400,39 @@ function App({ initialCfg }) {
|
|
|
3038
3400
|
useEffect4(() => {
|
|
3039
3401
|
effortRef.current = effort;
|
|
3040
3402
|
}, [effort]);
|
|
3403
|
+
useEffect4(() => {
|
|
3404
|
+
if (!cfg) return;
|
|
3405
|
+
const id = setInterval(() => {
|
|
3406
|
+
void checkForUpdate().then((result) => {
|
|
3407
|
+
if (result.hasUpdate) {
|
|
3408
|
+
setHasUpdate(true);
|
|
3409
|
+
setLatestVersion(result.latestVersion);
|
|
3410
|
+
if (!updateNudgedRef.current) {
|
|
3411
|
+
updateNudgedRef.current = true;
|
|
3412
|
+
setEvents((e) => [
|
|
3413
|
+
...e,
|
|
3414
|
+
{
|
|
3415
|
+
kind: "info",
|
|
3416
|
+
key: mkKey(),
|
|
3417
|
+
text: `update available: ${result.localVersion} \u2192 ${result.latestVersion}`
|
|
3418
|
+
}
|
|
3419
|
+
]);
|
|
3420
|
+
void isGitRepo().then((git) => {
|
|
3421
|
+
setEvents((e) => [
|
|
3422
|
+
...e,
|
|
3423
|
+
{
|
|
3424
|
+
kind: "info",
|
|
3425
|
+
key: mkKey(),
|
|
3426
|
+
text: git ? "run: git pull && npm install && npm run build then restart kimiflare" : "run: npm update -g kimiflare then restart"
|
|
3427
|
+
}
|
|
3428
|
+
]);
|
|
3429
|
+
});
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
});
|
|
3433
|
+
}, 30 * 60 * 1e3);
|
|
3434
|
+
return () => clearInterval(id);
|
|
3435
|
+
}, [cfg]);
|
|
3041
3436
|
const saveSessionSafe = useCallback(async () => {
|
|
3042
3437
|
if (!cfg) return;
|
|
3043
3438
|
if (!sessionIdRef.current) {
|
|
@@ -3080,6 +3475,11 @@ function App({ initialCfg }) {
|
|
|
3080
3475
|
setVerbose((v) => !v);
|
|
3081
3476
|
return;
|
|
3082
3477
|
}
|
|
3478
|
+
if (key.ctrl && inputChar === "t") {
|
|
3479
|
+
setOriginalTheme(theme);
|
|
3480
|
+
setShowThemePicker(true);
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3083
3483
|
});
|
|
3084
3484
|
const updateAssistant = useCallback(
|
|
3085
3485
|
(id, patch) => {
|
|
@@ -3150,7 +3550,7 @@ function App({ initialCfg }) {
|
|
|
3150
3550
|
}
|
|
3151
3551
|
}, [cfg, busy, saveSessionSafe]);
|
|
3152
3552
|
const openResumePicker = useCallback(async () => {
|
|
3153
|
-
const sessions = await listSessions(
|
|
3553
|
+
const sessions = await listSessions(200);
|
|
3154
3554
|
setResumeSessions(sessions);
|
|
3155
3555
|
}, []);
|
|
3156
3556
|
const runInit = useCallback(async () => {
|
|
@@ -3189,7 +3589,7 @@ function App({ initialCfg }) {
|
|
|
3189
3589
|
"Do not call `tasks_set` for this. Just read what you need, then write the file."
|
|
3190
3590
|
].join("\n");
|
|
3191
3591
|
setEvents((e) => [...e, { kind: "user", key: mkKey(), text: "/init" }]);
|
|
3192
|
-
messagesRef.current.push({ role: "user", content: prompt });
|
|
3592
|
+
messagesRef.current.push({ role: "user", content: sanitizeString(prompt) });
|
|
3193
3593
|
setBusy(true);
|
|
3194
3594
|
setTurnStartedAt(Date.now());
|
|
3195
3595
|
const controller = new AbortController();
|
|
@@ -3318,6 +3718,27 @@ function App({ initialCfg }) {
|
|
|
3318
3718
|
},
|
|
3319
3719
|
[]
|
|
3320
3720
|
);
|
|
3721
|
+
const handleThemePick = useCallback(
|
|
3722
|
+
(picked) => {
|
|
3723
|
+
if (!picked) {
|
|
3724
|
+
if (originalTheme) setTheme(originalTheme);
|
|
3725
|
+
setShowThemePicker(false);
|
|
3726
|
+
setOriginalTheme(null);
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3729
|
+
setTheme(picked);
|
|
3730
|
+
setCfg((c) => c ? { ...c, theme: picked.name } : c);
|
|
3731
|
+
if (cfg) void saveConfig({ ...cfg, theme: picked.name }).catch(() => {
|
|
3732
|
+
});
|
|
3733
|
+
setShowThemePicker(false);
|
|
3734
|
+
setOriginalTheme(null);
|
|
3735
|
+
setEvents((e) => [
|
|
3736
|
+
...e,
|
|
3737
|
+
{ kind: "info", key: mkKey(), text: `theme: ${picked.label}` }
|
|
3738
|
+
]);
|
|
3739
|
+
},
|
|
3740
|
+
[cfg, originalTheme]
|
|
3741
|
+
);
|
|
3321
3742
|
const handleSlash = useCallback(
|
|
3322
3743
|
(cmd) => {
|
|
3323
3744
|
const raw = cmd.trim();
|
|
@@ -3337,6 +3758,7 @@ function App({ initialCfg }) {
|
|
|
3337
3758
|
setTasksStartedAt(null);
|
|
3338
3759
|
setTasksStartTokens(0);
|
|
3339
3760
|
compactSuggestedRef.current = false;
|
|
3761
|
+
updateNudgedRef.current = false;
|
|
3340
3762
|
return true;
|
|
3341
3763
|
}
|
|
3342
3764
|
if (c === "/reasoning") {
|
|
@@ -3403,14 +3825,8 @@ use: /thinking low | medium | high`
|
|
|
3403
3825
|
}
|
|
3404
3826
|
if (c === "/theme") {
|
|
3405
3827
|
if (!arg) {
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
{
|
|
3409
|
-
kind: "info",
|
|
3410
|
-
key: mkKey(),
|
|
3411
|
-
text: `current: ${theme.name} \xB7 available: ${themeNames().join(", ")}`
|
|
3412
|
-
}
|
|
3413
|
-
]);
|
|
3828
|
+
setOriginalTheme(theme);
|
|
3829
|
+
setShowThemePicker(true);
|
|
3414
3830
|
return true;
|
|
3415
3831
|
}
|
|
3416
3832
|
const next = resolveTheme(arg);
|
|
@@ -3481,8 +3897,10 @@ use: /thinking low | medium | high`
|
|
|
3481
3897
|
return true;
|
|
3482
3898
|
}
|
|
3483
3899
|
if (c === "/update") {
|
|
3484
|
-
void checkForUpdate().then((result) => {
|
|
3900
|
+
void checkForUpdate(true).then((result) => {
|
|
3485
3901
|
if (result.hasUpdate) {
|
|
3902
|
+
setHasUpdate(true);
|
|
3903
|
+
setLatestVersion(result.latestVersion);
|
|
3486
3904
|
setEvents((e) => [
|
|
3487
3905
|
...e,
|
|
3488
3906
|
{
|
|
@@ -3502,6 +3920,8 @@ use: /thinking low | medium | high`
|
|
|
3502
3920
|
]);
|
|
3503
3921
|
});
|
|
3504
3922
|
} else {
|
|
3923
|
+
setHasUpdate(false);
|
|
3924
|
+
setLatestVersion(null);
|
|
3505
3925
|
setEvents((e) => [
|
|
3506
3926
|
...e,
|
|
3507
3927
|
{ kind: "info", key: mkKey(), text: "no update available" }
|
|
@@ -3526,7 +3946,7 @@ use: /thinking low | medium | high`
|
|
|
3526
3946
|
{
|
|
3527
3947
|
kind: "info",
|
|
3528
3948
|
key: mkKey(),
|
|
3529
|
-
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
|
|
3949
|
+
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 interactive theme picker (or ctrl+t)\n /theme NAME set theme by name\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 verbose \xB7 ctrl+t theme \xB7 shift+tab cycle mode \xB7 \u2191/\u2193 history"
|
|
3530
3950
|
}
|
|
3531
3951
|
]);
|
|
3532
3952
|
return true;
|
|
@@ -3543,7 +3963,7 @@ use: /thinking low | medium | high`
|
|
|
3543
3963
|
if (trimmed.startsWith("/") && handleSlash(trimmed)) return;
|
|
3544
3964
|
const display = displayText?.trim() || trimmed;
|
|
3545
3965
|
setEvents((e) => [...e, { kind: "user", key: mkKey(), text: display }]);
|
|
3546
|
-
messagesRef.current.push({ role: "user", content: trimmed });
|
|
3966
|
+
messagesRef.current.push({ role: "user", content: sanitizeString(trimmed) });
|
|
3547
3967
|
setBusy(true);
|
|
3548
3968
|
setTurnStartedAt(Date.now());
|
|
3549
3969
|
const controller = new AbortController();
|
|
@@ -3708,7 +4128,7 @@ use: /thinking low | medium | high`
|
|
|
3708
4128
|
}
|
|
3709
4129
|
}, [usage]);
|
|
3710
4130
|
if (!cfg) {
|
|
3711
|
-
return /* @__PURE__ */
|
|
4131
|
+
return /* @__PURE__ */ jsx13(
|
|
3712
4132
|
Onboarding,
|
|
3713
4133
|
{
|
|
3714
4134
|
onDone: (newCfg) => {
|
|
@@ -3722,12 +4142,15 @@ use: /thinking low | medium | high`
|
|
|
3722
4142
|
);
|
|
3723
4143
|
}
|
|
3724
4144
|
if (resumeSessions !== null) {
|
|
3725
|
-
return /* @__PURE__ */
|
|
4145
|
+
return /* @__PURE__ */ jsx13(Box12, { flexDirection: "column", children: /* @__PURE__ */ jsx13(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick, theme }) });
|
|
4146
|
+
}
|
|
4147
|
+
if (showThemePicker) {
|
|
4148
|
+
return /* @__PURE__ */ jsx13(Box12, { flexDirection: "column", children: /* @__PURE__ */ jsx13(ThemePicker, { themes: themeList(), current: theme, onPick: handleThemePick }) });
|
|
3726
4149
|
}
|
|
3727
4150
|
const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
|
|
3728
|
-
return /* @__PURE__ */
|
|
3729
|
-
!hasConversation && events.length === 0 ? /* @__PURE__ */
|
|
3730
|
-
perm ? /* @__PURE__ */
|
|
4151
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
4152
|
+
!hasConversation && events.length === 0 ? /* @__PURE__ */ jsx13(Welcome, { theme }) : /* @__PURE__ */ jsx13(ChatView, { events, showReasoning, theme, verbose }),
|
|
4153
|
+
perm ? /* @__PURE__ */ jsx13(
|
|
3731
4154
|
PermissionModal,
|
|
3732
4155
|
{
|
|
3733
4156
|
tool: perm.tool,
|
|
@@ -3738,8 +4161,8 @@ use: /thinking low | medium | high`
|
|
|
3738
4161
|
setPerm(null);
|
|
3739
4162
|
}
|
|
3740
4163
|
}
|
|
3741
|
-
) : /* @__PURE__ */
|
|
3742
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
4164
|
+
) : /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
4165
|
+
tasks.length > 0 && /* @__PURE__ */ jsx13(
|
|
3743
4166
|
TaskList,
|
|
3744
4167
|
{
|
|
3745
4168
|
tasks,
|
|
@@ -3748,11 +4171,11 @@ use: /thinking low | medium | high`
|
|
|
3748
4171
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
3749
4172
|
}
|
|
3750
4173
|
),
|
|
3751
|
-
queue.length > 0 && /* @__PURE__ */
|
|
4174
|
+
queue.length > 0 && /* @__PURE__ */ jsx13(Box12, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs12(Text13, { color: theme.queue.color, dimColor: theme.queue.dim, children: [
|
|
3752
4175
|
"\u23F3 ",
|
|
3753
4176
|
q.display
|
|
3754
4177
|
] }, `queue_${i}`)) }),
|
|
3755
|
-
/* @__PURE__ */
|
|
4178
|
+
/* @__PURE__ */ jsx13(
|
|
3756
4179
|
StatusBar,
|
|
3757
4180
|
{
|
|
3758
4181
|
model: cfg.model,
|
|
@@ -3762,12 +4185,14 @@ use: /thinking low | medium | high`
|
|
|
3762
4185
|
theme,
|
|
3763
4186
|
mode,
|
|
3764
4187
|
effort,
|
|
3765
|
-
contextLimit: CONTEXT_LIMIT
|
|
4188
|
+
contextLimit: CONTEXT_LIMIT,
|
|
4189
|
+
hasUpdate,
|
|
4190
|
+
latestVersion
|
|
3766
4191
|
}
|
|
3767
4192
|
),
|
|
3768
|
-
/* @__PURE__ */
|
|
3769
|
-
/* @__PURE__ */
|
|
3770
|
-
/* @__PURE__ */
|
|
4193
|
+
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, children: [
|
|
4194
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.accent, children: "\u203A " }),
|
|
4195
|
+
/* @__PURE__ */ jsx13(
|
|
3771
4196
|
CustomTextInput,
|
|
3772
4197
|
{
|
|
3773
4198
|
value: input,
|
|
@@ -3815,8 +4240,8 @@ use: /thinking low | medium | high`
|
|
|
3815
4240
|
] })
|
|
3816
4241
|
] });
|
|
3817
4242
|
}
|
|
3818
|
-
async function renderApp(cfg) {
|
|
3819
|
-
const instance = render(/* @__PURE__ */
|
|
4243
|
+
async function renderApp(cfg, updateResult) {
|
|
4244
|
+
const instance = render(/* @__PURE__ */ jsx13(App, { initialCfg: cfg, initialUpdateResult: updateResult }));
|
|
3820
4245
|
await instance.waitUntilExit();
|
|
3821
4246
|
}
|
|
3822
4247
|
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, nextAssistantId, nextKey, mkKey, EFFORT_DESCRIPTIONS;
|
|
@@ -3827,10 +4252,12 @@ var init_app = __esm({
|
|
|
3827
4252
|
init_system_prompt();
|
|
3828
4253
|
init_compact();
|
|
3829
4254
|
init_executor();
|
|
4255
|
+
init_messages();
|
|
3830
4256
|
init_chat();
|
|
3831
4257
|
init_status();
|
|
3832
4258
|
init_permission();
|
|
3833
4259
|
init_resume_picker();
|
|
4260
|
+
init_theme_picker();
|
|
3834
4261
|
init_task_list();
|
|
3835
4262
|
init_text_input();
|
|
3836
4263
|
init_update_check();
|
|
@@ -3858,6 +4285,7 @@ init_config();
|
|
|
3858
4285
|
init_loop();
|
|
3859
4286
|
init_system_prompt();
|
|
3860
4287
|
init_executor();
|
|
4288
|
+
init_update_check();
|
|
3861
4289
|
import { Command } from "commander";
|
|
3862
4290
|
import { readFileSync as readFileSync2 } from "fs";
|
|
3863
4291
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -3876,6 +4304,7 @@ program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.
|
|
|
3876
4304
|
var opts = program.opts();
|
|
3877
4305
|
async function main() {
|
|
3878
4306
|
const cfg = await loadConfig();
|
|
4307
|
+
const updateResult = await checkForUpdate();
|
|
3879
4308
|
if (opts.print !== void 0) {
|
|
3880
4309
|
if (!cfg) {
|
|
3881
4310
|
console.error(
|
|
@@ -3889,7 +4318,8 @@ async function main() {
|
|
|
3889
4318
|
model,
|
|
3890
4319
|
prompt: opts.print,
|
|
3891
4320
|
allowAll: !!opts.dangerouslyAllowAll,
|
|
3892
|
-
showReasoning: !!opts.reasoning
|
|
4321
|
+
showReasoning: !!opts.reasoning,
|
|
4322
|
+
updateResult
|
|
3893
4323
|
});
|
|
3894
4324
|
return;
|
|
3895
4325
|
}
|
|
@@ -3902,12 +4332,21 @@ async function main() {
|
|
|
3902
4332
|
const { renderApp: renderApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
|
|
3903
4333
|
if (cfg) {
|
|
3904
4334
|
const model = opts.model ?? cfg.model ?? DEFAULT_MODEL;
|
|
3905
|
-
await renderApp2({ ...cfg, model });
|
|
4335
|
+
await renderApp2({ ...cfg, model }, updateResult);
|
|
3906
4336
|
} else {
|
|
3907
|
-
await renderApp2(null);
|
|
4337
|
+
await renderApp2(null, updateResult);
|
|
3908
4338
|
}
|
|
3909
4339
|
}
|
|
3910
4340
|
async function runPrintMode(opts2) {
|
|
4341
|
+
if (opts2.updateResult.hasUpdate) {
|
|
4342
|
+
const git = await isGitRepo();
|
|
4343
|
+
process.stderr.write(
|
|
4344
|
+
`\x1B[33mkimiflare update available: ${opts2.updateResult.localVersion} \u2192 ${opts2.updateResult.latestVersion}\x1B[0m
|
|
4345
|
+
\x1B[33m ${git ? "git pull && npm install && npm run build" : "npm update -g kimiflare"} then restart\x1B[0m
|
|
4346
|
+
|
|
4347
|
+
`
|
|
4348
|
+
);
|
|
4349
|
+
}
|
|
3911
4350
|
const cwd = process.cwd();
|
|
3912
4351
|
const executor = new ToolExecutor(ALL_TOOLS);
|
|
3913
4352
|
const messages = [
|