@datacore-one/mcp 1.3.0 → 1.4.1

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
@@ -222,6 +222,12 @@ var ConfigSchema = z.object({
222
222
  engagement: z.object({
223
223
  enabled: z.boolean().default(true),
224
224
  inline_xp: z.boolean().default(false)
225
+ }).default({}),
226
+ injection: z.object({
227
+ directive_cap: z.number().default(10),
228
+ consider_cap: z.number().default(5),
229
+ spread_cap: z.number().default(3),
230
+ spread_budget: z.number().default(480)
225
231
  }).default({})
226
232
  });
227
233
  var cachedConfig = null;
@@ -246,7 +252,7 @@ function getConfig() {
246
252
  // package.json
247
253
  var package_default = {
248
254
  name: "@datacore-one/mcp",
249
- version: "1.3.0",
255
+ version: "1.4.1",
250
256
  description: "Datacore MCP server \u2014 The Software of You",
251
257
  type: "module",
252
258
  bin: {
@@ -259,7 +265,7 @@ var package_default = {
259
265
  test: "vitest run",
260
266
  "test:watch": "vitest",
261
267
  start: "node dist/index.js",
262
- release: `npm test && npm run build && npm version \${VERSION:-patch} && npm publish --access public && npm install -g @datacore-one/mcp@$(node -p 'require("./package.json").version')`
268
+ release: `npm test && npm version \${VERSION:-patch} && npm run build && npm publish --access public && npm install -g @datacore-one/mcp@$(node -p 'require("./package.json").version')`
263
269
  },
264
270
  dependencies: {
265
271
  "@modelcontextprotocol/sdk": "^1.0.0",
@@ -334,7 +340,17 @@ var TOOLS = [
334
340
  scope: z2.string().optional().describe("Scope: global | agent:X | command:X"),
335
341
  tags: z2.array(z2.string()).optional(),
336
342
  domain: z2.string().optional().describe("Dot-notation domain: software.architecture"),
337
- visibility: z2.enum(["private", "public", "template"]).optional()
343
+ visibility: z2.enum(["private", "public", "template"]).optional(),
344
+ knowledge_anchors: z2.array(z2.object({
345
+ path: z2.string().describe("Path to related document (e.g., zettel/Data-Pricing.md)"),
346
+ relevance: z2.enum(["primary", "supporting", "example"]).optional().describe("Anchor relevance level"),
347
+ snippet: z2.string().optional().describe("Short snippet from the document (max 200 chars)"),
348
+ snippet_extracted_at: z2.string().optional().describe("ISO date when snippet was extracted")
349
+ })).optional().describe("Links to related knowledge documents"),
350
+ dual_coding: z2.object({
351
+ example: z2.string().optional().describe("Concrete example illustrating the engram"),
352
+ analogy: z2.string().optional().describe("Analogy to aid understanding")
353
+ }).optional().describe("Dual coding: example and/or analogy for richer encoding")
338
354
  })
339
355
  },
340
356
  {
@@ -343,6 +359,7 @@ var TOOLS = [
343
359
  inputSchema: z2.object({
344
360
  prompt: z2.string().describe("The task or question to match against"),
345
361
  scope: z2.string().optional().describe("Filter by scope: global | agent:X | module:X | command:X"),
362
+ session_id: z2.string().optional().describe("Session ID for co-access tracking (from session.start)"),
346
363
  max_tokens: z2.number().optional().describe("Token budget (default: 8000)"),
347
364
  min_relevance: z2.number().optional().describe("Minimum score threshold (default: 0.3)")
348
365
  })
@@ -434,6 +451,7 @@ var TOOLS = [
434
451
  description: "End a session \u2014 captures journal summary and creates engrams from suggestions. Call before the conversation ends to preserve what was learned.",
435
452
  inputSchema: z2.object({
436
453
  summary: z2.string().describe("Session summary for the journal"),
454
+ session_id: z2.string().optional().describe("Session ID from session.start (for co-access tracking)"),
437
455
  tags: z2.array(z2.string()).optional().describe("Tags for the journal entry"),
438
456
  engram_suggestions: z2.array(z2.object({
439
457
  statement: z2.string().describe("The knowledge assertion"),
@@ -588,6 +606,25 @@ var KnowledgeTypeSchema = z3.object({
588
606
  memory_class: z3.enum(["semantic", "episodic", "procedural", "metacognitive"]),
589
607
  cognitive_level: z3.enum(["remember", "understand", "apply", "analyze", "evaluate", "create"])
590
608
  });
609
+ var KnowledgeAnchorSchema = z3.object({
610
+ path: z3.string(),
611
+ relevance: z3.enum(["primary", "supporting", "example"]).default("supporting"),
612
+ snippet: z3.string().max(200).optional(),
613
+ snippet_extracted_at: z3.string().optional()
614
+ });
615
+ var AssociationSchema = z3.object({
616
+ target_type: z3.enum(["engram", "document"]),
617
+ target: z3.string(),
618
+ strength: z3.number().min(0).max(0.95),
619
+ type: z3.enum(["semantic", "temporal", "causal", "co_accessed"])
620
+ });
621
+ var DualCodingSchema = z3.object({
622
+ example: z3.string().optional(),
623
+ analogy: z3.string().optional()
624
+ }).refine(
625
+ (d) => d.example || d.analogy,
626
+ "At least one of example or analogy must be provided"
627
+ );
591
628
  var RelationsSchema = z3.object({
592
629
  broader: z3.array(z3.string()).default([]),
593
630
  narrower: z3.array(z3.string()).default([]),
@@ -624,6 +661,9 @@ var EngramSchema = z3.object({
624
661
  activation: ActivationSchema,
625
662
  provenance: ProvenanceSchema.optional(),
626
663
  feedback_signals: FeedbackSignalsSchema.optional(),
664
+ knowledge_anchors: z3.array(KnowledgeAnchorSchema).default([]),
665
+ associations: z3.array(AssociationSchema).default([]),
666
+ dual_coding: DualCodingSchema.optional(),
627
667
  tags: z3.array(z3.string()).default([]),
628
668
  pack: z3.string().nullable().default(null),
629
669
  abstract: z3.string().nullable().default(null),
@@ -800,6 +840,14 @@ async function handleLearn(args2, engramsPath, service) {
800
840
  rationale: args2.rationale,
801
841
  derivation_count: 1,
802
842
  domain: args2.domain,
843
+ knowledge_anchors: args2.knowledge_anchors?.map((a) => ({
844
+ path: a.path,
845
+ relevance: a.relevance ?? "supporting",
846
+ snippet: a.snippet,
847
+ snippet_extracted_at: a.snippet_extracted_at
848
+ })) ?? [],
849
+ associations: [],
850
+ dual_coding: args2.dual_coding?.example || args2.dual_coding?.analogy ? args2.dual_coding : void 0,
803
851
  tags: args2.tags ?? [],
804
852
  activation: {
805
853
  retrieval_strength: autoPromote ? 0.7 : 0.5,
@@ -850,6 +898,7 @@ async function handleLearn(args2, engramsPath, service) {
850
898
 
851
899
  // src/tools/inject-tool.ts
852
900
  import * as fs5 from "fs";
901
+ import * as path4 from "path";
853
902
  import * as yaml3 from "js-yaml";
854
903
 
855
904
  // src/decay.ts
@@ -872,38 +921,81 @@ function engramState(retrievalStrength) {
872
921
  // src/inject.ts
873
922
  var DEFAULT_MAX_TOKENS = 8e3;
874
923
  var DEFAULT_MIN_RELEVANCE = 0.3;
875
- var TOKENS_PER_ENGRAM = 40;
876
924
  var MAX_PER_PACK = 5;
877
925
  var MAX_PER_DOMAIN = 10;
878
- function selectEngrams(ctx, personalEngrams, packs) {
879
- const promptLower = ctx.prompt.toLowerCase();
880
- const promptWords = new Set(promptLower.split(/\W+/).filter((w) => w.length > 2));
881
- const scored = [];
882
- for (const engram of personalEngrams) {
883
- if (engram.status !== "active") continue;
884
- const score = scoreEngram(engram, promptLower, promptWords, [], ctx.scope, false);
885
- if (score > 0) scored.push({ engram, score });
886
- }
887
- for (const pack of packs) {
888
- if (pack.manifest["x-datacore"].injection_policy === "on_request") continue;
889
- const matchTerms = pack.manifest["x-datacore"].match_terms;
890
- for (const engram of pack.engrams) {
891
- if (engram.status !== "active") continue;
892
- const score = scoreEngram(engram, promptLower, promptWords, matchTerms, ctx.scope, true);
893
- if (score > 0) scored.push({ engram, score });
926
+ var DIP19_CONSIDER_MAX = 5;
927
+ var DIP19_CONSIDER_BUDGET = 200;
928
+ var RELEVANCE_RANK = { primary: 0, supporting: 1, example: 2 };
929
+ function estimateTokens(engram) {
930
+ const { keyword_match: _km, raw_score: _rs, score: _s, associations: _a, ...wire } = engram;
931
+ const serialized = JSON.stringify(wire);
932
+ return Math.ceil(serialized.length / 4);
933
+ }
934
+ function tokenize(text) {
935
+ return new Set(text.toLowerCase().split(/\W+/).filter((w) => w.length > 2));
936
+ }
937
+ function anchorBoost(engram, taskWords) {
938
+ if (!engram.knowledge_anchors?.length) return 0;
939
+ const threshold = taskWords.size <= 1 ? 1 : 2;
940
+ let boost = 0;
941
+ for (const anchor of engram.knowledge_anchors) {
942
+ if (!anchor.snippet) continue;
943
+ const snippetWords = tokenize(anchor.snippet);
944
+ let overlap = 0;
945
+ for (const word of taskWords) {
946
+ if (snippetWords.has(word)) overlap++;
894
947
  }
948
+ if (overlap >= threshold) boost += 0.5;
895
949
  }
896
- const maxTokens = ctx.maxTokens ?? DEFAULT_MAX_TOKENS;
897
- const minRelevance = ctx.minRelevance ?? DEFAULT_MIN_RELEVANCE;
898
- const passing = scored.filter((s) => s.score >= minRelevance);
899
- passing.sort((a, b) => b.score - a.score);
900
- const selected = fillTokenBudget(passing, maxTokens);
901
- const splitPoint = Math.ceil(selected.length * 2 / 3);
902
- return {
903
- directives: selected.slice(0, splitPoint),
904
- consider: selected.slice(splitPoint),
905
- tokens_used: selected.length * TOKENS_PER_ENGRAM
950
+ return Math.min(boost, 2);
951
+ }
952
+ function flattenRelations(engram) {
953
+ if (!engram.relations) return [];
954
+ const associations = [];
955
+ for (const id of engram.relations.broader) {
956
+ associations.push({ target_type: "engram", target: id, type: "semantic", strength: 0.5 });
957
+ }
958
+ for (const id of engram.relations.narrower) {
959
+ associations.push({ target_type: "engram", target: id, type: "semantic", strength: 0.5 });
960
+ }
961
+ for (const id of engram.relations.related) {
962
+ associations.push({ target_type: "engram", target: id, type: "semantic", strength: 0.5 });
963
+ }
964
+ return associations;
965
+ }
966
+ function stripAssociations(engram) {
967
+ const { associations: _, ...rest } = engram;
968
+ return rest;
969
+ }
970
+ function stripScoring(engram) {
971
+ const { keyword_match: _, raw_score: _r, score: _s, ...rest } = engram;
972
+ return rest;
973
+ }
974
+ function aggregateAnchors(directives, consider) {
975
+ const seen = /* @__PURE__ */ new Map();
976
+ const processPool = (pool) => {
977
+ for (const engram of pool) {
978
+ if (!engram.knowledge_anchors?.length) continue;
979
+ for (const anchor of engram.knowledge_anchors) {
980
+ const existing = seen.get(anchor.path);
981
+ const rank = RELEVANCE_RANK[anchor.relevance] ?? 2;
982
+ const existingRank = existing ? RELEVANCE_RANK[existing.anchor.relevance] ?? 2 : Infinity;
983
+ if (!existing || rank < existingRank || rank === existingRank && engram.score > existing.engramScore) {
984
+ seen.set(anchor.path, { anchor, engramScore: engram.score });
985
+ }
986
+ }
987
+ }
906
988
  };
989
+ processPool(directives);
990
+ processPool(consider);
991
+ const entries = Array.from(seen.values());
992
+ entries.sort((a, b) => {
993
+ const rankA = RELEVANCE_RANK[a.anchor.relevance] ?? 2;
994
+ const rankB = RELEVANCE_RANK[b.anchor.relevance] ?? 2;
995
+ if (rankA !== rankB) return rankA - rankB;
996
+ return b.engramScore - a.engramScore;
997
+ });
998
+ return entries.slice(0, 10).map((e) => e.anchor);
907
999
  }
908
1000
  function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilter, isPack) {
909
1001
  if (scopeFilter) {
@@ -946,8 +1038,9 @@ function fillTokenBudget(scored, maxTokens) {
946
1038
  const packCounts = /* @__PURE__ */ new Map();
947
1039
  const domainCounts = /* @__PURE__ */ new Map();
948
1040
  let tokensUsed = 0;
949
- for (const { engram } of scored) {
950
- if (tokensUsed + TOKENS_PER_ENGRAM > maxTokens) break;
1041
+ for (const engram of scored) {
1042
+ const cost = estimateTokens(engram);
1043
+ if (tokensUsed + cost > maxTokens) continue;
951
1044
  const pack = engram.pack ?? "__personal__";
952
1045
  const packCount = packCounts.get(pack) ?? 0;
953
1046
  if (packCount >= MAX_PER_PACK && pack !== "__personal__") continue;
@@ -956,11 +1049,120 @@ function fillTokenBudget(scored, maxTokens) {
956
1049
  const domainCount = domainCounts.get(topDomain) ?? 0;
957
1050
  if (domainCount >= MAX_PER_DOMAIN) continue;
958
1051
  result.push(engram);
959
- tokensUsed += TOKENS_PER_ENGRAM;
1052
+ tokensUsed += cost;
960
1053
  packCounts.set(pack, packCount + 1);
961
1054
  domainCounts.set(topDomain, domainCount + 1);
962
1055
  }
963
- return result;
1056
+ return { selected: result, tokens_used: tokensUsed };
1057
+ }
1058
+ function selectAndSpread(ctx, personalEngrams, packs) {
1059
+ const config = getConfig();
1060
+ const spreadCap = config.injection?.spread_cap ?? 3;
1061
+ const spreadBudget = config.injection?.spread_budget ?? 480;
1062
+ const promptLower = ctx.prompt.toLowerCase();
1063
+ const promptWords = new Set(promptLower.split(/\W+/).filter((w) => w.length > 2));
1064
+ const maxTokens = ctx.maxTokens ?? DEFAULT_MAX_TOKENS;
1065
+ const minRelevance = ctx.minRelevance ?? DEFAULT_MIN_RELEVANCE;
1066
+ const engramMap = /* @__PURE__ */ new Map();
1067
+ const scored = [];
1068
+ for (const engram of personalEngrams) {
1069
+ if (engram.status !== "active") continue;
1070
+ engramMap.set(engram.id, engram);
1071
+ const raw = scoreEngram(engram, promptLower, promptWords, [], ctx.scope, false);
1072
+ if (raw > 0) {
1073
+ scored.push({ ...engram, keyword_match: raw, raw_score: raw, score: raw });
1074
+ }
1075
+ }
1076
+ for (const pack of packs) {
1077
+ if (pack.manifest["x-datacore"].injection_policy === "on_request") continue;
1078
+ const matchTerms = pack.manifest["x-datacore"].match_terms;
1079
+ for (const engram of pack.engrams) {
1080
+ if (engram.status !== "active") continue;
1081
+ engramMap.set(engram.id, engram);
1082
+ const raw = scoreEngram(engram, promptLower, promptWords, matchTerms, ctx.scope, true);
1083
+ if (raw > 0) {
1084
+ scored.push({ ...engram, keyword_match: raw, raw_score: raw, score: raw });
1085
+ }
1086
+ }
1087
+ }
1088
+ const filtered = scored.filter((s) => s.score >= minRelevance);
1089
+ const maxKm = Math.max(...filtered.map((e) => e.keyword_match), 1);
1090
+ for (const e of filtered) {
1091
+ e.keyword_match = e.keyword_match / maxKm * 10;
1092
+ }
1093
+ for (const e of filtered) {
1094
+ const aBoost = anchorBoost(e, promptWords);
1095
+ e.score = e.keyword_match + aBoost;
1096
+ }
1097
+ filtered.sort((a, b) => b.score - a.score);
1098
+ const { selected: directives, tokens_used: directiveTokens } = fillTokenBudget(filtered, maxTokens);
1099
+ const directiveIds = new Set(directives.map((e) => e.id));
1100
+ const directivePackCounts = /* @__PURE__ */ new Map();
1101
+ for (const e of directives) {
1102
+ const pack = e.pack ?? "__personal__";
1103
+ directivePackCounts.set(pack, (directivePackCounts.get(pack) ?? 0) + 1);
1104
+ }
1105
+ const dip19Remainder = filtered.filter((e) => {
1106
+ if (directiveIds.has(e.id)) return false;
1107
+ const pack = e.pack ?? "__personal__";
1108
+ if (pack !== "__personal__" && (directivePackCounts.get(pack) ?? 0) >= MAX_PER_PACK) return false;
1109
+ return true;
1110
+ });
1111
+ const { selected: dip19Consider } = fillTokenBudget(
1112
+ dip19Remainder,
1113
+ DIP19_CONSIDER_BUDGET
1114
+ );
1115
+ const dip19Pool = dip19Consider.slice(0, DIP19_CONSIDER_MAX);
1116
+ const dip19PoolTokens = dip19Pool.reduce((acc, e) => acc + estimateTokens(e), 0);
1117
+ if (directives.length === 0 && dip19Pool.length === 0) {
1118
+ return {
1119
+ directives: [],
1120
+ consider: [],
1121
+ related_documents: [],
1122
+ tokens_used: { directives: 0, consider: 0 }
1123
+ };
1124
+ }
1125
+ const maxFirstPass = Math.max(...directives.map((e) => e.score), 1);
1126
+ const visited = new Set(directives.map((e) => e.id));
1127
+ for (const e of dip19Pool) visited.add(e.id);
1128
+ const spreadCandidates = [];
1129
+ let spreadTokens = 0;
1130
+ for (const directive of directives) {
1131
+ const assocs = directive.associations?.length ? directive.associations : flattenRelations(directive);
1132
+ for (const assoc of assocs) {
1133
+ if (assoc.target_type !== "engram") continue;
1134
+ if (visited.has(assoc.target)) continue;
1135
+ const target = engramMap.get(assoc.target);
1136
+ if (!target || target.status !== "active") continue;
1137
+ const spreadScore = directive.score / maxFirstPass * assoc.strength;
1138
+ if (spreadScore < minRelevance * 0.5) continue;
1139
+ const spreadEngram = {
1140
+ ...target,
1141
+ keyword_match: 0,
1142
+ raw_score: 0,
1143
+ score: spreadScore
1144
+ };
1145
+ const cost = estimateTokens(spreadEngram);
1146
+ if (spreadTokens + cost > spreadBudget) continue;
1147
+ if (spreadCandidates.length >= spreadCap) break;
1148
+ spreadCandidates.push(spreadEngram);
1149
+ spreadTokens += cost;
1150
+ visited.add(assoc.target);
1151
+ }
1152
+ }
1153
+ const allConsider = [...dip19Pool, ...spreadCandidates];
1154
+ const agentDirectives = directives.map(stripAssociations);
1155
+ const agentConsider = allConsider.map(stripAssociations);
1156
+ const relatedDocs = aggregateAnchors(agentDirectives, agentConsider);
1157
+ const wireDirectives = agentDirectives.map(stripScoring);
1158
+ const wireConsider = agentConsider.map(stripScoring);
1159
+ const considerTokens = dip19PoolTokens + spreadTokens;
1160
+ return {
1161
+ directives: wireDirectives,
1162
+ consider: wireConsider,
1163
+ related_documents: relatedDocs,
1164
+ tokens_used: { directives: directiveTokens, consider: considerTokens }
1165
+ };
964
1166
  }
965
1167
 
966
1168
  // src/tools/inject-tool.ts
@@ -970,16 +1172,17 @@ async function handleInject(args2, paths) {
970
1172
  const ctx = {
971
1173
  prompt: args2.prompt,
972
1174
  scope: args2.scope,
1175
+ session_id: args2.session_id,
973
1176
  maxTokens: args2.max_tokens,
974
1177
  minRelevance: args2.min_relevance
975
1178
  };
976
- const result = selectEngrams(ctx, personalEngrams, packs);
1179
+ const result = selectAndSpread(ctx, personalEngrams, packs);
977
1180
  const totalCount = result.directives.length + result.consider.length;
978
1181
  if (totalCount === 0) {
979
1182
  return {
980
1183
  text: "",
981
1184
  count: 0,
982
- tokens_used: 0,
1185
+ tokens_used: { directives: 0, consider: 0 },
983
1186
  _hints: buildHints({
984
1187
  next: "No engrams matched this task. Use datacore.recall to search all sources, or datacore.learn to record new knowledge.",
985
1188
  related: ["datacore.recall", "datacore.learn"]
@@ -999,6 +1202,10 @@ async function handleInject(args2, paths) {
999
1202
  lines.push(formatEngram(e, totalCount));
1000
1203
  }
1001
1204
  }
1205
+ const relatedDocs = paths.basePath ? result.related_documents.filter((doc) => fs5.existsSync(path4.join(paths.basePath, doc.path))) : result.related_documents;
1206
+ if (relatedDocs.length > 0) {
1207
+ lines.push("\n" + formatRelatedDocs(relatedDocs));
1208
+ }
1002
1209
  updateUsageTracking(
1003
1210
  paths.engramsPath,
1004
1211
  personalEngrams,
@@ -1010,6 +1217,7 @@ async function handleInject(args2, paths) {
1010
1217
  text: lines.join("\n"),
1011
1218
  count: totalCount,
1012
1219
  tokens_used: result.tokens_used,
1220
+ related_documents: relatedDocs.length > 0 ? relatedDocs.length : void 0,
1013
1221
  _hints: buildHints({
1014
1222
  next: `After task, call datacore.feedback on helpful/unhelpful engrams.${idsList}`,
1015
1223
  related: ["datacore.feedback", "datacore.session.end"]
@@ -1048,6 +1256,12 @@ function formatEngram(engram, totalCount) {
1048
1256
  if (engram.contraindications?.length) {
1049
1257
  text += `
1050
1258
  Except: ${engram.contraindications.join(", ")}`;
1259
+ }
1260
+ if (engram.dual_coding) {
1261
+ if (engram.dual_coding.example) text += `
1262
+ Example: ${engram.dual_coding.example}`;
1263
+ if (engram.dual_coding.analogy) text += `
1264
+ Analogy: ${engram.dual_coding.analogy}`;
1051
1265
  }
1052
1266
  return text;
1053
1267
  }
@@ -1057,10 +1271,19 @@ function formatEngram(engram, totalCount) {
1057
1271
  }
1058
1272
  return `- ${engram.statement}`;
1059
1273
  }
1274
+ function formatRelatedDocs(docs) {
1275
+ const lines = ["## RELATED DOCUMENTS\n"];
1276
+ for (const doc of docs) {
1277
+ let line = `- [${doc.relevance}] ${doc.path}`;
1278
+ if (doc.snippet) line += ` \u2014 "${doc.snippet}"`;
1279
+ lines.push(line);
1280
+ }
1281
+ return lines.join("\n");
1282
+ }
1060
1283
 
1061
1284
  // src/tools/search.ts
1062
1285
  import * as fs6 from "fs";
1063
- import * as path4 from "path";
1286
+ import * as path5 from "path";
1064
1287
  var CONTENT_CACHE_MAX = 500;
1065
1288
  var contentCache = /* @__PURE__ */ new Map();
1066
1289
  function getCachedContent(filePath) {
@@ -1136,7 +1359,7 @@ function searchDir(dirPath, query) {
1136
1359
  function walkDir(dir) {
1137
1360
  const files = [];
1138
1361
  for (const entry of fs6.readdirSync(dir, { withFileTypes: true })) {
1139
- const fullPath = path4.join(dir, entry.name);
1362
+ const fullPath = path5.join(dir, entry.name);
1140
1363
  if (entry.isDirectory()) files.push(...walkDir(fullPath));
1141
1364
  else files.push(fullPath);
1142
1365
  }
@@ -1164,17 +1387,17 @@ function extractSnippet(content, query) {
1164
1387
  function extractTitle(content, filePath) {
1165
1388
  const match = content.match(/^#\s+(.+)$/m);
1166
1389
  if (match) return match[1].trim();
1167
- return path4.basename(filePath, path4.extname(filePath));
1390
+ return path5.basename(filePath, path5.extname(filePath));
1168
1391
  }
1169
1392
  function extractDate(filePath) {
1170
- const match = path4.basename(filePath).match(/^(\d{4}-\d{2}-\d{2})/);
1393
+ const match = path5.basename(filePath).match(/^(\d{4}-\d{2}-\d{2})/);
1171
1394
  if (match) return match[1];
1172
1395
  return void 0;
1173
1396
  }
1174
1397
 
1175
1398
  // src/tools/ingest.ts
1176
1399
  import * as fs7 from "fs";
1177
- import * as path5 from "path";
1400
+ import * as path6 from "path";
1178
1401
  async function handleIngest(args2, paths) {
1179
1402
  const contentError = validateContent(args2.content);
1180
1403
  if (contentError) return { success: false, error: contentError };
@@ -1185,8 +1408,8 @@ async function handleIngest(args2, paths) {
1185
1408
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
1186
1409
  const slug = (args2.title ?? "ingested").toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50);
1187
1410
  const fileName = `${timestamp}-${slug}.md`;
1188
- const filePath = path5.join(paths.knowledgePath, fileName);
1189
- fs7.mkdirSync(path5.dirname(filePath), { recursive: true });
1411
+ const filePath = path6.join(paths.knowledgePath, fileName);
1412
+ fs7.mkdirSync(path6.dirname(filePath), { recursive: true });
1190
1413
  const frontmatter = `---
1191
1414
  title: "${args2.title ?? "Ingested Note"}"
1192
1415
  created: "${(/* @__PURE__ */ new Date()).toISOString()}"
@@ -1232,18 +1455,18 @@ function extractEngramSuggestions(content) {
1232
1455
 
1233
1456
  // src/tools/status.ts
1234
1457
  import * as fs9 from "fs";
1235
- import * as path7 from "path";
1458
+ import * as path8 from "path";
1236
1459
 
1237
1460
  // src/trust.ts
1238
1461
  import * as fs8 from "fs";
1239
- import * as path6 from "path";
1462
+ import * as path7 from "path";
1240
1463
  import * as crypto from "crypto";
1241
1464
  function computePackChecksum(packDir) {
1242
1465
  const files = ["SKILL.md", "engrams.yaml"];
1243
1466
  const hash = crypto.createHash("sha256");
1244
1467
  let hasContent = false;
1245
1468
  for (const file of files) {
1246
- const filePath = path6.join(packDir, file);
1469
+ const filePath = path7.join(packDir, file);
1247
1470
  if (fs8.existsSync(filePath)) {
1248
1471
  hash.update(fs8.readFileSync(filePath));
1249
1472
  hasContent = true;
@@ -1600,7 +1823,7 @@ async function handleStatus(paths, updateAvailable2, engagementService2) {
1600
1823
  const packIntegrity = [];
1601
1824
  for (const regPack of packs_default.packs) {
1602
1825
  if (!regPack.checksum) continue;
1603
- const packDir = path7.join(paths.packsPath, regPack.id);
1826
+ const packDir = path8.join(paths.packsPath, regPack.id);
1604
1827
  if (!fs9.existsSync(packDir)) continue;
1605
1828
  const result = verifyPackChecksum(packDir, regPack.checksum);
1606
1829
  packIntegrity.push({ name: regPack.id, valid: result.valid });
@@ -1617,7 +1840,7 @@ async function handleStatus(paths, updateAvailable2, engagementService2) {
1617
1840
  recommendations.push(`${candidateCount} candidate engrams awaiting review. Use datacore.promote or enable engrams.auto_promote in config.yaml.`);
1618
1841
  }
1619
1842
  const { date: today } = localDate();
1620
- const todayJournal = path7.join(paths.journalPath, `${today}.md`);
1843
+ const todayJournal = path8.join(paths.journalPath, `${today}.md`);
1621
1844
  if (!fs9.existsSync(todayJournal)) {
1622
1845
  recommendations.push("No journal entry today. Use datacore.capture to start one.");
1623
1846
  }
@@ -1668,7 +1891,7 @@ function countFiles(dir, ext) {
1668
1891
  if (!fs9.existsSync(dir)) return 0;
1669
1892
  let count = 0;
1670
1893
  for (const entry of fs9.readdirSync(dir, { withFileTypes: true })) {
1671
- const fullPath = path7.join(dir, entry.name);
1894
+ const fullPath = path8.join(dir, entry.name);
1672
1895
  if (entry.isDirectory()) count += countFiles(fullPath, ext);
1673
1896
  else if (entry.name.endsWith(ext)) count++;
1674
1897
  }
@@ -1681,26 +1904,26 @@ function countDirs(dir) {
1681
1904
 
1682
1905
  // src/tools/discover.ts
1683
1906
  import * as fs10 from "fs";
1684
- import * as path8 from "path";
1907
+ import * as path9 from "path";
1685
1908
  function handleDiscover(args2, packsDir) {
1686
- const bundledDir = path8.join(
1687
- path8.dirname(new URL(import.meta.url).pathname),
1909
+ const bundledDir = path9.join(
1910
+ path9.dirname(new URL(import.meta.url).pathname),
1688
1911
  "..",
1689
1912
  "packs"
1690
1913
  );
1691
1914
  let packs = packs_default.packs.map((p) => {
1692
- const localDir = path8.join(packsDir, p.id);
1693
- const installed = fs10.existsSync(path8.join(localDir, "SKILL.md"));
1915
+ const localDir = path9.join(packsDir, p.id);
1916
+ const installed = fs10.existsSync(path9.join(localDir, "SKILL.md"));
1694
1917
  let installedVersion;
1695
1918
  if (installed) {
1696
1919
  try {
1697
- const content = fs10.readFileSync(path8.join(localDir, "SKILL.md"), "utf8");
1920
+ const content = fs10.readFileSync(path9.join(localDir, "SKILL.md"), "utf8");
1698
1921
  const match = content.match(/version:\s*["']?([^"'\n]+)/);
1699
1922
  installedVersion = match?.[1];
1700
1923
  } catch {
1701
1924
  }
1702
1925
  }
1703
- const bundled = fs10.existsSync(path8.join(bundledDir, p.id, "SKILL.md"));
1926
+ const bundled = fs10.existsSync(path9.join(bundledDir, p.id, "SKILL.md"));
1704
1927
  return {
1705
1928
  ...p,
1706
1929
  installed,
@@ -1732,7 +1955,7 @@ function handleDiscover(args2, packsDir) {
1732
1955
 
1733
1956
  // src/tools/install.ts
1734
1957
  import * as fs11 from "fs";
1735
- import * as path9 from "path";
1958
+ import * as path10 from "path";
1736
1959
  import * as yaml4 from "js-yaml";
1737
1960
  import * as os2 from "os";
1738
1961
  import { execSync } from "child_process";
@@ -1747,7 +1970,7 @@ async function handleInstall(args2, packsDir) {
1747
1970
  if (resolved.error) return { success: false, error: resolved.error };
1748
1971
  srcDir = resolved.path;
1749
1972
  }
1750
- const skillPath = path9.join(srcDir, "SKILL.md");
1973
+ const skillPath = path10.join(srcDir, "SKILL.md");
1751
1974
  if (!fs11.existsSync(skillPath)) {
1752
1975
  return { success: false, error: "No SKILL.md found in source directory" };
1753
1976
  }
@@ -1762,9 +1985,9 @@ async function handleInstall(args2, packsDir) {
1762
1985
  if (!packId) {
1763
1986
  return { success: false, error: "Missing x-datacore.id in SKILL.md frontmatter" };
1764
1987
  }
1765
- const destDir = path9.join(packsDir, packId);
1766
- if (fs11.existsSync(path9.join(destDir, "SKILL.md"))) {
1767
- const existingContent = fs11.readFileSync(path9.join(destDir, "SKILL.md"), "utf8");
1988
+ const destDir = path10.join(packsDir, packId);
1989
+ if (fs11.existsSync(path10.join(destDir, "SKILL.md"))) {
1990
+ const existingContent = fs11.readFileSync(path10.join(destDir, "SKILL.md"), "utf8");
1768
1991
  const existingMatch = existingContent.match(/version:\s*["']?([^"'\n]+)/);
1769
1992
  const existingVersion = existingMatch?.[1];
1770
1993
  if (existingVersion === newVersion) {
@@ -1785,14 +2008,14 @@ function verifyInstalledChecksum(packId, destDir) {
1785
2008
  return result.valid;
1786
2009
  }
1787
2010
  async function downloadPack(url) {
1788
- const tmpDir = fs11.mkdtempSync(path9.join(os2.tmpdir(), "datacore-pack-"));
2011
+ const tmpDir = fs11.mkdtempSync(path10.join(os2.tmpdir(), "datacore-pack-"));
1789
2012
  try {
1790
2013
  const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
1791
2014
  if (!res.ok) return { error: `Download failed: HTTP ${res.status}` };
1792
2015
  const buffer = Buffer.from(await res.arrayBuffer());
1793
- const archivePath = path9.join(tmpDir, "pack.tar.gz");
2016
+ const archivePath = path10.join(tmpDir, "pack.tar.gz");
1794
2017
  fs11.writeFileSync(archivePath, buffer);
1795
- const extractDir = path9.join(tmpDir, "extracted");
2018
+ const extractDir = path10.join(tmpDir, "extracted");
1796
2019
  fs11.mkdirSync(extractDir);
1797
2020
  execSync(`tar xzf ${JSON.stringify(archivePath)} -C ${JSON.stringify(extractDir)}`, { timeout: 1e4 });
1798
2021
  const packRoot = findPackRoot(extractDir);
@@ -1803,10 +2026,10 @@ async function downloadPack(url) {
1803
2026
  }
1804
2027
  }
1805
2028
  function findPackRoot(dir) {
1806
- if (fs11.existsSync(path9.join(dir, "SKILL.md"))) return dir;
2029
+ if (fs11.existsSync(path10.join(dir, "SKILL.md"))) return dir;
1807
2030
  for (const entry of fs11.readdirSync(dir, { withFileTypes: true })) {
1808
2031
  if (entry.isDirectory()) {
1809
- const found = findPackRoot(path9.join(dir, entry.name));
2032
+ const found = findPackRoot(path10.join(dir, entry.name));
1810
2033
  if (found) return found;
1811
2034
  }
1812
2035
  }
@@ -1820,17 +2043,17 @@ function resolvePackId(packId, packsDir) {
1820
2043
  if (registryPack.download_url) {
1821
2044
  return { error: `Pack "${packId}" must be installed via URL: ${registryPack.download_url}` };
1822
2045
  }
1823
- const bundledDir = path9.join(
1824
- path9.dirname(new URL(import.meta.url).pathname),
2046
+ const bundledDir = path10.join(
2047
+ path10.dirname(new URL(import.meta.url).pathname),
1825
2048
  "..",
1826
2049
  "packs",
1827
2050
  packId
1828
2051
  );
1829
- if (fs11.existsSync(path9.join(bundledDir, "SKILL.md"))) {
2052
+ if (fs11.existsSync(path10.join(bundledDir, "SKILL.md"))) {
1830
2053
  return { path: bundledDir };
1831
2054
  }
1832
- const localDir = path9.join(packsDir, packId);
1833
- if (fs11.existsSync(path9.join(localDir, "SKILL.md"))) {
2055
+ const localDir = path10.join(packsDir, packId);
2056
+ if (fs11.existsSync(path10.join(localDir, "SKILL.md"))) {
1834
2057
  return { path: localDir };
1835
2058
  }
1836
2059
  return { error: `Pack "${packId}" is registered but not available locally. It may need to be downloaded manually.` };
@@ -1838,7 +2061,7 @@ function resolvePackId(packId, packsDir) {
1838
2061
 
1839
2062
  // src/tools/export.ts
1840
2063
  import * as fs12 from "fs";
1841
- import * as path10 from "path";
2064
+ import * as path11 from "path";
1842
2065
  import * as yaml5 from "js-yaml";
1843
2066
  async function handleExport(args2, paths, service) {
1844
2067
  const allEngrams = loadEngrams(paths.engramsPath);
@@ -1871,7 +2094,7 @@ async function handleExport(args2, paths, service) {
1871
2094
  return { success: false, error: "No engrams match the filter criteria" };
1872
2095
  }
1873
2096
  const packId = args2.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50);
1874
- const packDir = path10.join(paths.packsPath, packId);
2097
+ const packDir = path11.join(paths.packsPath, packId);
1875
2098
  if (!args2.confirm) {
1876
2099
  return {
1877
2100
  success: true,
@@ -1907,7 +2130,7 @@ ${args2.description}
1907
2130
 
1908
2131
  Exported ${selected.length} engrams.
1909
2132
  `;
1910
- fs12.writeFileSync(path10.join(packDir, "SKILL.md"), skillContent);
2133
+ fs12.writeFileSync(path11.join(packDir, "SKILL.md"), skillContent);
1911
2134
  const exportEngrams = selected.map((e) => ({
1912
2135
  id: e.id,
1913
2136
  version: e.version,
@@ -1929,7 +2152,7 @@ Exported ${selected.length} engrams.
1929
2152
  feedback_signals: { positive: 0, negative: 0 }
1930
2153
  }));
1931
2154
  fs12.writeFileSync(
1932
- path10.join(packDir, "engrams.yaml"),
2155
+ path11.join(packDir, "engrams.yaml"),
1933
2156
  yaml5.dump({ engrams: exportEngrams }, { lineWidth: 120, noRefs: true, quotingType: '"' })
1934
2157
  );
1935
2158
  if (service?.isEnabled() && selected.length >= 5) {
@@ -1943,18 +2166,18 @@ Exported ${selected.length} engrams.
1943
2166
 
1944
2167
  // src/modules.ts
1945
2168
  import * as fs13 from "fs";
1946
- import * as path11 from "path";
2169
+ import * as path12 from "path";
1947
2170
  import * as yaml6 from "js-yaml";
1948
2171
  function discoverModules(storage2) {
1949
2172
  const modules = [];
1950
2173
  if (storage2.mode !== "full") return modules;
1951
- const globalModulesDir = path11.join(storage2.basePath, ".datacore", "modules");
2174
+ const globalModulesDir = path12.join(storage2.basePath, ".datacore", "modules");
1952
2175
  modules.push(...scanModulesDir(globalModulesDir, "global"));
1953
2176
  try {
1954
2177
  const entries = fs13.readdirSync(storage2.basePath);
1955
2178
  for (const entry of entries) {
1956
2179
  if (/^\d+-/.test(entry)) {
1957
- const spaceModulesDir = path11.join(storage2.basePath, entry, ".datacore", "modules");
2180
+ const spaceModulesDir = path12.join(storage2.basePath, entry, ".datacore", "modules");
1958
2181
  modules.push(...scanModulesDir(spaceModulesDir, "space", entry));
1959
2182
  }
1960
2183
  }
@@ -1968,8 +2191,8 @@ function scanModulesDir(modulesDir, scope, spaceName) {
1968
2191
  try {
1969
2192
  const entries = fs13.readdirSync(modulesDir);
1970
2193
  for (const entry of entries) {
1971
- const modulePath = path11.join(modulesDir, entry);
1972
- const manifestPath = path11.join(modulePath, "module.yaml");
2194
+ const modulePath = path12.join(modulesDir, entry);
2195
+ const manifestPath = path12.join(modulePath, "module.yaml");
1973
2196
  if (!fs13.existsSync(manifestPath)) continue;
1974
2197
  try {
1975
2198
  const raw = fs13.readFileSync(manifestPath, "utf-8");
@@ -1994,12 +2217,12 @@ async function loadModuleTools(modules, storage2) {
1994
2217
  for (const mod of modules) {
1995
2218
  const declaredTools = mod.manifest.provides?.tools;
1996
2219
  if (!declaredTools || declaredTools.length === 0) continue;
1997
- const toolsIndexPath = path11.join(mod.modulePath, "tools", "index.js");
2220
+ const toolsIndexPath = path12.join(mod.modulePath, "tools", "index.js");
1998
2221
  if (!fs13.existsSync(toolsIndexPath)) continue;
1999
2222
  try {
2000
2223
  const toolsModule = await import(toolsIndexPath);
2001
2224
  const moduleTools2 = toolsModule.tools || toolsModule.default?.tools || [];
2002
- const dataPath = mod.scope === "space" && mod.spaceName ? path11.join(storage2.basePath, mod.spaceName, ".datacore", "modules", mod.name, "data") : path11.join(storage2.basePath, "0-personal", ".datacore", "modules", mod.name, "data");
2225
+ const dataPath = mod.scope === "space" && mod.spaceName ? path12.join(storage2.basePath, mod.spaceName, ".datacore", "modules", mod.name, "data") : path12.join(storage2.basePath, "0-personal", ".datacore", "modules", mod.name, "data");
2003
2226
  const context = {
2004
2227
  storage: storage2,
2005
2228
  modulePath: mod.modulePath,
@@ -2096,7 +2319,7 @@ async function handleModulesInfo(args2, storage2, cachedModules) {
2096
2319
 
2097
2320
  // src/tools/modules-health.ts
2098
2321
  import * as fs14 from "fs";
2099
- import * as path12 from "path";
2322
+ import * as path13 from "path";
2100
2323
  async function handleModulesHealth(args2, storage2, cachedModules) {
2101
2324
  const modules = cachedModules ?? discoverModules(storage2);
2102
2325
  if (args2.module) {
@@ -2118,10 +2341,10 @@ async function handleModulesHealth(args2, storage2, cachedModules) {
2118
2341
  async function checkModule(mod, storage2) {
2119
2342
  const issues = [];
2120
2343
  const manifest = mod.manifest;
2121
- if (!fs14.existsSync(path12.join(mod.modulePath, "SKILL.md"))) {
2344
+ if (!fs14.existsSync(path13.join(mod.modulePath, "SKILL.md"))) {
2122
2345
  issues.push("Missing SKILL.md (ecosystem entry point)");
2123
2346
  }
2124
- if (!fs14.existsSync(path12.join(mod.modulePath, "CLAUDE.base.md"))) {
2347
+ if (!fs14.existsSync(path13.join(mod.modulePath, "CLAUDE.base.md"))) {
2125
2348
  issues.push("Missing CLAUDE.base.md (AI context)");
2126
2349
  }
2127
2350
  if (!manifest.manifest_version || manifest.manifest_version < 2) {
@@ -2137,7 +2360,7 @@ async function checkModule(mod, storage2) {
2137
2360
  const provides = manifest.provides;
2138
2361
  const declaredTools = provides?.tools || [];
2139
2362
  if (declaredTools.length > 0) {
2140
- const toolsIndex = path12.join(mod.modulePath, "tools", "index.js");
2363
+ const toolsIndex = path13.join(mod.modulePath, "tools", "index.js");
2141
2364
  if (!fs14.existsSync(toolsIndex)) {
2142
2365
  issues.push(`Declares ${declaredTools.length} tools but tools/index.js not found`);
2143
2366
  } else {
@@ -2157,7 +2380,7 @@ async function checkModule(mod, storage2) {
2157
2380
  const suspectExts = [".db", ".sqlite", ".json"];
2158
2381
  const suspectDirs = ["output", "data", "state"];
2159
2382
  for (const dir of suspectDirs) {
2160
- const fullPath = path12.join(mod.modulePath, dir);
2383
+ const fullPath = path13.join(mod.modulePath, dir);
2161
2384
  if (fs14.existsSync(fullPath) && fs14.statSync(fullPath).isDirectory()) {
2162
2385
  issues.push(`Data dir '${dir}/' found in module code (should be in space data path)`);
2163
2386
  }
@@ -2238,7 +2461,7 @@ async function handleForget(args2, engramsPath, service) {
2238
2461
  }
2239
2462
 
2240
2463
  // src/tools/feedback.ts
2241
- import * as path13 from "path";
2464
+ import * as path14 from "path";
2242
2465
  function findEngram(engramId, engramsPath, packsPath) {
2243
2466
  const personal = loadEngrams(engramsPath);
2244
2467
  const found = personal.find((e) => e.id === engramId);
@@ -2248,14 +2471,14 @@ function findEngram(engramId, engramsPath, packsPath) {
2248
2471
  const packEngram = pack.engrams.find((e) => e.id === engramId);
2249
2472
  if (packEngram) {
2250
2473
  const packId = pack.manifest["x-datacore"]?.id;
2251
- const packEngramsPath = packId ? path13.join(packsPath, packId, "engrams.yaml") : void 0;
2474
+ const packEngramsPath = packId ? path14.join(packsPath, packId, "engrams.yaml") : void 0;
2252
2475
  return { engram: packEngram, source: "pack", packEngrams: pack.engrams, packEngramsPath };
2253
2476
  }
2254
2477
  }
2255
2478
  return null;
2256
2479
  }
2257
2480
  async function handleFeedback(args2, engramsPath, packsPath, service) {
2258
- const pPath = packsPath ?? path13.join(path13.dirname(engramsPath), "packs");
2481
+ const pPath = packsPath ?? path14.join(path14.dirname(engramsPath), "packs");
2259
2482
  if (args2.signals && args2.signals.length > 0) {
2260
2483
  return handleBatchFeedback(args2.signals, engramsPath, pPath, service);
2261
2484
  }
@@ -2323,7 +2546,7 @@ async function handleBatchFeedback(signals, engramsPath, packsPath, service) {
2323
2546
  const packId = pack.manifest["x-datacore"]?.id;
2324
2547
  if (packId) {
2325
2548
  dirtyPackFiles.set(
2326
- path13.join(packsPath, packId, "engrams.yaml"),
2549
+ path14.join(packsPath, packId, "engrams.yaml"),
2327
2550
  pack.engrams
2328
2551
  );
2329
2552
  }
@@ -2372,23 +2595,24 @@ async function handleBatchFeedback(signals, engramsPath, packsPath, service) {
2372
2595
 
2373
2596
  // src/tools/session-start.ts
2374
2597
  import * as fs18 from "fs";
2375
- import * as path17 from "path";
2598
+ import * as path18 from "path";
2599
+ import * as crypto2 from "crypto";
2376
2600
 
2377
2601
  // src/engagement/service.ts
2378
2602
  import * as fs17 from "fs";
2379
- import * as path16 from "path";
2603
+ import * as path17 from "path";
2380
2604
 
2381
2605
  // src/engagement/profile.ts
2382
2606
  import * as fs15 from "fs";
2383
- import * as path14 from "path";
2607
+ import * as path15 from "path";
2384
2608
  import * as yaml7 from "js-yaml";
2385
2609
  var PROFILE_DIR = "engagement";
2386
2610
  var PROFILE_FILE = "profile.yaml";
2387
2611
  function engagementDir(basePath) {
2388
- return path14.join(basePath, ".datacore", PROFILE_DIR);
2612
+ return path15.join(basePath, ".datacore", PROFILE_DIR);
2389
2613
  }
2390
2614
  function profilePath(basePath) {
2391
- return path14.join(engagementDir(basePath), PROFILE_FILE);
2615
+ return path15.join(engagementDir(basePath), PROFILE_FILE);
2392
2616
  }
2393
2617
  function createDefaultProfile() {
2394
2618
  return EngagementProfileSchema.parse({ version: 4 });
@@ -2426,7 +2650,7 @@ function ensureEngagementDir(basePath) {
2426
2650
  if (!fs15.existsSync(dir)) {
2427
2651
  fs15.mkdirSync(dir, { recursive: true });
2428
2652
  }
2429
- const gitignorePath = path14.join(basePath, ".datacore", ".gitignore");
2653
+ const gitignorePath = path15.join(basePath, ".datacore", ".gitignore");
2430
2654
  if (fs15.existsSync(gitignorePath)) {
2431
2655
  const content = fs15.readFileSync(gitignorePath, "utf8");
2432
2656
  if (!content.includes("engagement/profile.yaml")) {
@@ -2437,7 +2661,7 @@ function ensureEngagementDir(basePath) {
2437
2661
 
2438
2662
  // src/engagement/actions.ts
2439
2663
  import * as fs16 from "fs";
2440
- import * as path15 from "path";
2664
+ import * as path16 from "path";
2441
2665
  import * as yaml8 from "js-yaml";
2442
2666
  var BUNDLED_ACTIONS = {
2443
2667
  version: 1,
@@ -2510,7 +2734,7 @@ var BUNDLED_ACTIONS = {
2510
2734
  }
2511
2735
  };
2512
2736
  function loadActions(basePath) {
2513
- const actionsPath = path15.join(basePath, ".datacore", "engagement", "xp-actions.yaml");
2737
+ const actionsPath = path16.join(basePath, ".datacore", "engagement", "xp-actions.yaml");
2514
2738
  if (!fs16.existsSync(actionsPath)) {
2515
2739
  return BUNDLED_ACTIONS;
2516
2740
  }
@@ -2523,8 +2747,8 @@ function loadActions(basePath) {
2523
2747
  }
2524
2748
  }
2525
2749
  function writeDefaultActions(basePath) {
2526
- const dir = path15.join(basePath, ".datacore", "engagement");
2527
- const actionsPath = path15.join(dir, "xp-actions.yaml");
2750
+ const dir = path16.join(basePath, ".datacore", "engagement");
2751
+ const actionsPath = path16.join(dir, "xp-actions.yaml");
2528
2752
  if (fs16.existsSync(actionsPath)) return;
2529
2753
  if (!fs16.existsSync(dir)) {
2530
2754
  fs16.mkdirSync(dir, { recursive: true });
@@ -2769,9 +2993,9 @@ var EngagementService = class {
2769
2993
  async init() {
2770
2994
  if (!this.isEnabled() || this.initialized) return;
2771
2995
  ensureEngagementDir(this.basePath);
2772
- const profilePath2 = path16.join(this.basePath, ".datacore", "engagement", "profile.yaml");
2773
- const engramsPath = path16.join(this.basePath, ".datacore", "learning", "engrams.yaml");
2774
- const coreEngramsPath = path16.join(this.basePath, "engrams.yaml");
2996
+ const profilePath2 = path17.join(this.basePath, ".datacore", "engagement", "profile.yaml");
2997
+ const engramsPath = path17.join(this.basePath, ".datacore", "learning", "engrams.yaml");
2998
+ const coreEngramsPath = path17.join(this.basePath, "engrams.yaml");
2775
2999
  if (!fs17.existsSync(profilePath2)) {
2776
3000
  const actualEngramsPath = fs17.existsSync(engramsPath) ? engramsPath : coreEngramsPath;
2777
3001
  if (fs17.existsSync(actualEngramsPath)) {
@@ -3221,18 +3445,19 @@ function dismissChallenge(profile, challengeId) {
3221
3445
 
3222
3446
  // src/tools/session-start.ts
3223
3447
  async function handleSessionStart(args2, storage2, bridge, engagementService2) {
3448
+ const session_id = crypto2.randomUUID();
3224
3449
  let engrams = null;
3225
3450
  if (args2.task) {
3226
3451
  const injectResult = await handleInject(
3227
- { prompt: args2.task, scope: args2.tags?.length ? `tags:${args2.tags.join(",")}` : void 0 },
3228
- { engramsPath: storage2.engramsPath, packsPath: storage2.packsPath }
3452
+ { prompt: args2.task, session_id, scope: args2.tags?.length ? `tags:${args2.tags.join(",")}` : void 0 },
3453
+ { engramsPath: storage2.engramsPath, packsPath: storage2.packsPath, basePath: storage2.basePath }
3229
3454
  );
3230
3455
  if (injectResult.count > 0) {
3231
3456
  engrams = { text: injectResult.text, count: injectResult.count };
3232
3457
  }
3233
3458
  }
3234
3459
  const { date: today } = localDate();
3235
- const journalFile = path17.join(storage2.journalPath, `${today}.md`);
3460
+ const journalFile = path18.join(storage2.journalPath, `${today}.md`);
3236
3461
  const journal_today = fs18.existsSync(journalFile) ? fs18.readFileSync(journalFile, "utf8") : null;
3237
3462
  const allEngrams = loadEngrams(storage2.engramsPath);
3238
3463
  const pending_candidates = allEngrams.filter((e) => e.status === "candidate").length;
@@ -3324,7 +3549,7 @@ async function handleSessionStart(args2, storage2, bridge, engagementService2) {
3324
3549
  } catch {
3325
3550
  }
3326
3551
  }
3327
- return { engrams, journal_today, pending_candidates, recommendations, guide, engagement, _hints: hints };
3552
+ return { session_id, engrams, journal_today, pending_candidates, recommendations, guide, engagement, _hints: hints };
3328
3553
  }
3329
3554
  var SESSION_GUIDE_FULL = `## Datacore Quick Start
3330
3555
 
@@ -3695,7 +3920,7 @@ import {
3695
3920
  ListResourceTemplatesRequestSchema
3696
3921
  } from "@modelcontextprotocol/sdk/types.js";
3697
3922
  import * as fs19 from "fs";
3698
- import * as path18 from "path";
3923
+ import * as path19 from "path";
3699
3924
  function registerResources(server, storage2) {
3700
3925
  server.setRequestHandler(ListResourcesRequestSchema, async () => ({
3701
3926
  resources: [
@@ -3776,7 +4001,7 @@ function registerResources(server, storage2) {
3776
4001
  const journalMatch = uri.match(/^datacore:\/\/journal\/(.+)$/);
3777
4002
  if (journalMatch) {
3778
4003
  const dateStr = journalMatch[1] === "today" ? localDate().date : journalMatch[1];
3779
- const filePath = path18.join(storage2.journalPath, `${dateStr}.md`);
4004
+ const filePath = path19.join(storage2.journalPath, `${dateStr}.md`);
3780
4005
  if (!fs19.existsSync(filePath)) {
3781
4006
  return { contents: [{ uri, mimeType: "text/markdown", text: `No journal entry for ${dateStr}` }] };
3782
4007
  }
@@ -4027,7 +4252,7 @@ function registerPrompts(server) {
4027
4252
  // src/datacortex.ts
4028
4253
  import { execFile } from "child_process";
4029
4254
  import * as fs20 from "fs";
4030
- import * as path19 from "path";
4255
+ import * as path20 from "path";
4031
4256
  var DatacortexBridge = class {
4032
4257
  pythonPath;
4033
4258
  scriptPath;
@@ -4037,8 +4262,8 @@ var DatacortexBridge = class {
4037
4262
  }
4038
4263
  findBridgeScript(datacorePath) {
4039
4264
  const candidates = [
4040
- path19.join(datacorePath, ".datacore", "modules", "datacortex", "lib", "bridge.py"),
4041
- path19.join(datacorePath, ".datacore", "modules", "datacortex", "bridge.py")
4265
+ path20.join(datacorePath, ".datacore", "modules", "datacortex", "lib", "bridge.py"),
4266
+ path20.join(datacorePath, ".datacore", "modules", "datacortex", "bridge.py")
4042
4267
  ];
4043
4268
  for (const candidate of candidates) {
4044
4269
  if (fs20.existsSync(candidate)) return candidate;
@@ -4171,7 +4396,7 @@ async function routeTool(name, args2) {
4171
4396
  result = await handleLearn(validated, storage.engramsPath, getEngagementService());
4172
4397
  break;
4173
4398
  case "datacore.inject":
4174
- result = await handleInject(validated, { engramsPath: storage.engramsPath, packsPath: storage.packsPath });
4399
+ result = await handleInject(validated, { engramsPath: storage.engramsPath, packsPath: storage.packsPath, basePath: storage.basePath });
4175
4400
  break;
4176
4401
  case "datacore.search":
4177
4402
  result = await handleSearch(validated, { journalPath: storage.journalPath, knowledgePath: storage.knowledgePath }, datacortexBridge);