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 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.selectedSkills && opts2.selectedSkills.length > 0 ? `
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
- const res = await fetch(`${CLOUD_API_URL}/v1/usage`, { headers });
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
- const 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}`;
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.gateway?.metadata) {
6870
- for (const [k, v] of Object.entries(opts2.gateway.metadata)) {
6871
- headers[`cf-aig-metadata-${k}`] = String(v);
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 basename5 = file.split("/").pop() ?? file;
6953
- if (lowerQuery.includes(basename5.toLowerCase()) || basename5.toLowerCase().includes(lowerQuery)) {
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: readFile20 } = await import("fs/promises");
9066
- const data = await readFile20(img.path, "base64");
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: readFile20 }) => readFile20(path, "utf8").then((c) => this.lspManager?.notifyChange(path, c)).catch(() => {
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/router.ts
13158
- import { minimatch } from "minimatch";
13159
- function matchSkill(skill, prompt, cwd) {
13160
- if (!skill.enabled) return false;
13161
- if (skill.match.length === 0) return true;
13162
- for (const pattern of skill.match) {
13163
- if (pattern.includes("/") || pattern.includes("*")) {
13164
- if (minimatch(cwd, pattern) || minimatch(cwd, `**/${pattern}`)) {
13165
- return true;
13166
- }
13167
- }
13168
- if (prompt.toLowerCase().includes(pattern.toLowerCase())) {
13169
- return true;
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
- return false;
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 findConflicts(skill, memorySnippets) {
13175
- const conflicts = [];
13176
- for (const mem of memorySnippets) {
13177
- const memLower = mem.toLowerCase();
13178
- const skillLower = skill.name.toLowerCase();
13179
- if (memLower.includes(skillLower) || skillLower.includes(memLower)) {
13180
- conflicts.push({
13181
- skillName: skill.name,
13182
- memoryContent: mem.slice(0, 200),
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
- return conflicts;
13189
- }
13190
- function selectSkills(skills, options) {
13191
- const tierBudget = TIER_BUDGETS[options.tier];
13192
- const effectiveBudget = Math.min(tierBudget, options.maxSkillTokens);
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 budgetUsed = effectiveBudget > 0 ? Math.round(runningTotal / effectiveBudget * 100) : 0;
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
- selectedSkills: selected,
13211
- droppedSkills: dropped,
13212
- totalSkillTokens: runningTotal,
13213
- budgetUsed,
13214
- memoryConflicts: allConflicts
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 TIER_BUDGETS;
13218
- var init_router = __esm({
13219
- "src/skills/router.ts"() {
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/index.ts
13230
- async function routeSkills(skillDir, opts2) {
13231
- const skills = await loadSkillsFromDir(skillDir);
13232
- return selectSkills(skills, opts2);
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 readFile15 } from "fs/promises";
13244
- import { join as join21 } from "path";
13245
- import matter2 from "gray-matter";
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: join21(cwd, ".kimiflare", "skills"),
13249
- globalDir: join21(process.env.HOME ?? "", ".config", "kimiflare", "skills")
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 = join21(dir, `${opts2.name}.md`);
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 readFile15(skill.filePath, "utf-8");
13300
- const parsed = matter2(raw);
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 readFile16 } from "fs/promises";
13328
- import { basename as basename3 } from "path";
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 readFile16(filePath);
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: basename3(filePath),
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 readFile17, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
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 join22 } from "path";
13744
+ import { join as join23 } from "path";
13369
13745
  function statePath() {
13370
- const xdg = process.env.XDG_CONFIG_HOME || join22(homedir13(), ".config");
13371
- return join22(xdg, "kimiflare", "state.json");
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 readFile17(statePath(), "utf8");
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(join22(path, ".."), { recursive: true });
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 join23, relative as relative4, sep as sep2 } from "path";
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 join23(cwd, ".kimiflare", "commands");
13837
+ return join24(cwd, ".kimiflare", "commands");
13462
13838
  }
13463
13839
  function globalCommandsDir() {
13464
- const xdg = process.env.XDG_CONFIG_HOME || join23(homedir14(), ".config");
13465
- return join23(xdg, "kimiflare", "commands");
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 join24 } from "path";
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 = join24(cwd, sig);
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(join24(cwd, c))) return c;
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 = join24(cwd, r);
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(join24(cwd, c))) {
14706
+ if (existsSync3(join25(cwd, c))) {
14331
14707
  try {
14332
- const s = statSync3(join24(cwd, c));
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(join24(cwd, ".git"))
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(join24(cwd, n))
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 readFile18, readdir as readdir5 } from "fs/promises";
16277
- import { join as join25 } from "path";
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 join25(cwd, ".kimiflare", "themes");
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 readdir5(dir);
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 = join25(dir, file);
16745
+ const path = join26(dir, file);
16370
16746
  let raw;
16371
16747
  try {
16372
- raw = await readFile18(path, "utf-8");
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 = join25(
16519
- process.env.XDG_CONFIG_HOME || join25(homedir15(), ".config"),
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 readFile19 } from "fs/promises";
16711
- import { join as join26 } from "path";
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 || join26(homedir16(), ".local", "share");
16715
- return join26(xdg, "kimiflare");
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 join26(usageDir3(), "usage.json");
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 readFile19(usagePath3(), "utf8");
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 join27 } from "path";
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 = join27(cwd, ".gitignore");
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 ?? join27(process.cwd(), ".kimiflare", "memory.db");
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(join27(cwd, "KIMI.md"))) {
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: readFile20 }) => readFile20(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
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(join27(cwd, "KIMI.md"))) {
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 = join27(sessionsDir3(), `${sessionIdRef.current}.json`);
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(join27(sessionsDir3(), `${currentId}.json`));
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(join27(process.cwd(), "KIMI.md")) && !kimiMdStale) {
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
- skillResult = await routeSkills(skillsDirRef.current, {
19684
- cwd: process.cwd(),
19685
- prompt: trimmed,
19686
- memorySnippets: [],
19687
- // TODO: wire memory snippets when available
19688
- tier: classification.tier,
19689
- maxSkillTokens: CONTEXT_LIMIT - 1e4
19690
- // leave headroom
19691
- });
19692
- setSkillsActive(skillResult.selectedSkills.length);
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
- selectedSkills
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
- selectedSkills
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?.selectedSkills.length ?? 0,
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: readFile20 }) => readFile20(path, "utf8").then((c) => lspManagerRef.current.notifyChange(path, c)).catch(() => {
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(join27(process.cwd(), ".kimiflare")),
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();