kimiflare 0.25.0 → 0.26.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 +997 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -83,6 +83,7 @@ async function loadConfig() {
|
|
|
83
83
|
const envMemoryMaxAgeDays = readNumberEnv("KIMIFLARE_MEMORY_MAX_AGE_DAYS");
|
|
84
84
|
const envMemoryMaxEntries = readNumberEnv("KIMIFLARE_MEMORY_MAX_ENTRIES");
|
|
85
85
|
const envMemoryEmbeddingModel = process.env.KIMIFLARE_MEMORY_EMBEDDING_MODEL;
|
|
86
|
+
const envPlumbingModel = process.env.KIMIFLARE_PLUMBING_MODEL;
|
|
86
87
|
const envCodeMode = readBooleanEnv("KIMIFLARE_CODE_MODE");
|
|
87
88
|
if (envAccount && envToken) {
|
|
88
89
|
return {
|
|
@@ -107,6 +108,7 @@ async function loadConfig() {
|
|
|
107
108
|
memoryMaxAgeDays: envMemoryMaxAgeDays,
|
|
108
109
|
memoryMaxEntries: envMemoryMaxEntries,
|
|
109
110
|
memoryEmbeddingModel: envMemoryEmbeddingModel,
|
|
111
|
+
plumbingModel: envPlumbingModel,
|
|
110
112
|
codeMode: envCodeMode
|
|
111
113
|
};
|
|
112
114
|
}
|
|
@@ -137,6 +139,7 @@ async function loadConfig() {
|
|
|
137
139
|
memoryMaxAgeDays: envMemoryMaxAgeDays ?? parsed.memoryMaxAgeDays,
|
|
138
140
|
memoryMaxEntries: envMemoryMaxEntries ?? parsed.memoryMaxEntries,
|
|
139
141
|
memoryEmbeddingModel: envMemoryEmbeddingModel ?? parsed.memoryEmbeddingModel,
|
|
142
|
+
plumbingModel: envPlumbingModel ?? parsed.plumbingModel,
|
|
140
143
|
codeMode: envCodeMode ?? parsed.codeMode
|
|
141
144
|
};
|
|
142
145
|
}
|
|
@@ -880,7 +883,7 @@ function schemaToTsType(prop, required = true) {
|
|
|
880
883
|
types.push(`${itemType}[]`);
|
|
881
884
|
} else if (prop.type === "object") {
|
|
882
885
|
if (prop.properties && Object.keys(prop.properties).length > 0) {
|
|
883
|
-
const entries = Object.entries(prop.properties).map(([key, val]) => {
|
|
886
|
+
const entries = Object.entries(prop.properties).sort(([a], [b]) => a.localeCompare(b)).map(([key, val]) => {
|
|
884
887
|
const isReq = prop.required?.includes(key) ?? false;
|
|
885
888
|
return ` ${key}${isReq ? "" : "?"}: ${schemaToTsType(val, isReq)};`;
|
|
886
889
|
}).join("\n");
|
|
@@ -901,7 +904,7 @@ ${entries}
|
|
|
901
904
|
return required ? result : `${result} | undefined`;
|
|
902
905
|
}
|
|
903
906
|
function generateInterface(name, properties, required = []) {
|
|
904
|
-
const entries = Object.entries(properties).map(([key, val]) => {
|
|
907
|
+
const entries = Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)).map(([key, val]) => {
|
|
905
908
|
const isReq = required.includes(key);
|
|
906
909
|
return ` ${key}${isReq ? "" : "?"}: ${schemaToTsType(val, isReq)};`;
|
|
907
910
|
}).join("\n");
|
|
@@ -921,13 +924,14 @@ function generateTypeScriptApi(tools) {
|
|
|
921
924
|
const inputInterfaces = [];
|
|
922
925
|
const outputInterfaces = [];
|
|
923
926
|
const methodEntries = [];
|
|
924
|
-
for (const tool of tools) {
|
|
927
|
+
for (const tool of [...tools].sort((a, b) => a.name.localeCompare(b.name))) {
|
|
925
928
|
const baseName = sanitizeTypeName(tool.name);
|
|
926
929
|
const inputName = `${baseName}_Input`;
|
|
927
930
|
const outputName = `${baseName}_Output`;
|
|
928
931
|
const params = tool.parameters;
|
|
929
|
-
|
|
930
|
-
|
|
932
|
+
const sortedPropKeys = params.properties ? Object.keys(params.properties).sort((a, b) => a.localeCompare(b)) : [];
|
|
933
|
+
if (sortedPropKeys.length > 0 && params.properties) {
|
|
934
|
+
inputInterfaces.push(generateInterface(inputName, params.properties, [...params.required ?? []].sort((a, b) => a.localeCompare(b))));
|
|
931
935
|
inputInterfaces.push("");
|
|
932
936
|
methodEntries.push(` /**`);
|
|
933
937
|
methodEntries.push(` * ${tool.description.replace(/\n/g, "\n * ")}`);
|
|
@@ -1148,7 +1152,14 @@ async function runAgentTurn(opts2) {
|
|
|
1148
1152
|
let toolDefs;
|
|
1149
1153
|
let codeModeApiString = "";
|
|
1150
1154
|
if (codeMode) {
|
|
1151
|
-
|
|
1155
|
+
const toolsKey = stableStringify(opts2.tools);
|
|
1156
|
+
const cached = codeModeApiCache.get(toolsKey);
|
|
1157
|
+
if (cached) {
|
|
1158
|
+
codeModeApiString = cached;
|
|
1159
|
+
} else {
|
|
1160
|
+
codeModeApiString = generateTypeScriptApi(opts2.tools);
|
|
1161
|
+
codeModeApiCache.set(toolsKey, codeModeApiString);
|
|
1162
|
+
}
|
|
1152
1163
|
toolDefs = [
|
|
1153
1164
|
{
|
|
1154
1165
|
type: "function",
|
|
@@ -1183,6 +1194,9 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
1183
1194
|
}
|
|
1184
1195
|
let turn = 0;
|
|
1185
1196
|
let lastUsage = null;
|
|
1197
|
+
const recentToolCalls = [];
|
|
1198
|
+
const LOOP_WINDOW = 8;
|
|
1199
|
+
const LOOP_THRESHOLD = 2;
|
|
1186
1200
|
for (let iter = 0; iter < max; iter++) {
|
|
1187
1201
|
turn++;
|
|
1188
1202
|
const previousMessages = opts2.messages.slice();
|
|
@@ -1313,6 +1327,28 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
1313
1327
|
}
|
|
1314
1328
|
for (const tc of toolCalls) {
|
|
1315
1329
|
if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
1330
|
+
const loopSignature = `${tc.function.name}:${stableStringify(tc.function.arguments)}`;
|
|
1331
|
+
const loopCount = recentToolCalls.filter((s) => s === loopSignature).length;
|
|
1332
|
+
if (loopCount >= LOOP_THRESHOLD) {
|
|
1333
|
+
const warning = `Loop detected: you have called ${tc.function.name} with the same arguments multiple times in a row. Consider a different approach.`;
|
|
1334
|
+
const loopResult = {
|
|
1335
|
+
tool_call_id: tc.id,
|
|
1336
|
+
name: tc.function.name,
|
|
1337
|
+
content: warning,
|
|
1338
|
+
ok: false
|
|
1339
|
+
};
|
|
1340
|
+
toolResults.push(loopResult);
|
|
1341
|
+
opts2.messages.push({
|
|
1342
|
+
role: "tool",
|
|
1343
|
+
tool_call_id: tc.id,
|
|
1344
|
+
content: sanitizeString(warning),
|
|
1345
|
+
name: tc.function.name
|
|
1346
|
+
});
|
|
1347
|
+
opts2.callbacks.onToolResult?.(loopResult);
|
|
1348
|
+
recentToolCalls.push(loopSignature);
|
|
1349
|
+
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1316
1352
|
if (codeMode && tc.function.name === "execute_code") {
|
|
1317
1353
|
const args = JSON.parse(tc.function.arguments || "{}");
|
|
1318
1354
|
const code = args.code || "";
|
|
@@ -1353,6 +1389,8 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
1353
1389
|
name: "execute_code"
|
|
1354
1390
|
});
|
|
1355
1391
|
opts2.callbacks.onToolResult?.(result);
|
|
1392
|
+
recentToolCalls.push(loopSignature);
|
|
1393
|
+
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
1356
1394
|
} else {
|
|
1357
1395
|
const result = await opts2.executor.run(
|
|
1358
1396
|
{ id: tc.id, name: tc.function.name, arguments: tc.function.arguments },
|
|
@@ -1367,6 +1405,8 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
1367
1405
|
name: result.name
|
|
1368
1406
|
});
|
|
1369
1407
|
opts2.callbacks.onToolResult?.(result);
|
|
1408
|
+
recentToolCalls.push(loopSignature);
|
|
1409
|
+
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
1370
1410
|
}
|
|
1371
1411
|
}
|
|
1372
1412
|
if (opts2.sessionId && lastUsage) {
|
|
@@ -1392,6 +1432,7 @@ function validateToolArguments(raw) {
|
|
|
1392
1432
|
return "{}";
|
|
1393
1433
|
}
|
|
1394
1434
|
}
|
|
1435
|
+
var codeModeApiCache;
|
|
1395
1436
|
var init_loop = __esm({
|
|
1396
1437
|
"src/agent/loop.ts"() {
|
|
1397
1438
|
"use strict";
|
|
@@ -1401,6 +1442,7 @@ var init_loop = __esm({
|
|
|
1401
1442
|
init_cost_debug();
|
|
1402
1443
|
init_strip_reasoning();
|
|
1403
1444
|
init_code_mode();
|
|
1445
|
+
codeModeApiCache = /* @__PURE__ */ new Map();
|
|
1404
1446
|
}
|
|
1405
1447
|
});
|
|
1406
1448
|
|
|
@@ -3236,6 +3278,39 @@ function emptySessionState(task = "") {
|
|
|
3236
3278
|
artifact_index: {}
|
|
3237
3279
|
};
|
|
3238
3280
|
}
|
|
3281
|
+
function serializeArtifactStore(store) {
|
|
3282
|
+
const MAX_ARTIFACT_CHARS = 5e4;
|
|
3283
|
+
const out = [];
|
|
3284
|
+
for (const a of store.list()) {
|
|
3285
|
+
out.push({
|
|
3286
|
+
id: a.id,
|
|
3287
|
+
type: a.type,
|
|
3288
|
+
summary: a.summary,
|
|
3289
|
+
raw: a.raw.slice(0, MAX_ARTIFACT_CHARS),
|
|
3290
|
+
source: a.source,
|
|
3291
|
+
path: a.path,
|
|
3292
|
+
lineRange: a.lineRange,
|
|
3293
|
+
ts: a.ts
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
return out;
|
|
3297
|
+
}
|
|
3298
|
+
function deserializeArtifactStore(data) {
|
|
3299
|
+
const store = new ArtifactStore();
|
|
3300
|
+
for (const a of data) {
|
|
3301
|
+
store.add({
|
|
3302
|
+
id: a.id,
|
|
3303
|
+
type: a.type,
|
|
3304
|
+
summary: a.summary,
|
|
3305
|
+
raw: a.raw,
|
|
3306
|
+
source: a.source,
|
|
3307
|
+
path: a.path,
|
|
3308
|
+
lineRange: a.lineRange,
|
|
3309
|
+
ts: a.ts
|
|
3310
|
+
});
|
|
3311
|
+
}
|
|
3312
|
+
return store;
|
|
3313
|
+
}
|
|
3239
3314
|
function formatRecalledArtifacts(recalled) {
|
|
3240
3315
|
if (recalled.length === 0) return "";
|
|
3241
3316
|
const lines = ["[recalled artifacts]"];
|
|
@@ -4101,6 +4176,12 @@ var init_chat = __esm({
|
|
|
4101
4176
|
evt.text
|
|
4102
4177
|
] });
|
|
4103
4178
|
}
|
|
4179
|
+
if (evt.kind === "memory") {
|
|
4180
|
+
return /* @__PURE__ */ jsxs4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: [
|
|
4181
|
+
"\u25C8 ",
|
|
4182
|
+
evt.text
|
|
4183
|
+
] });
|
|
4184
|
+
}
|
|
4104
4185
|
return /* @__PURE__ */ jsxs4(Text4, { color: theme.error, children: [
|
|
4105
4186
|
"! ",
|
|
4106
4187
|
evt.text
|
|
@@ -5427,7 +5508,7 @@ function HelpMenu({ theme, themes, currentThemeName, customCommands, onDone, onC
|
|
|
5427
5508
|
key: cat.key
|
|
5428
5509
|
}));
|
|
5429
5510
|
if (customs.length > 0) {
|
|
5430
|
-
items2.push({ label: "
|
|
5511
|
+
items2.push({ label: "Run custom commands", value: "custom", key: "custom" });
|
|
5431
5512
|
}
|
|
5432
5513
|
items2.push({ label: "(close)", value: "__close__", key: "__close__" });
|
|
5433
5514
|
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
@@ -5611,6 +5692,16 @@ var init_help_menu = __esm({
|
|
|
5611
5692
|
{ command: "/community", description: "join our Discord server" }
|
|
5612
5693
|
]
|
|
5613
5694
|
},
|
|
5695
|
+
{
|
|
5696
|
+
key: "commands",
|
|
5697
|
+
label: "Commands",
|
|
5698
|
+
commands: [
|
|
5699
|
+
{ command: "/command create", description: "create a new custom slash command" },
|
|
5700
|
+
{ command: "/command edit", description: "edit an existing custom command" },
|
|
5701
|
+
{ command: "/command delete", description: "delete a custom command" },
|
|
5702
|
+
{ command: "/command list", description: "list all custom commands" }
|
|
5703
|
+
]
|
|
5704
|
+
},
|
|
5614
5705
|
{
|
|
5615
5706
|
key: "config",
|
|
5616
5707
|
label: "Config",
|
|
@@ -6425,11 +6516,11 @@ function updateAccessedAt(db, ids) {
|
|
|
6425
6516
|
function searchMemoriesFts(db, query, repoPath, limit = 50) {
|
|
6426
6517
|
const sql = repoPath ? `SELECT m.*, rank FROM memories m
|
|
6427
6518
|
JOIN memories_fts fts ON m.rowid = fts.rowid
|
|
6428
|
-
WHERE memories_fts MATCH ? AND m.repo_path = ? AND m.forgotten = 0 AND m.superseded_by IS NULL
|
|
6519
|
+
WHERE memories_fts MATCH ? AND m.repo_path = ? AND m.forgotten = 0 AND m.superseded_by IS NULL AND m.category != 'task'
|
|
6429
6520
|
ORDER BY rank
|
|
6430
6521
|
LIMIT ?` : `SELECT m.*, rank FROM memories m
|
|
6431
6522
|
JOIN memories_fts fts ON m.rowid = fts.rowid
|
|
6432
|
-
WHERE memories_fts MATCH ? AND m.forgotten = 0 AND m.superseded_by IS NULL
|
|
6523
|
+
WHERE memories_fts MATCH ? AND m.forgotten = 0 AND m.superseded_by IS NULL AND m.category != 'task'
|
|
6433
6524
|
ORDER BY rank
|
|
6434
6525
|
LIMIT ?`;
|
|
6435
6526
|
const params = repoPath ? [`${query}*`, repoPath, limit] : [`${query}*`, limit];
|
|
@@ -6442,7 +6533,7 @@ function searchMemoriesFts(db, query, repoPath, limit = 50) {
|
|
|
6442
6533
|
function listMemoriesForVectorSearch(db, repoPath, since, limit = 2e3) {
|
|
6443
6534
|
const rows = db.prepare(
|
|
6444
6535
|
`SELECT * FROM memories
|
|
6445
|
-
WHERE repo_path = ? AND created_at >= ? AND forgotten = 0 AND superseded_by IS NULL
|
|
6536
|
+
WHERE repo_path = ? AND created_at >= ? AND forgotten = 0 AND superseded_by IS NULL AND category != 'task'
|
|
6446
6537
|
ORDER BY accessed_at DESC
|
|
6447
6538
|
LIMIT ?`
|
|
6448
6539
|
).all(repoPath, since, limit);
|
|
@@ -6889,7 +6980,20 @@ function redactSecrets(text) {
|
|
|
6889
6980
|
}
|
|
6890
6981
|
return result;
|
|
6891
6982
|
}
|
|
6892
|
-
|
|
6983
|
+
function deterministicTopicKey(content) {
|
|
6984
|
+
return content.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, "_").slice(0, 60);
|
|
6985
|
+
}
|
|
6986
|
+
function pickTopicKey(content, existingKeys) {
|
|
6987
|
+
const normalized = deterministicTopicKey(content);
|
|
6988
|
+
if (!normalized) return null;
|
|
6989
|
+
for (const existing of existingKeys) {
|
|
6990
|
+
if (normalized.includes(existing) || existing.includes(normalized)) {
|
|
6991
|
+
return existing;
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
return normalized;
|
|
6995
|
+
}
|
|
6996
|
+
var SECRET_PATTERNS, VERIFY_SYSTEM, HYPOTHETICAL_QUERIES_SYSTEM, MemoryManager;
|
|
6893
6997
|
var init_manager2 = __esm({
|
|
6894
6998
|
"src/memory/manager.ts"() {
|
|
6895
6999
|
"use strict";
|
|
@@ -6917,19 +7021,12 @@ Return a JSON object:
|
|
|
6917
7021
|
"confidence": "high" | "medium" | "low",
|
|
6918
7022
|
"corrected_content": string | null // if minor correction needed, provide it; otherwise null
|
|
6919
7023
|
}`;
|
|
6920
|
-
TOPIC_KEY_SYSTEM = `You are a topic normalization engine. Given a new memory and a list of existing topic keys for this project, decide whether the new memory belongs to an existing topic or needs a new one.
|
|
6921
|
-
|
|
6922
|
-
Rules:
|
|
6923
|
-
- Topic keys are lowercase snake_case, max 3 words.
|
|
6924
|
-
- If the new memory is about the same topic as an existing key, return the existing key.
|
|
6925
|
-
- If it's a genuinely new topic, generate a new normalized key.
|
|
6926
|
-
- Return ONLY the topic key string, nothing else.`;
|
|
6927
7024
|
HYPOTHETICAL_QUERIES_SYSTEM = `Given a memory, generate 3-5 short search queries a user might type to find it.
|
|
6928
7025
|
Cover different phrasings: declarative, interrogative, and keyword-based.
|
|
6929
7026
|
|
|
6930
7027
|
Return a JSON array of strings. Example:
|
|
6931
7028
|
["what package manager does this project use?", "pnpm preference", "user likes pnpm over npm"]`;
|
|
6932
|
-
MemoryManager = class {
|
|
7029
|
+
MemoryManager = class _MemoryManager {
|
|
6933
7030
|
db = null;
|
|
6934
7031
|
opts;
|
|
6935
7032
|
constructor(opts2) {
|
|
@@ -6957,6 +7054,14 @@ Return a JSON array of strings. Example:
|
|
|
6957
7054
|
gateway: this.opts.gateway
|
|
6958
7055
|
};
|
|
6959
7056
|
}
|
|
7057
|
+
get plumbingLlmOpts() {
|
|
7058
|
+
return {
|
|
7059
|
+
accountId: this.opts.accountId,
|
|
7060
|
+
apiToken: this.opts.apiToken,
|
|
7061
|
+
model: this.opts.plumbingModel ?? "@cf/meta/llama-4-scout-17b-16e-instruct",
|
|
7062
|
+
gateway: this.opts.gateway
|
|
7063
|
+
};
|
|
7064
|
+
}
|
|
6960
7065
|
shouldRedact() {
|
|
6961
7066
|
return this.opts.redactSecrets !== false;
|
|
6962
7067
|
}
|
|
@@ -6977,7 +7082,7 @@ Return a JSON array of strings. Example:
|
|
|
6977
7082
|
if (verified.corrected_content) {
|
|
6978
7083
|
safeContent = verified.corrected_content;
|
|
6979
7084
|
}
|
|
6980
|
-
const topicKey =
|
|
7085
|
+
const topicKey = this.normalizeTopicKey(safeContent, repoPath);
|
|
6981
7086
|
const supersededIds = [];
|
|
6982
7087
|
if (topicKey) {
|
|
6983
7088
|
const existing = findMemoriesByTopicKey(this.db, repoPath, topicKey);
|
|
@@ -7029,6 +7134,38 @@ Return a JSON array of strings. Example:
|
|
|
7029
7134
|
}
|
|
7030
7135
|
return retrieveMemories({ db: this.db, query });
|
|
7031
7136
|
}
|
|
7137
|
+
/**
|
|
7138
|
+
* Format recalled memories as a compact context block for injection into messages.
|
|
7139
|
+
*/
|
|
7140
|
+
static formatRecalled(results) {
|
|
7141
|
+
if (results.length === 0) return "";
|
|
7142
|
+
const lines = ["[recalled memories]"];
|
|
7143
|
+
for (const r of results) {
|
|
7144
|
+
const files = r.memory.relatedFiles.length > 0 ? ` [${r.memory.relatedFiles.join(", ")}]` : "";
|
|
7145
|
+
lines.push(`- [${r.memory.category}] ${r.memory.content}${files}`);
|
|
7146
|
+
}
|
|
7147
|
+
return lines.join("\n");
|
|
7148
|
+
}
|
|
7149
|
+
/**
|
|
7150
|
+
* Synthesize recalled memories into a dense prose paragraph.
|
|
7151
|
+
* Uses the lightweight plumbing model (Scout) to keep costs low.
|
|
7152
|
+
*/
|
|
7153
|
+
async synthesizeRecalled(results, signal) {
|
|
7154
|
+
if (results.length === 0) return "";
|
|
7155
|
+
const raw = _MemoryManager.formatRecalled(results);
|
|
7156
|
+
const text = await runKimiText({
|
|
7157
|
+
...this.plumbingLlmOpts,
|
|
7158
|
+
signal,
|
|
7159
|
+
messages: [
|
|
7160
|
+
{
|
|
7161
|
+
role: "system",
|
|
7162
|
+
content: "You are a context-synthesis engine. Given a list of recalled memories about a codebase, produce a single dense paragraph of context for a coding assistant. Preserve all facts, file paths, and decisions. Do not add information not present in the memories. Be terse."
|
|
7163
|
+
},
|
|
7164
|
+
{ role: "user", content: raw }
|
|
7165
|
+
]
|
|
7166
|
+
});
|
|
7167
|
+
return text || raw;
|
|
7168
|
+
}
|
|
7032
7169
|
/**
|
|
7033
7170
|
* Soft-delete a memory by ID.
|
|
7034
7171
|
*/
|
|
@@ -7088,7 +7225,7 @@ Return a JSON array of strings. Example:
|
|
|
7088
7225
|
}
|
|
7089
7226
|
async verifyMemory(content, signal) {
|
|
7090
7227
|
const text = await runKimiText({
|
|
7091
|
-
...this.
|
|
7228
|
+
...this.plumbingLlmOpts,
|
|
7092
7229
|
signal,
|
|
7093
7230
|
messages: [
|
|
7094
7231
|
{ role: "system", content: VERIFY_SYSTEM },
|
|
@@ -7112,31 +7249,13 @@ Context: This memory was explicitly provided by the user during a conversation.`
|
|
|
7112
7249
|
const corrected = typeof rec.corrected_content === "string" ? rec.corrected_content : null;
|
|
7113
7250
|
return { valid, corrected_content: corrected };
|
|
7114
7251
|
}
|
|
7115
|
-
|
|
7252
|
+
normalizeTopicKey(content, repoPath) {
|
|
7116
7253
|
const existingKeys = listTopicKeys(this.db, repoPath);
|
|
7117
|
-
|
|
7118
|
-
const text = await runKimiText({
|
|
7119
|
-
...this.llmOpts,
|
|
7120
|
-
signal,
|
|
7121
|
-
messages: [
|
|
7122
|
-
{ role: "system", content: TOPIC_KEY_SYSTEM },
|
|
7123
|
-
{
|
|
7124
|
-
role: "user",
|
|
7125
|
-
content: `Existing topic keys:
|
|
7126
|
-
${keysBlock}
|
|
7127
|
-
|
|
7128
|
-
New memory: "${content}"
|
|
7129
|
-
|
|
7130
|
-
Return only the topic key string.`
|
|
7131
|
-
}
|
|
7132
|
-
]
|
|
7133
|
-
});
|
|
7134
|
-
const key = text.trim().toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "").slice(0, 60);
|
|
7135
|
-
return key || null;
|
|
7254
|
+
return pickTopicKey(content, existingKeys);
|
|
7136
7255
|
}
|
|
7137
7256
|
async generateHypotheticalQueries(content, signal) {
|
|
7138
7257
|
const text = await runKimiText({
|
|
7139
|
-
...this.
|
|
7258
|
+
...this.plumbingLlmOpts,
|
|
7140
7259
|
signal,
|
|
7141
7260
|
messages: [
|
|
7142
7261
|
{ role: "system", content: HYPOTHETICAL_QUERIES_SYSTEM },
|
|
@@ -7194,6 +7313,18 @@ var init_state = __esm({
|
|
|
7194
7313
|
});
|
|
7195
7314
|
|
|
7196
7315
|
// src/commands/frontmatter.ts
|
|
7316
|
+
function serializeFrontmatter(data) {
|
|
7317
|
+
const lines = [];
|
|
7318
|
+
for (const [key, value] of Object.entries(data)) {
|
|
7319
|
+
if (value === void 0 || value === "") continue;
|
|
7320
|
+
lines.push(`${key}: ${value}`);
|
|
7321
|
+
}
|
|
7322
|
+
if (lines.length === 0) return "";
|
|
7323
|
+
return `---
|
|
7324
|
+
${lines.join("\n")}
|
|
7325
|
+
---
|
|
7326
|
+
`;
|
|
7327
|
+
}
|
|
7197
7328
|
function parseFrontmatter(input) {
|
|
7198
7329
|
const errors = [];
|
|
7199
7330
|
if (!FENCE.test(input)) {
|
|
@@ -7532,19 +7663,566 @@ var init_renderer = __esm({
|
|
|
7532
7663
|
}
|
|
7533
7664
|
});
|
|
7534
7665
|
|
|
7666
|
+
// src/commands/save.ts
|
|
7667
|
+
import { mkdir as mkdir8, writeFile as writeFile8, unlink as unlink2 } from "fs/promises";
|
|
7668
|
+
import { dirname as dirname5 } from "path";
|
|
7669
|
+
async function saveCustomCommand(opts2) {
|
|
7670
|
+
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
7671
|
+
const filepath = `${dir}/${opts2.name}.md`;
|
|
7672
|
+
const data = {};
|
|
7673
|
+
if (opts2.description) data.description = opts2.description;
|
|
7674
|
+
if (opts2.mode) data.mode = opts2.mode;
|
|
7675
|
+
if (opts2.model) data.model = opts2.model;
|
|
7676
|
+
if (opts2.effort) data.effort = opts2.effort;
|
|
7677
|
+
const frontmatter = serializeFrontmatter(data);
|
|
7678
|
+
const content = frontmatter + opts2.template;
|
|
7679
|
+
await mkdir8(dirname5(filepath), { recursive: true });
|
|
7680
|
+
await writeFile8(filepath, content, "utf8");
|
|
7681
|
+
return { filepath };
|
|
7682
|
+
}
|
|
7683
|
+
async function deleteCustomCommand(cmd) {
|
|
7684
|
+
await unlink2(cmd.filepath);
|
|
7685
|
+
}
|
|
7686
|
+
var init_save = __esm({
|
|
7687
|
+
"src/commands/save.ts"() {
|
|
7688
|
+
"use strict";
|
|
7689
|
+
init_frontmatter();
|
|
7690
|
+
init_loader();
|
|
7691
|
+
}
|
|
7692
|
+
});
|
|
7693
|
+
|
|
7694
|
+
// src/ui/command-wizard.tsx
|
|
7695
|
+
import { useState as useState7 } from "react";
|
|
7696
|
+
import { Box as Box13, Text as Text14, useInput as useInput3, useWindowSize as useWindowSize2 } from "ink";
|
|
7697
|
+
import SelectInput5 from "ink-select-input";
|
|
7698
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7699
|
+
function CommandWizard({ theme, mode, initial, existingNames, builtinNames, onDone, onSave }) {
|
|
7700
|
+
const [step, setStep] = useState7("name");
|
|
7701
|
+
const [name, setName] = useState7(initial?.name ?? "");
|
|
7702
|
+
const [description, setDescription] = useState7(initial?.description ?? "");
|
|
7703
|
+
const [template, setTemplate] = useState7(initial?.template ?? "");
|
|
7704
|
+
const [cmdMode, setCmdMode] = useState7(initial?.mode);
|
|
7705
|
+
const [cmdEffort, setCmdEffort] = useState7(initial?.effort);
|
|
7706
|
+
const [cmdModel, setCmdModel] = useState7(initial?.model);
|
|
7707
|
+
const [source, setSource] = useState7(initial?.source ?? "project");
|
|
7708
|
+
const [error, setError] = useState7(null);
|
|
7709
|
+
const { columns } = useWindowSize2();
|
|
7710
|
+
const totalSteps = 5;
|
|
7711
|
+
const stepIndex = step === "name" ? 1 : step === "description" ? 2 : step === "template" ? 3 : step === "advanced" || step === "mode" || step === "effort" || step === "model" ? 4 : step === "location" ? 4 : 5;
|
|
7712
|
+
const isEditingSelf = (n) => initial !== void 0 && initial.name === n;
|
|
7713
|
+
const validateName = (n) => {
|
|
7714
|
+
const trimmed = n.trim();
|
|
7715
|
+
if (!trimmed) return "name is required";
|
|
7716
|
+
if (!NAME_RE.test(trimmed)) return "invalid name: use letters, numbers, _ - / only; must start with a letter";
|
|
7717
|
+
if (builtinNames.has(trimmed.toLowerCase())) return `/${trimmed} is a built-in command`;
|
|
7718
|
+
if (existingNames.includes(trimmed) && !isEditingSelf(trimmed)) return `/${trimmed} already exists`;
|
|
7719
|
+
return null;
|
|
7720
|
+
};
|
|
7721
|
+
useInput3((_input, key) => {
|
|
7722
|
+
if (key.escape) {
|
|
7723
|
+
onDone();
|
|
7724
|
+
}
|
|
7725
|
+
});
|
|
7726
|
+
const handleNameSubmit = (value) => {
|
|
7727
|
+
const trimmed = value.trim();
|
|
7728
|
+
const err = validateName(trimmed);
|
|
7729
|
+
if (err) {
|
|
7730
|
+
setError(err);
|
|
7731
|
+
return;
|
|
7732
|
+
}
|
|
7733
|
+
setError(null);
|
|
7734
|
+
setName(trimmed);
|
|
7735
|
+
setStep("description");
|
|
7736
|
+
};
|
|
7737
|
+
const handleDescriptionSubmit = (value) => {
|
|
7738
|
+
setDescription(value.trim());
|
|
7739
|
+
setStep("template");
|
|
7740
|
+
};
|
|
7741
|
+
const handleTemplateSubmit = (value) => {
|
|
7742
|
+
const trimmed = value.trim();
|
|
7743
|
+
if (!trimmed) {
|
|
7744
|
+
setError("template cannot be empty");
|
|
7745
|
+
return;
|
|
7746
|
+
}
|
|
7747
|
+
setError(null);
|
|
7748
|
+
setTemplate(trimmed);
|
|
7749
|
+
setStep("advanced");
|
|
7750
|
+
};
|
|
7751
|
+
const handleAdvancedChoice = (choice) => {
|
|
7752
|
+
if (choice === "skip") {
|
|
7753
|
+
setCmdMode(void 0);
|
|
7754
|
+
setCmdEffort(void 0);
|
|
7755
|
+
setCmdModel("");
|
|
7756
|
+
if (mode === "edit" && initial) {
|
|
7757
|
+
setSource(initial.source);
|
|
7758
|
+
setStep("confirm");
|
|
7759
|
+
} else {
|
|
7760
|
+
setStep("location");
|
|
7761
|
+
}
|
|
7762
|
+
} else {
|
|
7763
|
+
setStep("mode");
|
|
7764
|
+
}
|
|
7765
|
+
};
|
|
7766
|
+
const handleModeChoice = (m) => {
|
|
7767
|
+
setCmdMode(m === "none" ? void 0 : m);
|
|
7768
|
+
setStep("effort");
|
|
7769
|
+
};
|
|
7770
|
+
const handleEffortChoice = (e) => {
|
|
7771
|
+
setCmdEffort(e === "none" ? void 0 : e);
|
|
7772
|
+
setStep("model");
|
|
7773
|
+
};
|
|
7774
|
+
const handleModelSubmit = (value) => {
|
|
7775
|
+
const trimmed = value.trim();
|
|
7776
|
+
setCmdModel(trimmed || void 0);
|
|
7777
|
+
if (mode === "edit" && initial) {
|
|
7778
|
+
setSource(initial.source);
|
|
7779
|
+
setStep("confirm");
|
|
7780
|
+
} else {
|
|
7781
|
+
setStep("location");
|
|
7782
|
+
}
|
|
7783
|
+
};
|
|
7784
|
+
const handleLocationChoice = (s) => {
|
|
7785
|
+
setSource(s);
|
|
7786
|
+
setStep("confirm");
|
|
7787
|
+
};
|
|
7788
|
+
const handleConfirm = (choice) => {
|
|
7789
|
+
if (choice === "cancel") {
|
|
7790
|
+
onDone();
|
|
7791
|
+
return;
|
|
7792
|
+
}
|
|
7793
|
+
onSave({
|
|
7794
|
+
name,
|
|
7795
|
+
description: description || void 0,
|
|
7796
|
+
template,
|
|
7797
|
+
source,
|
|
7798
|
+
mode: cmdMode,
|
|
7799
|
+
model: cmdModel || void 0,
|
|
7800
|
+
effort: cmdEffort
|
|
7801
|
+
});
|
|
7802
|
+
};
|
|
7803
|
+
const previewContent = () => {
|
|
7804
|
+
const data = {};
|
|
7805
|
+
if (description) data.description = description;
|
|
7806
|
+
if (cmdMode) data.mode = cmdMode;
|
|
7807
|
+
if (cmdModel) data.model = cmdModel;
|
|
7808
|
+
if (cmdEffort) data.effort = cmdEffort;
|
|
7809
|
+
const fm = Object.entries(data).map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
7810
|
+
if (fm) {
|
|
7811
|
+
return `---
|
|
7812
|
+
${fm}
|
|
7813
|
+
---
|
|
7814
|
+
${template}`;
|
|
7815
|
+
}
|
|
7816
|
+
return template;
|
|
7817
|
+
};
|
|
7818
|
+
const renderStep = () => {
|
|
7819
|
+
switch (step) {
|
|
7820
|
+
case "name":
|
|
7821
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7822
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7823
|
+
mode === "create" ? "Create" : "Edit",
|
|
7824
|
+
" custom command \u2014 Name (",
|
|
7825
|
+
stepIndex,
|
|
7826
|
+
"/",
|
|
7827
|
+
totalSteps,
|
|
7828
|
+
")"
|
|
7829
|
+
] }),
|
|
7830
|
+
error && /* @__PURE__ */ jsx14(Text14, { color: theme.error, children: error }),
|
|
7831
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
7832
|
+
CustomTextInput,
|
|
7833
|
+
{
|
|
7834
|
+
value: name,
|
|
7835
|
+
onChange: setName,
|
|
7836
|
+
onSubmit: handleNameSubmit,
|
|
7837
|
+
focus: true
|
|
7838
|
+
}
|
|
7839
|
+
) }),
|
|
7840
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "letters, numbers, _ - / only; must start with a letter" })
|
|
7841
|
+
] });
|
|
7842
|
+
case "description":
|
|
7843
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7844
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7845
|
+
mode === "create" ? "Create" : "Edit",
|
|
7846
|
+
" custom command \u2014 Description (",
|
|
7847
|
+
stepIndex,
|
|
7848
|
+
"/",
|
|
7849
|
+
totalSteps,
|
|
7850
|
+
")"
|
|
7851
|
+
] }),
|
|
7852
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
7853
|
+
CustomTextInput,
|
|
7854
|
+
{
|
|
7855
|
+
value: description,
|
|
7856
|
+
onChange: setDescription,
|
|
7857
|
+
onSubmit: handleDescriptionSubmit,
|
|
7858
|
+
focus: true
|
|
7859
|
+
}
|
|
7860
|
+
) }),
|
|
7861
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Press Enter to skip" })
|
|
7862
|
+
] });
|
|
7863
|
+
case "template": {
|
|
7864
|
+
const guide = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
|
|
7865
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.accent, bold: true, children: "What is this?" }),
|
|
7866
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "A prompt template \u2014 instructions to the AI." }),
|
|
7867
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
7868
|
+
"When you type /",
|
|
7869
|
+
name || "yourcommand",
|
|
7870
|
+
" later, this gets sent to the model."
|
|
7871
|
+
] }),
|
|
7872
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
7873
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.accent, bold: true, children: "Variables" }),
|
|
7874
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
7875
|
+
" ",
|
|
7876
|
+
"$1, $2 ... \u2192 arguments you type"
|
|
7877
|
+
] }),
|
|
7878
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
7879
|
+
" ",
|
|
7880
|
+
"$ARGUMENTS \u2192 everything after the command"
|
|
7881
|
+
] })
|
|
7882
|
+
] }),
|
|
7883
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
7884
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.accent, bold: true, children: "Dynamic inlines" }),
|
|
7885
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
7886
|
+
" ",
|
|
7887
|
+
"!`git diff` \u2192 shell output inlined"
|
|
7888
|
+
] }),
|
|
7889
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
7890
|
+
" ",
|
|
7891
|
+
"@README.md \u2192 file contents inlined"
|
|
7892
|
+
] })
|
|
7893
|
+
] }),
|
|
7894
|
+
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
7895
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.accent, bold: true, children: "Example" }),
|
|
7896
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Review this PR diff:" }),
|
|
7897
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "!`git diff main...HEAD`" }),
|
|
7898
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Focus on: $1" })
|
|
7899
|
+
] })
|
|
7900
|
+
] });
|
|
7901
|
+
const inputArea = /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, children: [
|
|
7902
|
+
error && /* @__PURE__ */ jsx14(Text14, { color: theme.error, children: error }),
|
|
7903
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
7904
|
+
CustomTextInput,
|
|
7905
|
+
{
|
|
7906
|
+
value: template,
|
|
7907
|
+
onChange: setTemplate,
|
|
7908
|
+
onSubmit: handleTemplateSubmit,
|
|
7909
|
+
focus: true,
|
|
7910
|
+
enablePaste: true
|
|
7911
|
+
}
|
|
7912
|
+
) }),
|
|
7913
|
+
columns < 100 && /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7914
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Paste multi-line templates with Ctrl+V." }),
|
|
7915
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Variables: $1 $2 ... $ARGUMENTS Shell: !`cmd` File: @path" })
|
|
7916
|
+
] })
|
|
7917
|
+
] });
|
|
7918
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7919
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7920
|
+
mode === "create" ? "Create" : "Edit",
|
|
7921
|
+
" custom command \u2014 Template (",
|
|
7922
|
+
stepIndex,
|
|
7923
|
+
"/",
|
|
7924
|
+
totalSteps,
|
|
7925
|
+
")"
|
|
7926
|
+
] }),
|
|
7927
|
+
columns >= 100 ? /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", marginTop: 1, children: [
|
|
7928
|
+
/* @__PURE__ */ jsx14(Box13, { flexDirection: "column", width: "50%", children: inputArea }),
|
|
7929
|
+
/* @__PURE__ */ jsx14(Box13, { flexDirection: "column", width: "50%", children: guide })
|
|
7930
|
+
] }) : /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", marginTop: 1, children: inputArea })
|
|
7931
|
+
] });
|
|
7932
|
+
}
|
|
7933
|
+
case "advanced": {
|
|
7934
|
+
const items = [
|
|
7935
|
+
{ label: "Set advanced options", value: "set", key: "set" },
|
|
7936
|
+
{ label: "Skip", value: "skip", key: "skip" },
|
|
7937
|
+
{ label: "\u2190 Cancel", value: "cancel", key: "cancel" }
|
|
7938
|
+
];
|
|
7939
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7940
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7941
|
+
mode === "create" ? "Create" : "Edit",
|
|
7942
|
+
" custom command \u2014 Options (",
|
|
7943
|
+
stepIndex,
|
|
7944
|
+
"/",
|
|
7945
|
+
totalSteps,
|
|
7946
|
+
")"
|
|
7947
|
+
] }),
|
|
7948
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
7949
|
+
SelectInput5,
|
|
7950
|
+
{
|
|
7951
|
+
items,
|
|
7952
|
+
onSelect: (item) => {
|
|
7953
|
+
if (item.value === "cancel") onDone();
|
|
7954
|
+
else handleAdvancedChoice(item.value);
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7957
|
+
) })
|
|
7958
|
+
] });
|
|
7959
|
+
}
|
|
7960
|
+
case "mode": {
|
|
7961
|
+
const items = [
|
|
7962
|
+
{ label: cmdMode === void 0 ? "none \xB7 current" : "none", value: "none", key: "none" },
|
|
7963
|
+
{ label: cmdMode === "edit" ? "edit \xB7 current" : "edit", value: "edit", key: "edit" },
|
|
7964
|
+
{ label: cmdMode === "plan" ? "plan \xB7 current" : "plan", value: "plan", key: "plan" },
|
|
7965
|
+
{ label: cmdMode === "auto" ? "auto \xB7 current" : "auto", value: "auto", key: "auto" },
|
|
7966
|
+
{ label: "\u2190 Back", value: "__back__", key: "__back__" }
|
|
7967
|
+
];
|
|
7968
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7969
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7970
|
+
"Mode override (",
|
|
7971
|
+
stepIndex,
|
|
7972
|
+
"/",
|
|
7973
|
+
totalSteps,
|
|
7974
|
+
")"
|
|
7975
|
+
] }),
|
|
7976
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Saved to file but not yet enforced at runtime" }),
|
|
7977
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
7978
|
+
SelectInput5,
|
|
7979
|
+
{
|
|
7980
|
+
items,
|
|
7981
|
+
onSelect: (item) => {
|
|
7982
|
+
if (item.value === "__back__") setStep("advanced");
|
|
7983
|
+
else handleModeChoice(item.value);
|
|
7984
|
+
}
|
|
7985
|
+
}
|
|
7986
|
+
) })
|
|
7987
|
+
] });
|
|
7988
|
+
}
|
|
7989
|
+
case "effort": {
|
|
7990
|
+
const items = [
|
|
7991
|
+
{ label: cmdEffort === void 0 ? "none \xB7 current" : "none", value: "none", key: "none" },
|
|
7992
|
+
{ label: cmdEffort === "low" ? "low \xB7 current" : "low", value: "low", key: "low" },
|
|
7993
|
+
{ label: cmdEffort === "medium" ? "medium \xB7 current" : "medium", value: "medium", key: "medium" },
|
|
7994
|
+
{ label: cmdEffort === "high" ? "high \xB7 current" : "high", value: "high", key: "high" },
|
|
7995
|
+
{ label: "\u2190 Back", value: "__back__", key: "__back__" }
|
|
7996
|
+
];
|
|
7997
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
7998
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
7999
|
+
"Reasoning effort (",
|
|
8000
|
+
stepIndex,
|
|
8001
|
+
"/",
|
|
8002
|
+
totalSteps,
|
|
8003
|
+
")"
|
|
8004
|
+
] }),
|
|
8005
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
8006
|
+
SelectInput5,
|
|
8007
|
+
{
|
|
8008
|
+
items,
|
|
8009
|
+
onSelect: (item) => {
|
|
8010
|
+
if (item.value === "__back__") setStep("mode");
|
|
8011
|
+
else handleEffortChoice(item.value);
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
) })
|
|
8015
|
+
] });
|
|
8016
|
+
}
|
|
8017
|
+
case "model":
|
|
8018
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8019
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
8020
|
+
"Model override (",
|
|
8021
|
+
stepIndex,
|
|
8022
|
+
"/",
|
|
8023
|
+
totalSteps,
|
|
8024
|
+
")"
|
|
8025
|
+
] }),
|
|
8026
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
8027
|
+
CustomTextInput,
|
|
8028
|
+
{
|
|
8029
|
+
value: cmdModel ?? "",
|
|
8030
|
+
onChange: setCmdModel,
|
|
8031
|
+
onSubmit: handleModelSubmit,
|
|
8032
|
+
focus: true
|
|
8033
|
+
}
|
|
8034
|
+
) }),
|
|
8035
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Press Enter to skip" })
|
|
8036
|
+
] });
|
|
8037
|
+
case "location": {
|
|
8038
|
+
const items = [
|
|
8039
|
+
{ label: source === "project" ? "Project \xB7 current" : "Project", value: "project", key: "project" },
|
|
8040
|
+
{ label: source === "global" ? "Global \xB7 current" : "Global", value: "global", key: "global" },
|
|
8041
|
+
{ label: "\u2190 Back", value: "__back__", key: "__back__" }
|
|
8042
|
+
];
|
|
8043
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8044
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
8045
|
+
"Save location (",
|
|
8046
|
+
stepIndex,
|
|
8047
|
+
"/",
|
|
8048
|
+
totalSteps,
|
|
8049
|
+
")"
|
|
8050
|
+
] }),
|
|
8051
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
8052
|
+
SelectInput5,
|
|
8053
|
+
{
|
|
8054
|
+
items,
|
|
8055
|
+
onSelect: (item) => {
|
|
8056
|
+
if (item.value === "__back__") setStep("advanced");
|
|
8057
|
+
else handleLocationChoice(item.value);
|
|
8058
|
+
}
|
|
8059
|
+
}
|
|
8060
|
+
) }),
|
|
8061
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: "Project: .kimiflare/commands/ Global: ~/.config/kimiflare/commands/" })
|
|
8062
|
+
] });
|
|
8063
|
+
}
|
|
8064
|
+
case "confirm": {
|
|
8065
|
+
const items = [
|
|
8066
|
+
{ label: "Save", value: "save", key: "save" },
|
|
8067
|
+
{ label: "Cancel", value: "cancel", key: "cancel" }
|
|
8068
|
+
];
|
|
8069
|
+
return /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8070
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.accent, bold: true, children: [
|
|
8071
|
+
mode === "create" ? "Create" : "Edit",
|
|
8072
|
+
" custom command \u2014 Confirm (",
|
|
8073
|
+
stepIndex,
|
|
8074
|
+
"/",
|
|
8075
|
+
totalSteps,
|
|
8076
|
+
")"
|
|
8077
|
+
] }),
|
|
8078
|
+
/* @__PURE__ */ jsxs13(Text14, { color: theme.info.color, dimColor: true, children: [
|
|
8079
|
+
source === "project" ? ".kimiflare/commands/" : "~/.config/kimiflare/commands/",
|
|
8080
|
+
name,
|
|
8081
|
+
".md"
|
|
8082
|
+
] }),
|
|
8083
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, flexDirection: "column", children: previewContent().split("\n").map((line, i) => /* @__PURE__ */ jsx14(Text14, { color: theme.info.color, dimColor: true, children: line || " " }, i)) }),
|
|
8084
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(
|
|
8085
|
+
SelectInput5,
|
|
8086
|
+
{
|
|
8087
|
+
items,
|
|
8088
|
+
onSelect: (item) => handleConfirm(item.value)
|
|
8089
|
+
}
|
|
8090
|
+
) })
|
|
8091
|
+
] });
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
8094
|
+
};
|
|
8095
|
+
return /* @__PURE__ */ jsx14(Box13, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: renderStep() });
|
|
8096
|
+
}
|
|
8097
|
+
var NAME_RE;
|
|
8098
|
+
var init_command_wizard = __esm({
|
|
8099
|
+
"src/ui/command-wizard.tsx"() {
|
|
8100
|
+
"use strict";
|
|
8101
|
+
init_text_input();
|
|
8102
|
+
NAME_RE = /^[a-zA-Z][a-zA-Z0-9_\-/]*$/;
|
|
8103
|
+
}
|
|
8104
|
+
});
|
|
8105
|
+
|
|
8106
|
+
// src/ui/command-picker.tsx
|
|
8107
|
+
import { Box as Box14, Text as Text15 } from "ink";
|
|
8108
|
+
import SelectInput6 from "ink-select-input";
|
|
8109
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
8110
|
+
function CommandPicker({ theme, commands, title, onPick }) {
|
|
8111
|
+
const items = commands.map((cmd) => ({
|
|
8112
|
+
label: `/${cmd.name.padEnd(20)} ${cmd.description ?? ""}`,
|
|
8113
|
+
value: cmd,
|
|
8114
|
+
key: cmd.name
|
|
8115
|
+
}));
|
|
8116
|
+
items.push({ label: "\u2190 Cancel", value: null, key: "__cancel__" });
|
|
8117
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
8118
|
+
/* @__PURE__ */ jsx15(Text15, { color: theme.accent, bold: true, children: title }),
|
|
8119
|
+
/* @__PURE__ */ jsx15(Text15, { color: theme.info.color, dimColor: false, children: "Arrow keys to navigate, Enter to select." }),
|
|
8120
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(
|
|
8121
|
+
SelectInput6,
|
|
8122
|
+
{
|
|
8123
|
+
items,
|
|
8124
|
+
onSelect: (item) => {
|
|
8125
|
+
if (item.key === "__cancel__") {
|
|
8126
|
+
onPick(null);
|
|
8127
|
+
} else {
|
|
8128
|
+
onPick(item.value);
|
|
8129
|
+
}
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8132
|
+
) })
|
|
8133
|
+
] });
|
|
8134
|
+
}
|
|
8135
|
+
var init_command_picker = __esm({
|
|
8136
|
+
"src/ui/command-picker.tsx"() {
|
|
8137
|
+
"use strict";
|
|
8138
|
+
}
|
|
8139
|
+
});
|
|
8140
|
+
|
|
8141
|
+
// src/ui/command-list.tsx
|
|
8142
|
+
import { Box as Box15, Text as Text16, useInput as useInput4 } from "ink";
|
|
8143
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
8144
|
+
function CommandList({ theme, commands, onDone }) {
|
|
8145
|
+
useInput4((_input, key) => {
|
|
8146
|
+
if (key.escape) {
|
|
8147
|
+
onDone();
|
|
8148
|
+
}
|
|
8149
|
+
});
|
|
8150
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
8151
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.accent, bold: true, children: "Custom commands" }),
|
|
8152
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.info.color, dimColor: false, children: "Esc to close." }),
|
|
8153
|
+
/* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
8154
|
+
commands.length === 0 && /* @__PURE__ */ jsx16(Text16, { color: theme.info.color, dimColor: true, children: "No custom commands found." }),
|
|
8155
|
+
commands.map((cmd) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginBottom: 1, children: [
|
|
8156
|
+
/* @__PURE__ */ jsxs15(Text16, { color: theme.accent, bold: true, children: [
|
|
8157
|
+
"/",
|
|
8158
|
+
cmd.name
|
|
8159
|
+
] }),
|
|
8160
|
+
/* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8161
|
+
" ",
|
|
8162
|
+
"source: ",
|
|
8163
|
+
cmd.source
|
|
8164
|
+
] }),
|
|
8165
|
+
/* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8166
|
+
" ",
|
|
8167
|
+
"path: ",
|
|
8168
|
+
cmd.filepath
|
|
8169
|
+
] }),
|
|
8170
|
+
cmd.description && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8171
|
+
" ",
|
|
8172
|
+
"desc: ",
|
|
8173
|
+
cmd.description
|
|
8174
|
+
] }),
|
|
8175
|
+
cmd.mode && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8176
|
+
" ",
|
|
8177
|
+
"mode: ",
|
|
8178
|
+
cmd.mode
|
|
8179
|
+
] }),
|
|
8180
|
+
cmd.effort && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8181
|
+
" ",
|
|
8182
|
+
"effort: ",
|
|
8183
|
+
cmd.effort
|
|
8184
|
+
] }),
|
|
8185
|
+
cmd.model && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8186
|
+
" ",
|
|
8187
|
+
"model: ",
|
|
8188
|
+
cmd.model
|
|
8189
|
+
] }),
|
|
8190
|
+
/* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8191
|
+
" ",
|
|
8192
|
+
"template:"
|
|
8193
|
+
] }),
|
|
8194
|
+
cmd.template.split("\n").slice(0, 5).map((line, i) => /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8195
|
+
" ",
|
|
8196
|
+
line || " "
|
|
8197
|
+
] }, i)),
|
|
8198
|
+
cmd.template.split("\n").length > 5 && /* @__PURE__ */ jsxs15(Text16, { color: theme.info.color, dimColor: true, children: [
|
|
8199
|
+
" ",
|
|
8200
|
+
"..."
|
|
8201
|
+
] })
|
|
8202
|
+
] }, cmd.name))
|
|
8203
|
+
] })
|
|
8204
|
+
] });
|
|
8205
|
+
}
|
|
8206
|
+
var init_command_list = __esm({
|
|
8207
|
+
"src/ui/command-list.tsx"() {
|
|
8208
|
+
"use strict";
|
|
8209
|
+
}
|
|
8210
|
+
});
|
|
8211
|
+
|
|
7535
8212
|
// src/app.tsx
|
|
7536
8213
|
var app_exports = {};
|
|
7537
8214
|
__export(app_exports, {
|
|
7538
8215
|
renderApp: () => renderApp
|
|
7539
8216
|
});
|
|
7540
|
-
import { useState as
|
|
7541
|
-
import { Box as
|
|
8217
|
+
import { useState as useState8, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
|
|
8218
|
+
import { Box as Box16, Text as Text17, useApp, useInput as useInput5, render } from "ink";
|
|
8219
|
+
import SelectInput7 from "ink-select-input";
|
|
7542
8220
|
import { existsSync } from "fs";
|
|
7543
8221
|
import { join as join13 } from "path";
|
|
7544
|
-
import { unlink as
|
|
8222
|
+
import { unlink as unlink3 } from "fs/promises";
|
|
7545
8223
|
import { spawn as spawn2 } from "child_process";
|
|
7546
8224
|
import { platform as platform2 } from "os";
|
|
7547
|
-
import { jsx as
|
|
8225
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
7548
8226
|
function gatewayFromConfig(cfg) {
|
|
7549
8227
|
if (!cfg.aiGatewayId) return void 0;
|
|
7550
8228
|
return {
|
|
@@ -7615,8 +8293,8 @@ function findImagePaths(text) {
|
|
|
7615
8293
|
}
|
|
7616
8294
|
function App({ initialCfg, initialUpdateResult }) {
|
|
7617
8295
|
const { exit } = useApp();
|
|
7618
|
-
const [cfg, setCfg] =
|
|
7619
|
-
const [events, setRawEvents] =
|
|
8296
|
+
const [cfg, setCfg] = useState8(initialCfg);
|
|
8297
|
+
const [events, setRawEvents] = useState8([]);
|
|
7620
8298
|
const setEvents = useCallback(
|
|
7621
8299
|
(updater) => {
|
|
7622
8300
|
setRawEvents((prev) => {
|
|
@@ -7626,34 +8304,38 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7626
8304
|
},
|
|
7627
8305
|
[]
|
|
7628
8306
|
);
|
|
7629
|
-
const [input, setInput] =
|
|
7630
|
-
const [busy, setBusy] =
|
|
7631
|
-
const [usage, setUsage] =
|
|
7632
|
-
const [sessionUsage, setSessionUsage] =
|
|
7633
|
-
const [gatewayMeta, setGatewayMeta] =
|
|
7634
|
-
const [showReasoning, setShowReasoning] =
|
|
7635
|
-
const [perm, setPerm] =
|
|
7636
|
-
const [queue, setQueue] =
|
|
7637
|
-
const [history, setHistory] =
|
|
7638
|
-
const [historyIndex, setHistoryIndex] =
|
|
7639
|
-
const [draftInput, setDraftInput] =
|
|
7640
|
-
const [mode, setMode] =
|
|
7641
|
-
const [codeMode, setCodeMode] =
|
|
7642
|
-
const [effort, setEffort] =
|
|
8307
|
+
const [input, setInput] = useState8("");
|
|
8308
|
+
const [busy, setBusy] = useState8(false);
|
|
8309
|
+
const [usage, setUsage] = useState8(null);
|
|
8310
|
+
const [sessionUsage, setSessionUsage] = useState8(null);
|
|
8311
|
+
const [gatewayMeta, setGatewayMeta] = useState8(null);
|
|
8312
|
+
const [showReasoning, setShowReasoning] = useState8(false);
|
|
8313
|
+
const [perm, setPerm] = useState8(null);
|
|
8314
|
+
const [queue, setQueue] = useState8([]);
|
|
8315
|
+
const [history, setHistory] = useState8([]);
|
|
8316
|
+
const [historyIndex, setHistoryIndex] = useState8(-1);
|
|
8317
|
+
const [draftInput, setDraftInput] = useState8("");
|
|
8318
|
+
const [mode, setMode] = useState8("edit");
|
|
8319
|
+
const [codeMode, setCodeMode] = useState8(initialCfg?.codeMode ?? false);
|
|
8320
|
+
const [effort, setEffort] = useState8(
|
|
7643
8321
|
initialCfg?.reasoningEffort ?? DEFAULT_REASONING_EFFORT
|
|
7644
8322
|
);
|
|
7645
|
-
const [theme, setTheme] =
|
|
7646
|
-
const [resumeSessions, setResumeSessions] =
|
|
7647
|
-
const [showThemePicker, setShowThemePicker] =
|
|
7648
|
-
const [showHelpMenu, setShowHelpMenu] =
|
|
7649
|
-
const [originalTheme, setOriginalTheme] =
|
|
7650
|
-
const [
|
|
7651
|
-
const [
|
|
7652
|
-
const [
|
|
7653
|
-
const [
|
|
7654
|
-
const [
|
|
7655
|
-
const [
|
|
7656
|
-
const [
|
|
8323
|
+
const [theme, setTheme] = useState8(resolveTheme(initialCfg?.theme));
|
|
8324
|
+
const [resumeSessions, setResumeSessions] = useState8(null);
|
|
8325
|
+
const [showThemePicker, setShowThemePicker] = useState8(false);
|
|
8326
|
+
const [showHelpMenu, setShowHelpMenu] = useState8(false);
|
|
8327
|
+
const [originalTheme, setOriginalTheme] = useState8(null);
|
|
8328
|
+
const [commandWizard, setCommandWizard] = useState8(null);
|
|
8329
|
+
const [commandPicker, setCommandPicker] = useState8(null);
|
|
8330
|
+
const [commandToDelete, setCommandToDelete] = useState8(null);
|
|
8331
|
+
const [showCommandList, setShowCommandList] = useState8(false);
|
|
8332
|
+
const [tasks, setTasks] = useState8([]);
|
|
8333
|
+
const [tasksStartedAt, setTasksStartedAt] = useState8(null);
|
|
8334
|
+
const [tasksStartTokens, setTasksStartTokens] = useState8(0);
|
|
8335
|
+
const [turnStartedAt, setTurnStartedAt] = useState8(null);
|
|
8336
|
+
const [verbose, setVerbose] = useState8(false);
|
|
8337
|
+
const [hasUpdate, setHasUpdate] = useState8(initialUpdateResult?.hasUpdate ?? false);
|
|
8338
|
+
const [latestVersion, setLatestVersion] = useState8(initialUpdateResult?.latestVersion ?? null);
|
|
7657
8339
|
const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
|
|
7658
8340
|
const messagesRef = useRef3(
|
|
7659
8341
|
makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
|
|
@@ -7677,6 +8359,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7677
8359
|
const mcpToolsRef = useRef3([]);
|
|
7678
8360
|
const mcpInitRef = useRef3(false);
|
|
7679
8361
|
const memoryManagerRef = useRef3(null);
|
|
8362
|
+
const sessionStartRecallRef = useRef3(null);
|
|
7680
8363
|
const pendingTextRef = useRef3(/* @__PURE__ */ new Map());
|
|
7681
8364
|
const flushTimeoutRef = useRef3(null);
|
|
7682
8365
|
const customCommandsRef = useRef3([]);
|
|
@@ -7712,6 +8395,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7712
8395
|
accountId: cfg.accountId,
|
|
7713
8396
|
apiToken: cfg.apiToken,
|
|
7714
8397
|
model: cfg.model,
|
|
8398
|
+
plumbingModel: cfg.plumbingModel,
|
|
7715
8399
|
embeddingModel: cfg.memoryEmbeddingModel,
|
|
7716
8400
|
gateway: gatewayFromConfig(cfg),
|
|
7717
8401
|
maxAgeDays: cfg.memoryMaxAgeDays ?? RETENTION.memoryMaxAgeDays,
|
|
@@ -7724,7 +8408,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7724
8408
|
if (total > 0) {
|
|
7725
8409
|
setEvents((e) => [
|
|
7726
8410
|
...e,
|
|
7727
|
-
{ kind: "
|
|
8411
|
+
{ kind: "memory", key: mkKey(), text: `memory cleanup: removed ${total} stale entries` }
|
|
7728
8412
|
]);
|
|
7729
8413
|
}
|
|
7730
8414
|
});
|
|
@@ -7732,10 +8416,27 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7732
8416
|
if (fixed > 0) {
|
|
7733
8417
|
setEvents((e) => [
|
|
7734
8418
|
...e,
|
|
7735
|
-
{ kind: "
|
|
8419
|
+
{ kind: "memory", key: mkKey(), text: `memory backfill: embedded ${fixed} un-vectorized entries` }
|
|
7736
8420
|
]);
|
|
7737
8421
|
}
|
|
7738
8422
|
});
|
|
8423
|
+
const cwd = process.cwd();
|
|
8424
|
+
sessionStartRecallRef.current = (async () => {
|
|
8425
|
+
try {
|
|
8426
|
+
const results = await manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
8427
|
+
if (results.length > 0) {
|
|
8428
|
+
const text = await manager.synthesizeRecalled(results);
|
|
8429
|
+
const lastSystemIdx = messagesRef.current.findLastIndex((m) => m.role === "system");
|
|
8430
|
+
const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messagesRef.current.length;
|
|
8431
|
+
messagesRef.current.splice(insertIdx, 0, { role: "system", content: text });
|
|
8432
|
+
setEvents((e) => [
|
|
8433
|
+
...e,
|
|
8434
|
+
{ kind: "memory", key: mkKey(), text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} about this repo` }
|
|
8435
|
+
]);
|
|
8436
|
+
}
|
|
8437
|
+
} catch {
|
|
8438
|
+
}
|
|
8439
|
+
})();
|
|
7739
8440
|
} else {
|
|
7740
8441
|
memoryManagerRef.current?.close();
|
|
7741
8442
|
memoryManagerRef.current = null;
|
|
@@ -7754,6 +8455,20 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7754
8455
|
}
|
|
7755
8456
|
});
|
|
7756
8457
|
}, [cfg, setEvents]);
|
|
8458
|
+
const reloadCustomCommands = useCallback(async () => {
|
|
8459
|
+
const { commands, warnings } = await loadCustomCommands(process.cwd());
|
|
8460
|
+
customCommandsRef.current = commands;
|
|
8461
|
+
for (const w of warnings) {
|
|
8462
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `commands: ${w}` }]);
|
|
8463
|
+
}
|
|
8464
|
+
const shadowed = commands.filter((c) => BUILTIN_COMMAND_NAMES.has(c.name.toLowerCase()));
|
|
8465
|
+
for (const c of shadowed) {
|
|
8466
|
+
setEvents((e) => [
|
|
8467
|
+
...e,
|
|
8468
|
+
{ kind: "info", key: mkKey(), text: `commands: /${c.name} (${c.filepath}) shadowed by built-in \u2014 will not run` }
|
|
8469
|
+
]);
|
|
8470
|
+
}
|
|
8471
|
+
}, [setEvents]);
|
|
7757
8472
|
useEffect4(() => {
|
|
7758
8473
|
if (!cfg || updateCheckedRef.current) return;
|
|
7759
8474
|
updateCheckedRef.current = true;
|
|
@@ -7956,12 +8671,13 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
7956
8671
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7957
8672
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7958
8673
|
messages: messagesRef.current,
|
|
7959
|
-
sessionState: compiledContextRef.current ? sessionStateRef.current : void 0
|
|
8674
|
+
sessionState: compiledContextRef.current ? sessionStateRef.current : void 0,
|
|
8675
|
+
artifactStore: serializeArtifactStore(artifactStoreRef.current)
|
|
7960
8676
|
});
|
|
7961
8677
|
} catch {
|
|
7962
8678
|
}
|
|
7963
8679
|
}, [cfg, ensureSessionId]);
|
|
7964
|
-
|
|
8680
|
+
useInput5((inputChar, key) => {
|
|
7965
8681
|
if (key.ctrl && inputChar === "c") {
|
|
7966
8682
|
if (busy && activeControllerRef.current) {
|
|
7967
8683
|
activeControllerRef.current.abort();
|
|
@@ -8337,8 +9053,26 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
8337
9053
|
sessionIdRef.current = file.id;
|
|
8338
9054
|
if (file.sessionState && compiledContextRef.current) {
|
|
8339
9055
|
sessionStateRef.current = file.sessionState;
|
|
9056
|
+
}
|
|
9057
|
+
if (file.artifactStore) {
|
|
9058
|
+
artifactStoreRef.current = deserializeArtifactStore(file.artifactStore);
|
|
9059
|
+
} else {
|
|
8340
9060
|
artifactStoreRef.current = new ArtifactStore();
|
|
8341
9061
|
}
|
|
9062
|
+
const manager = memoryManagerRef.current;
|
|
9063
|
+
if (manager) {
|
|
9064
|
+
try {
|
|
9065
|
+
const cwd = process.cwd();
|
|
9066
|
+
const results = await manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
9067
|
+
if (results.length > 0) {
|
|
9068
|
+
const text = await manager.synthesizeRecalled(results);
|
|
9069
|
+
const lastSystemIdx = messagesRef.current.findLastIndex((m) => m.role === "system");
|
|
9070
|
+
const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messagesRef.current.length;
|
|
9071
|
+
messagesRef.current.splice(insertIdx, 0, { role: "system", content: text });
|
|
9072
|
+
}
|
|
9073
|
+
} catch {
|
|
9074
|
+
}
|
|
9075
|
+
}
|
|
8342
9076
|
setEvents([
|
|
8343
9077
|
{
|
|
8344
9078
|
kind: "info",
|
|
@@ -8656,7 +9390,7 @@ use: /thinking low | medium | high`
|
|
|
8656
9390
|
setCfg(next);
|
|
8657
9391
|
void saveConfig(next).catch(() => {
|
|
8658
9392
|
});
|
|
8659
|
-
setEvents((e) => [...e, { kind: "
|
|
9393
|
+
setEvents((e) => [...e, { kind: "memory", key: mkKey(), text: "memory enabled" }]);
|
|
8660
9394
|
return true;
|
|
8661
9395
|
}
|
|
8662
9396
|
if (arg === "off") {
|
|
@@ -8664,7 +9398,7 @@ use: /thinking low | medium | high`
|
|
|
8664
9398
|
setCfg(next);
|
|
8665
9399
|
void saveConfig(next).catch(() => {
|
|
8666
9400
|
});
|
|
8667
|
-
setEvents((e) => [...e, { kind: "
|
|
9401
|
+
setEvents((e) => [...e, { kind: "memory", key: mkKey(), text: "memory disabled" }]);
|
|
8668
9402
|
return true;
|
|
8669
9403
|
}
|
|
8670
9404
|
if (!cfg.memoryEnabled) {
|
|
@@ -8673,7 +9407,7 @@ use: /thinking low | medium | high`
|
|
|
8673
9407
|
}
|
|
8674
9408
|
if (arg === "clear") {
|
|
8675
9409
|
const cleared = memoryManagerRef.current?.clearRepo(process.cwd()) ?? 0;
|
|
8676
|
-
setEvents((e) => [...e, { kind: "
|
|
9410
|
+
setEvents((e) => [...e, { kind: "memory", key: mkKey(), text: `cleared ${cleared} memories for this repo` }]);
|
|
8677
9411
|
return true;
|
|
8678
9412
|
}
|
|
8679
9413
|
if (arg.startsWith("search ")) {
|
|
@@ -8808,7 +9542,7 @@ ${lines.join("\n")}` }]);
|
|
|
8808
9542
|
return true;
|
|
8809
9543
|
}
|
|
8810
9544
|
if (c === "/logout") {
|
|
8811
|
-
|
|
9545
|
+
unlink3(configPath()).catch(() => {
|
|
8812
9546
|
});
|
|
8813
9547
|
setEvents((e) => [
|
|
8814
9548
|
...e,
|
|
@@ -8817,6 +9551,30 @@ ${lines.join("\n")}` }]);
|
|
|
8817
9551
|
setCfg(null);
|
|
8818
9552
|
return true;
|
|
8819
9553
|
}
|
|
9554
|
+
if (c === "/command") {
|
|
9555
|
+
const sub = rest[0]?.toLowerCase() ?? "";
|
|
9556
|
+
if (sub === "create") {
|
|
9557
|
+
setCommandWizard({ mode: "create" });
|
|
9558
|
+
return true;
|
|
9559
|
+
}
|
|
9560
|
+
if (sub === "edit") {
|
|
9561
|
+
setCommandPicker({ mode: "edit" });
|
|
9562
|
+
return true;
|
|
9563
|
+
}
|
|
9564
|
+
if (sub === "delete") {
|
|
9565
|
+
setCommandPicker({ mode: "delete" });
|
|
9566
|
+
return true;
|
|
9567
|
+
}
|
|
9568
|
+
if (sub === "list") {
|
|
9569
|
+
setShowCommandList(true);
|
|
9570
|
+
return true;
|
|
9571
|
+
}
|
|
9572
|
+
setEvents((e) => [
|
|
9573
|
+
...e,
|
|
9574
|
+
{ kind: "info", key: mkKey(), text: "usage: /command create | edit | delete | list" }
|
|
9575
|
+
]);
|
|
9576
|
+
return true;
|
|
9577
|
+
}
|
|
8820
9578
|
if (c === "/help") {
|
|
8821
9579
|
setShowHelpMenu(true);
|
|
8822
9580
|
return true;
|
|
@@ -8835,6 +9593,47 @@ ${lines.join("\n")}` }]);
|
|
|
8835
9593
|
},
|
|
8836
9594
|
[handleSlash]
|
|
8837
9595
|
);
|
|
9596
|
+
const handleCommandSave = useCallback(
|
|
9597
|
+
async (opts2) => {
|
|
9598
|
+
setCommandWizard(null);
|
|
9599
|
+
try {
|
|
9600
|
+
if (commandWizard?.mode === "edit" && commandWizard.initial && commandWizard.initial.name !== opts2.name) {
|
|
9601
|
+
await deleteCustomCommand(commandWizard.initial);
|
|
9602
|
+
}
|
|
9603
|
+
const result = await saveCustomCommand(opts2);
|
|
9604
|
+
await reloadCustomCommands();
|
|
9605
|
+
setEvents((e) => [
|
|
9606
|
+
...e,
|
|
9607
|
+
{ kind: "info", key: mkKey(), text: `saved /${opts2.name} \u2192 ${result.filepath}` }
|
|
9608
|
+
]);
|
|
9609
|
+
} catch (err) {
|
|
9610
|
+
setEvents((e) => [
|
|
9611
|
+
...e,
|
|
9612
|
+
{ kind: "error", key: mkKey(), text: `failed to save /${opts2.name}: ${err.message}` }
|
|
9613
|
+
]);
|
|
9614
|
+
}
|
|
9615
|
+
},
|
|
9616
|
+
[commandWizard, reloadCustomCommands, setEvents]
|
|
9617
|
+
);
|
|
9618
|
+
const handleCommandDelete = useCallback(
|
|
9619
|
+
async (cmd) => {
|
|
9620
|
+
setCommandToDelete(null);
|
|
9621
|
+
try {
|
|
9622
|
+
await deleteCustomCommand(cmd);
|
|
9623
|
+
await reloadCustomCommands();
|
|
9624
|
+
setEvents((e) => [
|
|
9625
|
+
...e,
|
|
9626
|
+
{ kind: "info", key: mkKey(), text: `deleted /${cmd.name} (${cmd.filepath})` }
|
|
9627
|
+
]);
|
|
9628
|
+
} catch (err) {
|
|
9629
|
+
setEvents((e) => [
|
|
9630
|
+
...e,
|
|
9631
|
+
{ kind: "error", key: mkKey(), text: `failed to delete /${cmd.name}: ${err.message}` }
|
|
9632
|
+
]);
|
|
9633
|
+
}
|
|
9634
|
+
},
|
|
9635
|
+
[reloadCustomCommands, setEvents]
|
|
9636
|
+
);
|
|
8838
9637
|
const processMessage = useCallback(
|
|
8839
9638
|
async (text, displayText) => {
|
|
8840
9639
|
if (!cfg) return;
|
|
@@ -8897,6 +9696,10 @@ ${lines.join("\n")}` }]);
|
|
|
8897
9696
|
content = parts;
|
|
8898
9697
|
}
|
|
8899
9698
|
}
|
|
9699
|
+
if (sessionStartRecallRef.current) {
|
|
9700
|
+
await sessionStartRecallRef.current;
|
|
9701
|
+
sessionStartRecallRef.current = null;
|
|
9702
|
+
}
|
|
8900
9703
|
setEvents((e) => [...e, { kind: "user", key: mkKey(), text: display, images: images.length > 0 ? images : void 0 }]);
|
|
8901
9704
|
messagesRef.current.push({ role: "user", content });
|
|
8902
9705
|
if (compiledContextRef.current) {
|
|
@@ -9088,6 +9891,30 @@ ${lines.join("\n")}` }]);
|
|
|
9088
9891
|
}
|
|
9089
9892
|
}
|
|
9090
9893
|
}
|
|
9894
|
+
const manager = memoryManagerRef.current;
|
|
9895
|
+
if (manager) {
|
|
9896
|
+
try {
|
|
9897
|
+
const cwd = process.cwd();
|
|
9898
|
+
const queryText = sessionStateRef.current.task || cwd;
|
|
9899
|
+
const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
|
|
9900
|
+
if (results.length > 0) {
|
|
9901
|
+
const text2 = await manager.synthesizeRecalled(results);
|
|
9902
|
+
const lastSystemIdx = messagesRef.current.findLastIndex((m) => m.role === "system");
|
|
9903
|
+
const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messagesRef.current.length;
|
|
9904
|
+
messagesRef.current.splice(insertIdx, 0, { role: "system", content: text2 });
|
|
9905
|
+
setEvents((e) => [
|
|
9906
|
+
...e,
|
|
9907
|
+
{
|
|
9908
|
+
kind: "memory",
|
|
9909
|
+
key: mkKey(),
|
|
9910
|
+
text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
|
|
9911
|
+
}
|
|
9912
|
+
]);
|
|
9913
|
+
await saveSessionSafe();
|
|
9914
|
+
}
|
|
9915
|
+
} catch {
|
|
9916
|
+
}
|
|
9917
|
+
}
|
|
9091
9918
|
} catch (e) {
|
|
9092
9919
|
if (e.name === "AbortError") {
|
|
9093
9920
|
setEvents((es) => [...es, { kind: "info", key: mkKey(), text: "(aborted)" }]);
|
|
@@ -9161,7 +9988,7 @@ ${lines.join("\n")}` }]);
|
|
|
9161
9988
|
}
|
|
9162
9989
|
}, [usage]);
|
|
9163
9990
|
if (!cfg) {
|
|
9164
|
-
return /* @__PURE__ */
|
|
9991
|
+
return /* @__PURE__ */ jsx17(
|
|
9165
9992
|
Onboarding,
|
|
9166
9993
|
{
|
|
9167
9994
|
onDone: (newCfg) => {
|
|
@@ -9175,13 +10002,13 @@ ${lines.join("\n")}` }]);
|
|
|
9175
10002
|
);
|
|
9176
10003
|
}
|
|
9177
10004
|
if (resumeSessions !== null) {
|
|
9178
|
-
return /* @__PURE__ */
|
|
10005
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(ResumePicker, { sessions: resumeSessions, onPick: handleResumePick, theme }) });
|
|
9179
10006
|
}
|
|
9180
10007
|
if (showThemePicker) {
|
|
9181
|
-
return /* @__PURE__ */
|
|
10008
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(ThemePicker, { themes: themeList(), current: theme, onPick: handleThemePick, onPreview: (t) => setTheme(t) }) });
|
|
9182
10009
|
}
|
|
9183
10010
|
if (showHelpMenu) {
|
|
9184
|
-
return /* @__PURE__ */
|
|
10011
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(
|
|
9185
10012
|
HelpMenu,
|
|
9186
10013
|
{
|
|
9187
10014
|
theme,
|
|
@@ -9193,10 +10020,79 @@ ${lines.join("\n")}` }]);
|
|
|
9193
10020
|
}
|
|
9194
10021
|
) });
|
|
9195
10022
|
}
|
|
10023
|
+
if (commandWizard) {
|
|
10024
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(
|
|
10025
|
+
CommandWizard,
|
|
10026
|
+
{
|
|
10027
|
+
theme,
|
|
10028
|
+
mode: commandWizard.mode,
|
|
10029
|
+
initial: commandWizard.initial,
|
|
10030
|
+
existingNames: customCommandsRef.current.map((c) => c.name),
|
|
10031
|
+
builtinNames: BUILTIN_COMMAND_NAMES,
|
|
10032
|
+
onDone: () => setCommandWizard(null),
|
|
10033
|
+
onSave: handleCommandSave
|
|
10034
|
+
}
|
|
10035
|
+
) });
|
|
10036
|
+
}
|
|
10037
|
+
if (commandPicker) {
|
|
10038
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(
|
|
10039
|
+
CommandPicker,
|
|
10040
|
+
{
|
|
10041
|
+
theme,
|
|
10042
|
+
commands: customCommandsRef.current,
|
|
10043
|
+
title: commandPicker.mode === "edit" ? "Edit custom command" : "Delete custom command",
|
|
10044
|
+
onPick: (cmd) => {
|
|
10045
|
+
setCommandPicker(null);
|
|
10046
|
+
if (!cmd) return;
|
|
10047
|
+
if (commandPicker.mode === "edit") {
|
|
10048
|
+
setCommandWizard({ mode: "edit", initial: cmd });
|
|
10049
|
+
} else {
|
|
10050
|
+
setCommandToDelete(cmd);
|
|
10051
|
+
}
|
|
10052
|
+
}
|
|
10053
|
+
}
|
|
10054
|
+
) });
|
|
10055
|
+
}
|
|
10056
|
+
if (commandToDelete) {
|
|
10057
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
|
|
10058
|
+
/* @__PURE__ */ jsxs16(Text17, { color: theme.accent, bold: true, children: [
|
|
10059
|
+
"Delete /",
|
|
10060
|
+
commandToDelete.name,
|
|
10061
|
+
"?"
|
|
10062
|
+
] }),
|
|
10063
|
+
/* @__PURE__ */ jsx17(Text17, { color: theme.info.color, dimColor: true, children: commandToDelete.filepath }),
|
|
10064
|
+
/* @__PURE__ */ jsx17(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
10065
|
+
SelectInput7,
|
|
10066
|
+
{
|
|
10067
|
+
items: [
|
|
10068
|
+
{ label: "Yes, delete", value: "yes", key: "yes" },
|
|
10069
|
+
{ label: "Cancel", value: "cancel", key: "cancel" }
|
|
10070
|
+
],
|
|
10071
|
+
onSelect: (item) => {
|
|
10072
|
+
if (item.value === "yes") {
|
|
10073
|
+
void handleCommandDelete(commandToDelete);
|
|
10074
|
+
} else {
|
|
10075
|
+
setCommandToDelete(null);
|
|
10076
|
+
}
|
|
10077
|
+
}
|
|
10078
|
+
}
|
|
10079
|
+
) })
|
|
10080
|
+
] });
|
|
10081
|
+
}
|
|
10082
|
+
if (showCommandList) {
|
|
10083
|
+
return /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx17(
|
|
10084
|
+
CommandList,
|
|
10085
|
+
{
|
|
10086
|
+
theme,
|
|
10087
|
+
commands: customCommandsRef.current,
|
|
10088
|
+
onDone: () => setShowCommandList(false)
|
|
10089
|
+
}
|
|
10090
|
+
) });
|
|
10091
|
+
}
|
|
9196
10092
|
const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
|
|
9197
|
-
return /* @__PURE__ */
|
|
9198
|
-
!hasConversation && events.length === 0 ? /* @__PURE__ */
|
|
9199
|
-
perm ? /* @__PURE__ */
|
|
10093
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
10094
|
+
!hasConversation && events.length === 0 ? /* @__PURE__ */ jsx17(Welcome, { theme, accountId: cfg.accountId }) : /* @__PURE__ */ jsx17(ChatView, { events, showReasoning, theme, verbose }),
|
|
10095
|
+
perm ? /* @__PURE__ */ jsx17(
|
|
9200
10096
|
PermissionModal,
|
|
9201
10097
|
{
|
|
9202
10098
|
tool: perm.tool,
|
|
@@ -9207,8 +10103,8 @@ ${lines.join("\n")}` }]);
|
|
|
9207
10103
|
setPerm(null);
|
|
9208
10104
|
}
|
|
9209
10105
|
}
|
|
9210
|
-
) : /* @__PURE__ */
|
|
9211
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
10106
|
+
) : /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, children: [
|
|
10107
|
+
tasks.length > 0 && /* @__PURE__ */ jsx17(
|
|
9212
10108
|
TaskList,
|
|
9213
10109
|
{
|
|
9214
10110
|
tasks,
|
|
@@ -9217,11 +10113,11 @@ ${lines.join("\n")}` }]);
|
|
|
9217
10113
|
tokensDelta: Math.max(0, (usage?.prompt_tokens ?? 0) - tasksStartTokens)
|
|
9218
10114
|
}
|
|
9219
10115
|
),
|
|
9220
|
-
queue.length > 0 && /* @__PURE__ */
|
|
10116
|
+
queue.length > 0 && /* @__PURE__ */ jsx17(Box16, { flexDirection: "column", marginBottom: 1, children: queue.map((q, i) => /* @__PURE__ */ jsxs16(Text17, { color: theme.queue.color, dimColor: theme.queue.dim, children: [
|
|
9221
10117
|
"\u23F3 ",
|
|
9222
10118
|
q.display
|
|
9223
10119
|
] }, `queue_${i}`)) }),
|
|
9224
|
-
/* @__PURE__ */
|
|
10120
|
+
/* @__PURE__ */ jsx17(
|
|
9225
10121
|
StatusBar,
|
|
9226
10122
|
{
|
|
9227
10123
|
model: cfg.model,
|
|
@@ -9239,9 +10135,9 @@ ${lines.join("\n")}` }]);
|
|
|
9239
10135
|
codeMode
|
|
9240
10136
|
}
|
|
9241
10137
|
),
|
|
9242
|
-
/* @__PURE__ */
|
|
9243
|
-
/* @__PURE__ */
|
|
9244
|
-
/* @__PURE__ */
|
|
10138
|
+
/* @__PURE__ */ jsxs16(Box16, { marginTop: 1, children: [
|
|
10139
|
+
/* @__PURE__ */ jsx17(Text17, { color: theme.accent, children: "\u203A " }),
|
|
10140
|
+
/* @__PURE__ */ jsx17(
|
|
9245
10141
|
CustomTextInput,
|
|
9246
10142
|
{
|
|
9247
10143
|
value: input,
|
|
@@ -9290,7 +10186,7 @@ ${lines.join("\n")}` }]);
|
|
|
9290
10186
|
] });
|
|
9291
10187
|
}
|
|
9292
10188
|
async function renderApp(cfg, updateResult) {
|
|
9293
|
-
const instance = render(/* @__PURE__ */
|
|
10189
|
+
const instance = render(/* @__PURE__ */ jsx17(App, { initialCfg: cfg, initialUpdateResult: updateResult }), {
|
|
9294
10190
|
incrementalRendering: true
|
|
9295
10191
|
});
|
|
9296
10192
|
await instance.waitUntilExit();
|
|
@@ -9331,6 +10227,10 @@ var init_app = __esm({
|
|
|
9331
10227
|
init_version();
|
|
9332
10228
|
init_loader();
|
|
9333
10229
|
init_renderer();
|
|
10230
|
+
init_save();
|
|
10231
|
+
init_command_wizard();
|
|
10232
|
+
init_command_picker();
|
|
10233
|
+
init_command_list();
|
|
9334
10234
|
FEEDBACK_WORKER_URL = "https://kimiflare-feedback.sina-b35.workers.dev";
|
|
9335
10235
|
CONTEXT_LIMIT = 262e3;
|
|
9336
10236
|
AUTO_COMPACT_SUGGEST_PCT = 0.8;
|