kontexta-mcp 2.0.8 → 3.0.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.
@@ -161,4 +161,5 @@ The matrix below is grouped by intent. For each tool: when to reach for it, the
161
161
  |---|---|---|---|
162
162
  | `register_project` | Register a new project root with kontexta | Already registered | `list_projects` |
163
163
  | `onboard_agent` | Write/update the rules block in CLAUDE.md / AGENTS.md / etc. | Editing regular project content | `update_file` |
164
+ | `transfer_agent_context` | Copy CLAUDE.md / AGENTS.md / `.cursor/rules/*.mdc` etc. from the project repo into Kontexta's KB. Originals are NEVER deleted by this tool. | User wants files to stay in the repo (default) | `register_project` (which keeps files in place) |
164
165
  <!-- END kontexta:rules v{{VERSION}} -->
package/dist/index.js CHANGED
@@ -57,6 +57,14 @@ function defaultDataDir() {
57
57
  function isWebContext() {
58
58
  return process.env.npm_package_name === "kxta-web" || !!process.env.NEXT_RUNTIME || !!process.env.__NEXT_PAGES_DIR;
59
59
  }
60
+ function isTempOrTestPath(p) {
61
+ const lower = p.toLowerCase();
62
+ const tmp = os.tmpdir().toLowerCase();
63
+ return lower.startsWith("/tmp") || lower.startsWith(tmp) || lower.includes(`${path.sep}tmp${path.sep}`) || lower.includes("test") || lower.includes("-tmp-") || process.platform === "win32" && lower.includes("\\temp\\");
64
+ }
65
+ function resetDataDirCache() {
66
+ _resolvedDataDir = null;
67
+ }
60
68
  function getDataDir() {
61
69
  if (_resolvedDataDir)
62
70
  return _resolvedDataDir;
@@ -66,31 +74,40 @@ function getDataDir() {
66
74
  const isWeb = isWebContext();
67
75
  if (isWeb && envOverride) {
68
76
  _resolvedDataDir = path.resolve(envOverride);
69
- try {
70
- fs.writeFileSync(cacheFile, _resolvedDataDir, "utf8");
71
- } catch {
77
+ if (!isTempOrTestPath(_resolvedDataDir)) {
78
+ try {
79
+ fs.writeFileSync(cacheFile, _resolvedDataDir, "utf8");
80
+ } catch {
81
+ }
72
82
  }
73
83
  return _resolvedDataDir;
74
84
  }
75
- const isTest = !!process.env.VITEST || process.env.NODE_ENV === "test" || envOverride && (envOverride.includes("test") || envOverride.includes("tmp"));
76
- if (!isTest && fs.existsSync(cacheFile)) {
85
+ if (envOverride) {
86
+ _resolvedDataDir = path.resolve(envOverride);
87
+ const isTestEnv2 = !!process.env.VITEST || process.env.NODE_ENV === "test";
88
+ if (!isTempOrTestPath(_resolvedDataDir) && !isTestEnv2) {
89
+ try {
90
+ fs.writeFileSync(cacheFile, _resolvedDataDir, "utf8");
91
+ } catch {
92
+ }
93
+ }
94
+ return _resolvedDataDir;
95
+ }
96
+ const isTestEnv = !!process.env.VITEST || process.env.NODE_ENV === "test";
97
+ if (!isTestEnv && fs.existsSync(cacheFile)) {
77
98
  try {
78
99
  const cached = fs.readFileSync(cacheFile, "utf8").trim();
79
- if (cached && path.isAbsolute(cached)) {
100
+ if (cached && path.isAbsolute(cached) && !isTempOrTestPath(cached)) {
80
101
  _resolvedDataDir = cached;
81
102
  return _resolvedDataDir;
82
103
  }
104
+ try {
105
+ fs.unlinkSync(cacheFile);
106
+ } catch {
107
+ }
83
108
  } catch {
84
109
  }
85
110
  }
86
- if (envOverride) {
87
- _resolvedDataDir = path.resolve(envOverride);
88
- try {
89
- fs.writeFileSync(cacheFile, _resolvedDataDir, "utf8");
90
- } catch {
91
- }
92
- return _resolvedDataDir;
93
- }
94
111
  _resolvedDataDir = defaultDataDir();
95
112
  return _resolvedDataDir;
96
113
  }
@@ -149,7 +166,7 @@ __export(safety_exports, {
149
166
  track: () => track,
150
167
  withLock: () => withLock
151
168
  });
152
- import { resolve as resolve2, sep, isAbsolute as isAbsolute2 } from "path";
169
+ import { resolve as resolve2, sep as sep2, isAbsolute as isAbsolute2 } from "path";
153
170
  import { AsyncLocalStorage } from "async_hooks";
154
171
  function assertPathInside(base3, name50) {
155
172
  if (typeof name50 !== "string" || name50.length === 0) {
@@ -163,7 +180,7 @@ function assertPathInside(base3, name50) {
163
180
  }
164
181
  const baseResolved = resolve2(base3);
165
182
  const target = resolve2(baseResolved, name50);
166
- if (target !== baseResolved && !target.startsWith(baseResolved + sep)) {
183
+ if (target !== baseResolved && !target.startsWith(baseResolved + sep2)) {
167
184
  throw new Error("Invalid path: escapes base directory");
168
185
  }
169
186
  return target;
@@ -420,8 +437,8 @@ var init_extensions = __esm({
420
437
  // ../../packages/core/dist/git/index.js
421
438
  import { createHash } from "crypto";
422
439
  import simpleGit from "simple-git";
423
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, copyFileSync, mkdirSync as mkdirSync3, existsSync as existsSync3, rmSync, readdirSync as readdirSync2, statSync, lstatSync, unlinkSync, renameSync } from "fs";
424
- import { join as join3, relative, dirname as dirname2, isAbsolute as isAbsolute3, resolve as resolve3, sep as sep2 } from "path";
440
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, copyFileSync, mkdirSync as mkdirSync3, existsSync as existsSync3, rmSync, readdirSync as readdirSync2, statSync, lstatSync, unlinkSync as unlinkSync2, renameSync } from "fs";
441
+ import { join as join3, relative, dirname as dirname2, isAbsolute as isAbsolute3, resolve as resolve3, sep as sep3 } from "path";
425
442
  import { spawnSync } from "child_process";
426
443
  function redactCredentials(s3) {
427
444
  return s3.replace(/([a-z][a-z0-9+.-]*:\/\/)([^:@\/\s]+:[^@\/\s]+)@/gi, "$1***:***@");
@@ -540,7 +557,7 @@ async function restoreVersion(repoDir, filePath, commitHash) {
540
557
  renameSync(tmpPath, filePath);
541
558
  } catch (e3) {
542
559
  try {
543
- unlinkSync(tmpPath);
560
+ unlinkSync2(tmpPath);
544
561
  } catch {
545
562
  }
546
563
  throw e3;
@@ -818,7 +835,7 @@ async function _syncBackupLocked(projectId, dataDir2, onStage) {
818
835
  }
819
836
  } else if (!expectedBackupPaths.has(fullPath)) {
820
837
  try {
821
- unlinkSync(fullPath);
838
+ unlinkSync2(fullPath);
822
839
  } catch {
823
840
  }
824
841
  }
@@ -888,7 +905,7 @@ async function _syncBackupLocked(projectId, dataDir2, onStage) {
888
905
  if (project.path) {
889
906
  const localAbsolutePath = join3(project.path, relativePath);
890
907
  const projectResolved = resolve3(project.path);
891
- if (resolve3(localAbsolutePath) !== projectResolved && !resolve3(localAbsolutePath).startsWith(projectResolved + sep2)) {
908
+ if (resolve3(localAbsolutePath) !== projectResolved && !resolve3(localAbsolutePath).startsWith(projectResolved + sep3)) {
892
909
  continue;
893
910
  }
894
911
  mkdirSync3(dirname2(localAbsolutePath), { recursive: true });
@@ -954,12 +971,12 @@ async function _syncBackupLocked(projectId, dataDir2, onStage) {
954
971
  continue;
955
972
  const localAbsolutePath = join3(project.path, insideBackup);
956
973
  const resolvedLocal = resolve3(localAbsolutePath);
957
- if (resolvedLocal !== projectResolved && !resolvedLocal.startsWith(projectResolved + sep2)) {
974
+ if (resolvedLocal !== projectResolved && !resolvedLocal.startsWith(projectResolved + sep3)) {
958
975
  continue;
959
976
  }
960
977
  try {
961
978
  if (existsSync3(localAbsolutePath)) {
962
- unlinkSync(localAbsolutePath);
979
+ unlinkSync2(localAbsolutePath);
963
980
  }
964
981
  } catch (e3) {
965
982
  console.warn(`syncBackup: failed to remove ${localAbsolutePath}:`, e3);
@@ -1001,8 +1018,8 @@ var init_git = __esm({
1001
1018
 
1002
1019
  // ../../packages/core/dist/files/index.js
1003
1020
  import { createHash as createHash2 } from "crypto";
1004
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, renameSync as renameSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync3, lstatSync as lstatSync2, existsSync as existsSync4, rmSync as rmSync2 } from "fs";
1005
- import { join as join4, dirname as dirname3, resolve as resolve4, sep as sep3, isAbsolute as isAbsolute4 } from "path";
1021
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, renameSync as renameSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync3, lstatSync as lstatSync2, existsSync as existsSync4, rmSync as rmSync2 } from "fs";
1022
+ import { join as join4, dirname as dirname3, resolve as resolve4, sep as sep4, isAbsolute as isAbsolute4 } from "path";
1006
1023
  function listProjectFolders(projectPath) {
1007
1024
  const folders = [];
1008
1025
  function scan(dir, currentRel) {
@@ -1031,6 +1048,47 @@ function listProjectFolders(projectPath) {
1031
1048
  }
1032
1049
  return folders;
1033
1050
  }
1051
+ function listProjectFoldersWithFiles(projectPath) {
1052
+ const folderFileCount = /* @__PURE__ */ new Map();
1053
+ function scan(dir, currentRel) {
1054
+ const entries = readdirSync3(dir);
1055
+ for (const entry of entries) {
1056
+ if (entry.startsWith(".") || entry === "node_modules")
1057
+ continue;
1058
+ const fullPath = join4(dir, entry);
1059
+ const relPath = currentRel ? join4(currentRel, entry) : entry;
1060
+ try {
1061
+ const lst = lstatSync2(fullPath);
1062
+ if (lst.isSymbolicLink())
1063
+ continue;
1064
+ if (lst.isDirectory()) {
1065
+ scan(fullPath, relPath);
1066
+ } else if (lst.isFile()) {
1067
+ const ext = entry.endsWith(".mmd") ? ".mmd" : entry.endsWith(".md") ? ".md" : "";
1068
+ if (ext) {
1069
+ const parts = relPath.split("/");
1070
+ for (let i4 = 0; i4 < parts.length - 1; i4++) {
1071
+ const ancestor = parts.slice(0, i4 + 1).join("/");
1072
+ folderFileCount.set(ancestor, (folderFileCount.get(ancestor) ?? 0) + 1);
1073
+ }
1074
+ }
1075
+ }
1076
+ } catch (e3) {
1077
+ }
1078
+ }
1079
+ }
1080
+ try {
1081
+ scan(projectPath, "");
1082
+ } catch (e3) {
1083
+ console.error("Failed to scan project folders with files:", e3);
1084
+ }
1085
+ const result = [];
1086
+ for (const [folder, count] of folderFileCount.entries()) {
1087
+ if (count > 0)
1088
+ result.push(folder);
1089
+ }
1090
+ return result.sort();
1091
+ }
1034
1092
  function computeHash(content) {
1035
1093
  return createHash2("sha256").update(content, "utf8").digest("hex");
1036
1094
  }
@@ -1137,7 +1195,7 @@ async function createFile(opts) {
1137
1195
  }
1138
1196
  } else {
1139
1197
  try {
1140
- unlinkSync2(filePath);
1198
+ unlinkSync3(filePath);
1141
1199
  } catch {
1142
1200
  }
1143
1201
  }
@@ -1255,11 +1313,11 @@ function deleteFile(id, dataDir2) {
1255
1313
  if (file && dataDir2) {
1256
1314
  const knowledgeRoot = resolve4(dataDir2, "knowledge");
1257
1315
  const filePathResolved = isAbsolute4(file.path) ? file.path : resolve4(dataDir2, file.path);
1258
- const inKnowledge = filePathResolved === knowledgeRoot || filePathResolved.startsWith(knowledgeRoot + sep3);
1316
+ const inKnowledge = filePathResolved === knowledgeRoot || filePathResolved.startsWith(knowledgeRoot + sep4);
1259
1317
  if (file.project_id === null && inKnowledge) {
1260
1318
  try {
1261
1319
  if (existsSync4(filePathResolved)) {
1262
- unlinkSync2(filePathResolved);
1320
+ unlinkSync3(filePathResolved);
1263
1321
  }
1264
1322
  } catch (e3) {
1265
1323
  console.error("Failed to delete Knowledge Base file from disk:", e3);
@@ -1316,9 +1374,15 @@ function listFiles(opts) {
1316
1374
  }
1317
1375
  if (filters.folder !== void 0) {
1318
1376
  const segment = escapeLike(filters.folder);
1319
- sql += " AND (path LIKE ? ESCAPE '\\' OR path LIKE ? ESCAPE '\\')";
1320
- params.push(`%/${segment}/%`);
1321
- params.push(`%\\${segment}\\%`);
1377
+ if (filters.project_path) {
1378
+ sql += " AND (path LIKE ? ESCAPE '\\' OR path LIKE ? ESCAPE '\\')";
1379
+ params.push(`${filters.project_path}/${segment}/%`);
1380
+ params.push(`${filters.project_path}\\${segment}\\%`);
1381
+ } else {
1382
+ sql += " AND (path LIKE ? ESCAPE '\\' OR path LIKE ? ESCAPE '\\')";
1383
+ params.push(`%/${segment}/%`);
1384
+ params.push(`%\\${segment}\\%`);
1385
+ }
1322
1386
  }
1323
1387
  }
1324
1388
  sql += " ORDER BY updated_at DESC";
@@ -1565,27 +1629,33 @@ function registerProject(name50, path3, description, remoteUrl) {
1565
1629
  `);
1566
1630
  const absolutePath = resolve5(path3);
1567
1631
  const result = insertStmt.run(name50, slug, absolutePath, description || null, remoteUrl || null);
1632
+ let projectId;
1568
1633
  if (result.changes > 0) {
1569
- const projectId = Number(result.lastInsertRowid);
1570
- return db2.prepare("SELECT * FROM projects WHERE id = ?").get(projectId);
1571
- }
1572
- const byName = db2.prepare("SELECT * FROM projects WHERE name = ?").get(name50);
1573
- const bySlug = db2.prepare("SELECT * FROM projects WHERE slug = ?").get(slug);
1574
- const existing = byName ?? bySlug;
1575
- if (!existing) {
1576
- throw new Error(`registerProject: insert ignored but no matching project found for name='${name50}'`);
1577
- }
1578
- if (existing.path !== absolutePath) {
1579
- const conflicts = [];
1580
- if (byName)
1581
- conflicts.push(`name conflicts with '${byName.name}' at '${byName.path}'`);
1582
- if (bySlug && bySlug.id !== byName?.id)
1583
- conflicts.push(`slug '${slug}' conflicts with '${bySlug.name}' at '${bySlug.path}'`);
1584
- const err = new Error(`Cannot register '${name50}' at '${path3}': ${conflicts.join("; ")}. Pick a different name or unregister the existing project first.`);
1585
- err.code = "PROJECT_CONFLICT";
1586
- throw err;
1587
- }
1588
- return existing;
1634
+ projectId = Number(result.lastInsertRowid);
1635
+ } else {
1636
+ const byName = db2.prepare("SELECT * FROM projects WHERE name = ?").get(name50);
1637
+ const bySlug = db2.prepare("SELECT * FROM projects WHERE slug = ?").get(slug);
1638
+ const existing = byName ?? bySlug;
1639
+ if (!existing) {
1640
+ throw new Error(`registerProject: insert ignored but no matching project found for name='${name50}'`);
1641
+ }
1642
+ if (existing.path !== absolutePath) {
1643
+ const conflicts = [];
1644
+ if (byName)
1645
+ conflicts.push(`name conflicts with '${byName.name}' at '${byName.path}'`);
1646
+ if (bySlug && bySlug.id !== byName?.id)
1647
+ conflicts.push(`slug '${slug}' conflicts with '${bySlug.name}' at '${bySlug.path}'`);
1648
+ const err = new Error(`Cannot register '${name50}' at '${path3}': ${conflicts.join("; ")}. Pick a different name or unregister the existing project first.`);
1649
+ err.code = "PROJECT_CONFLICT";
1650
+ throw err;
1651
+ }
1652
+ projectId = existing.id;
1653
+ }
1654
+ const newlyIndexed = reconcileIndex({ projectId, dataDir: getDataDir() }).newRecords.length;
1655
+ return {
1656
+ ...db2.prepare("SELECT * FROM projects WHERE id = ?").get(projectId),
1657
+ newlyIndexed
1658
+ };
1589
1659
  }
1590
1660
  function unregisterProject(projectId, dataDir2) {
1591
1661
  const db2 = getDatabase();
@@ -1661,9 +1731,14 @@ function reconcileIndex(opts) {
1661
1731
  } catch (e3) {
1662
1732
  if (isTopLevel) {
1663
1733
  if (typeof projectId === "number") {
1664
- throw new Error(`Failed to read project root ${dir}: ${e3?.message ?? e3}`);
1734
+ if (e3?.code === "ENOENT") {
1735
+ console.warn(`reconcileIndex: project root does not exist yet: ${dir}`);
1736
+ } else {
1737
+ throw new Error(`Failed to read project root ${dir}: ${e3?.message ?? e3}`);
1738
+ }
1739
+ } else {
1740
+ console.warn(`reconcileIndex: failed to read KB root ${dir}: ${e3?.message ?? e3}`);
1665
1741
  }
1666
- console.warn(`reconcileIndex: failed to read KB root ${dir}: ${e3?.message ?? e3}`);
1667
1742
  }
1668
1743
  return;
1669
1744
  }
@@ -1758,7 +1833,9 @@ function reconcileIndex(opts) {
1758
1833
  return { scope, newly_indexed, refreshed, pruned, newRecords };
1759
1834
  }
1760
1835
  function discoverFiles(projectId, dataDir2) {
1761
- return reconcileIndex({ projectId, dataDir: dataDir2 }).newRecords;
1836
+ reconcileIndex({ projectId, dataDir: dataDir2 });
1837
+ const db2 = getDatabase();
1838
+ return db2.prepare("SELECT * FROM files WHERE project_id = ? ORDER BY path").all(projectId);
1762
1839
  }
1763
1840
  function getTagsForFiles(fileIds) {
1764
1841
  const out = /* @__PURE__ */ new Map();
@@ -1805,6 +1882,7 @@ var init_metadata = __esm({
1805
1882
  init_safety();
1806
1883
  init_files();
1807
1884
  init_extensions();
1885
+ init_paths();
1808
1886
  FtsQueryError = class extends Error {
1809
1887
  code = "FTS_PARSE";
1810
1888
  constructor(message) {
@@ -1862,8 +1940,8 @@ var init_settings = __esm({
1862
1940
  });
1863
1941
 
1864
1942
  // ../../packages/core/dist/agent-rules/index.js
1865
- import { lstatSync as lstatSync4, readdirSync as readdirSync5, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4, readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync3, existsSync as existsSync6 } from "fs";
1866
- import { join as join6, sep as sep4, dirname as dirname4, isAbsolute as isAbsolute5 } from "path";
1943
+ import { lstatSync as lstatSync4, readdirSync as readdirSync5, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4, readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync4, existsSync as existsSync6 } from "fs";
1944
+ import { join as join6, sep as sep5, dirname as dirname4, isAbsolute as isAbsolute5 } from "path";
1867
1945
  import { fileURLToPath as fileURLToPath2 } from "url";
1868
1946
  function loadCorePackageVersion() {
1869
1947
  try {
@@ -1926,7 +2004,7 @@ function isRegularNonSymlink(absPath) {
1926
2004
  }
1927
2005
  }
1928
2006
  function toForwardSlashes(p) {
1929
- return sep4 === "/" ? p : p.split(sep4).join("/");
2007
+ return sep5 === "/" ? p : p.split(sep5).join("/");
1930
2008
  }
1931
2009
  function detectAgentContextFiles(projectPath) {
1932
2010
  const out = [];
@@ -1975,8 +2053,8 @@ function parseMarker(content) {
1975
2053
  function injectOrUpdate(content, block, version2) {
1976
2054
  const parsed = parseMarker(content);
1977
2055
  if (parsed === null) {
1978
- const sep9 = content.length === 0 ? "" : content.endsWith("\n\n") ? "" : content.endsWith("\n") ? "\n" : "\n\n";
1979
- return { action: "updated", content: content + sep9 + block };
2056
+ const sep10 = content.length === 0 ? "" : content.endsWith("\n\n") ? "" : content.endsWith("\n") ? "\n" : "\n\n";
2057
+ return { action: "updated", content: content + sep10 + block };
1980
2058
  }
1981
2059
  if (parsed.kind === "malformed") {
1982
2060
  throw new InjectError("malformed", "kontexta rules marker is malformed (BEGIN with no matching END)");
@@ -1999,7 +2077,7 @@ function atomicWrite(absPath, content) {
1999
2077
  renameSync3(tmp, absPath);
2000
2078
  } catch (e3) {
2001
2079
  try {
2002
- unlinkSync3(tmp);
2080
+ unlinkSync4(tmp);
2003
2081
  } catch {
2004
2082
  }
2005
2083
  throw e3;
@@ -130556,7 +130634,7 @@ var init_dist3 = __esm({
130556
130634
  }
130557
130635
  });
130558
130636
 
130559
- // ../../node_modules/.pnpm/@csstools+css-calc@3.2.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenizer@4.0.0__5q6mm7d5muktbf6idkt2s7pica/node_modules/@csstools/css-calc/dist/index.mjs
130637
+ // ../../node_modules/.pnpm/@csstools+css-calc@3.2.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenizer@_3b33f237655dfa7a35d4b0433ee15cf1/node_modules/@csstools/css-calc/dist/index.mjs
130560
130638
  function toLowerCaseAZ(e3) {
130561
130639
  return e3.replace(M, (e4) => String.fromCharCode(e4.charCodeAt(0) + 32));
130562
130640
  }
@@ -131315,7 +131393,7 @@ function replaceComponentValues2(n3, r5) {
131315
131393
  }
131316
131394
  var ParseError2, ParseErrorWithComponentValues, y, M, T, x, P, k, W, O, U, L, $2, V, Z, z, q, G, R, j, Y, _, H, J, K, Q;
131317
131395
  var init_dist4 = __esm({
131318
- "../../node_modules/.pnpm/@csstools+css-calc@3.2.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenizer@4.0.0__5q6mm7d5muktbf6idkt2s7pica/node_modules/@csstools/css-calc/dist/index.mjs"() {
131396
+ "../../node_modules/.pnpm/@csstools+css-calc@3.2.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenizer@_3b33f237655dfa7a35d4b0433ee15cf1/node_modules/@csstools/css-calc/dist/index.mjs"() {
131319
131397
  "use strict";
131320
131398
  init_dist3();
131321
131399
  init_dist2();
@@ -132439,7 +132517,7 @@ var init_dist5 = __esm({
132439
132517
  }
132440
132518
  });
132441
132519
 
132442
- // ../../node_modules/.pnpm/@csstools+css-color-parser@4.1.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenize_2jw36v2skt7mvdil6fqdameniu/node_modules/@csstools/css-color-parser/dist/index.mjs
132520
+ // ../../node_modules/.pnpm/@csstools+css-color-parser@4.1.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-to_402b4b31fb8b001854d943f6a3e18a48/node_modules/@csstools/css-color-parser/dist/index.mjs
132443
132521
  function convertNaNToZero(e3) {
132444
132522
  return [Number.isNaN(e3[0]) ? 0 : e3[0], Number.isNaN(e3[1]) ? 0 : e3[1], Number.isNaN(e3[2]) ? 0 : e3[2]];
132445
132523
  }
@@ -133504,7 +133582,7 @@ function color(e3) {
133504
133582
  }
133505
133583
  var he, me, pe, Ne, be, ge, ve, fe, ye;
133506
133584
  var init_dist6 = __esm({
133507
- "../../node_modules/.pnpm/@csstools+css-color-parser@4.1.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-tokenize_2jw36v2skt7mvdil6fqdameniu/node_modules/@csstools/css-color-parser/dist/index.mjs"() {
133585
+ "../../node_modules/.pnpm/@csstools+css-color-parser@4.1.1_@csstools+css-parser-algorithms@4.0.0_@csstools+css-to_402b4b31fb8b001854d943f6a3e18a48/node_modules/@csstools/css-color-parser/dist/index.mjs"() {
133508
133586
  "use strict";
133509
133587
  init_dist2();
133510
133588
  init_dist5();
@@ -137503,7 +137581,7 @@ var require_util7 = __commonJS({
137503
137581
  return path3;
137504
137582
  });
137505
137583
  exports.normalize = normalize3;
137506
- function join18(aRoot, aPath) {
137584
+ function join17(aRoot, aPath) {
137507
137585
  if (aRoot === "") {
137508
137586
  aRoot = ".";
137509
137587
  }
@@ -137535,7 +137613,7 @@ var require_util7 = __commonJS({
137535
137613
  }
137536
137614
  return joined;
137537
137615
  }
137538
- exports.join = join18;
137616
+ exports.join = join17;
137539
137617
  exports.isAbsolute = function(aPath) {
137540
137618
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
137541
137619
  };
@@ -137749,7 +137827,7 @@ var require_util7 = __commonJS({
137749
137827
  parsed.path = parsed.path.substring(0, index + 1);
137750
137828
  }
137751
137829
  }
137752
- sourceURL = join18(urlGenerate(parsed), sourceURL);
137830
+ sourceURL = join17(urlGenerate(parsed), sourceURL);
137753
137831
  }
137754
137832
  return normalize3(sourceURL);
137755
137833
  }
@@ -329707,17 +329785,17 @@ var init_whats_new = __esm({
329707
329785
  });
329708
329786
 
329709
329787
  // ../../packages/core/dist/project-map/index.js
329710
- import { sep as sep5, join as join8, basename as basename2 } from "path";
329788
+ import { sep as sep6, join as join8, basename as basename2 } from "path";
329711
329789
  function emptyNode() {
329712
329790
  return { dirs: /* @__PURE__ */ new Map(), files: [] };
329713
329791
  }
329714
329792
  function stripRoot(filePath, root2) {
329715
- const rootWithSep = root2.endsWith(sep5) ? root2 : root2 + sep5;
329793
+ const rootWithSep = root2.endsWith(sep6) ? root2 : root2 + sep6;
329716
329794
  if (filePath === root2)
329717
329795
  return [];
329718
329796
  if (!filePath.startsWith(rootWithSep))
329719
329797
  return null;
329720
- return filePath.slice(rootWithSep.length).split(sep5).filter(Boolean);
329798
+ return filePath.slice(rootWithSep.length).split(sep6).filter(Boolean);
329721
329799
  }
329722
329800
  function locateFile(file, projectsById, dataDir2) {
329723
329801
  if (file.project_id == null) {
@@ -329860,73 +329938,6 @@ var init_project_map = __esm({
329860
329938
  }
329861
329939
  });
329862
329940
 
329863
- // ../../packages/core/dist/compat/env-shim.js
329864
- function migrateEnvVars() {
329865
- const migrated = [];
329866
- for (const [oldKey, newKey] of RENAMED_VARS) {
329867
- if (process.env[oldKey] && !process.env[newKey]) {
329868
- process.env[newKey] = process.env[oldKey];
329869
- migrated.push(oldKey);
329870
- }
329871
- }
329872
- if (migrated.length > 0) {
329873
- console.warn(`[Kontexta] Deprecated env vars migrated: ${migrated.join(", ")}. Rename to KONTEXTA_* prefix. Support removed in v2.0.`);
329874
- }
329875
- return migrated;
329876
- }
329877
- var RENAMED_VARS;
329878
- var init_env_shim = __esm({
329879
- "../../packages/core/dist/compat/env-shim.js"() {
329880
- "use strict";
329881
- RENAMED_VARS = [
329882
- ["MNEXIS_DATA_DIR", "KONTEXTA_DATA_DIR"],
329883
- ["MNEXIS_DB_PATH", "KONTEXTA_DB_PATH"],
329884
- ["MNEXIS_WS_HOST", "KONTEXTA_WS_HOST"],
329885
- ["MNEXIS_WS_ORIGINS", "KONTEXTA_WS_ORIGINS"],
329886
- ["MNEXIS_WS_TOKEN", "KONTEXTA_WS_TOKEN"],
329887
- ["MNEXIS_EXPORT_MAX_BYTES", "KONTEXTA_EXPORT_MAX_BYTES"],
329888
- ["MNEXIS_INSTALL_HINT", "KONTEXTA_INSTALL_HINT"],
329889
- ["MNEXIS_PROJECT_TOKEN_WARN", "KONTEXTA_PROJECT_TOKEN_WARN"],
329890
- ["MNEXIS_SHUTDOWN_DRAIN_MS", "KONTEXTA_SHUTDOWN_DRAIN_MS"]
329891
- ];
329892
- }
329893
- });
329894
-
329895
- // ../../packages/core/dist/compat/file-migration.js
329896
- import { existsSync as existsSync7, renameSync as renameSync4, copyFileSync as copyFileSync2 } from "fs";
329897
- import { join as join9 } from "path";
329898
- function migrateDataFiles(dataDir2) {
329899
- for (const [oldName, newName] of DB_RENAMES) {
329900
- const oldPath = join9(dataDir2, oldName);
329901
- const newPath = join9(dataDir2, newName);
329902
- if (existsSync7(oldPath) && !existsSync7(newPath)) {
329903
- copyFileSync2(oldPath, oldPath + ".bak");
329904
- renameSync4(oldPath, newPath);
329905
- console.warn(`[Kontexta] Migrated ${oldName} \u2192 ${newName} (backup: ${oldName}.bak). Automatic migration removed in v2.0.`);
329906
- }
329907
- }
329908
- }
329909
- function migrateProjectConfig(projectRoot) {
329910
- const oldConfig = join9(projectRoot, "mnexis.json");
329911
- const newConfig = join9(projectRoot, "kontexta.json");
329912
- if (existsSync7(oldConfig) && !existsSync7(newConfig)) {
329913
- copyFileSync2(oldConfig, oldConfig + ".bak");
329914
- renameSync4(oldConfig, newConfig);
329915
- console.warn(`[Kontexta] Migrated mnexis.json \u2192 kontexta.json in ${projectRoot} (backup: mnexis.json.bak). Automatic migration removed in v2.0.`);
329916
- }
329917
- }
329918
- var DB_RENAMES;
329919
- var init_file_migration = __esm({
329920
- "../../packages/core/dist/compat/file-migration.js"() {
329921
- "use strict";
329922
- DB_RENAMES = [
329923
- ["mnexis.db", "kontexta.db"],
329924
- ["mnexis.db-wal", "kontexta.db-wal"],
329925
- ["mnexis.db-shm", "kontexta.db-shm"]
329926
- ];
329927
- }
329928
- });
329929
-
329930
329941
  // ../../packages/core/dist/journal/types.js
329931
329942
  var init_types2 = __esm({
329932
329943
  "../../packages/core/dist/journal/types.js"() {
@@ -329936,7 +329947,7 @@ var init_types2 = __esm({
329936
329947
 
329937
329948
  // ../../packages/core/dist/journal/writer.js
329938
329949
  import { mkdirSync as mkdirSync6, openSync, closeSync, writeSync, fsyncSync } from "fs";
329939
- import { join as join10, dirname as dirname5 } from "path";
329950
+ import { join as join9, dirname as dirname5 } from "path";
329940
329951
  var JournalWriter;
329941
329952
  var init_writer = __esm({
329942
329953
  "../../packages/core/dist/journal/writer.js"() {
@@ -329946,7 +329957,7 @@ var init_writer = __esm({
329946
329957
  currentDay = null;
329947
329958
  rawDir;
329948
329959
  constructor(opts) {
329949
- this.rawDir = join10(opts.baseDir, opts.projectSlug, "raw");
329960
+ this.rawDir = join9(opts.baseDir, opts.projectSlug, "raw");
329950
329961
  }
329951
329962
  append(event) {
329952
329963
  const day = event.ts.slice(0, 10);
@@ -329968,7 +329979,7 @@ var init_writer = __esm({
329968
329979
  closeSync(this.fd);
329969
329980
  this.fd = null;
329970
329981
  }
329971
- const path3 = join10(this.rawDir, `${day}.jsonl`);
329982
+ const path3 = join9(this.rawDir, `${day}.jsonl`);
329972
329983
  mkdirSync6(dirname5(path3), { recursive: true });
329973
329984
  this.fd = openSync(path3, "a");
329974
329985
  this.currentDay = day;
@@ -330023,14 +330034,14 @@ var init_redact = __esm({
330023
330034
  });
330024
330035
 
330025
330036
  // ../../packages/core/dist/journal/high-water.js
330026
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync5, mkdirSync as mkdirSync7, existsSync as existsSync8 } from "fs";
330027
- import { join as join11 } from "path";
330037
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync7, existsSync as existsSync7 } from "fs";
330038
+ import { join as join10 } from "path";
330028
330039
  function pathFor(baseDir, projectSlug2) {
330029
- return join11(baseDir, projectSlug2, ".distilled-up-to.json");
330040
+ return join10(baseDir, projectSlug2, ".distilled-up-to.json");
330030
330041
  }
330031
330042
  function readHighWater(baseDir, projectSlug2) {
330032
330043
  const p = pathFor(baseDir, projectSlug2);
330033
- if (!existsSync8(p))
330044
+ if (!existsSync7(p))
330034
330045
  return null;
330035
330046
  try {
330036
330047
  const raw = readFileSync7(p, "utf8");
@@ -330044,12 +330055,12 @@ function readHighWater(baseDir, projectSlug2) {
330044
330055
  }
330045
330056
  }
330046
330057
  function writeHighWater(baseDir, projectSlug2, hw) {
330047
- const dir = join11(baseDir, projectSlug2);
330058
+ const dir = join10(baseDir, projectSlug2);
330048
330059
  mkdirSync7(dir, { recursive: true });
330049
330060
  const final = pathFor(baseDir, projectSlug2);
330050
330061
  const tmp = `${final}.tmp`;
330051
330062
  writeFileSync5(tmp, JSON.stringify(hw, null, 2));
330052
- renameSync5(tmp, final);
330063
+ renameSync4(tmp, final);
330053
330064
  }
330054
330065
  var init_high_water = __esm({
330055
330066
  "../../packages/core/dist/journal/high-water.js"() {
@@ -330669,12 +330680,12 @@ var init_repository = __esm({
330669
330680
  });
330670
330681
 
330671
330682
  // ../../packages/core/dist/journal/cooldown.js
330672
- import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, mkdirSync as mkdirSync8 } from "fs";
330673
- import { join as join12 } from "path";
330683
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5, mkdirSync as mkdirSync8 } from "fs";
330684
+ import { join as join11 } from "path";
330674
330685
  function acquireCooldown(baseDir, projectSlug2, cooldownSeconds) {
330675
- mkdirSync8(join12(baseDir, projectSlug2), { recursive: true });
330676
- const lockPath = join12(baseDir, projectSlug2, ".distill.lock");
330677
- if (existsSync9(lockPath)) {
330686
+ mkdirSync8(join11(baseDir, projectSlug2), { recursive: true });
330687
+ const lockPath = join11(baseDir, projectSlug2, ".distill.lock");
330688
+ if (existsSync8(lockPath)) {
330678
330689
  try {
330679
330690
  const ts = Number(readFileSync8(lockPath, "utf8"));
330680
330691
  if (!isNaN(ts) && Date.now() - ts < cooldownSeconds * 1e3)
@@ -330686,10 +330697,10 @@ function acquireCooldown(baseDir, projectSlug2, cooldownSeconds) {
330686
330697
  return true;
330687
330698
  }
330688
330699
  function releaseCooldown(baseDir, projectSlug2) {
330689
- const lockPath = join12(baseDir, projectSlug2, ".distill.lock");
330690
- if (existsSync9(lockPath)) {
330700
+ const lockPath = join11(baseDir, projectSlug2, ".distill.lock");
330701
+ if (existsSync8(lockPath)) {
330691
330702
  try {
330692
- unlinkSync4(lockPath);
330703
+ unlinkSync5(lockPath);
330693
330704
  } catch {
330694
330705
  }
330695
330706
  }
@@ -330701,16 +330712,16 @@ var init_cooldown = __esm({
330701
330712
  });
330702
330713
 
330703
330714
  // ../../packages/core/dist/journal/distill.js
330704
- import { readFileSync as readFileSync9, readdirSync as readdirSync6, existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
330705
- import { join as join13 } from "path";
330715
+ import { readFileSync as readFileSync9, readdirSync as readdirSync6, existsSync as existsSync9, mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
330716
+ import { join as join12 } from "path";
330706
330717
  function rawDir(opts) {
330707
- return join13(opts.dataDir, ...REL_BASE, opts.projectSlug, "raw");
330718
+ return join12(opts.dataDir, ...REL_BASE, opts.projectSlug, "raw");
330708
330719
  }
330709
330720
  function distilledDir(opts, ts) {
330710
- return join13(opts.dataDir, ...REL_BASE, opts.projectSlug, ts.slice(0, 4), ts.slice(5, 7), ts.slice(8, 10));
330721
+ return join12(opts.dataDir, ...REL_BASE, opts.projectSlug, ts.slice(0, 4), ts.slice(5, 7), ts.slice(8, 10));
330711
330722
  }
330712
330723
  async function distillJournal(opts) {
330713
- const cooldownBase = join13(opts.dataDir, ...REL_BASE);
330724
+ const cooldownBase = join12(opts.dataDir, ...REL_BASE);
330714
330725
  const cooldownSec = opts.cooldownSeconds ?? 0;
330715
330726
  if (!acquireCooldown(cooldownBase, opts.projectSlug, cooldownSec)) {
330716
330727
  return {
@@ -330722,7 +330733,7 @@ async function distillJournal(opts) {
330722
330733
  };
330723
330734
  }
330724
330735
  try {
330725
- const hw = readHighWater(join13(opts.dataDir, ...REL_BASE), opts.projectSlug);
330736
+ const hw = readHighWater(join12(opts.dataDir, ...REL_BASE), opts.projectSlug);
330726
330737
  const since = hw?.last_event_ts ?? "0000-01-01T00:00:00Z";
330727
330738
  const cutoff = new Date(opts.now.getTime() - opts.inFlightWindowSeconds * 1e3).toISOString();
330728
330739
  const events = readRawEvents(opts, since, cutoff, opts.maxEvents);
@@ -330738,7 +330749,7 @@ async function distillJournal(opts) {
330738
330749
  const dir = distilledDir(opts, lastEvent.ts);
330739
330750
  mkdirSync9(dir, { recursive: true });
330740
330751
  const filename = `task-${bucket.task_slug}.md`;
330741
- const filePath = join13(dir, filename);
330752
+ const filePath = join12(dir, filename);
330742
330753
  const fm = buildFrontmatter2(bucket, opts.projectSlug);
330743
330754
  const entry = renderMechanicalEntry({
330744
330755
  task_slug: bucket.task_slug,
@@ -330746,7 +330757,7 @@ async function distillJournal(opts) {
330746
330757
  now: lastEvent.ts,
330747
330758
  extraPatterns: opts.extraPatterns
330748
330759
  });
330749
- if (existsSync10(filePath)) {
330760
+ if (existsSync9(filePath)) {
330750
330761
  const existing = readFileSync9(filePath, "utf8");
330751
330762
  writeFileSync7(filePath, replaceOrAppendEntry(existing, fm, entry));
330752
330763
  } else {
@@ -330768,7 +330779,7 @@ async function distillJournal(opts) {
330768
330779
  });
330769
330780
  }
330770
330781
  const newHw = events[events.length - 1].ts;
330771
- writeHighWater(join13(opts.dataDir, ...REL_BASE), opts.projectSlug, {
330782
+ writeHighWater(join12(opts.dataDir, ...REL_BASE), opts.projectSlug, {
330772
330783
  last_event_ts: newHw,
330773
330784
  last_distilled_at: opts.now.toISOString(),
330774
330785
  events_processed: (hw?.events_processed ?? 0) + events.length
@@ -330786,17 +330797,17 @@ async function distillJournal(opts) {
330786
330797
  }
330787
330798
  function readRawEvents(opts, sinceTs, untilTs, max2) {
330788
330799
  const dirs = [rawDir(opts)];
330789
- const defaultDir = join13(opts.dataDir, ...REL_BASE, "default", "raw");
330790
- if (defaultDir !== dirs[0] && existsSync10(defaultDir)) {
330800
+ const defaultDir = join12(opts.dataDir, ...REL_BASE, "default", "raw");
330801
+ if (defaultDir !== dirs[0] && existsSync9(defaultDir)) {
330791
330802
  dirs.push(defaultDir);
330792
330803
  }
330793
330804
  const out = [];
330794
330805
  for (const dir of dirs) {
330795
- if (!existsSync10(dir))
330806
+ if (!existsSync9(dir))
330796
330807
  continue;
330797
330808
  const files = readdirSync6(dir).filter((f3) => f3.endsWith(".jsonl")).sort();
330798
330809
  for (const f3 of files) {
330799
- const lines = readFileSync9(join13(dir, f3), "utf8").split("\n").filter(Boolean);
330810
+ const lines = readFileSync9(join12(dir, f3), "utf8").split("\n").filter(Boolean);
330800
330811
  for (const line of lines) {
330801
330812
  try {
330802
330813
  const ev = JSON.parse(line);
@@ -330983,17 +330994,17 @@ var init_git_watcher = __esm({
330983
330994
  });
330984
330995
 
330985
330996
  // ../../packages/core/dist/journal/presence.js
330986
- import { readdirSync as readdirSync7, statSync as statSync3, existsSync as existsSync11 } from "fs";
330987
- import { join as join14 } from "path";
330997
+ import { readdirSync as readdirSync7, statSync as statSync3, existsSync as existsSync10 } from "fs";
330998
+ import { join as join13 } from "path";
330988
330999
  function isMcpActive(baseDir, projectSlug2, windowSec) {
330989
- const rawDir2 = join14(baseDir, projectSlug2, "raw");
330990
- if (!existsSync11(rawDir2))
331000
+ const rawDir2 = join13(baseDir, projectSlug2, "raw");
331001
+ if (!existsSync10(rawDir2))
330991
331002
  return false;
330992
331003
  const cutoff = Date.now() - windowSec * 1e3;
330993
331004
  for (const f3 of readdirSync7(rawDir2)) {
330994
331005
  if (!f3.endsWith(".jsonl"))
330995
331006
  continue;
330996
- if (statSync3(join14(rawDir2, f3)).mtimeMs >= cutoff)
331007
+ if (statSync3(join13(rawDir2, f3)).mtimeMs >= cutoff)
330997
331008
  return true;
330998
331009
  }
330999
331010
  return false;
@@ -331005,8 +331016,8 @@ var init_presence = __esm({
331005
331016
  });
331006
331017
 
331007
331018
  // ../../packages/core/dist/journal/housekeep.js
331008
- import { readdirSync as readdirSync8, statSync as statSync4, unlinkSync as unlinkSync5, renameSync as renameSync6, mkdirSync as mkdirSync10, existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
331009
- import { join as join15 } from "path";
331019
+ import { readdirSync as readdirSync8, statSync as statSync4, unlinkSync as unlinkSync6, renameSync as renameSync5, mkdirSync as mkdirSync10, existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
331020
+ import { join as join14 } from "path";
331010
331021
  function lastEventTs(path3) {
331011
331022
  try {
331012
331023
  const content = readFileSync10(path3, "utf8");
@@ -331030,12 +331041,12 @@ function housekeepJournal(cfg) {
331030
331041
  };
331031
331042
  if (cfg.retention.raw_days > 0) {
331032
331043
  const cutoff = now.getTime() - cfg.retention.raw_days * 864e5;
331033
- const rawDir2 = join15(cfg.baseDir, cfg.projectSlug, "raw");
331034
- if (existsSync12(rawDir2)) {
331044
+ const rawDir2 = join14(cfg.baseDir, cfg.projectSlug, "raw");
331045
+ if (existsSync11(rawDir2)) {
331035
331046
  const hw = readHighWater(cfg.baseDir, cfg.projectSlug);
331036
331047
  const highWaterTs = hw?.last_event_ts ?? null;
331037
331048
  for (const f3 of readdirSync8(rawDir2).filter((n3) => n3.endsWith(".jsonl"))) {
331038
- const p = join15(rawDir2, f3);
331049
+ const p = join14(rawDir2, f3);
331039
331050
  if (statSync4(p).mtimeMs >= cutoff)
331040
331051
  continue;
331041
331052
  const fileLastTs = lastEventTs(p);
@@ -331043,7 +331054,7 @@ function housekeepJournal(cfg) {
331043
331054
  result.raw_files_skipped_undistilled++;
331044
331055
  continue;
331045
331056
  }
331046
- unlinkSync5(p);
331057
+ unlinkSync6(p);
331047
331058
  result.raw_files_pruned++;
331048
331059
  }
331049
331060
  }
@@ -331057,12 +331068,12 @@ function housekeepJournal(cfg) {
331057
331068
  JOIN projects p ON p.id = jm.project_id
331058
331069
  WHERE p.slug = ? AND jm.last_active_at < ?
331059
331070
  `).all(cfg.projectSlug, archiveCutoff);
331060
- const archiveDir = join15(cfg.baseDir, cfg.projectSlug, "_archive");
331071
+ const archiveDir = join14(cfg.baseDir, cfg.projectSlug, "_archive");
331061
331072
  mkdirSync10(archiveDir, { recursive: true });
331062
331073
  for (const row of cold) {
331063
- const dest = join15(archiveDir, row.path.split("/").pop() ?? `task-${row.file_id}.md`);
331064
- if (!existsSync12(dest) && existsSync12(row.path)) {
331065
- renameSync6(row.path, dest);
331074
+ const dest = join14(archiveDir, row.path.split("/").pop() ?? `task-${row.file_id}.md`);
331075
+ if (!existsSync11(dest) && existsSync11(row.path)) {
331076
+ renameSync5(row.path, dest);
331066
331077
  db2.prepare(`UPDATE files SET path = ? WHERE id = ?`).run(dest, row.file_id);
331067
331078
  result.archived_tasks++;
331068
331079
  }
@@ -331215,13 +331226,11 @@ __export(dist_exports2, {
331215
331226
  journalRefsByValue: () => journalRefsByValue,
331216
331227
  listFiles: () => listFiles,
331217
331228
  listProjectFolders: () => listProjectFolders,
331229
+ listProjectFoldersWithFiles: () => listProjectFoldersWithFiles,
331218
331230
  listProjects: () => listProjects,
331219
331231
  listTags: () => listTags,
331220
331232
  loadExtraPatterns: () => loadExtraPatterns,
331221
331233
  markUpgradeApplied: () => markUpgradeApplied,
331222
- migrateDataFiles: () => migrateDataFiles,
331223
- migrateEnvVars: () => migrateEnvVars,
331224
- migrateProjectConfig: () => migrateProjectConfig,
331225
331234
  moveFile: () => moveFile,
331226
331235
  openTasksForProject: () => openTasksForProject,
331227
331236
  parseMarker: () => parseMarker,
@@ -331236,6 +331245,7 @@ __export(dist_exports2, {
331236
331245
  removeTags: () => removeTags,
331237
331246
  renderMechanicalEntry: () => renderMechanicalEntry,
331238
331247
  replaceSection: () => replaceSection,
331248
+ resetDataDirCache: () => resetDataDirCache,
331239
331249
  resolveSince: () => resolveSince,
331240
331250
  restoreVersion: () => restoreVersion,
331241
331251
  runPatterns: () => runPatterns,
@@ -331278,14 +331288,28 @@ var init_dist7 = __esm({
331278
331288
  init_clip();
331279
331289
  init_whats_new();
331280
331290
  init_project_map();
331281
- init_env_shim();
331282
- init_file_migration();
331283
331291
  init_journal();
331284
331292
  }
331285
331293
  });
331286
331294
 
331295
+ // src/re2-compat.ts
331296
+ import { createRequire as createRequire4 } from "module";
331297
+ var require5, RE2Class, re2_compat_default;
331298
+ var init_re2_compat = __esm({
331299
+ "src/re2-compat.ts"() {
331300
+ "use strict";
331301
+ require5 = createRequire4(import.meta.url);
331302
+ try {
331303
+ RE2Class = require5("re2");
331304
+ } catch (e3) {
331305
+ console.warn("kontexta-mcp: Failed to load native 're2' module, falling back to standard RegExp.");
331306
+ RE2Class = RegExp;
331307
+ }
331308
+ re2_compat_default = RE2Class;
331309
+ }
331310
+ });
331311
+
331287
331312
  // src/hands/sanitizer.ts
331288
- import RE2 from "re2";
331289
331313
  function rejectNul(s3) {
331290
331314
  if (s3.includes("\0")) {
331291
331315
  throw new Error("NUL byte not permitted in param value");
@@ -331321,7 +331345,7 @@ function isLiteralArgv0(s3) {
331321
331345
  function compilePattern(src) {
331322
331346
  let r5;
331323
331347
  try {
331324
- r5 = new RE2(src);
331348
+ r5 = new re2_compat_default(src);
331325
331349
  } catch (e3) {
331326
331350
  throw new Error(`invalid pattern: ${e3?.message ?? e3}`);
331327
331351
  }
@@ -331358,6 +331382,7 @@ var SAFE_INT_MIN, SAFE_INT_MAX, DEFAULT_STRING_PATTERN, MAX_STRING_LENGTH, CONTR
331358
331382
  var init_sanitizer = __esm({
331359
331383
  "src/hands/sanitizer.ts"() {
331360
331384
  "use strict";
331385
+ init_re2_compat();
331361
331386
  SAFE_INT_MIN = Number.MIN_SAFE_INTEGER;
331362
331387
  SAFE_INT_MAX = Number.MAX_SAFE_INTEGER;
331363
331388
  DEFAULT_STRING_PATTERN = "^[^-\\s][^\\n\\r]*$";
@@ -331376,7 +331401,7 @@ __export(executor_exports, {
331376
331401
  resolveCwd: () => resolveCwd
331377
331402
  });
331378
331403
  import { spawn } from "child_process";
331379
- import { resolve as resolvePath, sep as sep7 } from "path";
331404
+ import { resolve as resolvePath, sep as sep8 } from "path";
331380
331405
  import { realpathSync } from "fs";
331381
331406
  function resolveArgv(command, params, defs, argSeparator) {
331382
331407
  const resolvedValues = {};
@@ -331432,7 +331457,7 @@ function resolveCwd(projectRoot, workingDir) {
331432
331457
  } catch {
331433
331458
  throw new Error(`workingDir does not exist: ${workingDir}`);
331434
331459
  }
331435
- if (real !== rootReal && !real.startsWith(rootReal + sep7)) {
331460
+ if (real !== rootReal && !real.startsWith(rootReal + sep8)) {
331436
331461
  throw new Error(`workingDir resolved outside project root`);
331437
331462
  }
331438
331463
  return real;
@@ -331596,12 +331621,13 @@ ${tailStr}`;
331596
331621
 
331597
331622
  // src/index.ts
331598
331623
  init_dist7();
331624
+ init_re2_compat();
331599
331625
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
331600
331626
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
331601
331627
  import { z as z6 } from "zod";
331602
- import RE22 from "re2";
331603
- import { isAbsolute as isAbsolute7, join as join17, resolve as resolve7, sep as sep8, dirname as dirname6 } from "path";
331604
- import { statSync as statSync5, openSync as openSync2, readSync, closeSync as closeSync2, readFileSync as readFileSync12, existsSync as existsSync14, realpathSync as realpathSync2 } from "fs";
331628
+ import { isAbsolute as isAbsolute7, join as join16, resolve as resolve7, sep as sep9, dirname as dirname6 } from "path";
331629
+ import { statSync as statSync5, lstatSync as lstatSync5, openSync as openSync2, readSync, closeSync as closeSync2, readFileSync as readFileSync12, existsSync as existsSync13, realpathSync as realpathSync2 } from "fs";
331630
+ import { createHash as createHash3 } from "crypto";
331605
331631
  import { fileURLToPath as fileURLToPath3 } from "url";
331606
331632
 
331607
331633
  // src/hands/registry.ts
@@ -331609,9 +331635,8 @@ import { z as z2 } from "zod";
331609
331635
 
331610
331636
  // src/hands/loader.ts
331611
331637
  init_sanitizer();
331612
- init_dist7();
331613
- import { readFileSync as readFileSync11, existsSync as existsSync13 } from "fs";
331614
- import { join as join16, isAbsolute as isAbsolute6, normalize as normalize2, sep as sep6 } from "path";
331638
+ import { readFileSync as readFileSync11, existsSync as existsSync12 } from "fs";
331639
+ import { join as join15, isAbsolute as isAbsolute6, normalize as normalize2, sep as sep7 } from "path";
331615
331640
  var TOOL_NAME_RE = /^[a-z][a-z0-9-]*$/;
331616
331641
  var PARAM_NAME_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
331617
331642
  var FORBIDDEN_ENV = /* @__PURE__ */ new Set([
@@ -331628,9 +331653,8 @@ var TIMEOUT_DEFAULT = 6e4;
331628
331653
  var OUTPUT_MAX = 1e6;
331629
331654
  var OUTPUT_DEFAULT = 1e5;
331630
331655
  function loadProjectConfig(projectRoot) {
331631
- migrateProjectConfig(projectRoot);
331632
- const file = join16(projectRoot, "kontexta.json");
331633
- if (!existsSync13(file)) {
331656
+ const file = join15(projectRoot, "kontexta.json");
331657
+ if (!existsSync12(file)) {
331634
331658
  return { found: false, tools: {}, disabled: [], warnings: [], errors: [] };
331635
331659
  }
331636
331660
  let raw;
@@ -331680,7 +331704,7 @@ function validateTool(name50, def, projectRoot) {
331680
331704
  }
331681
331705
  if (!isLiteralArgv0(def.command[0])) return reject("argv[0] must be literal (no {{param}})");
331682
331706
  const argv0 = def.command[0];
331683
- if (!isAbsolute6(argv0) && (argv0.includes("/") || argv0.includes(sep6))) {
331707
+ if (!isAbsolute6(argv0) && (argv0.includes("/") || argv0.includes(sep7))) {
331684
331708
  return reject("argv[0] must be absolute or a bare command name (no relative paths)");
331685
331709
  }
331686
331710
  const paramDefs = def.params ?? {};
@@ -331713,7 +331737,7 @@ function validateTool(name50, def, projectRoot) {
331713
331737
  if (typeof def.workingDir !== "string") return reject("workingDir must be string");
331714
331738
  if (isAbsolute6(def.workingDir)) return reject("workingDir must be relative");
331715
331739
  const norm = normalize2(def.workingDir);
331716
- if (norm.startsWith("..") || norm.split(sep6).includes("..")) return reject("workingDir must not contain ..");
331740
+ if (norm.startsWith("..") || norm.split(sep7).includes("..")) return reject("workingDir must not contain ..");
331717
331741
  }
331718
331742
  if (def.env !== void 0) {
331719
331743
  if (typeof def.env !== "object" || def.env === null) return reject("env must be object");
@@ -332551,7 +332575,7 @@ function getAgentRulesWarning(projectId) {
332551
332575
  }
332552
332576
  const outdatedProjects = [];
332553
332577
  for (const p of projects) {
332554
- if (!p || !p.path || !existsSync14(p.path)) continue;
332578
+ if (!p || !p.path || !existsSync13(p.path)) continue;
332555
332579
  const contextFiles = detectAgentContextFiles(p.path);
332556
332580
  if (contextFiles.length === 0) continue;
332557
332581
  const statuses = checkAgentRulesStatus(p.path, contextFiles);
@@ -332620,8 +332644,8 @@ var pkgVersionFound = false;
332620
332644
  try {
332621
332645
  let currentDir = dirname6(fileURLToPath3(import.meta.url));
332622
332646
  while (currentDir !== dirname6(currentDir)) {
332623
- const p = join17(currentDir, "package.json");
332624
- if (existsSync14(p)) {
332647
+ const p = join16(currentDir, "package.json");
332648
+ if (existsSync13(p)) {
332625
332649
  const pkg = JSON.parse(readFileSync12(p, "utf8"));
332626
332650
  if (pkg.name === "kontexta-mcp" && pkg.version) {
332627
332651
  pkgVersion = pkg.version;
@@ -332642,7 +332666,7 @@ var server = new McpServer({
332642
332666
  version: pkgVersion
332643
332667
  });
332644
332668
  var handsRegistry = new HandsRegistry(server);
332645
- var baseJournalDir = join17(dataDir, "knowledge", "journal");
332669
+ var baseJournalDir = join16(dataDir, "knowledge", "journal");
332646
332670
  var projectSlug = process.env.KONTEXTA_DEFAULT_PROJECT_SLUG ?? "default";
332647
332671
  var agent = process.env.KONTEXTA_AGENT ?? "unknown";
332648
332672
  var sid = `${process.pid}-${Date.now().toString(36)}`;
@@ -332700,8 +332724,8 @@ server.tool(
332700
332724
  const journalFolder = "journal";
332701
332725
  const title = `journal-${today}`;
332702
332726
  const db2 = getDatabase();
332703
- const knowledgeDir = join17(dataDir, "knowledge");
332704
- const expectedPath = join17(knowledgeDir, journalFolder, `${title}.md`);
332727
+ const knowledgeDir = join16(dataDir, "knowledge");
332728
+ const expectedPath = join16(knowledgeDir, journalFolder, `${title}.md`);
332705
332729
  const existingRow = db2.prepare("SELECT id, path FROM files WHERE path = ? AND project_id IS NULL").get(expectedPath);
332706
332730
  if (existingRow) {
332707
332731
  const existing = readFile(existingRow.id);
@@ -332831,7 +332855,7 @@ server.tool(
332831
332855
  folder = parts.length > 1 ? parts.slice(0, -1).join("/") : null;
332832
332856
  }
332833
332857
  } else {
332834
- const knowledgeRoot = join17(dataDir, "knowledge");
332858
+ const knowledgeRoot = join16(dataDir, "knowledge");
332835
332859
  if (file.path?.startsWith(knowledgeRoot)) {
332836
332860
  const rel = file.path.slice(knowledgeRoot.length).replace(/^[\/\\]+/, "");
332837
332861
  const parts = rel.split(/[\/\\]/);
@@ -332984,7 +333008,7 @@ server.tool(
332984
333008
  try {
332985
333009
  let re;
332986
333010
  try {
332987
- re = new RE22(pattern, case_insensitive ? "i" : "");
333011
+ re = new re2_compat_default(pattern, case_insensitive ? "i" : "");
332988
333012
  } catch (e3) {
332989
333013
  throw new Error(`invalid regex: ${e3?.message ?? e3}`);
332990
333014
  }
@@ -333039,7 +333063,7 @@ server.tool(
333039
333063
  try {
333040
333064
  let re;
333041
333065
  try {
333042
- re = new RE22(pattern, case_insensitive ? "i" : "");
333066
+ re = new re2_compat_default(pattern, case_insensitive ? "i" : "");
333043
333067
  } catch (e3) {
333044
333068
  throw new Error(`invalid regex: ${e3?.message ?? e3}`);
333045
333069
  }
@@ -333280,7 +333304,7 @@ server.tool(
333280
333304
  async () => {
333281
333305
  const result = listProjects();
333282
333306
  const augmented = result.map((p) => {
333283
- const has_hands = !!(p.path && existsSync14(p.path) && existsSync14(`${p.path}/kontexta.json`));
333307
+ const has_hands = !!(p.path && existsSync13(p.path) && existsSync13(`${p.path}/kontexta.json`));
333284
333308
  const contextFiles = p.path ? detectAgentContextFiles(p.path) : [];
333285
333309
  const statuses = p.path ? checkAgentRulesStatus(p.path, contextFiles) : [];
333286
333310
  const outdated = statuses.filter((s3) => !s3.upToDate);
@@ -333488,6 +333512,130 @@ RETURNS: { written: [{ path, action: created|updated|skipped, version }], skippe
333488
333512
  }
333489
333513
  }
333490
333514
  );
333515
+ server.tool(
333516
+ "transfer_agent_context",
333517
+ `COPY existing agent context files (CLAUDE.md, AGENTS.md, .cursor/rules/*.mdc, etc.) from a project's repo into Kontexta's per-project knowledge base so they're indexed by FTS5 and can be git-synced through Kontexta's own backup engine.
333518
+
333519
+ This tool ONLY COPIES. It never deletes or modifies the originals in your repo. After a successful transfer, the response includes the list of source paths so the user can manually remove them if desired. No tool argument, no flag, and no code path in this tool ever calls a destructive filesystem operation against \`project.path\`.
333520
+
333521
+ MANDATORY: This tool writes new files into Kontexta's data dir. You MUST seek explicit user consent before calling. Set 'confirm: true' only after the user has agreed.
333522
+
333523
+ PARAMETERS:
333524
+ - project_id: number, required. Project ID returned from register_project.
333525
+ - confirm: boolean, required. Must be true.
333526
+ - files: string[], optional. Project-relative paths to transfer. Omit or pass [] to transfer all detected agent context files (uses the same detection list as register_project / onboard_agent).
333527
+
333528
+ RETURNS: { transferred: [{ source_path, kb_id, kb_path, est_tokens }], skipped: [{ source_path, reason }], next_action }
333529
+ Skip reasons: "missing" | "symlink" | "outside_project" | "already_transferred_same_content" | "read_error" | "write_error".
333530
+
333531
+ IDEMPOTENT: re-running with the same files copies nothing if the content is unchanged \u2014 duplicate transfers are detected via SHA-256 hash comparison against existing project KB rows.`,
333532
+ {
333533
+ project_id: z6.number().describe("Project ID returned from register_project"),
333534
+ confirm: z6.boolean().describe("MANDATORY: Set to true only after obtaining explicit user consent."),
333535
+ files: z6.array(z6.string()).optional().describe("Project-relative paths to transfer. Omit to transfer all detected context files.")
333536
+ },
333537
+ async ({ project_id, confirm, files }) => {
333538
+ try {
333539
+ if (confirm !== true) {
333540
+ return {
333541
+ isError: true,
333542
+ content: [{
333543
+ type: "text",
333544
+ text: JSON.stringify({
333545
+ error: "User consent required",
333546
+ details: "This tool copies project files into Kontexta's KB. Explain the proposed transfer to the user and obtain explicit consent, then re-run with 'confirm: true'. Originals in the project repo are NOT touched."
333547
+ }, null, 2)
333548
+ }]
333549
+ };
333550
+ }
333551
+ const db2 = getDatabase();
333552
+ const project = db2.prepare("SELECT id, name, slug, path FROM projects WHERE id = ?").get(project_id);
333553
+ if (!project || !project.path) {
333554
+ return {
333555
+ isError: true,
333556
+ content: [{ type: "text", text: JSON.stringify({ error: `Project ${project_id} not found or has no path` }, null, 2) }]
333557
+ };
333558
+ }
333559
+ const projectPath = project.path;
333560
+ const targetRels = files && files.length > 0 ? files : detectAgentContextFiles(projectPath);
333561
+ const existingHashes = new Set(
333562
+ db2.prepare("SELECT content_hash FROM files WHERE project_id = ? AND storage_type = 'local' AND content_hash IS NOT NULL").all(project.id).map((r5) => r5.content_hash)
333563
+ );
333564
+ const transferred = [];
333565
+ const skipped = [];
333566
+ for (const rel of targetRels) {
333567
+ let abs2;
333568
+ try {
333569
+ abs2 = assertPathInside(projectPath, rel);
333570
+ } catch {
333571
+ skipped.push({ source_path: rel, reason: "outside_project" });
333572
+ continue;
333573
+ }
333574
+ let stat;
333575
+ try {
333576
+ stat = lstatSync5(abs2);
333577
+ } catch {
333578
+ stat = null;
333579
+ }
333580
+ if (!stat) {
333581
+ skipped.push({ source_path: rel, reason: "missing" });
333582
+ continue;
333583
+ }
333584
+ if (stat.isSymbolicLink()) {
333585
+ skipped.push({ source_path: rel, reason: "symlink" });
333586
+ continue;
333587
+ }
333588
+ if (!stat.isFile()) {
333589
+ skipped.push({ source_path: rel, reason: "missing" });
333590
+ continue;
333591
+ }
333592
+ let content;
333593
+ try {
333594
+ content = readFileSync12(abs2, "utf8");
333595
+ } catch {
333596
+ skipped.push({ source_path: rel, reason: "read_error" });
333597
+ continue;
333598
+ }
333599
+ const hash = createHash3("sha256").update(content, "utf8").digest("hex");
333600
+ if (existingHashes.has(hash)) {
333601
+ skipped.push({ source_path: rel, reason: "already_transferred_same_content" });
333602
+ continue;
333603
+ }
333604
+ const titleSource = rel.replace(/\.[^./]+$/, "");
333605
+ const title = titleSource || rel;
333606
+ try {
333607
+ const created = await createFile({
333608
+ title,
333609
+ content,
333610
+ destination: "kontexta",
333611
+ projectId: project.id,
333612
+ folder: "agent-context",
333613
+ dataDir,
333614
+ sourcePath: abs2
333615
+ });
333616
+ existingHashes.add(hash);
333617
+ transferred.push({
333618
+ source_path: rel,
333619
+ kb_id: created.id,
333620
+ kb_path: created.path,
333621
+ est_tokens: estimateTokensFromBuffer(Buffer.from(content, "utf8"))
333622
+ });
333623
+ } catch (e3) {
333624
+ skipped.push({ source_path: rel, reason: `write_error: ${e3?.message ?? String(e3)}` });
333625
+ }
333626
+ }
333627
+ const next_action = transferred.length > 0 ? `Copied ${transferred.length} file(s) into Kontexta's KB. Originals in your repo are unchanged. To remove them yourself: ${transferred.map((t3) => `rm "${join16(projectPath, t3.source_path)}"`).join(" && ")}` : "No files were transferred. See skipped[] for reasons.";
333628
+ return {
333629
+ content: [{ type: "text", text: JSON.stringify({ transferred, skipped, next_action }, null, 2) }]
333630
+ };
333631
+ } catch (e3) {
333632
+ return {
333633
+ isError: true,
333634
+ content: [{ type: "text", text: JSON.stringify({ error: e3?.message ?? String(e3) }, null, 2) }]
333635
+ };
333636
+ }
333637
+ }
333638
+ );
333491
333639
  server.tool(
333492
333640
  "commit_backup",
333493
333641
  "SIDE-EFFECTFUL \u2014 TOUCHES THE NETWORK. Sync the project's KB data into its git backup directory, create a commit, and `git push` to `origin`. AUTH: relies on the local user's git credentials (SSH agent, credential helper, etc.) \u2014 there is no in-server auth. Kontexta does not rate-limit, but the remote may. Idempotent in steady state: a no-op commit is skipped, but the push still runs. Throws if the project has no configured backup repo or if push fails (network, auth, conflict). Returns `{success, copied_files_count, copied_paths}`. Use after a batch of KB writes to get changes off-machine.",
@@ -333761,7 +333909,7 @@ server.tool(
333761
333909
  );
333762
333910
  function resolveFolderBase(projectId) {
333763
333911
  if (projectId === void 0 || projectId === null) {
333764
- return join17(dataDir, "knowledge");
333912
+ return join16(dataDir, "knowledge");
333765
333913
  }
333766
333914
  const project = getDatabase().prepare("SELECT path FROM projects WHERE id = ?").get(projectId);
333767
333915
  if (!project?.path) {
@@ -333886,7 +334034,7 @@ server.tool(
333886
334034
  if (!project?.path) throw new Error(`Project not found for file ${file_id}`);
333887
334035
  base3 = project.path;
333888
334036
  } else {
333889
- base3 = join17(dataDir, "knowledge");
334037
+ base3 = join16(dataDir, "knowledge");
333890
334038
  }
333891
334039
  let baseResolved;
333892
334040
  try {
@@ -333902,8 +334050,8 @@ server.tool(
333902
334050
  } catch {
333903
334051
  throw new Error(`Destination parent directory does not exist: ${destParent}`);
333904
334052
  }
333905
- const destResolved = join17(destParentReal, destAbs.slice(destParent.length + (destParent.endsWith(sep8) ? 0 : 1)));
333906
- if (destResolved !== baseResolved && !destResolved.startsWith(baseResolved + sep8)) {
334053
+ const destResolved = join16(destParentReal, destAbs.slice(destParent.length + (destParent.endsWith(sep9) ? 0 : 1)));
334054
+ if (destResolved !== baseResolved && !destResolved.startsWith(baseResolved + sep9)) {
333907
334055
  throw new Error(`new_path must be inside ${base3}`);
333908
334056
  }
333909
334057
  let srcResolved;
@@ -333912,7 +334060,7 @@ server.tool(
333912
334060
  } catch {
333913
334061
  srcResolved = resolve7(file.path);
333914
334062
  }
333915
- if (srcResolved !== baseResolved && !srcResolved.startsWith(baseResolved + sep8)) {
334063
+ if (srcResolved !== baseResolved && !srcResolved.startsWith(baseResolved + sep9)) {
333916
334064
  throw new Error(`source path ${file.path} is no longer inside ${base3}; refusing to move`);
333917
334065
  }
333918
334066
  const updated = moveFile(file_id, new_path);
@@ -334607,7 +334755,7 @@ server.tool(
334607
334755
  "Re-scan every registered project's `kontexta.json` and rebuild the live Hands tool registry \u2014 newly-declared tools become callable immediately, removed tools disappear from `tools/list`. SIDE EFFECT is on the running MCP session's tool inventory only (no disk writes). Idempotent. No external auth or rate limits. Takes no parameters. Returns per-project load results (counts of registered/disabled tools and any validation warnings). Use after editing a `kontexta.json` mid-session; for the schema see `describe_hands_schema`.",
334608
334756
  {},
334609
334757
  async () => {
334610
- const projects = listProjects().filter((p) => p.path && existsSync14(p.path)).map((p) => ({ name: p.name, root: p.path }));
334758
+ const projects = listProjects().filter((p) => p.path && existsSync13(p.path)).map((p) => ({ name: p.name, root: p.path }));
334611
334759
  const r5 = handsRegistry.reloadAll(projects);
334612
334760
  return { content: [{ type: "text", text: JSON.stringify(r5, null, 2) }] };
334613
334761
  }
@@ -334638,7 +334786,7 @@ server.tool(
334638
334786
  async function main() {
334639
334787
  const transport = new StdioServerTransport();
334640
334788
  {
334641
- const projects = listProjects().filter((p) => p.path && existsSync14(p.path)).map((p) => ({ name: p.name, root: p.path }));
334789
+ const projects = listProjects().filter((p) => p.path && existsSync13(p.path)).map((p) => ({ name: p.name, root: p.path }));
334642
334790
  const r5 = handsRegistry.reloadAll(projects);
334643
334791
  console.error(
334644
334792
  `Kontexta Hands: loaded ${r5.perProject.length} projects, registered ${r5.totalRegistered} tools (${r5.totalDisabled} disabled)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kontexta-mcp",
3
- "version": "2.0.8",
3
+ "version": "3.0.0",
4
4
  "description": "The local Brain and Hands for AI coding agents (MCP Server)",
5
5
  "keywords": [
6
6
  "mcp",
@@ -38,7 +38,7 @@
38
38
  "./hands/types": "./dist/hands/types.js"
39
39
  },
40
40
  "engines": {
41
- "node": ">=20"
41
+ "node": ">=22"
42
42
  },
43
43
  "files": [
44
44
  "dist",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@modelcontextprotocol/sdk": "^1.12.0",
64
- "better-sqlite3": "^11.7.0",
64
+ "better-sqlite3": "^12.10.0",
65
65
  "chokidar": "^4.0.0",
66
66
  "kxta-core": "workspace:*",
67
67
  "re2": "^1.24.1",
@@ -73,5 +73,5 @@
73
73
  "tsup": "^8.3.0",
74
74
  "typescript": "^5.7.0"
75
75
  },
76
- "rulesVersion": "2.0.0"
76
+ "rulesVersion": "2.1.0"
77
77
  }