kimiflare 0.56.0 → 0.57.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 +556 -144
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.js +18 -7
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3285,7 +3285,11 @@ ${toolsBlock}`;
|
|
|
3285
3285
|
Project context from ${ctx.name} (${ctx.lineCount} lines, treat as authoritative):
|
|
3286
3286
|
${ctx.content.trim()}` : "";
|
|
3287
3287
|
const modeBlock = opts2.mode ? systemPromptForMode(opts2.mode) : "";
|
|
3288
|
-
const skillsBlock = opts2.
|
|
3288
|
+
const skillsBlock = opts2.skillContext ? `
|
|
3289
|
+
|
|
3290
|
+
## Relevant Skills
|
|
3291
|
+
|
|
3292
|
+
${opts2.skillContext}` : opts2.selectedSkills && opts2.selectedSkills.length > 0 ? `
|
|
3289
3293
|
|
|
3290
3294
|
Active skills for this turn:
|
|
3291
3295
|
${opts2.selectedSkills.map((s) => `--- ${s.name} ---
|
|
@@ -6246,7 +6250,12 @@ async function pollForToken(deviceCode, deviceId) {
|
|
|
6246
6250
|
async function fetchCloudUsage(token, deviceId) {
|
|
6247
6251
|
const headers = { Authorization: `Bearer ${token}` };
|
|
6248
6252
|
if (deviceId) headers["X-Device-ID"] = deviceId;
|
|
6249
|
-
|
|
6253
|
+
let res;
|
|
6254
|
+
try {
|
|
6255
|
+
res = await fetch(`${CLOUD_API_URL}/v1/usage`, { headers });
|
|
6256
|
+
} catch {
|
|
6257
|
+
return null;
|
|
6258
|
+
}
|
|
6250
6259
|
if (!res.ok) return null;
|
|
6251
6260
|
const data = await res.json();
|
|
6252
6261
|
if (typeof data.remaining !== "number" || typeof data.input_token_limit !== "number" || typeof data.input_tokens_used !== "number" || typeof data.expires_at !== "string") {
|
|
@@ -6860,21 +6869,28 @@ async function fetchWithRetry(url, init, retries = 3) {
|
|
|
6860
6869
|
}
|
|
6861
6870
|
async function fetchEmbeddings(opts2) {
|
|
6862
6871
|
const model = opts2.model ?? DEFAULT_MODEL2;
|
|
6863
|
-
|
|
6872
|
+
let url;
|
|
6864
6873
|
const headers = {
|
|
6865
|
-
Authorization: `Bearer ${opts2.apiToken}`,
|
|
6866
6874
|
"Content-Type": "application/json",
|
|
6867
6875
|
"User-Agent": getUserAgent()
|
|
6868
6876
|
};
|
|
6869
|
-
if (opts2.
|
|
6870
|
-
|
|
6871
|
-
|
|
6877
|
+
if (opts2.cloudMode) {
|
|
6878
|
+
url = "https://api.kimiflare.com/v1/embeddings";
|
|
6879
|
+
if (opts2.cloudToken) headers.Authorization = `Bearer ${opts2.cloudToken}`;
|
|
6880
|
+
if (opts2.cloudDeviceId) headers["X-Device-ID"] = opts2.cloudDeviceId;
|
|
6881
|
+
} else {
|
|
6882
|
+
url = opts2.gateway ? `https://gateway.ai.cloudflare.com/v1/${opts2.accountId}/${opts2.gateway.id}/workers-ai/${model}` : `https://api.cloudflare.com/client/v4/accounts/${opts2.accountId}/ai/run/${model}`;
|
|
6883
|
+
headers.Authorization = `Bearer ${opts2.apiToken}`;
|
|
6884
|
+
if (opts2.gateway?.metadata) {
|
|
6885
|
+
for (const [k, v] of Object.entries(opts2.gateway.metadata)) {
|
|
6886
|
+
headers[`cf-aig-metadata-${k}`] = String(v);
|
|
6887
|
+
}
|
|
6872
6888
|
}
|
|
6873
6889
|
}
|
|
6874
6890
|
const results = [];
|
|
6875
6891
|
for (const text of opts2.texts) {
|
|
6876
6892
|
const truncated = truncateForEmbedding(text);
|
|
6877
|
-
const body = JSON.stringify({ text: [truncated] });
|
|
6893
|
+
const body = opts2.cloudMode ? JSON.stringify({ model, texts: [truncated] }) : JSON.stringify({ text: [truncated] });
|
|
6878
6894
|
const res = await fetchWithRetry(url, { method: "POST", headers, body });
|
|
6879
6895
|
const json = await res.json();
|
|
6880
6896
|
let vectors = [];
|
|
@@ -6949,8 +6965,8 @@ function computeExactScore(memory, queryText, cwd) {
|
|
|
6949
6965
|
let score = 0;
|
|
6950
6966
|
const lowerQuery = queryText.toLowerCase();
|
|
6951
6967
|
for (const file of memory.relatedFiles) {
|
|
6952
|
-
const
|
|
6953
|
-
if (lowerQuery.includes(
|
|
6968
|
+
const basename6 = file.split("/").pop() ?? file;
|
|
6969
|
+
if (lowerQuery.includes(basename6.toLowerCase()) || basename6.toLowerCase().includes(lowerQuery)) {
|
|
6954
6970
|
score += 0.3;
|
|
6955
6971
|
}
|
|
6956
6972
|
if (cwd && file.startsWith(cwd)) {
|
|
@@ -9062,8 +9078,8 @@ var init_session = __esm({
|
|
|
9062
9078
|
const parts = [{ type: "text", text }];
|
|
9063
9079
|
for (const img of options.images) {
|
|
9064
9080
|
if ("path" in img) {
|
|
9065
|
-
const { readFile:
|
|
9066
|
-
const data = await
|
|
9081
|
+
const { readFile: readFile21 } = await import("fs/promises");
|
|
9082
|
+
const data = await readFile21(img.path, "base64");
|
|
9067
9083
|
const mimeType = img.path.endsWith(".png") ? "image/png" : img.path.endsWith(".jpg") || img.path.endsWith(".jpeg") ? "image/jpeg" : "image/webp";
|
|
9068
9084
|
parts.push({ type: "image_url", image_url: { url: `data:${mimeType};base64,${data}` } });
|
|
9069
9085
|
} else {
|
|
@@ -9307,7 +9323,7 @@ var init_session = __esm({
|
|
|
9307
9323
|
this.lspManager?.notifyChange(path, content);
|
|
9308
9324
|
} else {
|
|
9309
9325
|
void import("fs/promises").then(
|
|
9310
|
-
({ readFile:
|
|
9326
|
+
({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
|
|
9311
9327
|
})
|
|
9312
9328
|
).catch(() => {
|
|
9313
9329
|
});
|
|
@@ -13154,70 +13170,176 @@ var init_loader = __esm({
|
|
|
13154
13170
|
}
|
|
13155
13171
|
});
|
|
13156
13172
|
|
|
13157
|
-
// src/skills/
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13173
|
+
// src/skills/db.ts
|
|
13174
|
+
function initSkillsSchema(db) {
|
|
13175
|
+
db.exec(`
|
|
13176
|
+
CREATE TABLE IF NOT EXISTS skill_index (
|
|
13177
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
13178
|
+
name TEXT NOT NULL,
|
|
13179
|
+
description TEXT,
|
|
13180
|
+
file_path TEXT NOT NULL,
|
|
13181
|
+
content_hash TEXT NOT NULL,
|
|
13182
|
+
parser_version INTEGER NOT NULL DEFAULT 1,
|
|
13183
|
+
updated_at INTEGER NOT NULL
|
|
13184
|
+
);
|
|
13185
|
+
|
|
13186
|
+
CREATE TABLE IF NOT EXISTS skill_sections (
|
|
13187
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
13188
|
+
skill_id INTEGER NOT NULL,
|
|
13189
|
+
heading TEXT NOT NULL,
|
|
13190
|
+
body TEXT NOT NULL,
|
|
13191
|
+
embedding BLOB NOT NULL,
|
|
13192
|
+
FOREIGN KEY (skill_id) REFERENCES skill_index(id) ON DELETE CASCADE
|
|
13193
|
+
);
|
|
13194
|
+
|
|
13195
|
+
CREATE INDEX IF NOT EXISTS idx_skill_path ON skill_index(file_path);
|
|
13196
|
+
`);
|
|
13197
|
+
}
|
|
13198
|
+
function getSkillByPath(db, filePath) {
|
|
13199
|
+
const row = db.prepare("SELECT id, content_hash, parser_version FROM skill_index WHERE file_path = ?").get(filePath);
|
|
13200
|
+
if (!row) return null;
|
|
13201
|
+
return { id: row.id, contentHash: row.content_hash, parserVersion: row.parser_version };
|
|
13202
|
+
}
|
|
13203
|
+
function upsertSkill(db, skill) {
|
|
13204
|
+
const existing = getSkillByPath(db, skill.filePath);
|
|
13205
|
+
const now2 = Date.now();
|
|
13206
|
+
if (existing) {
|
|
13207
|
+
db.prepare(
|
|
13208
|
+
`UPDATE skill_index
|
|
13209
|
+
SET name = ?, description = ?, content_hash = ?, parser_version = ?, updated_at = ?
|
|
13210
|
+
WHERE id = ?`
|
|
13211
|
+
).run(skill.name, skill.description, skill.contentHash, skill.parserVersion, now2, existing.id);
|
|
13212
|
+
db.prepare("DELETE FROM skill_sections WHERE skill_id = ?").run(existing.id);
|
|
13213
|
+
return existing.id;
|
|
13171
13214
|
}
|
|
13172
|
-
|
|
13215
|
+
const result = db.prepare(
|
|
13216
|
+
`INSERT INTO skill_index (name, description, file_path, content_hash, parser_version, updated_at)
|
|
13217
|
+
VALUES (?, ?, ?, ?, ?, ?)`
|
|
13218
|
+
).run(skill.name, skill.description, skill.filePath, skill.contentHash, skill.parserVersion, now2);
|
|
13219
|
+
return Number(result.lastInsertRowid);
|
|
13173
13220
|
}
|
|
13174
|
-
function
|
|
13175
|
-
const
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
memoryId: ""
|
|
13184
|
-
// populated by caller if available
|
|
13185
|
-
});
|
|
13186
|
-
}
|
|
13221
|
+
function insertSections(db, skillId, sections, embeddings) {
|
|
13222
|
+
const insert = db.prepare(
|
|
13223
|
+
`INSERT INTO skill_sections (skill_id, heading, body, embedding)
|
|
13224
|
+
VALUES (?, ?, ?, ?)`
|
|
13225
|
+
);
|
|
13226
|
+
for (let i = 0; i < sections.length; i++) {
|
|
13227
|
+
const section = sections[i];
|
|
13228
|
+
const embedding = embeddings[i];
|
|
13229
|
+
insert.run(skillId, section.heading, section.body, Buffer.from(embedding.buffer));
|
|
13187
13230
|
}
|
|
13188
|
-
|
|
13189
|
-
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
const matched = skills.filter((s) => matchSkill(s, options.prompt, options.cwd));
|
|
13194
|
-
const selected = [];
|
|
13195
|
-
const dropped = [];
|
|
13196
|
-
const allConflicts = [];
|
|
13197
|
-
let runningTotal = 0;
|
|
13198
|
-
for (const skill of matched) {
|
|
13199
|
-
const conflicts = findConflicts(skill, options.memorySnippets);
|
|
13200
|
-
allConflicts.push(...conflicts);
|
|
13201
|
-
if (runningTotal + skill.estimatedTokens <= effectiveBudget) {
|
|
13202
|
-
selected.push(skill);
|
|
13203
|
-
runningTotal += skill.estimatedTokens;
|
|
13204
|
-
} else {
|
|
13205
|
-
dropped.push(skill);
|
|
13206
|
-
}
|
|
13231
|
+
}
|
|
13232
|
+
function deleteOrphanedSkills(db, existingPaths) {
|
|
13233
|
+
if (existingPaths.length === 0) {
|
|
13234
|
+
const result2 = db.prepare("DELETE FROM skill_index").run();
|
|
13235
|
+
return Number(result2.changes);
|
|
13207
13236
|
}
|
|
13208
|
-
const
|
|
13237
|
+
const placeholders = existingPaths.map(() => "?").join(",");
|
|
13238
|
+
const result = db.prepare(`DELETE FROM skill_index WHERE file_path NOT IN (${placeholders})`).run(...existingPaths);
|
|
13239
|
+
return Number(result.changes);
|
|
13240
|
+
}
|
|
13241
|
+
function listAllSectionRows(db) {
|
|
13242
|
+
return db.prepare(
|
|
13243
|
+
`SELECT s.id, s.heading, s.body, s.embedding, i.name, i.description, i.file_path
|
|
13244
|
+
FROM skill_sections s
|
|
13245
|
+
JOIN skill_index i ON s.skill_id = i.id`
|
|
13246
|
+
).all();
|
|
13247
|
+
}
|
|
13248
|
+
function rowToSectionResult(row) {
|
|
13209
13249
|
return {
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13250
|
+
id: row.id,
|
|
13251
|
+
heading: row.heading,
|
|
13252
|
+
body: row.body,
|
|
13253
|
+
name: row.name,
|
|
13254
|
+
description: row.description,
|
|
13255
|
+
filePath: row.file_path
|
|
13215
13256
|
};
|
|
13216
13257
|
}
|
|
13217
|
-
var
|
|
13218
|
-
|
|
13219
|
-
|
|
13258
|
+
var init_db2 = __esm({
|
|
13259
|
+
"src/skills/db.ts"() {
|
|
13260
|
+
"use strict";
|
|
13261
|
+
}
|
|
13262
|
+
});
|
|
13263
|
+
|
|
13264
|
+
// src/skills/search.ts
|
|
13265
|
+
async function searchSections(query, db, opts2) {
|
|
13266
|
+
const embeddings = await fetchEmbeddings({
|
|
13267
|
+
accountId: opts2.accountId,
|
|
13268
|
+
apiToken: opts2.apiToken,
|
|
13269
|
+
model: opts2.model,
|
|
13270
|
+
texts: [query],
|
|
13271
|
+
gateway: opts2.gateway,
|
|
13272
|
+
cloudMode: opts2.cloudMode,
|
|
13273
|
+
cloudToken: opts2.cloudToken,
|
|
13274
|
+
cloudDeviceId: opts2.cloudDeviceId
|
|
13275
|
+
});
|
|
13276
|
+
const queryEmbedding = embeddings[0];
|
|
13277
|
+
if (!queryEmbedding) {
|
|
13278
|
+
throw new Error("Failed to embed query: no embedding returned");
|
|
13279
|
+
}
|
|
13280
|
+
const rows = listAllSectionRows(db);
|
|
13281
|
+
const scored = [];
|
|
13282
|
+
for (const row of rows) {
|
|
13283
|
+
const sectionEmbedding = new Float32Array(row.embedding);
|
|
13284
|
+
const similarity = cosineSimilarity(queryEmbedding, sectionEmbedding);
|
|
13285
|
+
scored.push({
|
|
13286
|
+
...rowToSectionResult(row),
|
|
13287
|
+
similarity
|
|
13288
|
+
});
|
|
13289
|
+
}
|
|
13290
|
+
scored.sort((a, b) => b.similarity - a.similarity);
|
|
13291
|
+
return scored;
|
|
13292
|
+
}
|
|
13293
|
+
var init_search = __esm({
|
|
13294
|
+
"src/skills/search.ts"() {
|
|
13295
|
+
"use strict";
|
|
13296
|
+
init_embeddings();
|
|
13297
|
+
init_db2();
|
|
13298
|
+
}
|
|
13299
|
+
});
|
|
13300
|
+
|
|
13301
|
+
// src/skills/format.ts
|
|
13302
|
+
function estimateTokens(text) {
|
|
13303
|
+
return Math.ceil(text.length / 4);
|
|
13304
|
+
}
|
|
13305
|
+
function formatSection(section) {
|
|
13306
|
+
return `### ${section.name} \u2014 ${section.heading}
|
|
13307
|
+
${section.body}
|
|
13308
|
+
|
|
13309
|
+
`;
|
|
13310
|
+
}
|
|
13311
|
+
function packSections(sections, budget) {
|
|
13312
|
+
let context = "";
|
|
13313
|
+
let used = 0;
|
|
13314
|
+
let count = 0;
|
|
13315
|
+
for (const section of sections) {
|
|
13316
|
+
if (section.similarity < MIN_SIMILARITY) break;
|
|
13317
|
+
const text = formatSection(section);
|
|
13318
|
+
const tokens = estimateTokens(text);
|
|
13319
|
+
if (used + tokens > budget) break;
|
|
13320
|
+
context += text;
|
|
13321
|
+
used += tokens;
|
|
13322
|
+
count++;
|
|
13323
|
+
}
|
|
13324
|
+
return { context, tokens: used, count };
|
|
13325
|
+
}
|
|
13326
|
+
function buildSkillContext(sections, tier, maxSkillTokens) {
|
|
13327
|
+
const tierBudget = TIER_BUDGETS[tier];
|
|
13328
|
+
const effectiveBudget = Math.min(tierBudget, maxSkillTokens ?? tierBudget);
|
|
13329
|
+
const packed = packSections(sections, effectiveBudget);
|
|
13330
|
+
const budgetUsed = effectiveBudget > 0 ? Math.round(packed.tokens / effectiveBudget * 100) : 0;
|
|
13331
|
+
return {
|
|
13332
|
+
skillContext: packed.context,
|
|
13333
|
+
sectionCount: packed.count,
|
|
13334
|
+
totalTokens: packed.tokens,
|
|
13335
|
+
budgetUsed
|
|
13336
|
+
};
|
|
13337
|
+
}
|
|
13338
|
+
var MIN_SIMILARITY, TIER_BUDGETS;
|
|
13339
|
+
var init_format = __esm({
|
|
13340
|
+
"src/skills/format.ts"() {
|
|
13220
13341
|
"use strict";
|
|
13342
|
+
MIN_SIMILARITY = 0.3;
|
|
13221
13343
|
TIER_BUDGETS = {
|
|
13222
13344
|
light: 2e3,
|
|
13223
13345
|
medium: 8e3,
|
|
@@ -13226,27 +13348,281 @@ var init_router = __esm({
|
|
|
13226
13348
|
}
|
|
13227
13349
|
});
|
|
13228
13350
|
|
|
13229
|
-
// src/skills/
|
|
13230
|
-
async function
|
|
13231
|
-
const
|
|
13232
|
-
|
|
13351
|
+
// src/skills/router.ts
|
|
13352
|
+
async function selectSkills(opts2, deps) {
|
|
13353
|
+
const sections = await searchSections(opts2.prompt, deps.db, {
|
|
13354
|
+
accountId: deps.accountId,
|
|
13355
|
+
apiToken: deps.apiToken,
|
|
13356
|
+
model: deps.embeddingModel,
|
|
13357
|
+
gateway: deps.gateway,
|
|
13358
|
+
cloudMode: deps.cloudMode,
|
|
13359
|
+
cloudToken: deps.cloudToken,
|
|
13360
|
+
cloudDeviceId: deps.cloudDeviceId
|
|
13361
|
+
});
|
|
13362
|
+
return buildSkillContext(sections, opts2.tier, opts2.maxSkillTokens);
|
|
13363
|
+
}
|
|
13364
|
+
var init_router = __esm({
|
|
13365
|
+
"src/skills/router.ts"() {
|
|
13366
|
+
"use strict";
|
|
13367
|
+
init_search();
|
|
13368
|
+
init_format();
|
|
13369
|
+
}
|
|
13370
|
+
});
|
|
13371
|
+
|
|
13372
|
+
// src/skills/discovery.ts
|
|
13373
|
+
import { readdir as readdir5, stat as stat6, readFile as readFile15 } from "fs/promises";
|
|
13374
|
+
import { join as join21, extname as extname2 } from "path";
|
|
13375
|
+
async function dirExists(path) {
|
|
13376
|
+
try {
|
|
13377
|
+
const s = await stat6(path);
|
|
13378
|
+
return s.isDirectory();
|
|
13379
|
+
} catch {
|
|
13380
|
+
return false;
|
|
13381
|
+
}
|
|
13233
13382
|
}
|
|
13383
|
+
async function fileExists(path) {
|
|
13384
|
+
try {
|
|
13385
|
+
const s = await stat6(path);
|
|
13386
|
+
return s.isFile();
|
|
13387
|
+
} catch {
|
|
13388
|
+
return false;
|
|
13389
|
+
}
|
|
13390
|
+
}
|
|
13391
|
+
async function scanSkillDir(dirPath, source) {
|
|
13392
|
+
if (!await dirExists(dirPath)) return [];
|
|
13393
|
+
const entries = await readdir5(dirPath, { withFileTypes: true });
|
|
13394
|
+
const files = [];
|
|
13395
|
+
for (const entry of entries) {
|
|
13396
|
+
if (!entry.isFile()) continue;
|
|
13397
|
+
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
13398
|
+
files.push({ filePath: join21(dirPath, entry.name), source });
|
|
13399
|
+
}
|
|
13400
|
+
return files;
|
|
13401
|
+
}
|
|
13402
|
+
async function discoverSkills(cwd) {
|
|
13403
|
+
const agentsSkills = await scanSkillDir(join21(cwd, ".agents", "skills"), "agents");
|
|
13404
|
+
const agentsMd = await fileExists(join21(cwd, "AGENTS.md")) ? [{ filePath: join21(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
13405
|
+
const githubSkills = await scanSkillDir(join21(cwd, ".github", "skills"), "github");
|
|
13406
|
+
const kimiflareSkills = await scanSkillDir(join21(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
13407
|
+
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
13408
|
+
return ordered;
|
|
13409
|
+
}
|
|
13410
|
+
async function readSkillFile(filePath) {
|
|
13411
|
+
const bytes = await readFile15(filePath);
|
|
13412
|
+
return { bytes, text: bytes.toString("utf-8") };
|
|
13413
|
+
}
|
|
13414
|
+
var SKILL_EXTENSIONS;
|
|
13415
|
+
var init_discovery = __esm({
|
|
13416
|
+
"src/skills/discovery.ts"() {
|
|
13417
|
+
"use strict";
|
|
13418
|
+
SKILL_EXTENSIONS = /* @__PURE__ */ new Set([".md"]);
|
|
13419
|
+
}
|
|
13420
|
+
});
|
|
13421
|
+
|
|
13422
|
+
// src/skills/parser.ts
|
|
13423
|
+
import matter2 from "gray-matter";
|
|
13424
|
+
import { createHash as createHash2 } from "crypto";
|
|
13425
|
+
function sha256(input) {
|
|
13426
|
+
return createHash2("sha256").update(input).digest("hex");
|
|
13427
|
+
}
|
|
13428
|
+
function computeContentHash(rawText, parserVersion) {
|
|
13429
|
+
return sha256(`${rawText}
|
|
13430
|
+
<!-- parser_version: ${parserVersion} -->`);
|
|
13431
|
+
}
|
|
13432
|
+
function extractDescription(body, heading) {
|
|
13433
|
+
const lines = body.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
13434
|
+
if (lines.length === 0) return heading;
|
|
13435
|
+
const first = lines[0];
|
|
13436
|
+
if (first.startsWith("```") || first.startsWith("-") || first.startsWith("*") || first.startsWith("#") || first.match(/^\d+\./) || first.length < 20) {
|
|
13437
|
+
return heading;
|
|
13438
|
+
}
|
|
13439
|
+
const sentenceMatch = first.match(/^(.+?[.!?])(?:\s|$)/);
|
|
13440
|
+
if (sentenceMatch) {
|
|
13441
|
+
return sentenceMatch[1];
|
|
13442
|
+
}
|
|
13443
|
+
return first.length <= 120 ? first : heading;
|
|
13444
|
+
}
|
|
13445
|
+
function splitIntoSections(markdown) {
|
|
13446
|
+
const lines = markdown.split("\n");
|
|
13447
|
+
const sections = [];
|
|
13448
|
+
let currentHeading = "";
|
|
13449
|
+
let currentBody = [];
|
|
13450
|
+
for (const line of lines) {
|
|
13451
|
+
const h2Match = line.match(/^##\s+(.*)$/);
|
|
13452
|
+
if (h2Match) {
|
|
13453
|
+
const body = currentBody.join("\n").trim();
|
|
13454
|
+
if (body.length > 0 || currentHeading) {
|
|
13455
|
+
sections.push({
|
|
13456
|
+
heading: currentHeading,
|
|
13457
|
+
body
|
|
13458
|
+
});
|
|
13459
|
+
}
|
|
13460
|
+
currentHeading = h2Match[1].trim();
|
|
13461
|
+
currentBody = [];
|
|
13462
|
+
} else {
|
|
13463
|
+
currentBody.push(line);
|
|
13464
|
+
}
|
|
13465
|
+
}
|
|
13466
|
+
const finalBody = currentBody.join("\n").trim();
|
|
13467
|
+
if (finalBody.length > 0 || currentHeading) {
|
|
13468
|
+
sections.push({
|
|
13469
|
+
heading: currentHeading,
|
|
13470
|
+
body: finalBody
|
|
13471
|
+
});
|
|
13472
|
+
}
|
|
13473
|
+
return sections;
|
|
13474
|
+
}
|
|
13475
|
+
function parseSkillFile(filePath, rawText) {
|
|
13476
|
+
const parsed = matter2(rawText);
|
|
13477
|
+
const name = typeof parsed.data.name === "string" ? parsed.data.name : "";
|
|
13478
|
+
const description = typeof parsed.data.description === "string" ? parsed.data.description : "";
|
|
13479
|
+
if (!name) {
|
|
13480
|
+
throw new Error(`Skill file missing required 'name' field: ${filePath}`);
|
|
13481
|
+
}
|
|
13482
|
+
const sections = splitIntoSections(parsed.content);
|
|
13483
|
+
if (sections.length === 0) {
|
|
13484
|
+
sections.push({ heading: name, body: parsed.content.trim() });
|
|
13485
|
+
}
|
|
13486
|
+
const firstSection = sections[0];
|
|
13487
|
+
if (firstSection && firstSection.heading === "") {
|
|
13488
|
+
firstSection.heading = name;
|
|
13489
|
+
}
|
|
13490
|
+
return {
|
|
13491
|
+
name,
|
|
13492
|
+
description,
|
|
13493
|
+
filePath,
|
|
13494
|
+
contentHash: computeContentHash(rawText, PARSER_VERSION),
|
|
13495
|
+
parserVersion: PARSER_VERSION,
|
|
13496
|
+
sections
|
|
13497
|
+
};
|
|
13498
|
+
}
|
|
13499
|
+
function parseAgentsMd(filePath, rawText) {
|
|
13500
|
+
const sections = splitIntoSections(rawText);
|
|
13501
|
+
const skills = [];
|
|
13502
|
+
for (const section of sections) {
|
|
13503
|
+
if (!section.heading) continue;
|
|
13504
|
+
const description = extractDescription(section.body, section.heading);
|
|
13505
|
+
skills.push({
|
|
13506
|
+
name: section.heading,
|
|
13507
|
+
description,
|
|
13508
|
+
filePath,
|
|
13509
|
+
contentHash: computeContentHash(rawText, PARSER_VERSION),
|
|
13510
|
+
parserVersion: PARSER_VERSION,
|
|
13511
|
+
sections: [{ heading: section.heading, body: section.body }]
|
|
13512
|
+
});
|
|
13513
|
+
}
|
|
13514
|
+
return skills;
|
|
13515
|
+
}
|
|
13516
|
+
var PARSER_VERSION;
|
|
13517
|
+
var init_parser = __esm({
|
|
13518
|
+
"src/skills/parser.ts"() {
|
|
13519
|
+
"use strict";
|
|
13520
|
+
PARSER_VERSION = 1;
|
|
13521
|
+
}
|
|
13522
|
+
});
|
|
13523
|
+
|
|
13524
|
+
// src/skills/indexer.ts
|
|
13525
|
+
function buildEmbeddingInput(skill, section) {
|
|
13526
|
+
return `${skill.name}: ${skill.description}
|
|
13527
|
+
|
|
13528
|
+
${section.heading}
|
|
13529
|
+
${section.body}`;
|
|
13530
|
+
}
|
|
13531
|
+
async function indexSkills(opts2) {
|
|
13532
|
+
initSkillsSchema(opts2.db);
|
|
13533
|
+
const discovered = await discoverSkills(opts2.cwd);
|
|
13534
|
+
const errors = [];
|
|
13535
|
+
const parsedSkills = [];
|
|
13536
|
+
for (const file of discovered) {
|
|
13537
|
+
try {
|
|
13538
|
+
const { text } = await readSkillFile(file.filePath);
|
|
13539
|
+
if (file.source === "agents-md") {
|
|
13540
|
+
const skills = parseAgentsMd(file.filePath, text);
|
|
13541
|
+
parsedSkills.push(...skills);
|
|
13542
|
+
} else {
|
|
13543
|
+
const skill = parseSkillFile(file.filePath, text);
|
|
13544
|
+
parsedSkills.push(skill);
|
|
13545
|
+
}
|
|
13546
|
+
} catch (err) {
|
|
13547
|
+
errors.push(`Failed to parse ${file.filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
13548
|
+
}
|
|
13549
|
+
}
|
|
13550
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
13551
|
+
const deduped = [];
|
|
13552
|
+
for (const skill of parsedSkills) {
|
|
13553
|
+
if (seenNames.has(skill.name)) continue;
|
|
13554
|
+
seenNames.add(skill.name);
|
|
13555
|
+
deduped.push(skill);
|
|
13556
|
+
}
|
|
13557
|
+
let indexed = 0;
|
|
13558
|
+
let skipped = 0;
|
|
13559
|
+
for (const skill of deduped) {
|
|
13560
|
+
const existing = getSkillByPath(opts2.db, skill.filePath);
|
|
13561
|
+
if (existing && existing.contentHash === skill.contentHash && existing.parserVersion === skill.parserVersion) {
|
|
13562
|
+
skipped++;
|
|
13563
|
+
continue;
|
|
13564
|
+
}
|
|
13565
|
+
const skillId = upsertSkill(opts2.db, skill);
|
|
13566
|
+
if (skill.sections.length > 0) {
|
|
13567
|
+
const inputs = skill.sections.map((section) => buildEmbeddingInput(skill, section));
|
|
13568
|
+
try {
|
|
13569
|
+
const embeddings = await fetchEmbeddings({
|
|
13570
|
+
accountId: opts2.accountId,
|
|
13571
|
+
apiToken: opts2.apiToken,
|
|
13572
|
+
model: opts2.embeddingModel,
|
|
13573
|
+
texts: inputs,
|
|
13574
|
+
gateway: opts2.gateway,
|
|
13575
|
+
cloudMode: opts2.cloudMode,
|
|
13576
|
+
cloudToken: opts2.cloudToken,
|
|
13577
|
+
cloudDeviceId: opts2.cloudDeviceId
|
|
13578
|
+
});
|
|
13579
|
+
insertSections(opts2.db, skillId, skill.sections, embeddings);
|
|
13580
|
+
} catch (err) {
|
|
13581
|
+
errors.push(
|
|
13582
|
+
`Failed to embed sections for ${skill.filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
13583
|
+
);
|
|
13584
|
+
continue;
|
|
13585
|
+
}
|
|
13586
|
+
}
|
|
13587
|
+
indexed++;
|
|
13588
|
+
}
|
|
13589
|
+
const existingPaths = deduped.map((s) => s.filePath);
|
|
13590
|
+
const removed = deleteOrphanedSkills(opts2.db, existingPaths);
|
|
13591
|
+
return { indexed, skipped, removed, errors };
|
|
13592
|
+
}
|
|
13593
|
+
var init_indexer = __esm({
|
|
13594
|
+
"src/skills/indexer.ts"() {
|
|
13595
|
+
"use strict";
|
|
13596
|
+
init_embeddings();
|
|
13597
|
+
init_discovery();
|
|
13598
|
+
init_parser();
|
|
13599
|
+
init_db2();
|
|
13600
|
+
}
|
|
13601
|
+
});
|
|
13602
|
+
|
|
13603
|
+
// src/skills/index.ts
|
|
13234
13604
|
var init_skills = __esm({
|
|
13235
13605
|
"src/skills/index.ts"() {
|
|
13236
13606
|
"use strict";
|
|
13237
13607
|
init_loader();
|
|
13238
13608
|
init_router();
|
|
13609
|
+
init_indexer();
|
|
13610
|
+
init_search();
|
|
13611
|
+
init_format();
|
|
13612
|
+
init_discovery();
|
|
13613
|
+
init_parser();
|
|
13614
|
+
init_db2();
|
|
13239
13615
|
}
|
|
13240
13616
|
});
|
|
13241
13617
|
|
|
13242
13618
|
// src/skills/manager.ts
|
|
13243
|
-
import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as
|
|
13244
|
-
import { join as
|
|
13245
|
-
import
|
|
13619
|
+
import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as readFile16 } from "fs/promises";
|
|
13620
|
+
import { join as join22 } from "path";
|
|
13621
|
+
import matter3 from "gray-matter";
|
|
13246
13622
|
function getSkillDirs(cwd) {
|
|
13247
13623
|
return {
|
|
13248
|
-
projectDir:
|
|
13249
|
-
globalDir:
|
|
13624
|
+
projectDir: join22(cwd, ".kimiflare", "skills"),
|
|
13625
|
+
globalDir: join22(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
13250
13626
|
};
|
|
13251
13627
|
}
|
|
13252
13628
|
async function listAllSkills(cwd) {
|
|
@@ -13260,7 +13636,7 @@ async function listAllSkills(cwd) {
|
|
|
13260
13636
|
async function createSkill(opts2) {
|
|
13261
13637
|
const dirs = getSkillDirs(opts2.cwd);
|
|
13262
13638
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
13263
|
-
const filepath =
|
|
13639
|
+
const filepath = join22(dir, `${opts2.name}.md`);
|
|
13264
13640
|
const frontmatter = {
|
|
13265
13641
|
name: opts2.name,
|
|
13266
13642
|
enabled: true,
|
|
@@ -13296,8 +13672,8 @@ async function setSkillEnabled(name, enabled, cwd) {
|
|
|
13296
13672
|
const all = await listAllSkills(cwd);
|
|
13297
13673
|
const skill = all.project.find((s) => s.name === name) ?? all.global.find((s) => s.name === name);
|
|
13298
13674
|
if (!skill) throw new Error(`skill "${name}" not found`);
|
|
13299
|
-
const raw = await
|
|
13300
|
-
const parsed =
|
|
13675
|
+
const raw = await readFile16(skill.filePath, "utf-8");
|
|
13676
|
+
const parsed = matter3(raw);
|
|
13301
13677
|
parsed.data.enabled = enabled;
|
|
13302
13678
|
const yaml = Object.entries(parsed.data).map(([k, v]) => {
|
|
13303
13679
|
if (Array.isArray(v)) return `${k}:
|
|
@@ -13324,10 +13700,10 @@ var init_manager4 = __esm({
|
|
|
13324
13700
|
});
|
|
13325
13701
|
|
|
13326
13702
|
// src/util/image.ts
|
|
13327
|
-
import { readFile as
|
|
13328
|
-
import { basename as
|
|
13703
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
13704
|
+
import { basename as basename4 } from "path";
|
|
13329
13705
|
async function encodeImageFile(filePath) {
|
|
13330
|
-
const buf = await
|
|
13706
|
+
const buf = await readFile17(filePath);
|
|
13331
13707
|
if (buf.byteLength > MAX_IMAGE_BYTES) {
|
|
13332
13708
|
throw new Error(
|
|
13333
13709
|
`image too large (${(buf.byteLength / 1024 / 1024).toFixed(1)} MB); max is ${MAX_IMAGE_BYTES / 1024 / 1024} MB`
|
|
@@ -13337,7 +13713,7 @@ async function encodeImageFile(filePath) {
|
|
|
13337
13713
|
const mime = EXT_TO_MIME[ext] ?? "image/jpeg";
|
|
13338
13714
|
const b64 = buf.toString("base64");
|
|
13339
13715
|
return {
|
|
13340
|
-
filename:
|
|
13716
|
+
filename: basename4(filePath),
|
|
13341
13717
|
mime,
|
|
13342
13718
|
dataUrl: `data:${mime};base64,${b64}`
|
|
13343
13719
|
};
|
|
@@ -13363,16 +13739,16 @@ var init_image = __esm({
|
|
|
13363
13739
|
});
|
|
13364
13740
|
|
|
13365
13741
|
// src/util/state.ts
|
|
13366
|
-
import { readFile as
|
|
13742
|
+
import { readFile as readFile18, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
|
|
13367
13743
|
import { homedir as homedir13 } from "os";
|
|
13368
|
-
import { join as
|
|
13744
|
+
import { join as join23 } from "path";
|
|
13369
13745
|
function statePath() {
|
|
13370
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
13371
|
-
return
|
|
13746
|
+
const xdg = process.env.XDG_CONFIG_HOME || join23(homedir13(), ".config");
|
|
13747
|
+
return join23(xdg, "kimiflare", "state.json");
|
|
13372
13748
|
}
|
|
13373
13749
|
async function readState() {
|
|
13374
13750
|
try {
|
|
13375
|
-
const raw = await
|
|
13751
|
+
const raw = await readFile18(statePath(), "utf8");
|
|
13376
13752
|
return JSON.parse(raw);
|
|
13377
13753
|
} catch {
|
|
13378
13754
|
return {};
|
|
@@ -13380,7 +13756,7 @@ async function readState() {
|
|
|
13380
13756
|
}
|
|
13381
13757
|
async function writeState(state) {
|
|
13382
13758
|
const path = statePath();
|
|
13383
|
-
await mkdir12(
|
|
13759
|
+
await mkdir12(join23(path, ".."), { recursive: true });
|
|
13384
13760
|
await writeFile12(path, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
13385
13761
|
}
|
|
13386
13762
|
async function markCreatorMessageSeen(version) {
|
|
@@ -13455,14 +13831,14 @@ var init_frontmatter = __esm({
|
|
|
13455
13831
|
// src/commands/loader.ts
|
|
13456
13832
|
import { open, realpath } from "fs/promises";
|
|
13457
13833
|
import { homedir as homedir14 } from "os";
|
|
13458
|
-
import { join as
|
|
13834
|
+
import { join as join24, relative as relative4, sep as sep2 } from "path";
|
|
13459
13835
|
import fg3 from "fast-glob";
|
|
13460
13836
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
13461
|
-
return
|
|
13837
|
+
return join24(cwd, ".kimiflare", "commands");
|
|
13462
13838
|
}
|
|
13463
13839
|
function globalCommandsDir() {
|
|
13464
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
13465
|
-
return
|
|
13840
|
+
const xdg = process.env.XDG_CONFIG_HOME || join24(homedir14(), ".config");
|
|
13841
|
+
return join24(xdg, "kimiflare", "commands");
|
|
13466
13842
|
}
|
|
13467
13843
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
13468
13844
|
const warnings = [];
|
|
@@ -14283,12 +14659,12 @@ var init_command_wizard = __esm({
|
|
|
14283
14659
|
|
|
14284
14660
|
// src/init/context-generator.ts
|
|
14285
14661
|
import { existsSync as existsSync3, statSync as statSync3 } from "fs";
|
|
14286
|
-
import { join as
|
|
14662
|
+
import { join as join25 } from "path";
|
|
14287
14663
|
function detectFlavor(cwd) {
|
|
14288
14664
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
14289
14665
|
if (flavor === "generic") continue;
|
|
14290
14666
|
for (const sig of signatures) {
|
|
14291
|
-
const path =
|
|
14667
|
+
const path = join25(cwd, sig);
|
|
14292
14668
|
if (sig.includes("*")) {
|
|
14293
14669
|
try {
|
|
14294
14670
|
const parts = sig.split("*");
|
|
@@ -14309,14 +14685,14 @@ function detectFlavor(cwd) {
|
|
|
14309
14685
|
}
|
|
14310
14686
|
function findFile(cwd, candidates) {
|
|
14311
14687
|
for (const c of candidates) {
|
|
14312
|
-
if (existsSync3(
|
|
14688
|
+
if (existsSync3(join25(cwd, c))) return c;
|
|
14313
14689
|
}
|
|
14314
14690
|
return null;
|
|
14315
14691
|
}
|
|
14316
14692
|
function findSourceRoots(cwd) {
|
|
14317
14693
|
const roots = [];
|
|
14318
14694
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
14319
|
-
const p =
|
|
14695
|
+
const p = join25(cwd, r);
|
|
14320
14696
|
try {
|
|
14321
14697
|
const s = statSync3(p);
|
|
14322
14698
|
if (s.isDirectory()) roots.push(r);
|
|
@@ -14327,9 +14703,9 @@ function findSourceRoots(cwd) {
|
|
|
14327
14703
|
}
|
|
14328
14704
|
function findCiConfig(cwd) {
|
|
14329
14705
|
for (const c of CI_PATHS) {
|
|
14330
|
-
if (existsSync3(
|
|
14706
|
+
if (existsSync3(join25(cwd, c))) {
|
|
14331
14707
|
try {
|
|
14332
|
-
const s = statSync3(
|
|
14708
|
+
const s = statSync3(join25(cwd, c));
|
|
14333
14709
|
return s.isDirectory() ? c : c;
|
|
14334
14710
|
} catch {
|
|
14335
14711
|
}
|
|
@@ -14466,7 +14842,7 @@ function analyzeProject(cwd) {
|
|
|
14466
14842
|
ciConfig: findCiConfig(cwd),
|
|
14467
14843
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
14468
14844
|
sourceRoots: findSourceRoots(cwd),
|
|
14469
|
-
hasGit: existsSync3(
|
|
14845
|
+
hasGit: existsSync3(join25(cwd, ".git"))
|
|
14470
14846
|
};
|
|
14471
14847
|
}
|
|
14472
14848
|
function bashDiscoveryCommands(profile) {
|
|
@@ -14631,7 +15007,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
|
|
|
14631
15007
|
}
|
|
14632
15008
|
function buildInitPrompt(cwd) {
|
|
14633
15009
|
const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
14634
|
-
(n) => existsSync3(
|
|
15010
|
+
(n) => existsSync3(join25(cwd, n))
|
|
14635
15011
|
);
|
|
14636
15012
|
const isRefresh = existingName !== void 0;
|
|
14637
15013
|
const targetFilename = existingName ?? "KIMI.md";
|
|
@@ -16273,11 +16649,11 @@ var init_wcag = __esm({
|
|
|
16273
16649
|
});
|
|
16274
16650
|
|
|
16275
16651
|
// src/ui/theme-loader.ts
|
|
16276
|
-
import { readFile as
|
|
16277
|
-
import { join as
|
|
16652
|
+
import { readFile as readFile19, readdir as readdir6 } from "fs/promises";
|
|
16653
|
+
import { join as join26 } from "path";
|
|
16278
16654
|
import { homedir as homedir15 } from "os";
|
|
16279
16655
|
function projectThemesDir(cwd = process.cwd()) {
|
|
16280
|
-
return
|
|
16656
|
+
return join26(cwd, ".kimiflare", "themes");
|
|
16281
16657
|
}
|
|
16282
16658
|
function isHexColor(c) {
|
|
16283
16659
|
return /^#[0-9a-fA-F]{6}$/.test(c);
|
|
@@ -16361,15 +16737,15 @@ async function loadThemesFromDir(dir, source) {
|
|
|
16361
16737
|
const errors = [];
|
|
16362
16738
|
let files;
|
|
16363
16739
|
try {
|
|
16364
|
-
files = await
|
|
16740
|
+
files = await readdir6(dir);
|
|
16365
16741
|
} catch {
|
|
16366
16742
|
return { themes, errors };
|
|
16367
16743
|
}
|
|
16368
16744
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
16369
|
-
const path =
|
|
16745
|
+
const path = join26(dir, file);
|
|
16370
16746
|
let raw;
|
|
16371
16747
|
try {
|
|
16372
|
-
raw = await
|
|
16748
|
+
raw = await readFile19(path, "utf-8");
|
|
16373
16749
|
} catch (e) {
|
|
16374
16750
|
errors.push(`${path}: ${e instanceof Error ? e.message : String(e)}`);
|
|
16375
16751
|
continue;
|
|
@@ -16515,8 +16891,8 @@ var init_theme_loader = __esm({
|
|
|
16515
16891
|
"use strict";
|
|
16516
16892
|
init_wcag();
|
|
16517
16893
|
init_theme();
|
|
16518
|
-
USER_THEMES_DIR =
|
|
16519
|
-
process.env.XDG_CONFIG_HOME ||
|
|
16894
|
+
USER_THEMES_DIR = join26(
|
|
16895
|
+
process.env.XDG_CONFIG_HOME || join26(homedir15(), ".config"),
|
|
16520
16896
|
"kimiflare",
|
|
16521
16897
|
"themes"
|
|
16522
16898
|
);
|
|
@@ -16707,15 +17083,15 @@ var tui_report_exports = {};
|
|
|
16707
17083
|
__export(tui_report_exports, {
|
|
16708
17084
|
getCategoryReportText: () => getCategoryReportText
|
|
16709
17085
|
});
|
|
16710
|
-
import { readFile as
|
|
16711
|
-
import { join as
|
|
17086
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
17087
|
+
import { join as join27 } from "path";
|
|
16712
17088
|
import { homedir as homedir16 } from "os";
|
|
16713
17089
|
function usageDir3() {
|
|
16714
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
16715
|
-
return
|
|
17090
|
+
const xdg = process.env.XDG_DATA_HOME || join27(homedir16(), ".local", "share");
|
|
17091
|
+
return join27(xdg, "kimiflare");
|
|
16716
17092
|
}
|
|
16717
17093
|
function usagePath3() {
|
|
16718
|
-
return
|
|
17094
|
+
return join27(usageDir3(), "usage.json");
|
|
16719
17095
|
}
|
|
16720
17096
|
function today3() {
|
|
16721
17097
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -16727,7 +17103,7 @@ function daysAgo2(n) {
|
|
|
16727
17103
|
}
|
|
16728
17104
|
async function loadLog3() {
|
|
16729
17105
|
try {
|
|
16730
|
-
const raw = await
|
|
17106
|
+
const raw = await readFile20(usagePath3(), "utf8");
|
|
16731
17107
|
return JSON.parse(raw);
|
|
16732
17108
|
} catch {
|
|
16733
17109
|
return { version: 1, days: [], sessions: [] };
|
|
@@ -16797,7 +17173,7 @@ import React15, { useState as useState12, useRef as useRef3, useEffect as useEff
|
|
|
16797
17173
|
import { Box as Box23, Text as Text24, useApp, useInput as useInput9, render } from "ink";
|
|
16798
17174
|
import SelectInput10 from "ink-select-input";
|
|
16799
17175
|
import { existsSync as existsSync4, statSync as statSync4 } from "fs";
|
|
16800
|
-
import { join as
|
|
17176
|
+
import { join as join28 } from "path";
|
|
16801
17177
|
import { unlink as unlink4 } from "fs/promises";
|
|
16802
17178
|
import { execSync as execSync2 } from "child_process";
|
|
16803
17179
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -16875,7 +17251,7 @@ function buildFilePickerIgnoreList(cwd) {
|
|
|
16875
17251
|
];
|
|
16876
17252
|
const gitignorePatterns = [];
|
|
16877
17253
|
try {
|
|
16878
|
-
const gitignorePath =
|
|
17254
|
+
const gitignorePath = join28(cwd, ".gitignore");
|
|
16879
17255
|
const stats = statSync4(gitignorePath);
|
|
16880
17256
|
if (stats.size > MAX_GITIGNORE_SIZE) {
|
|
16881
17257
|
return hardcoded;
|
|
@@ -17113,7 +17489,6 @@ function App({
|
|
|
17113
17489
|
const [skillsActive, setSkillsActive] = useState12(0);
|
|
17114
17490
|
const [memoryRecalled, setMemoryRecalled] = useState12(false);
|
|
17115
17491
|
const [intentTier, setIntentTier] = useState12(null);
|
|
17116
|
-
const skillsDirRef = useRef3(join27(process.cwd(), ".kimiflare", "skills"));
|
|
17117
17492
|
const [kimiMdStale, setKimiMdStale] = useState12(false);
|
|
17118
17493
|
const [gitBranch, setGitBranch] = useState12(null);
|
|
17119
17494
|
const [lastSessionTopic, setLastSessionTopic] = useState12(null);
|
|
@@ -17419,7 +17794,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
17419
17794
|
}
|
|
17420
17795
|
});
|
|
17421
17796
|
if (cfg.memoryEnabled) {
|
|
17422
|
-
const dbPath = cfg.memoryDbPath ??
|
|
17797
|
+
const dbPath = cfg.memoryDbPath ?? join28(process.cwd(), ".kimiflare", "memory.db");
|
|
17423
17798
|
const manager = new MemoryManager({
|
|
17424
17799
|
dbPath,
|
|
17425
17800
|
accountId: cfg.accountId,
|
|
@@ -17468,7 +17843,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
17468
17843
|
} catch {
|
|
17469
17844
|
}
|
|
17470
17845
|
})();
|
|
17471
|
-
if (existsSync4(
|
|
17846
|
+
if (existsSync4(join28(cwd, "KIMI.md"))) {
|
|
17472
17847
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
17473
17848
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
17474
17849
|
if (driftCount >= 5) {
|
|
@@ -17479,6 +17854,32 @@ ${wcagWarnings.join("\n")}` }
|
|
|
17479
17854
|
memoryManagerRef.current?.close();
|
|
17480
17855
|
memoryManagerRef.current = null;
|
|
17481
17856
|
}
|
|
17857
|
+
const skillDbPath = cfg.memoryDbPath ?? join28(process.cwd(), ".kimiflare", "memory.db");
|
|
17858
|
+
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
17859
|
+
initSkillsSchema(skillDb);
|
|
17860
|
+
void indexSkills({
|
|
17861
|
+
cwd: process.cwd(),
|
|
17862
|
+
db: skillDb,
|
|
17863
|
+
accountId: cfg.accountId,
|
|
17864
|
+
apiToken: cfg.apiToken,
|
|
17865
|
+
gateway: gatewayFromConfig(cfg),
|
|
17866
|
+
embeddingModel: cfg.memoryEmbeddingModel,
|
|
17867
|
+
cloudMode: cfg.cloudMode,
|
|
17868
|
+
cloudToken: cloudToken ?? initialCloudToken,
|
|
17869
|
+
cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId
|
|
17870
|
+
}).then((result) => {
|
|
17871
|
+
if (result.indexed > 0) {
|
|
17872
|
+
setEvents((e) => [
|
|
17873
|
+
...e,
|
|
17874
|
+
{ kind: "info", key: mkKey(), text: `indexed ${result.indexed} skill${result.indexed === 1 ? "" : "s"}` }
|
|
17875
|
+
]);
|
|
17876
|
+
}
|
|
17877
|
+
if (result.errors.length > 0) {
|
|
17878
|
+
for (const err of result.errors) {
|
|
17879
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `skill index error: ${err}` }]);
|
|
17880
|
+
}
|
|
17881
|
+
}
|
|
17882
|
+
});
|
|
17482
17883
|
void loadCustomCommands(process.cwd()).then(({ commands, warnings }) => {
|
|
17483
17884
|
customCommandsRef.current = commands;
|
|
17484
17885
|
setCustomCommandsVersion((v) => v + 1);
|
|
@@ -18212,7 +18613,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
18212
18613
|
lspManagerRef.current.notifyChange(path, content);
|
|
18213
18614
|
} else {
|
|
18214
18615
|
void import("fs/promises").then(
|
|
18215
|
-
({ readFile:
|
|
18616
|
+
({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
18216
18617
|
})
|
|
18217
18618
|
);
|
|
18218
18619
|
}
|
|
@@ -18353,7 +18754,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
18353
18754
|
}
|
|
18354
18755
|
}
|
|
18355
18756
|
});
|
|
18356
|
-
if (existsSync4(
|
|
18757
|
+
if (existsSync4(join28(cwd, "KIMI.md"))) {
|
|
18357
18758
|
if (cacheStableRef.current) {
|
|
18358
18759
|
messagesRef.current[1] = {
|
|
18359
18760
|
role: "system",
|
|
@@ -19072,7 +19473,7 @@ ${lines.join("\n")}` }]);
|
|
|
19072
19473
|
try {
|
|
19073
19474
|
ensureSessionId();
|
|
19074
19475
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
19075
|
-
const filePath =
|
|
19476
|
+
const filePath = join28(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
19076
19477
|
await addCheckpoint(filePath, cp);
|
|
19077
19478
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: `checkpoint saved: "${label}"` }]);
|
|
19078
19479
|
} catch (e) {
|
|
@@ -19093,7 +19494,7 @@ ${lines.join("\n")}` }]);
|
|
|
19093
19494
|
void (async () => {
|
|
19094
19495
|
try {
|
|
19095
19496
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
19096
|
-
const file = await loadSession(
|
|
19497
|
+
const file = await loadSession(join28(sessionsDir3(), `${currentId}.json`));
|
|
19097
19498
|
const cps = file.checkpoints ?? [];
|
|
19098
19499
|
if (cps.length === 0) {
|
|
19099
19500
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "no checkpoints in this session" }]);
|
|
@@ -19662,7 +20063,7 @@ ${lines.join("\n")}` }]);
|
|
|
19662
20063
|
}
|
|
19663
20064
|
}
|
|
19664
20065
|
turnCounterRef.current += 1;
|
|
19665
|
-
if (turnCounterRef.current % 15 === 0 && existsSync4(
|
|
20066
|
+
if (turnCounterRef.current % 15 === 0 && existsSync4(join28(process.cwd(), "KIMI.md")) && !kimiMdStale) {
|
|
19666
20067
|
setEvents((e) => [
|
|
19667
20068
|
...e,
|
|
19668
20069
|
{ kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps KimiFlare stay accurate as your project evolves." }
|
|
@@ -19680,16 +20081,28 @@ ${lines.join("\n")}` }]);
|
|
|
19680
20081
|
}
|
|
19681
20082
|
let skillResult;
|
|
19682
20083
|
try {
|
|
19683
|
-
|
|
19684
|
-
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
19692
|
-
|
|
20084
|
+
const db = getMemoryDb();
|
|
20085
|
+
if (db) {
|
|
20086
|
+
skillResult = await selectSkills(
|
|
20087
|
+
{
|
|
20088
|
+
prompt: trimmed,
|
|
20089
|
+
tier: classification.tier,
|
|
20090
|
+
maxSkillTokens: CONTEXT_LIMIT - 1e4
|
|
20091
|
+
// leave headroom
|
|
20092
|
+
},
|
|
20093
|
+
{
|
|
20094
|
+
db,
|
|
20095
|
+
accountId: cfg.accountId,
|
|
20096
|
+
apiToken: cfg.apiToken,
|
|
20097
|
+
embeddingModel: cfg.memoryEmbeddingModel,
|
|
20098
|
+
gateway: gatewayFromConfig(cfg),
|
|
20099
|
+
cloudMode: cfg.cloudMode,
|
|
20100
|
+
cloudToken: cloudToken ?? initialCloudToken,
|
|
20101
|
+
cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId
|
|
20102
|
+
}
|
|
20103
|
+
);
|
|
20104
|
+
setSkillsActive(skillResult.sectionCount);
|
|
20105
|
+
}
|
|
19693
20106
|
} catch {
|
|
19694
20107
|
setSkillsActive(0);
|
|
19695
20108
|
}
|
|
@@ -19701,7 +20114,6 @@ ${lines.join("\n")}` }]);
|
|
|
19701
20114
|
const turnReasoningEffort = overrideEffort ?? effortForTier[classification.tier] ?? effortRef.current;
|
|
19702
20115
|
const effectiveCodeMode = classification.tier === "heavy";
|
|
19703
20116
|
setCodeMode(effectiveCodeMode);
|
|
19704
|
-
const selectedSkills = skillResult?.selectedSkills.map((s) => ({ name: s.name, body: s.body }));
|
|
19705
20117
|
if (cacheStableRef.current) {
|
|
19706
20118
|
messagesRef.current[1] = {
|
|
19707
20119
|
role: "system",
|
|
@@ -19710,7 +20122,7 @@ ${lines.join("\n")}` }]);
|
|
|
19710
20122
|
tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
|
|
19711
20123
|
model: cfg.model,
|
|
19712
20124
|
mode: modeRef.current,
|
|
19713
|
-
|
|
20125
|
+
skillContext: skillResult?.skillContext
|
|
19714
20126
|
})
|
|
19715
20127
|
};
|
|
19716
20128
|
} else {
|
|
@@ -19721,7 +20133,7 @@ ${lines.join("\n")}` }]);
|
|
|
19721
20133
|
tools: [...ALL_TOOLS, ...mcpToolsRef.current, ...lspToolsRef.current],
|
|
19722
20134
|
model: cfg.model,
|
|
19723
20135
|
mode: modeRef.current,
|
|
19724
|
-
|
|
20136
|
+
skillContext: skillResult?.skillContext
|
|
19725
20137
|
})
|
|
19726
20138
|
};
|
|
19727
20139
|
}
|
|
@@ -19731,7 +20143,7 @@ ${lines.join("\n")}` }]);
|
|
|
19731
20143
|
kind: "meta",
|
|
19732
20144
|
key: mkKey(),
|
|
19733
20145
|
intentTier: classification.tier,
|
|
19734
|
-
skillsActive: skillResult?.
|
|
20146
|
+
skillsActive: skillResult?.sectionCount ?? 0,
|
|
19735
20147
|
memoryRecalled: false
|
|
19736
20148
|
}
|
|
19737
20149
|
]);
|
|
@@ -19929,13 +20341,12 @@ ${lines.join("\n")}` }]);
|
|
|
19929
20341
|
cloudDeviceId: cloudDeviceId ?? initialCloudDeviceId,
|
|
19930
20342
|
onIterationEnd,
|
|
19931
20343
|
intentClassification: classification,
|
|
19932
|
-
selectedSkills,
|
|
19933
20344
|
onFileChange: (path, content2) => {
|
|
19934
20345
|
if (content2) {
|
|
19935
20346
|
lspManagerRef.current.notifyChange(path, content2);
|
|
19936
20347
|
} else {
|
|
19937
20348
|
void import("fs/promises").then(
|
|
19938
|
-
({ readFile:
|
|
20349
|
+
({ readFile: readFile21 }) => readFile21(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
|
|
19939
20350
|
})
|
|
19940
20351
|
);
|
|
19941
20352
|
}
|
|
@@ -20222,7 +20633,7 @@ ${lines.join("\n")}` }]);
|
|
|
20222
20633
|
{
|
|
20223
20634
|
servers: cfg?.lspServers ?? {},
|
|
20224
20635
|
currentScope: lspScope,
|
|
20225
|
-
hasProjectDir: existsSync4(
|
|
20636
|
+
hasProjectDir: existsSync4(join28(process.cwd(), ".kimiflare")),
|
|
20226
20637
|
onDone: () => setShowLspWizard(false),
|
|
20227
20638
|
onSave: (servers, enabled, scope) => {
|
|
20228
20639
|
setCfg((c) => c ? { ...c, lspEnabled: enabled, lspServers: servers } : c);
|
|
@@ -20518,6 +20929,7 @@ var init_app = __esm({
|
|
|
20518
20929
|
init_mode();
|
|
20519
20930
|
init_classify();
|
|
20520
20931
|
init_skills();
|
|
20932
|
+
init_db();
|
|
20521
20933
|
init_manager4();
|
|
20522
20934
|
init_sessions();
|
|
20523
20935
|
init_image();
|