@hanhnd/agent-kit 1.0.34 → 1.0.36

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.
Files changed (41) hide show
  1. package/dist/cli/commands/cli-digest-pending.test.js +19 -10
  2. package/dist/cli/commands/memory.js +44 -4
  3. package/dist/cli.js +348 -179
  4. package/dist/core/config/index.d.ts +3 -0
  5. package/dist/core/config/index.js +20 -0
  6. package/dist/entrypoints/server.js +1 -3
  7. package/dist/mcp/memory.d.ts +2 -1
  8. package/dist/mcp/memory.js +45 -18
  9. package/dist/server.js +294 -200
  10. package/dist/services/digest/constants.d.ts +3 -3
  11. package/dist/services/digest/constants.js +3 -3
  12. package/dist/services/digest/digest-background.test.js +19 -8
  13. package/dist/services/digest/digest-init.test.js +13 -2
  14. package/dist/services/digest/digest-pending.test.js +13 -2
  15. package/dist/services/digest/digest-processor.test.js +52 -0
  16. package/dist/services/digest/files.js +3 -3
  17. package/dist/services/digest/model-registry.js +2 -2
  18. package/dist/services/digest/processor.js +43 -13
  19. package/dist/services/digest/providers/llama-local.js +17 -28
  20. package/dist/services/digest/types.d.ts +3 -1
  21. package/dist/services/digest/types.js +1 -1
  22. package/dist/services/memory/chunker.d.ts +5 -2
  23. package/dist/services/memory/chunker.js +3 -1
  24. package/dist/services/memory/chunker.test.js +21 -11
  25. package/dist/services/memory/constants.js +1 -1
  26. package/dist/services/memory/embedder.js +1 -1
  27. package/dist/services/memory/index.d.ts +1 -1
  28. package/dist/services/memory/indexer.d.ts +2 -1
  29. package/dist/services/memory/indexer.js +24 -8
  30. package/dist/services/memory/indexer.test.js +38 -2
  31. package/dist/services/memory/memory.test.js +172 -15
  32. package/dist/services/memory/store.d.ts +9 -3
  33. package/dist/services/memory/store.js +132 -98
  34. package/dist/services/memory/store.test.js +239 -14
  35. package/dist/services/memory/types.d.ts +9 -1
  36. package/dist/services/memory/types.js +2 -1
  37. package/dist/utils/paths.d.ts +2 -0
  38. package/dist/utils/paths.js +2 -1
  39. package/dist/utils/utils.d.ts +1 -0
  40. package/dist/utils/utils.js +3 -3
  41. package/package.json +3 -5
package/dist/server.js CHANGED
@@ -1,18 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
2
  var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
6
  var __getProtoOf = Object.getPrototypeOf;
8
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
10
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
11
- }) : x)(function(x) {
12
- if (typeof require !== "undefined") return require.apply(this, arguments);
13
- throw Error('Dynamic require of "' + x + '" is not supported');
14
- });
15
- var __commonJS = (cb, mod) => function __require2() {
8
+ var __commonJS = (cb, mod) => function __require() {
16
9
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
17
10
  };
18
11
  var __export = (target, all) => {
@@ -6792,12 +6785,12 @@ var require_dist = __commonJS({
6792
6785
  throw new Error(`Unknown format "${name}"`);
6793
6786
  return f;
6794
6787
  };
6795
- function addFormats(ajv, list, fs11, exportName) {
6788
+ function addFormats(ajv, list, fs12, exportName) {
6796
6789
  var _a;
6797
6790
  var _b;
6798
6791
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6799
6792
  for (const f of list)
6800
- ajv.addFormat(f, fs11[f]);
6793
+ ajv.addFormat(f, fs12[f]);
6801
6794
  }
6802
6795
  module.exports = exports = formatsPlugin;
6803
6796
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -35889,7 +35882,7 @@ import * as path4 from "path";
35889
35882
 
35890
35883
  // src/utils/utils.ts
35891
35884
  function getWorkspaceRoot() {
35892
- return process.env.WORKSPACE_DIR || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.CLAUDE_WORKSPACE || process.env.CODEX_WORKSPACE || process.env.GEMINI_WORKSPACE || process.env.INIT_CWD || process.env.PWD || process.cwd();
35885
+ return process.env.WORKSPACE_DIR || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.INIT_CWD || process.env.PWD || process.cwd();
35893
35886
  }
35894
35887
  function mcpText(text) {
35895
35888
  return { content: [{ type: "text", text }] };
@@ -35897,11 +35890,18 @@ function mcpText(text) {
35897
35890
  function mcpJson(obj) {
35898
35891
  return mcpText(JSON.stringify(obj, null, 2));
35899
35892
  }
35893
+ function formatError2(err) {
35894
+ return err instanceof Error ? err.message : String(err);
35895
+ }
35900
35896
 
35901
35897
  // src/core/config/index.ts
35902
35898
  import * as fs2 from "fs";
35899
+ import * as os from "os";
35903
35900
  import * as path2 from "path";
35904
35901
 
35902
+ // src/services/memory/types.ts
35903
+ var SOURCE_TYPES = ["digest", "concept", "entity", "preference", "wiki"];
35904
+
35905
35905
  // src/services/memory/constants.ts
35906
35906
  var DEFAULT_MEMORY_CONFIG = {
35907
35907
  enabled: false,
@@ -35909,7 +35909,7 @@ var DEFAULT_MEMORY_CONFIG = {
35909
35909
  topK: 5,
35910
35910
  chunkSize: 1500,
35911
35911
  overlapLines: 2,
35912
- embeddingModel: "small" /* SMALL */,
35912
+ embeddingModel: "base" /* BASE */,
35913
35913
  vectorDimension: 384
35914
35914
  };
35915
35915
  var LOCK_RETRY_MS = 50;
@@ -35983,8 +35983,8 @@ function tryAcquireProcessLock(lockPath) {
35983
35983
  }
35984
35984
 
35985
35985
  // src/core/config/index.ts
35986
- function resolveMemoryConfig(settings2, workspaceRoot2) {
35987
- const override = settings2.memory ?? {};
35986
+ function resolveMemoryConfig(settings, workspaceRoot2) {
35987
+ const override = settings.memory ?? {};
35988
35988
  return {
35989
35989
  ...DEFAULT_MEMORY_CONFIG,
35990
35990
  ...override,
@@ -35992,24 +35992,26 @@ function resolveMemoryConfig(settings2, workspaceRoot2) {
35992
35992
  wikiDir: typeof override.wikiDir === "string" && override.wikiDir.length > 0 ? override.wikiDir : path2.join(workspaceRoot2, ".agent-kit", "wiki")
35993
35993
  };
35994
35994
  }
35995
- function loadProjectSettings(projectDir) {
35996
- const settingsPath = path2.join(projectDir, ".agent-kit", "settings.json");
35997
- if (fs2.existsSync(settingsPath)) {
35995
+ function getGlobalSettingsFile() {
35996
+ return path2.join(os.homedir(), ".agent-kit", "settings.json");
35997
+ }
35998
+ function loadGlobalSettings() {
35999
+ const file = getGlobalSettingsFile();
36000
+ if (fs2.existsSync(file)) {
35998
36001
  try {
35999
- return JSON.parse(fs2.readFileSync(settingsPath, "utf-8"));
36002
+ return JSON.parse(fs2.readFileSync(file, "utf-8"));
36000
36003
  } catch (error2) {
36001
- console.error(`[agent-kit] Warning: Failed to parse ${settingsPath}:`, error2);
36004
+ console.error(`[agent-kit] Warning: Failed to parse ${file}:`, error2);
36002
36005
  }
36003
36006
  }
36004
36007
  return {};
36005
36008
  }
36006
- function writeProjectSettings(workspaceRoot2, patch) {
36007
- const settingsPath = path2.join(workspaceRoot2, ".agent-kit", "settings.json");
36008
- const current = loadProjectSettings(workspaceRoot2);
36009
- atomicWriteJsonFile(settingsPath, { ...current, ...patch });
36009
+ function writeGlobalSettings(patch) {
36010
+ const current = loadGlobalSettings();
36011
+ atomicWriteJsonFile(getGlobalSettingsFile(), { ...current, ...patch });
36010
36012
  }
36011
- function resolveConversationDigestConfig(settings2) {
36012
- const digest = settings2.memory?.conversationDigest;
36013
+ function resolveConversationDigestConfig(settings) {
36014
+ const digest = settings.memory?.conversationDigest;
36013
36015
  if (!digest?.initialized || typeof digest.modelId !== "string" || typeof digest.initializedAt !== "string") {
36014
36016
  return void 0;
36015
36017
  }
@@ -36383,10 +36385,11 @@ import { writeFileSync as writeFileSync4 } from "fs";
36383
36385
  import * as fs5 from "fs";
36384
36386
 
36385
36387
  // src/utils/paths.ts
36386
- import * as os from "os";
36388
+ import * as os2 from "os";
36387
36389
  import * as path7 from "path";
36388
- var AGENT_KIT_HOME = path7.join(os.homedir(), ".agent-kit");
36390
+ var AGENT_KIT_HOME = path7.join(os2.homedir(), ".agent-kit");
36389
36391
  var CREDENTIALS_FILE = path7.join(AGENT_KIT_HOME, "credentials");
36392
+ var GLOBAL_SETTINGS_FILE = path7.join(AGENT_KIT_HOME, "settings.json");
36390
36393
  var MODEL_CACHE_DIR = path7.join(AGENT_KIT_HOME, "cache", "models");
36391
36394
  var FASTEMBED_CACHE_DIR = path7.join(MODEL_CACHE_DIR, "fastembed");
36392
36395
 
@@ -36758,6 +36761,7 @@ ${ticket.fields.labels?.join(", ") || "None"}`;
36758
36761
  }
36759
36762
 
36760
36763
  // src/mcp/memory.ts
36764
+ import * as fs11 from "fs";
36761
36765
  import * as path14 from "path";
36762
36766
 
36763
36767
  // src/services/memory/embedder.ts
@@ -36807,7 +36811,7 @@ var Embedder = class {
36807
36811
  const { EmbeddingModel, FlagEmbedding } = await import("fastembed");
36808
36812
  const modelMap = {
36809
36813
  ["tiny" /* TINY */]: EmbeddingModel.AllMiniLML6V2,
36810
- ["small" /* SMALL */]: EmbeddingModel.BGESmallENV15,
36814
+ ["base" /* BASE */]: EmbeddingModel.BGESmallENV15,
36811
36815
  ["large" /* LARGE */]: EmbeddingModel.BGEBaseENV15
36812
36816
  };
36813
36817
  const model = modelMap[this.modelName] ?? EmbeddingModel.BGESmallENV15;
@@ -36919,7 +36923,7 @@ function splitSection(text, maxLen) {
36919
36923
  if (byPara.every((p) => p.length <= maxLen)) return byPara;
36920
36924
  return byPara.flatMap((p) => p.length <= maxLen ? [p] : splitAtLine(p, maxLen));
36921
36925
  }
36922
- function chunkMarkdown(text, source, config2) {
36926
+ function chunkMarkdown(text, source, config2, meta) {
36923
36927
  if (!text || !text.trim()) return [];
36924
36928
  const { chunkSize, overlapLines } = config2;
36925
36929
  const lines = text.split("\n");
@@ -36958,11 +36962,13 @@ ${sectionText}` : sectionText;
36958
36962
  chunks.push({
36959
36963
  id: computeChunkId(content),
36960
36964
  source,
36965
+ sourceType: meta.sourceType,
36961
36966
  heading: section.heading,
36962
36967
  headingLevel: section.headingLevel,
36963
36968
  content,
36964
36969
  lineStart: firstLine,
36965
- lineEnd: lastLine
36970
+ lineEnd: lastLine,
36971
+ fileMtimeAt: meta.fileMtimeAt
36966
36972
  });
36967
36973
  if (pi === parts.length - 1) {
36968
36974
  prevOverlapLines = partLines.slice(-overlapLines);
@@ -36973,6 +36979,13 @@ ${sectionText}` : sectionText;
36973
36979
  }
36974
36980
 
36975
36981
  // src/services/memory/indexer.ts
36982
+ function deriveSourceType(source) {
36983
+ if (source.startsWith("compiled/provisional/conversation-digests/")) return "digest";
36984
+ if (source.startsWith("compiled/concepts/")) return "concept";
36985
+ if (source.startsWith("compiled/entities/")) return "entity";
36986
+ if (source === "compiled/preferences.md") return "preference";
36987
+ return "wiki";
36988
+ }
36976
36989
  var MemoryIndexer = class {
36977
36990
  constructor(store, embedder, config2) {
36978
36991
  this.store = store;
@@ -36993,7 +37006,15 @@ var MemoryIndexer = class {
36993
37006
  console.warn(`[memory-indexer] Cannot read file ${absolutePath}:`, err);
36994
37007
  return { indexed: 0, deleted: 0, skipped: existingChunkIds.size };
36995
37008
  }
36996
- const allChunks = chunkMarkdown(text, source, this.config);
37009
+ let fileMtimeAt;
37010
+ try {
37011
+ fileMtimeAt = fs6.statSync(absolutePath).mtimeMs;
37012
+ } catch (err) {
37013
+ console.warn(`[memory-indexer] Cannot stat file ${absolutePath}:`, err);
37014
+ fileMtimeAt = Date.now();
37015
+ }
37016
+ const sourceType = deriveSourceType(source);
37017
+ const allChunks = chunkMarkdown(text, source, this.config, { sourceType, fileMtimeAt });
36997
37018
  const currentChunkIds = new Set(allChunks.map((chunk) => chunk.id));
36998
37019
  const toIndex = allChunks.filter((chunk) => !existingChunkIds.has(chunk.id));
36999
37020
  const toDelete = [...existingChunkIds].filter((id) => !currentChunkIds.has(id));
@@ -37080,12 +37101,9 @@ var MemoryIndexer = class {
37080
37101
  scoreMap.set(r.id, { dense: 1 / (RRF_K + rank + 1), bm25: 0 });
37081
37102
  });
37082
37103
  bm25Results.forEach((r, rank) => {
37083
- const existing = scoreMap.get(r.id);
37084
- if (existing) {
37085
- existing.bm25 = 1 / (RRF_K + rank + 1);
37086
- } else {
37087
- scoreMap.set(r.id, { dense: 0, bm25: 1 / (RRF_K + rank + 1) });
37088
- }
37104
+ const entry = scoreMap.get(r.id) ?? { dense: 0, bm25: 0 };
37105
+ entry.bm25 = 1 / (RRF_K + rank + 1);
37106
+ scoreMap.set(r.id, entry);
37089
37107
  });
37090
37108
  const hasDense = this.store.vecAvailable && denseResults.length > 0;
37091
37109
  const numRetrievers = hasDense ? 2 : 1;
@@ -37157,9 +37175,11 @@ ${content}
37157
37175
 
37158
37176
  // src/services/memory/store.ts
37159
37177
  var import_stopword = __toESM(require_stopword_cjs(), 1);
37160
- import Database from "better-sqlite3";
37178
+ import Database from "libsql";
37161
37179
  import * as fs7 from "fs";
37162
37180
  import * as path9 from "path";
37181
+ var SCHEMA_VERSION = 3;
37182
+ var LibsqlDatabase = Database;
37163
37183
  var StoreError = class extends Error {
37164
37184
  constructor(message, cause) {
37165
37185
  super(message);
@@ -37174,13 +37194,11 @@ var MemoryStore = class {
37174
37194
  this.db = this.openDatabase(dbPath);
37175
37195
  }
37176
37196
  db;
37177
- _vecAvailable = false;
37178
37197
  openDatabase(dbPath) {
37179
37198
  try {
37180
- const db = new Database(dbPath);
37199
+ const db = new LibsqlDatabase(dbPath);
37181
37200
  db.pragma("journal_mode = WAL");
37182
37201
  db.pragma("busy_timeout = 5000");
37183
- this.loadVecExtension(db);
37184
37202
  this.createSchema(db);
37185
37203
  return db;
37186
37204
  } catch (err) {
@@ -37189,102 +37207,115 @@ var MemoryStore = class {
37189
37207
  fs7.unlinkSync(dbPath);
37190
37208
  } catch {
37191
37209
  }
37192
- const db = new Database(dbPath);
37193
- db.pragma("journal_mode = WAL");
37194
- db.pragma("busy_timeout = 5000");
37195
- this.loadVecExtension(db);
37196
- this.createSchema(db);
37197
- return db;
37198
- }
37199
- }
37200
- loadVecExtension(db) {
37201
- try {
37202
- const sqliteVec = __require("sqlite-vec");
37203
- sqliteVec.load(db);
37204
- this._vecAvailable = true;
37205
- } catch (err) {
37206
- console.warn("[memory-store] sqlite-vec unavailable, degrading to FTS5-only:", err);
37207
- this._vecAvailable = false;
37210
+ try {
37211
+ const db = new LibsqlDatabase(dbPath);
37212
+ db.pragma("journal_mode = WAL");
37213
+ db.pragma("busy_timeout = 5000");
37214
+ this.createSchema(db);
37215
+ return db;
37216
+ } catch (retryErr) {
37217
+ throw new StoreError("database open failed", retryErr);
37218
+ }
37208
37219
  }
37209
37220
  }
37210
37221
  createSchema(db) {
37211
- db.exec(`
37212
- CREATE TABLE IF NOT EXISTS memory_chunks (
37213
- rowid INTEGER PRIMARY KEY AUTOINCREMENT,
37214
- id TEXT NOT NULL UNIQUE,
37215
- source TEXT NOT NULL,
37216
- heading TEXT NOT NULL DEFAULT '',
37217
- heading_level INTEGER NOT NULL DEFAULT 0,
37218
- content TEXT NOT NULL,
37219
- line_start INTEGER NOT NULL,
37220
- line_end INTEGER NOT NULL,
37221
- indexed_at INTEGER NOT NULL
37222
- );
37222
+ try {
37223
+ const current = this.readUserVersion(db);
37224
+ if (current < SCHEMA_VERSION) {
37225
+ db.exec(`
37226
+ DROP TRIGGER IF EXISTS memory_chunks_ai;
37227
+ DROP TRIGGER IF EXISTS memory_chunks_ad;
37228
+ DROP TABLE IF EXISTS memory_fts;
37229
+ DROP TABLE IF EXISTS memory_vec;
37230
+ DROP INDEX IF EXISTS idx_memory_chunks_embedding;
37231
+ DROP TABLE IF EXISTS memory_chunks;
37232
+ `);
37233
+ db.pragma(`user_version = ${SCHEMA_VERSION}`);
37234
+ }
37235
+ db.exec(`
37236
+ CREATE TABLE IF NOT EXISTS memory_chunks (
37237
+ rowid INTEGER PRIMARY KEY AUTOINCREMENT,
37238
+ id TEXT NOT NULL UNIQUE,
37239
+ source TEXT NOT NULL,
37240
+ source_type TEXT NOT NULL DEFAULT 'wiki',
37241
+ heading TEXT NOT NULL DEFAULT '',
37242
+ heading_level INTEGER NOT NULL DEFAULT 0,
37243
+ content TEXT NOT NULL,
37244
+ line_start INTEGER NOT NULL,
37245
+ line_end INTEGER NOT NULL,
37246
+ indexed_at INTEGER NOT NULL,
37247
+ file_mtime_at INTEGER NOT NULL DEFAULT 0,
37248
+ embedding F32_BLOB(${this.config.vectorDimension}) NOT NULL
37249
+ );
37223
37250
 
37224
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
37225
- source,
37226
- heading,
37227
- content,
37228
- content='memory_chunks',
37229
- content_rowid='rowid'
37230
- );
37251
+ CREATE INDEX IF NOT EXISTS idx_memory_chunks_type_mtime
37252
+ ON memory_chunks (source_type, file_mtime_at DESC);
37231
37253
 
37232
- CREATE TRIGGER IF NOT EXISTS memory_chunks_ai
37233
- AFTER INSERT ON memory_chunks BEGIN
37234
- INSERT INTO memory_fts(rowid, source, heading, content)
37235
- VALUES (new.rowid, new.source, new.heading, new.content);
37236
- END;
37254
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
37255
+ source,
37256
+ heading,
37257
+ content,
37258
+ content='memory_chunks',
37259
+ content_rowid='rowid'
37260
+ );
37237
37261
 
37238
- CREATE TRIGGER IF NOT EXISTS memory_chunks_ad
37239
- AFTER DELETE ON memory_chunks BEGIN
37240
- INSERT INTO memory_fts(memory_fts, rowid, source, heading, content)
37241
- VALUES ('delete', old.rowid, old.source, old.heading, old.content);
37242
- END;
37243
- `);
37244
- if (this._vecAvailable) {
37245
- try {
37246
- db.exec(`
37247
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
37248
- embedding FLOAT[${this.config.vectorDimension}]
37249
- );
37250
- `);
37251
- } catch (err) {
37252
- console.warn("[memory-store] Failed to create memory_vec, disabling vector search:", err);
37253
- this._vecAvailable = false;
37254
- }
37262
+ CREATE TRIGGER IF NOT EXISTS memory_chunks_ai
37263
+ AFTER INSERT ON memory_chunks BEGIN
37264
+ INSERT INTO memory_fts(rowid, source, heading, content)
37265
+ VALUES (new.rowid, new.source, new.heading, new.content);
37266
+ END;
37267
+
37268
+ CREATE TRIGGER IF NOT EXISTS memory_chunks_ad
37269
+ AFTER DELETE ON memory_chunks BEGIN
37270
+ INSERT INTO memory_fts(memory_fts, rowid, source, heading, content)
37271
+ VALUES ('delete', old.rowid, old.source, old.heading, old.content);
37272
+ END;
37273
+
37274
+ CREATE INDEX IF NOT EXISTS idx_memory_chunks_embedding
37275
+ ON memory_chunks (libsql_vector_idx(embedding));
37276
+ `);
37277
+ } catch (err) {
37278
+ throw new StoreError("schema migration failed", err);
37255
37279
  }
37256
37280
  }
37281
+ readUserVersion(db) {
37282
+ const value = db.pragma("user_version", { simple: true });
37283
+ if (typeof value === "number") return value;
37284
+ if (Array.isArray(value)) {
37285
+ const [row] = value;
37286
+ return typeof row?.user_version === "number" ? row.user_version : 0;
37287
+ }
37288
+ if (value && typeof value === "object" && "user_version" in value) {
37289
+ const row = value;
37290
+ return typeof row.user_version === "number" ? row.user_version : 0;
37291
+ }
37292
+ return 0;
37293
+ }
37257
37294
  upsert(chunks, embeddings) {
37258
37295
  const insertChunk = this.db.prepare(`
37259
37296
  INSERT OR REPLACE INTO memory_chunks
37260
- (id, source, heading, heading_level, content, line_start, line_end, indexed_at)
37261
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
37297
+ (id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at, embedding)
37298
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?))
37262
37299
  `);
37263
- let insertVec = null;
37264
- if (this._vecAvailable) {
37265
- insertVec = this.db.prepare(`INSERT OR REPLACE INTO memory_vec (rowid, embedding) VALUES (?, ?)`);
37266
- }
37267
37300
  const upsertAll = this.db.transaction(() => {
37268
37301
  for (let i = 0; i < chunks.length; i++) {
37269
37302
  const chunk = chunks[i];
37270
37303
  try {
37304
+ const vectorBinding = this.toVectorBinding(embeddings[i]);
37271
37305
  this.db.prepare(`DELETE FROM memory_chunks WHERE id = ?`).run(chunk.id);
37272
- const info = insertChunk.run(
37306
+ insertChunk.run(
37273
37307
  chunk.id,
37274
37308
  chunk.source,
37309
+ chunk.sourceType,
37275
37310
  chunk.heading,
37276
37311
  chunk.headingLevel,
37277
37312
  chunk.content,
37278
37313
  chunk.lineStart,
37279
37314
  chunk.lineEnd,
37280
- Date.now()
37315
+ Date.now(),
37316
+ chunk.fileMtimeAt,
37317
+ vectorBinding
37281
37318
  );
37282
- if (insertVec && embeddings[i] && info.lastInsertRowid) {
37283
- const rowid = Number(info.lastInsertRowid);
37284
- const emb = embeddings[i];
37285
- const buf = Buffer.from(emb.buffer, emb.byteOffset, emb.byteLength);
37286
- insertVec.run(rowid, buf);
37287
- }
37288
37319
  } catch (err) {
37289
37320
  console.warn(`[memory-store] Failed to upsert chunk ${chunk.id}:`, err);
37290
37321
  }
@@ -37296,6 +37327,20 @@ var MemoryStore = class {
37296
37327
  throw new StoreError("Full batch upsert failed", err);
37297
37328
  }
37298
37329
  }
37330
+ toVectorBinding(embedding) {
37331
+ if (!embedding) throw new Error("missing embedding");
37332
+ if (!(embedding instanceof Float32Array)) throw new Error("missing embedding");
37333
+ if (embedding.length !== this.config.vectorDimension) throw new Error("embedding dimension mismatch");
37334
+ const values = Array.from(embedding, (value) => {
37335
+ if (!Number.isFinite(value)) throw new Error("embedding contains non-finite value");
37336
+ return value;
37337
+ });
37338
+ return JSON.stringify(values);
37339
+ }
37340
+ normalizeVectorDistance(distance) {
37341
+ if (distance <= 0) return 1;
37342
+ return Math.max(0, Math.min(1, 1 - distance));
37343
+ }
37299
37344
  hashesBySource(source) {
37300
37345
  const rows = this.db.prepare(`SELECT id FROM memory_chunks WHERE source = ?`).all(source);
37301
37346
  return new Set(rows.map((r) => r.id));
@@ -37304,13 +37349,22 @@ var MemoryStore = class {
37304
37349
  const rows = this.db.prepare(`SELECT DISTINCT source FROM memory_chunks`).all();
37305
37350
  return rows.map((r) => r.source);
37306
37351
  }
37352
+ getRecentSources(options) {
37353
+ const limit = Math.min(Math.max(1, options.limit || 5), 50);
37354
+ const whereClause = options.sourceType ? " WHERE source_type = ?" : "";
37355
+ const params = options.sourceType ? [options.sourceType, limit] : [limit];
37356
+ try {
37357
+ const rows = this.db.prepare(
37358
+ `SELECT source, MAX(file_mtime_at) AS t FROM memory_chunks${whereClause} GROUP BY source ORDER BY t DESC LIMIT ?`
37359
+ ).all(...params);
37360
+ return rows.map((row) => ({ source: row.source, fileMtimeAt: row.t }));
37361
+ } catch (err) {
37362
+ console.warn("[memory-store] Recent source lookup failed:", err);
37363
+ return [];
37364
+ }
37365
+ }
37307
37366
  deleteBySource(source) {
37308
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE source = ?`).all(source);
37309
37367
  const deleteAll = this.db.transaction(() => {
37310
- if (this._vecAvailable && rows.length > 0) {
37311
- const placeholders = rows.map(() => "?").join(", ");
37312
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${placeholders})`).run(...rows.map((r) => r.rowid));
37313
- }
37314
37368
  this.db.prepare(`DELETE FROM memory_chunks WHERE source = ?`).run(source);
37315
37369
  });
37316
37370
  deleteAll();
@@ -37318,30 +37372,24 @@ var MemoryStore = class {
37318
37372
  deleteByIds(ids) {
37319
37373
  if (ids.length === 0) return;
37320
37374
  const placeholders = ids.map(() => "?").join(", ");
37321
- const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE id IN (${placeholders})`).all(...ids);
37322
37375
  const deleteAll = this.db.transaction(() => {
37323
- if (this._vecAvailable && rows.length > 0) {
37324
- const rPlaceholders = rows.map(() => "?").join(", ");
37325
- this.db.prepare(`DELETE FROM memory_vec WHERE rowid IN (${rPlaceholders})`).run(...rows.map((r) => r.rowid));
37326
- }
37327
37376
  this.db.prepare(`DELETE FROM memory_chunks WHERE id IN (${placeholders})`).run(...ids);
37328
37377
  });
37329
37378
  deleteAll();
37330
37379
  }
37331
37380
  searchDense(embedding, limit) {
37332
- if (!this._vecAvailable) return [];
37333
37381
  try {
37334
- const buf = Buffer.from(embedding.buffer);
37382
+ const queryVector = this.toVectorBinding(embedding);
37335
37383
  const rows = this.db.prepare(
37336
- `SELECT mc.id, mv.distance
37337
- FROM memory_vec mv
37338
- JOIN memory_chunks mc ON mc.rowid = mv.rowid
37339
- WHERE mv.embedding MATCH ? AND k = ?
37340
- ORDER BY mv.distance`
37341
- ).all(buf, limit);
37384
+ `SELECT mc.id, vector_distance_cos(mc.embedding, vector32(?)) AS distance
37385
+ FROM vector_top_k('idx_memory_chunks_embedding', vector32(?), ?) AS vector_matches
37386
+ JOIN memory_chunks mc ON mc.rowid = vector_matches.id
37387
+ ORDER BY distance
37388
+ LIMIT ?`
37389
+ ).all(queryVector, queryVector, limit, limit);
37342
37390
  return rows.map((r) => ({
37343
37391
  id: r.id,
37344
- score: Math.max(0, 1 - r.distance)
37392
+ score: this.normalizeVectorDistance(r.distance)
37345
37393
  }));
37346
37394
  } catch (err) {
37347
37395
  console.warn("[memory-store] Dense search failed:", err);
@@ -37380,21 +37428,23 @@ var MemoryStore = class {
37380
37428
  if (ids.length === 0) return [];
37381
37429
  const placeholders = ids.map(() => "?").join(", ");
37382
37430
  const rows = this.db.prepare(
37383
- `SELECT id, source, heading, heading_level, content, line_start, line_end
37431
+ `SELECT id, source, source_type, heading, heading_level, content, line_start, line_end, file_mtime_at
37384
37432
  FROM memory_chunks WHERE id IN (${placeholders})`
37385
37433
  ).all(...ids);
37386
37434
  return rows.map((r) => ({
37387
37435
  id: r.id,
37388
37436
  source: r.source,
37437
+ sourceType: r.source_type,
37389
37438
  heading: r.heading,
37390
37439
  headingLevel: r.heading_level,
37391
37440
  content: r.content,
37392
37441
  lineStart: r.line_start,
37393
- lineEnd: r.line_end
37442
+ lineEnd: r.line_end,
37443
+ fileMtimeAt: r.file_mtime_at
37394
37444
  }));
37395
37445
  }
37396
37446
  get vecAvailable() {
37397
- return this._vecAvailable;
37447
+ return true;
37398
37448
  }
37399
37449
  close() {
37400
37450
  this.db.close();
@@ -37407,8 +37457,8 @@ import * as path13 from "node:path";
37407
37457
 
37408
37458
  // src/services/digest/constants.ts
37409
37459
  import * as path10 from "node:path";
37410
- var DEFAULT_DIGEST_MODEL_ID = "default" /* DEFAULT */;
37411
- var DEFAULT_DIGEST_MAX_INPUT_CHARS = 3e3;
37460
+ var DEFAULT_DIGEST_MODEL_ID = "base" /* BASE */;
37461
+ var DEFAULT_DIGEST_MAX_INPUT_CHARS = 1e4;
37412
37462
  var DEFAULT_DIGEST_TIMEOUT_MS = 12e4;
37413
37463
  var KIT_DIR = ".agent-kit";
37414
37464
  var WIKI_DIR = path10.join(KIT_DIR, "wiki");
@@ -37418,7 +37468,7 @@ var DIGEST_WORKER_DIR = path10.join(WIKI_DIR, "digest");
37418
37468
  var DIGEST_LOCKFILE_REL_PATH = path10.join(DIGEST_WORKER_DIR, "digest-worker.lock");
37419
37469
  var DIGEST_WORKER_STATUS_REL_PATH = path10.join(DIGEST_WORKER_DIR, "digest-worker.status.json");
37420
37470
  var DIGEST_WORKER_LOG_REL_PATH = path10.join(DIGEST_WORKER_DIR, "digest-worker.log");
37421
- var LLAMA_CONTEXT_SIZE = 4096;
37471
+ var LLAMA_CONTEXT_SIZE = 8192;
37422
37472
  var LLAMA_MAX_GENERATED_TOKENS = 512;
37423
37473
  var LLAMA_TEMPERATURE = 0.1;
37424
37474
 
@@ -37451,9 +37501,9 @@ function writeProvisionalDigestFile(outDir, input, markdown) {
37451
37501
  return markdownPath;
37452
37502
  }
37453
37503
  function writeConversationDigestSettings(workspaceRoot2, digest) {
37454
- const current = loadProjectSettings(workspaceRoot2);
37504
+ const current = loadGlobalSettings();
37455
37505
  const memory = current.memory ?? {};
37456
- writeProjectSettings(workspaceRoot2, {
37506
+ writeGlobalSettings({
37457
37507
  memory: {
37458
37508
  ...memory,
37459
37509
  enabled: memory.enabled ?? true,
@@ -37478,8 +37528,8 @@ var DIGEST_MODEL_REGISTRY = {
37478
37528
  sourceUrl: "https://huggingface.co/bartowski/Qwen2.5-0.5B-Instruct-GGUF",
37479
37529
  enabled: true
37480
37530
  },
37481
- ["default" /* DEFAULT */]: {
37482
- id: "default" /* DEFAULT */,
37531
+ ["base" /* BASE */]: {
37532
+ id: "base" /* BASE */,
37483
37533
  ggufUri: "hf:bartowski/Qwen2.5-1.5B-Instruct-GGUF/Qwen2.5-1.5B-Instruct-Q4_K_M.gguf",
37484
37534
  approxSizeBytes: 1e9,
37485
37535
  license: "Apache-2.0",
@@ -37556,39 +37606,19 @@ function buildPrompt(input, maxInputChars) {
37556
37606
  {
37557
37607
  role: "system",
37558
37608
  content: [
37559
- "# ROLE",
37560
- "You write short project-memory wiki pages from developer transcripts.",
37561
- "Your output is temporary recall to prevent blind steps.",
37562
- "",
37563
- "# RULES",
37564
- "1. Read the end of the export FIRST to discover the ultimate resolution.",
37565
- "2. What the user says LAST ALWAYS overrides earlier agreements.",
37566
- "3. Capture absolute engineering conclusions, never conversational pleasantries.",
37567
- "4. Return Markdown only. Do not wrap output in code blocks (```markdown ... ```)."
37609
+ "You are a technical summarizer.",
37610
+ "Focus ONLY on the final decisions made at the end of the transcript.",
37611
+ "Never invent or guess details.",
37612
+ "Keep the output concise and strictly factual."
37568
37613
  ].join("\n")
37569
37614
  },
37570
37615
  {
37571
37616
  role: "user",
37572
37617
  content: [
37573
- "Generate a high-level project memory page. STRICTLY adhere to this architectural layout:",
37574
- "",
37575
- "<layout>",
37576
- "# Digest: " + titleFromSource(input.sourcePath),
37577
- "- **Ultimate Core Resolution**: [Describe the final working state of the feature and what problem it solves in 1-2 sentences. No conversational filler.]",
37578
- "- **Architectural Changes**: [List 3-4 high-level engineering decisions made (e.g., shifts in hook timing, data isolation, atomic locks). Focus on systemic changes, NOT individual files.]",
37579
- "- **Component State**: [Briefly state how the Plugin side and the MCP/CLI side now interact based on the final decision.]",
37580
- "- **Considered & Rejected**: [List concepts proposed but discarded (e.g., initial hooks location, mocking strategies). Omit if empty.]",
37581
- "</layout>",
37582
- "",
37583
- "# CRITICAL RULES:",
37584
- "- DO NOT list individual file paths, line numbers, or specific test cases (EXCLUDE lists of files).",
37585
- "- Focus entirely on the SYSTEM DESIGN and ARCHITECTURE that the next engineer needs to know.",
37586
- "- Keep output under 300 tokens. Stop immediately after the last valid section.",
37587
- "",
37588
- "Source path: " + input.sourcePath,
37589
- '<conversation_export format="memory-kit">',
37618
+ "Transcript:",
37590
37619
  conversationExport,
37591
- "</conversation_export>"
37620
+ "",
37621
+ "Task: Write a brief summary paragraph of the final agreed-upon decisions in the transcript above. Then, provide a simple bulleted list of the specific technical changes or outcomes."
37592
37622
  ].join("\n")
37593
37623
  }
37594
37624
  ];
@@ -37651,7 +37681,18 @@ async function createLlamaLocalDigestProvider(modelId) {
37651
37681
  options.timeoutMs,
37652
37682
  () => new LlamaLocalDigestProviderError(`Llama provider timed out after ${options.timeoutMs}ms`)
37653
37683
  );
37654
- return sanitizeConversationDigestMarkdown(response);
37684
+ const metadata = `## Digest: ${titleFromSource(input.sourcePath)}
37685
+
37686
+ | Key | Value |
37687
+ | ------ | ----- |
37688
+ | **Source** | ${input.sourcePath} |
37689
+ | **Generated** | ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} |
37690
+ | **Model** | ${modelId} |
37691
+ `;
37692
+ const sanitized = sanitizeConversationDigestMarkdown(response);
37693
+ return `${metadata}
37694
+
37695
+ ${sanitized}`;
37655
37696
  } finally {
37656
37697
  await context.dispose();
37657
37698
  }
@@ -37685,19 +37726,25 @@ function discoverPendingConversationFiles(workspaceRoot2) {
37685
37726
  }
37686
37727
  });
37687
37728
  }
37688
- async function indexProvisionalDigestFile(workspaceRoot2, markdownPath) {
37729
+ async function indexProvisionalDigestFile(workspaceRoot2, markdownPath, indexer) {
37730
+ let store;
37689
37731
  try {
37690
- const settings2 = loadProjectSettings(workspaceRoot2);
37691
- const config2 = resolveMemoryConfig(settings2, workspaceRoot2);
37692
- const store = new MemoryStore(path13.join(config2.wikiDir, "index.db"), config2);
37693
- const embedder = { embed: async (_texts) => [], initialize: async () => {
37694
- } };
37695
- const indexer = new MemoryIndexer(store, embedder, config2);
37696
- await indexer.indexFile(markdownPath);
37732
+ if (indexer) {
37733
+ await indexer.indexFile(markdownPath);
37734
+ return { indexed: true };
37735
+ }
37736
+ const settings = loadGlobalSettings();
37737
+ const config2 = resolveMemoryConfig(settings, workspaceRoot2);
37738
+ if (config2.enabled !== true) return { indexed: false };
37739
+ store = new MemoryStore(path13.join(config2.wikiDir, "index.db"), config2);
37740
+ const embedder = new Embedder(config2.embeddingModel);
37741
+ await embedder.initialize();
37742
+ await new MemoryIndexer(store, embedder, config2).indexFile(markdownPath);
37697
37743
  return { indexed: true };
37698
37744
  } catch (err) {
37699
- const message = err instanceof Error ? err.message : String(err);
37700
- return { indexed: false, error: message };
37745
+ return { indexed: false, error: err instanceof Error ? err.message : String(err) };
37746
+ } finally {
37747
+ store?.close();
37701
37748
  }
37702
37749
  }
37703
37750
  async function digestConversationFile(options) {
@@ -37705,7 +37752,7 @@ async function digestConversationFile(options) {
37705
37752
  const input = readConversationDigestInput(options.workspaceRoot, options.inputPath);
37706
37753
  const existingPath = findExistingProvisionalDigest(outDir, input);
37707
37754
  if (existingPath) {
37708
- const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, existingPath);
37755
+ const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, existingPath, options.indexer);
37709
37756
  return {
37710
37757
  markdown: existingPath,
37711
37758
  status: "provisional",
@@ -37722,7 +37769,7 @@ async function digestConversationFile(options) {
37722
37769
  timeoutMs: options.timeoutMs ?? DEFAULT_DIGEST_TIMEOUT_MS
37723
37770
  });
37724
37771
  const markdownPath = writeProvisionalDigestFile(outDir, input, markdown);
37725
- const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, markdownPath);
37772
+ const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, markdownPath, options.indexer);
37726
37773
  return {
37727
37774
  markdown: markdownPath,
37728
37775
  status: "provisional",
@@ -37739,7 +37786,7 @@ async function digestPendingConversations({
37739
37786
  digestFn = digestConversationFile,
37740
37787
  onProgress
37741
37788
  }) {
37742
- const digestConfig = resolveConversationDigestConfig(loadProjectSettings(workspaceRoot2));
37789
+ const digestConfig = resolveConversationDigestConfig(loadGlobalSettings());
37743
37790
  if (!digestConfig || digestConfig.enabled === false) {
37744
37791
  return { ok: true, initialized: false, action: "noop", reason: "not-initialized" };
37745
37792
  }
@@ -37747,11 +37794,21 @@ async function digestPendingConversations({
37747
37794
  if (!tryAcquireProcessLock(lockPath)) {
37748
37795
  return { ok: true, initialized: true, action: "noop", reason: "locked" };
37749
37796
  }
37797
+ let closeIndexer;
37750
37798
  try {
37751
37799
  const candidates = discoverPendingConversationFiles(workspaceRoot2);
37752
37800
  if (candidates.length === 0) {
37753
37801
  return { ok: true, initialized: true, action: "noop", reason: "no-pending" };
37754
37802
  }
37803
+ let indexer;
37804
+ const memoryConfig = resolveMemoryConfig(loadGlobalSettings(), workspaceRoot2);
37805
+ if (memoryConfig.enabled === true) {
37806
+ const store = new MemoryStore(path13.join(memoryConfig.wikiDir, "index.db"), memoryConfig);
37807
+ const embedder = new Embedder(memoryConfig.embeddingModel);
37808
+ indexer = new MemoryIndexer(store, embedder, memoryConfig);
37809
+ closeIndexer = () => store.close();
37810
+ await embedder.initialize();
37811
+ }
37755
37812
  let count = 0;
37756
37813
  let skipped = 0;
37757
37814
  let errors = 0;
@@ -37760,7 +37817,8 @@ async function digestPendingConversations({
37760
37817
  const result = await digestFn({
37761
37818
  workspaceRoot: workspaceRoot2,
37762
37819
  inputPath: filePath,
37763
- modelId: digestConfig.modelId
37820
+ modelId: digestConfig.modelId,
37821
+ indexer
37764
37822
  });
37765
37823
  if (result.skipped) {
37766
37824
  skipped++;
@@ -37777,9 +37835,17 @@ async function digestPendingConversations({
37777
37835
  return { ok: true, initialized: true, action: "digested", count, skipped, errors };
37778
37836
  } catch (err) {
37779
37837
  const message = err instanceof Error ? err.message : String(err);
37838
+ console.warn("[digest] Pending conversation digest failed:", err);
37780
37839
  return { ok: false, initialized: true, action: "error", error: message };
37781
37840
  } finally {
37782
37841
  releaseLock(lockPath);
37842
+ if (closeIndexer) {
37843
+ try {
37844
+ closeIndexer();
37845
+ } catch (err) {
37846
+ console.warn("[digest] Failed to close memory indexer store:", err);
37847
+ }
37848
+ }
37783
37849
  }
37784
37850
  }
37785
37851
  async function initializeConversationDigestModel(input) {
@@ -37821,19 +37887,18 @@ async function initializeConversationDigestModel(input) {
37821
37887
  function registerMemoryToolHandlers(server2, indexer, store, config2, workspaceRoot2 = process.cwd()) {
37822
37888
  server2.tool(
37823
37889
  "kit_memory_search",
37824
- "Search persistent memory for context relevant to the current question. Returns semantically relevant results using hybrid dense+BM25+RRF search.",
37890
+ "Search persistent memory for factual or semantic matches (decisions, concepts, entities). Extract concise keywords only, removing stopwords and filler words from the user request before querying. Use kit_memory_recent for temporal or recency questions.",
37825
37891
  {
37826
- query: external_exports.string().min(1).describe("Search query"),
37892
+ query: external_exports.string().min(1).describe("Keyword-only search query with stopwords removed"),
37827
37893
  top_k: external_exports.number().int().positive().optional().describe("Number of results to return")
37828
37894
  },
37829
37895
  async ({ query, top_k }) => {
37830
37896
  try {
37831
37897
  const results = await indexer.search(query, top_k ?? config2.topK);
37898
+ const degradedNote = !store.vecAvailable ? "\u26A0\uFE0F Vector search unavailable \u2014 showing keyword-only results.\n\n" : "";
37832
37899
  if (results.length === 0) {
37833
- const degradedNote2 = !store.vecAvailable ? "\u26A0\uFE0F Vector search unavailable \u2014 showing keyword-only results.\n\n" : "";
37834
- return mcpText(`${degradedNote2}No memories found for query: "${query}"`);
37900
+ return mcpText(`${degradedNote}No memories found for query: "${query}"`);
37835
37901
  }
37836
- const degradedNote = !store.vecAvailable ? "\u26A0\uFE0F Vector search unavailable \u2014 showing keyword-only results.\n\n" : "";
37837
37902
  const formatted = results.map((r) => {
37838
37903
  const displaySource = r.chunk.source.replace(/^compiled\//, "");
37839
37904
  const content = r.contentSource === "fallback" ? `\u26A0\uFE0F Source file unavailable \u2014 showing matched chunk only:
@@ -37843,8 +37908,36 @@ ${content}`;
37843
37908
  }).join("\n\n---\n\n");
37844
37909
  return mcpText(`${degradedNote}${formatted}`);
37845
37910
  } catch (err) {
37846
- const message = err instanceof Error ? err.message : String(err);
37847
- return mcpText(`kit_memory_search failed: ${message}`);
37911
+ return mcpText(`kit_memory_search failed: ${formatError2(err)}`);
37912
+ }
37913
+ }
37914
+ );
37915
+ server2.tool(
37916
+ "kit_memory_recent",
37917
+ 'Return the N most recently updated memory sources. Optionally filter by source type. Use for temporal questions like "what did we do last session" or "recent".',
37918
+ {
37919
+ n: external_exports.number().int().positive().max(50).optional().describe("How many recent sources to return (default 5)"),
37920
+ source_type: external_exports.enum(SOURCE_TYPES).optional().describe("Optional source type filter")
37921
+ },
37922
+ async ({ n, source_type }) => {
37923
+ try {
37924
+ const rows = store.getRecentSources({ limit: n ?? 5, sourceType: source_type });
37925
+ if (rows.length === 0) return mcpText("No recent sources found.");
37926
+ const blocks = [];
37927
+ for (const row of rows) {
37928
+ try {
37929
+ const content = fs11.readFileSync(path14.join(config2.wikiDir, row.source), "utf8");
37930
+ const displaySource = row.source.replace(/^compiled\//, "");
37931
+ blocks.push(`### ${displaySource}
37932
+ ${content}`);
37933
+ } catch (err) {
37934
+ console.warn(`[memory] Skipping unavailable recent source ${row.source}:`, err);
37935
+ }
37936
+ }
37937
+ if (blocks.length === 0) return mcpText("No recent sources found.");
37938
+ return mcpText(blocks.join("\n\n---\n\n"));
37939
+ } catch (err) {
37940
+ return mcpText(`kit_memory_recent failed: ${formatError2(err)}`);
37848
37941
  }
37849
37942
  }
37850
37943
  );
@@ -37863,8 +37956,10 @@ ${content}`;
37863
37956
  message: "Saved to wiki/raw \u2014 will be indexed after next /wiki compile"
37864
37957
  });
37865
37958
  } catch (err) {
37866
- const message = err instanceof Error ? err.message : String(err);
37867
- return mcpJson({ saved: false, error: message });
37959
+ return mcpJson({
37960
+ saved: false,
37961
+ error: formatError2(err)
37962
+ });
37868
37963
  }
37869
37964
  }
37870
37965
  );
@@ -37877,7 +37972,7 @@ ${content}`;
37877
37972
  },
37878
37973
  async ({ model_id, enabled }) => {
37879
37974
  try {
37880
- const existingConfig = resolveConversationDigestConfig(loadProjectSettings(workspaceRoot2));
37975
+ const existingConfig = resolveConversationDigestConfig(loadGlobalSettings());
37881
37976
  const result = await initializeConversationDigestModel({
37882
37977
  workspaceRoot: workspaceRoot2,
37883
37978
  modelId: model_id ?? existingConfig?.modelId ?? DEFAULT_DIGEST_MODEL_ID,
@@ -37891,15 +37986,15 @@ ${content}`;
37891
37986
  error: result.error
37892
37987
  });
37893
37988
  } catch (err) {
37894
- const message = err instanceof Error ? err.message : String(err);
37895
- return mcpJson({ initialized: false, error: message });
37989
+ return mcpJson({ initialized: false, error: formatError2(err) });
37896
37990
  }
37897
37991
  }
37898
37992
  );
37899
37993
  }
37900
- function registerMemoryTools(server2, settings2, workspaceRoot2, overrides) {
37901
- if (settings2.memory?.enabled !== true) return null;
37902
- const config2 = overrides?.config ?? resolveMemoryConfig(settings2, workspaceRoot2);
37994
+ function registerMemoryTools(server2, workspaceRoot2, overrides) {
37995
+ const settings = overrides?.settings ?? loadGlobalSettings();
37996
+ if (settings.memory?.enabled !== true) return null;
37997
+ const config2 = overrides?.config ?? resolveMemoryConfig(settings, workspaceRoot2);
37903
37998
  const store = overrides?.store ?? new MemoryStore(path14.join(config2.wikiDir, "index.db"), config2);
37904
37999
  const indexer = overrides?.indexer ?? (() => {
37905
38000
  const embedder = new Embedder(config2.embeddingModel);
@@ -37918,8 +38013,7 @@ registerIntegrationTools(server);
37918
38013
  registerCoreTools(server);
37919
38014
  registerAgentTools(server);
37920
38015
  var workspaceRoot = getWorkspaceRoot();
37921
- var settings = loadProjectSettings(workspaceRoot);
37922
- var memoryIndexer = registerMemoryTools(server, settings, workspaceRoot);
38016
+ var memoryIndexer = registerMemoryTools(server, workspaceRoot);
37923
38017
  var transport = new StdioServerTransport();
37924
38018
  await server.connect(transport);
37925
38019
  if (memoryIndexer) {