@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 +339 -114
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/packs/datacore-starter-v1/engrams.yaml +28 -0
- package/packs/dips-v1/engrams.yaml +4957 -747
- package/packs/fds-principles-v1/engrams.yaml +48 -0
- package/packs/mcp-design-guidelines/SKILL.md +20 -0
- package/packs/mcp-design-guidelines/engrams.yaml +380 -0
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.
|
|
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
|
|
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
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
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
|
|
950
|
-
|
|
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 +=
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
1390
|
+
return path5.basename(filePath, path5.extname(filePath));
|
|
1168
1391
|
}
|
|
1169
1392
|
function extractDate(filePath) {
|
|
1170
|
-
const match =
|
|
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
|
|
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 =
|
|
1189
|
-
fs7.mkdirSync(
|
|
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
|
|
1458
|
+
import * as path8 from "path";
|
|
1236
1459
|
|
|
1237
1460
|
// src/trust.ts
|
|
1238
1461
|
import * as fs8 from "fs";
|
|
1239
|
-
import * as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
1907
|
+
import * as path9 from "path";
|
|
1685
1908
|
function handleDiscover(args2, packsDir) {
|
|
1686
|
-
const bundledDir =
|
|
1687
|
-
|
|
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 =
|
|
1693
|
-
const installed = fs10.existsSync(
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
1766
|
-
if (fs11.existsSync(
|
|
1767
|
-
const existingContent = fs11.readFileSync(
|
|
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(
|
|
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 =
|
|
2016
|
+
const archivePath = path10.join(tmpDir, "pack.tar.gz");
|
|
1794
2017
|
fs11.writeFileSync(archivePath, buffer);
|
|
1795
|
-
const extractDir =
|
|
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(
|
|
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(
|
|
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 =
|
|
1824
|
-
|
|
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(
|
|
2052
|
+
if (fs11.existsSync(path10.join(bundledDir, "SKILL.md"))) {
|
|
1830
2053
|
return { path: bundledDir };
|
|
1831
2054
|
}
|
|
1832
|
-
const localDir =
|
|
1833
|
-
if (fs11.existsSync(
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1972
|
-
const manifestPath =
|
|
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 =
|
|
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 ?
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ?
|
|
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 ??
|
|
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
|
-
|
|
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
|
|
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
|
|
2603
|
+
import * as path17 from "path";
|
|
2380
2604
|
|
|
2381
2605
|
// src/engagement/profile.ts
|
|
2382
2606
|
import * as fs15 from "fs";
|
|
2383
|
-
import * as
|
|
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
|
|
2612
|
+
return path15.join(basePath, ".datacore", PROFILE_DIR);
|
|
2389
2613
|
}
|
|
2390
2614
|
function profilePath(basePath) {
|
|
2391
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
2527
|
-
const actionsPath =
|
|
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 =
|
|
2773
|
-
const engramsPath =
|
|
2774
|
-
const coreEngramsPath =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
4041
|
-
|
|
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);
|