@datacore-one/mcp 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -237,7 +237,7 @@ function getConfig() {
237
237
  // package.json
238
238
  var package_default = {
239
239
  name: "@datacore-one/mcp",
240
- version: "1.1.0",
240
+ version: "1.1.2",
241
241
  description: "Datacore MCP server \u2014 The Software of You",
242
242
  type: "module",
243
243
  bin: {
@@ -933,7 +933,15 @@ async function handleInject(args2, paths) {
933
933
  const result = selectEngrams(ctx, personalEngrams, packs);
934
934
  const totalCount = result.directives.length + result.consider.length;
935
935
  if (totalCount === 0) {
936
- return { text: "", count: 0, tokens_used: 0 };
936
+ return {
937
+ text: "",
938
+ count: 0,
939
+ tokens_used: 0,
940
+ _hints: buildHints({
941
+ next: "No engrams matched this task. Use datacore.recall to search all sources, or datacore.learn to record new knowledge.",
942
+ related: ["datacore.recall", "datacore.learn"]
943
+ })
944
+ };
937
945
  }
938
946
  const lines = [];
939
947
  if (result.directives.length > 0) {
@@ -1330,6 +1338,11 @@ function countDirs(dir) {
1330
1338
  import * as fs10 from "fs";
1331
1339
  import * as path8 from "path";
1332
1340
  function handleDiscover(args2, packsDir) {
1341
+ const bundledDir = path8.join(
1342
+ path8.dirname(new URL(import.meta.url).pathname),
1343
+ "..",
1344
+ "packs"
1345
+ );
1333
1346
  let packs = packs_default.packs.map((p) => {
1334
1347
  const localDir = path8.join(packsDir, p.id);
1335
1348
  const installed = fs10.existsSync(path8.join(localDir, "SKILL.md"));
@@ -1342,12 +1355,13 @@ function handleDiscover(args2, packsDir) {
1342
1355
  } catch {
1343
1356
  }
1344
1357
  }
1358
+ const bundled = fs10.existsSync(path8.join(bundledDir, p.id, "SKILL.md"));
1345
1359
  return {
1346
1360
  ...p,
1347
1361
  installed,
1348
1362
  installed_version: installedVersion,
1349
1363
  upgradeable: installed && installedVersion !== p.version,
1350
- can_install: !!p.download_url
1364
+ can_install: !!p.download_url || bundled
1351
1365
  };
1352
1366
  });
1353
1367
  if (args2.query) {
@@ -1383,6 +1397,10 @@ async function handleInstall(args2, packsDir) {
1383
1397
  const downloaded = await downloadPack(srcDir);
1384
1398
  if (downloaded.error) return { success: false, error: downloaded.error };
1385
1399
  srcDir = downloaded.path;
1400
+ } else if (!srcDir.includes("/") && !srcDir.includes("\\")) {
1401
+ const resolved = resolvePackId(srcDir, packsDir);
1402
+ if (resolved.error) return { success: false, error: resolved.error };
1403
+ srcDir = resolved.path;
1386
1404
  }
1387
1405
  const skillPath = path9.join(srcDir, "SKILL.md");
1388
1406
  if (!fs11.existsSync(skillPath)) {
@@ -1449,6 +1467,29 @@ function findPackRoot(dir) {
1449
1467
  }
1450
1468
  return null;
1451
1469
  }
1470
+ function resolvePackId(packId, packsDir) {
1471
+ const registryPack = packs_default.packs.find((p) => p.id === packId);
1472
+ if (!registryPack) {
1473
+ return { error: `Pack "${packId}" not found in registry. Use datacore.packs.discover to browse available packs.` };
1474
+ }
1475
+ if (registryPack.download_url) {
1476
+ return { error: `Pack "${packId}" must be installed via URL: ${registryPack.download_url}` };
1477
+ }
1478
+ const bundledDir = path9.join(
1479
+ path9.dirname(new URL(import.meta.url).pathname),
1480
+ "..",
1481
+ "packs",
1482
+ packId
1483
+ );
1484
+ if (fs11.existsSync(path9.join(bundledDir, "SKILL.md"))) {
1485
+ return { path: bundledDir };
1486
+ }
1487
+ const localDir = path9.join(packsDir, packId);
1488
+ if (fs11.existsSync(path9.join(localDir, "SKILL.md"))) {
1489
+ return { path: localDir };
1490
+ }
1491
+ return { error: `Pack "${packId}" is registered but not available locally. It may need to be downloaded manually.` };
1492
+ }
1452
1493
 
1453
1494
  // src/tools/export.ts
1454
1495
  import * as fs12 from "fs";
@@ -1496,6 +1537,12 @@ async function handleExport(args2, paths) {
1496
1537
  }
1497
1538
  };
1498
1539
  }
1540
+ if (fs12.existsSync(packDir)) {
1541
+ return {
1542
+ success: false,
1543
+ error: `Pack directory already exists at ${packDir}. Remove it first or use a different name.`
1544
+ };
1545
+ }
1499
1546
  fs12.mkdirSync(packDir, { recursive: true });
1500
1547
  const skillContent = `---
1501
1548
  name: "${args2.name}"
@@ -1524,6 +1571,7 @@ Exported ${selected.length} engrams.
1524
1571
  visibility: e.visibility,
1525
1572
  statement: e.statement,
1526
1573
  rationale: e.rationale,
1574
+ contraindications: e.contraindications,
1527
1575
  tags: e.tags,
1528
1576
  domain: e.domain,
1529
1577
  status: "active",
@@ -1797,9 +1845,10 @@ async function handleForget(args2, engramsPath) {
1797
1845
  }
1798
1846
  if (args2.search) {
1799
1847
  const searchLower = args2.search.toLowerCase();
1800
- const matches = engrams.filter((e) => e.status !== "retired").filter(
1848
+ const allMatches = engrams.filter((e) => e.status !== "retired").filter(
1801
1849
  (e) => e.statement.toLowerCase().includes(searchLower) || e.id.toLowerCase().includes(searchLower) || e.tags.some((t) => t.toLowerCase().includes(searchLower))
1802
- ).slice(0, 10);
1850
+ );
1851
+ const matches = allMatches.slice(0, 100);
1803
1852
  if (matches.length === 0) {
1804
1853
  return { success: false, error: `No active engrams matching "${args2.search}"` };
1805
1854
  }
@@ -1810,26 +1859,44 @@ async function handleForget(args2, engramsPath) {
1810
1859
  saveEngrams(engramsPath, engrams);
1811
1860
  return { success: true, retired: { id: engram.id, statement: engram.statement } };
1812
1861
  }
1862
+ const truncated = allMatches.length > 100;
1813
1863
  return {
1814
1864
  success: false,
1815
1865
  matches: matches.map((e) => ({ id: e.id, statement: e.statement })),
1816
- error: `Multiple matches found. Specify an exact ID to retire.`
1866
+ total_matches: allMatches.length,
1867
+ error: `${allMatches.length} matches found${truncated ? " (showing first 100)" : ""}. Specify an exact ID to retire.`
1817
1868
  };
1818
1869
  }
1819
1870
  return { success: false, error: "Provide either id or search parameter" };
1820
1871
  }
1821
1872
 
1822
1873
  // src/tools/feedback.ts
1823
- async function handleFeedback(args2, engramsPath) {
1874
+ import * as path13 from "path";
1875
+ function findEngram(engramId, engramsPath, packsPath) {
1876
+ const personal = loadEngrams(engramsPath);
1877
+ const found = personal.find((e) => e.id === engramId);
1878
+ if (found) return { engram: found, source: "personal", personalEngrams: personal };
1879
+ const packs = loadAllPacks(packsPath);
1880
+ for (const pack of packs) {
1881
+ const packEngram = pack.engrams.find((e) => e.id === engramId);
1882
+ if (packEngram) {
1883
+ const packId = pack.manifest["x-datacore"]?.id;
1884
+ const packEngramsPath = packId ? path13.join(packsPath, packId, "engrams.yaml") : void 0;
1885
+ return { engram: packEngram, source: "pack", packEngrams: pack.engrams, packEngramsPath };
1886
+ }
1887
+ }
1888
+ return null;
1889
+ }
1890
+ async function handleFeedback(args2, engramsPath, packsPath) {
1891
+ const pPath = packsPath ?? path13.join(path13.dirname(engramsPath), "packs");
1824
1892
  if (args2.signals && args2.signals.length > 0) {
1825
- return handleBatchFeedback(args2.signals, engramsPath);
1893
+ return handleBatchFeedback(args2.signals, engramsPath, pPath);
1826
1894
  }
1827
- return handleSingleFeedback(args2.engram_id, args2.signal, args2.comment, engramsPath);
1895
+ return handleSingleFeedback(args2.engram_id, args2.signal, args2.comment, engramsPath, pPath);
1828
1896
  }
1829
- async function handleSingleFeedback(engram_id, signal, comment, engramsPath) {
1830
- const engrams = loadEngrams(engramsPath);
1831
- const engram = engrams.find((e) => e.id === engram_id);
1832
- if (!engram) {
1897
+ async function handleSingleFeedback(engram_id, signal, comment, engramsPath, packsPath) {
1898
+ const found = findEngram(engram_id, engramsPath, packsPath);
1899
+ if (!found) {
1833
1900
  return {
1834
1901
  mode: "single",
1835
1902
  success: false,
@@ -1843,29 +1910,55 @@ async function handleSingleFeedback(engram_id, signal, comment, engramsPath) {
1843
1910
  };
1844
1911
  }
1845
1912
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1846
- if (!engram.feedback_signals) {
1847
- engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
1913
+ if (!found.engram.feedback_signals) {
1914
+ found.engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
1915
+ }
1916
+ found.engram.feedback_signals[signal] += 1;
1917
+ found.engram.activation.last_accessed = today;
1918
+ if (found.source === "personal" && found.personalEngrams) {
1919
+ atomicWriteYaml(engramsPath, { engrams: found.personalEngrams });
1920
+ } else if (found.source === "pack" && found.packEngrams && found.packEngramsPath) {
1921
+ atomicWriteYaml(found.packEngramsPath, { engrams: found.packEngrams });
1848
1922
  }
1849
- engram.feedback_signals[signal] += 1;
1850
- engram.activation.last_accessed = today;
1851
- atomicWriteYaml(engramsPath, { engrams });
1852
1923
  return {
1853
1924
  mode: "single",
1854
1925
  success: true,
1855
1926
  engram_id,
1856
1927
  signal,
1857
- feedback_signals: { ...engram.feedback_signals }
1928
+ source: found.source,
1929
+ feedback_signals: { ...found.engram.feedback_signals }
1858
1930
  };
1859
1931
  }
1860
- async function handleBatchFeedback(signals, engramsPath) {
1861
- const engrams = loadEngrams(engramsPath);
1932
+ async function handleBatchFeedback(signals, engramsPath, packsPath) {
1862
1933
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1863
1934
  const results = [];
1864
1935
  const summary = { positive: 0, negative: 0, neutral: 0 };
1865
- let changed = false;
1936
+ const personal = loadEngrams(engramsPath);
1937
+ const packs = loadAllPacks(packsPath);
1938
+ let personalDirty = false;
1939
+ const dirtyPackFiles = /* @__PURE__ */ new Map();
1866
1940
  for (const { engram_id, signal } of signals) {
1867
- const engram = engrams.find((e) => e.id === engram_id);
1868
- if (!engram) {
1941
+ let engram = personal.find((e) => e.id === engram_id);
1942
+ let source;
1943
+ if (engram) {
1944
+ source = "personal";
1945
+ } else {
1946
+ for (const pack of packs) {
1947
+ engram = pack.engrams.find((e) => e.id === engram_id);
1948
+ if (engram) {
1949
+ source = "pack";
1950
+ const packId = pack.manifest["x-datacore"]?.id;
1951
+ if (packId) {
1952
+ dirtyPackFiles.set(
1953
+ path13.join(packsPath, packId, "engrams.yaml"),
1954
+ pack.engrams
1955
+ );
1956
+ }
1957
+ break;
1958
+ }
1959
+ }
1960
+ }
1961
+ if (!engram || !source) {
1869
1962
  results.push({ engram_id, signal, success: false, error: `Engram ${engram_id} not found` });
1870
1963
  continue;
1871
1964
  }
@@ -1875,11 +1968,14 @@ async function handleBatchFeedback(signals, engramsPath) {
1875
1968
  engram.feedback_signals[signal] += 1;
1876
1969
  engram.activation.last_accessed = today;
1877
1970
  summary[signal]++;
1878
- changed = true;
1879
- results.push({ engram_id, signal, success: true });
1971
+ if (source === "personal") personalDirty = true;
1972
+ results.push({ engram_id, signal, success: true, source });
1880
1973
  }
1881
- if (changed) {
1882
- atomicWriteYaml(engramsPath, { engrams });
1974
+ if (personalDirty) {
1975
+ atomicWriteYaml(engramsPath, { engrams: personal });
1976
+ }
1977
+ for (const [filePath, engrams] of dirtyPackFiles) {
1978
+ atomicWriteYaml(filePath, { engrams });
1883
1979
  }
1884
1980
  return {
1885
1981
  mode: "batch",
@@ -1894,7 +1990,7 @@ async function handleBatchFeedback(signals, engramsPath) {
1894
1990
 
1895
1991
  // src/tools/session-start.ts
1896
1992
  import * as fs15 from "fs";
1897
- import * as path13 from "path";
1993
+ import * as path14 from "path";
1898
1994
  async function handleSessionStart(args2, storage2, bridge) {
1899
1995
  let engrams = null;
1900
1996
  if (args2.task) {
@@ -1907,7 +2003,7 @@ async function handleSessionStart(args2, storage2, bridge) {
1907
2003
  }
1908
2004
  }
1909
2005
  const { date: today } = localDate();
1910
- const journalFile = path13.join(storage2.journalPath, `${today}.md`);
2006
+ const journalFile = path14.join(storage2.journalPath, `${today}.md`);
1911
2007
  const journal_today = fs15.existsSync(journalFile) ? fs15.readFileSync(journalFile, "utf8") : null;
1912
2008
  const allEngrams = loadEngrams(storage2.engramsPath);
1913
2009
  const pending_candidates = allEngrams.filter((e) => e.status === "candidate").length;
@@ -2114,7 +2210,7 @@ import {
2114
2210
  ListResourceTemplatesRequestSchema
2115
2211
  } from "@modelcontextprotocol/sdk/types.js";
2116
2212
  import * as fs16 from "fs";
2117
- import * as path14 from "path";
2213
+ import * as path15 from "path";
2118
2214
  function registerResources(server, storage2) {
2119
2215
  server.setRequestHandler(ListResourcesRequestSchema, async () => ({
2120
2216
  resources: [
@@ -2195,7 +2291,7 @@ function registerResources(server, storage2) {
2195
2291
  const journalMatch = uri.match(/^datacore:\/\/journal\/(.+)$/);
2196
2292
  if (journalMatch) {
2197
2293
  const dateStr = journalMatch[1] === "today" ? localDate().date : journalMatch[1];
2198
- const filePath = path14.join(storage2.journalPath, `${dateStr}.md`);
2294
+ const filePath = path15.join(storage2.journalPath, `${dateStr}.md`);
2199
2295
  if (!fs16.existsSync(filePath)) {
2200
2296
  return { contents: [{ uri, mimeType: "text/markdown", text: `No journal entry for ${dateStr}` }] };
2201
2297
  }
@@ -2431,7 +2527,7 @@ function registerPrompts(server) {
2431
2527
  // src/datacortex.ts
2432
2528
  import { execFile } from "child_process";
2433
2529
  import * as fs17 from "fs";
2434
- import * as path15 from "path";
2530
+ import * as path16 from "path";
2435
2531
  var DatacortexBridge = class {
2436
2532
  pythonPath;
2437
2533
  scriptPath;
@@ -2441,8 +2537,8 @@ var DatacortexBridge = class {
2441
2537
  }
2442
2538
  findBridgeScript(datacorePath) {
2443
2539
  const candidates = [
2444
- path15.join(datacorePath, ".datacore", "modules", "datacortex", "lib", "bridge.py"),
2445
- path15.join(datacorePath, ".datacore", "modules", "datacortex", "bridge.py")
2540
+ path16.join(datacorePath, ".datacore", "modules", "datacortex", "lib", "bridge.py"),
2541
+ path16.join(datacorePath, ".datacore", "modules", "datacortex", "bridge.py")
2446
2542
  ];
2447
2543
  for (const candidate of candidates) {
2448
2544
  if (fs17.existsSync(candidate)) return candidate;
@@ -2579,7 +2675,7 @@ async function routeTool(name, args2) {
2579
2675
  result = await handleForget(validated, storage.engramsPath);
2580
2676
  break;
2581
2677
  case "datacore.feedback":
2582
- result = await handleFeedback(validated, storage.engramsPath);
2678
+ result = await handleFeedback(validated, storage.engramsPath, storage.packsPath);
2583
2679
  break;
2584
2680
  case "datacore.session.start":
2585
2681
  result = await handleSessionStart(validated, storage, datacortexBridge);