@kaddo/mcp 3.129.0 → 3.129.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +149 -134
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25921,101 +25921,97 @@ function relFromDir(dir, filePath) {
25921
25921
  function sha256(content) {
25922
25922
  return createHash3("sha256").update(content, "utf-8").digest("hex");
25923
25923
  }
25924
- var GENERIC_HEADINGS = /* @__PURE__ */ new Set([
25925
- "purpose",
25926
- "proposito",
25927
- "prop\xF3sito",
25928
- "intent",
25929
- "goal",
25930
- "objetivo",
25931
- "summary",
25932
- "resumen",
25933
- "overview",
25934
- "context",
25935
- "contexto",
25936
- "scope",
25937
- "alcance",
25938
- "out of scope",
25939
- "fuera de alcance",
25940
- "acceptance criteria",
25941
- "criterios de aceptacion",
25942
- "criterios de aceptaci\xF3n",
25943
- "validation",
25944
- "validation scenarios",
25945
- "validacion",
25946
- "validaci\xF3n",
25947
- "escenarios de validacion",
25948
- "escenarios de validaci\xF3n",
25949
- "notes",
25950
- "notas",
25951
- "references",
25952
- "referencias",
25953
- "examples",
25954
- "ejemplos",
25955
- "learning",
25956
- "learnings",
25957
- "aprendizaje",
25958
- "aprendizajes",
25959
- // Work Item template sections
25960
- "problem",
25961
- "problema",
25962
- "expected result",
25963
- "resultado esperado",
25964
- "refinement",
25965
- "refinamiento",
25966
- "implementation guidance",
25967
- "guia de implementacion",
25968
- "gu\xEDa de implementaci\xF3n",
25969
- "definition of done",
25970
- "definicion de hecho",
25971
- "definici\xF3n de hecho",
25972
- "commit gate",
25973
- "future evolution",
25974
- "evolucion futura",
25975
- "evoluci\xF3n futura",
25976
- "guiding principle",
25977
- "principio rector",
25978
- "open questions",
25979
- "preguntas abiertas",
25980
- "dependencies",
25981
- "dependencias",
25982
- "conceptual model",
25983
- "goal"
25984
- ]);
25985
- var RULE_KEYWORDS = [
25986
- "siempre",
25987
- "nunca",
25988
- "debe",
25989
- "deben",
25990
- "requiere",
25991
- "requieren",
25992
- "invariante",
25993
- "restriccion",
25994
- "restricci\xF3n",
25995
- "regla",
25996
- "obligatorio",
25997
- "must",
25998
- "always",
25999
- "never",
26000
- "require",
26001
- "requires",
26002
- "constraint",
26003
- "invariant",
26004
- "rule"
26005
- ];
26006
- function normalizeHeading(h2) {
26007
- return h2.trim().toLowerCase().replace(/\s+/g, " ");
25924
+ var SHINGLE_SIZE = 6;
25925
+ var MIN_SHARED_RUN = 6;
25926
+ function stripNoise(text3) {
25927
+ return text3.replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/https?:\/\/\S+|www\.\S+/gi, " ");
26008
25928
  }
26009
- function distinctiveHeadings(body) {
26010
- const out = [];
26011
- for (const line of body.split(/\r?\n/)) {
26012
- const m2 = line.match(/^#{2,3}\s+(.+?)\s*$/);
26013
- if (!m2) continue;
26014
- const norm = normalizeHeading(m2[1]);
26015
- if (!norm || GENERIC_HEADINGS.has(norm)) continue;
26016
- out.push(norm);
25929
+ function contentBlocks(body) {
25930
+ const blocks = [];
25931
+ let cur = [];
25932
+ let inFence = false;
25933
+ const flush = () => {
25934
+ if (cur.length) blocks.push(cur);
25935
+ cur = [];
25936
+ };
25937
+ for (const raw of body.split(/\r?\n/)) {
25938
+ const t = raw.trim();
25939
+ if (/^```/.test(t)) {
25940
+ inFence = !inFence;
25941
+ flush();
25942
+ continue;
25943
+ }
25944
+ if (inFence) continue;
25945
+ if (t === "" || /^#{1,6}\s/.test(t) || /^>/.test(t)) {
25946
+ flush();
25947
+ continue;
25948
+ }
25949
+ const isListItem = /^([-*+]\s+|\d+\.\s+)/.test(t);
25950
+ if (isListItem) flush();
25951
+ const text3 = stripNoise(t.replace(/^([-*+]\s+|\d+\.\s+)/, ""));
25952
+ const matched = text3.toLowerCase().match(/[a-záéíóúñü0-9]+/gi);
25953
+ if (matched) cur.push(...matched);
26017
25954
  }
26018
- return [...new Set(out)];
25955
+ flush();
25956
+ return blocks;
25957
+ }
25958
+ function buildShingles(body) {
25959
+ const blocks = contentBlocks(body);
25960
+ const set = /* @__PURE__ */ new Set();
25961
+ for (const block of blocks) {
25962
+ for (let i = 0; i + SHINGLE_SIZE <= block.length; i++) {
25963
+ set.add(block.slice(i, i + SHINGLE_SIZE).join(" "));
25964
+ }
25965
+ }
25966
+ return { blocks, set };
25967
+ }
25968
+ function longestSharedRun(a2, b2) {
25969
+ let best = 0;
25970
+ let bestSnippet = "";
25971
+ for (const block of a2.blocks) {
25972
+ let run = 0;
25973
+ let runStart = 0;
25974
+ for (let i = 0; i + SHINGLE_SIZE <= block.length; i++) {
25975
+ const key = block.slice(i, i + SHINGLE_SIZE).join(" ");
25976
+ if (b2.set.has(key)) {
25977
+ if (run === 0) runStart = i;
25978
+ run += 1;
25979
+ if (run > best) {
25980
+ best = run;
25981
+ bestSnippet = block.slice(runStart, runStart + SHINGLE_SIZE + run - 1).join(" ");
25982
+ }
25983
+ } else {
25984
+ run = 0;
25985
+ }
25986
+ }
25987
+ }
25988
+ return { length: best, snippet: bestSnippet };
25989
+ }
25990
+ var NORMATIVE_RE = /(^|[^a-záéíóúñü])(must|should|shall|debe[ns]?|deber[ií]a[ns]?|se\s+debe|hay\s+que|requiere[ns]?|require[sd]?|no\s+debe|invariant[e]?|invariants|restricci[oó]n|constraint|regla|obligatori[oa])([^a-záéíóúñü]|$)/i;
25991
+ var PAST_RESULT_RE = /(compil[aoeéó]\w*|compiled|benchmark\w*|passed|succeed\w*|succeeded|ran\s+successfully|ejecut\w*|resultad\w*|crates?\b|ns\/op|µs\b|throughput|latenc\w*|baseline|measured|medid\w*|\d+\s*%|\bx\d|faster|slower)/i;
25992
+ var TEST_RE = /(\btest\w*|\bpruebas?\b|coverage|cobertura|verde[s]?|green\b|assert\w*)/i;
25993
+ var BENCH_RE = /(benchmark\w*|ns\/op|µs\b|throughput|latenc\w*|ops\/s|\d+\s*%|faster|slower|baseline)/i;
25994
+ var EXPERIMENT_RE = /(experiment\w*|experiment[oa]\w*|prototyp\w*|prototip\w*|spike\b|probamos|probé|intentamos)/i;
25995
+ function splitSentences(text3) {
25996
+ return text3.replace(/\s+/g, " ").split(/(?<=[.!?;])\s+/).map((s) => s.trim()).filter(Boolean);
25997
+ }
25998
+ function classifyLearningSentence(sentence) {
25999
+ const s = sentence.trim();
26000
+ if (!s) return "none";
26001
+ const normative = NORMATIVE_RE.test(s);
26002
+ const pastResult = PAST_RESULT_RE.test(s);
26003
+ if (normative && !pastResult) return "durable-rule";
26004
+ if (BENCH_RE.test(s)) return "benchmark-evidence";
26005
+ if (pastResult) return "historical-result";
26006
+ if (TEST_RE.test(s)) return "test-observation";
26007
+ if (EXPERIMENT_RE.test(s)) return "experimental-result";
26008
+ return "none";
26009
+ }
26010
+ function firstRuleFragment(learning) {
26011
+ for (const sentence of splitSentences(learning)) {
26012
+ if (classifyLearningSentence(sentence) === "durable-rule") return sentence;
26013
+ }
26014
+ return null;
26019
26015
  }
26020
26016
  function sectionBody(body, titles) {
26021
26017
  const lines = body.split(/\r?\n/);
@@ -26099,32 +26095,33 @@ function buildConsolidationPlan(dir, opts = {}) {
26099
26095
  requires_semantic_review: false
26100
26096
  });
26101
26097
  }
26102
- const canonical = scoped.filter(
26103
- (la) => la.layer !== null && !isWorkItem(la) && la.artifact.type !== "roadmap"
26104
- );
26105
- const byHeading = /* @__PURE__ */ new Map();
26106
- for (const la of canonical) {
26107
- for (const h2 of distinctiveHeadings(la.body)) {
26108
- const arr = byHeading.get(h2) ?? [];
26098
+ const comparable = scoped.filter(isComparableKnowledge);
26099
+ const shingleIndex = /* @__PURE__ */ new Map();
26100
+ const shinglesByRel = /* @__PURE__ */ new Map();
26101
+ for (const la of comparable) {
26102
+ const shingles = buildShingles(la.body);
26103
+ shinglesByRel.set(la.rel, shingles);
26104
+ for (const key of shingles.set) {
26105
+ const arr = shingleIndex.get(key) ?? [];
26109
26106
  arr.push(la);
26110
- byHeading.set(h2, arr);
26107
+ shingleIndex.set(key, arr);
26111
26108
  }
26112
26109
  }
26113
- const pairHeadings = /* @__PURE__ */ new Map();
26114
- for (const [heading, arts] of byHeading) {
26110
+ const candidatePairs = /* @__PURE__ */ new Map();
26111
+ for (const arts of shingleIndex.values()) {
26115
26112
  if (arts.length < 2) continue;
26116
26113
  for (let i = 0; i < arts.length; i++) {
26117
26114
  for (let j2 = i + 1; j2 < arts.length; j2++) {
26118
26115
  if (arts[i].rel === arts[j2].rel) continue;
26119
26116
  const key = [arts[i].rel, arts[j2].rel].sort().join("||");
26120
- const entry = pairHeadings.get(key) ?? { a: arts[i], b: arts[j2], shared: /* @__PURE__ */ new Set() };
26121
- entry.shared.add(heading);
26122
- pairHeadings.set(key, entry);
26117
+ if (!candidatePairs.has(key)) candidatePairs.set(key, { a: arts[i], b: arts[j2] });
26123
26118
  }
26124
26119
  }
26125
26120
  }
26126
- for (const { a: a2, b: b2, shared } of pairHeadings.values()) {
26127
- if (shared.size < 2) continue;
26121
+ for (const { a: a2, b: b2 } of candidatePairs.values()) {
26122
+ const run = longestSharedRun(shinglesByRel.get(a2.rel), shinglesByRel.get(b2.rel));
26123
+ if (run.length < MIN_SHARED_RUN) continue;
26124
+ const passageWords = SHINGLE_SIZE + run.length - 1;
26128
26125
  opportunities.push({
26129
26126
  id: stableOpportunityId("knowledge_redundancy", [label(a2), label(b2)]),
26130
26127
  category: "knowledge_redundancy",
@@ -26133,18 +26130,22 @@ function buildConsolidationPlan(dir, opts = {}) {
26133
26130
  title: `Possible overlapping content between ${label(a2)} and ${label(b2)}`,
26134
26131
  source_artifacts: [label(a2), label(b2)],
26135
26132
  target_artifacts: [label(a2), label(b2)],
26136
- evidence: [`Both artifacts declare the sections: ${[...shared].sort().join(", ")}.`],
26137
- rationale: "Shared section titles are a hint of potential overlap, NOT proof of duplication. Two documents can legitimately address the same topic from different layers/responsibilities.",
26133
+ evidence: [
26134
+ `A ${passageWords}-word passage appears verbatim in both artifacts: "${redactSecrets3(run.snippet)}".`
26135
+ ],
26136
+ rationale: "A verbatim shared passage is a hint of potential duplication, NOT proof. Two documents can legitimately restate context from different layers/responsibilities; shared template structure alone was NOT used.",
26138
26137
  possible_impact: "If genuinely duplicated, the same fact can drift out of sync across files.",
26139
- suggested_action: "Semantic review: compare the sections; if one restates the other, keep a single reference location and link the rest. Preserve layer separation.",
26138
+ suggested_action: "Semantic review: compare the overlapping passage; if one restates the other, keep a single reference location and link the rest. Preserve layer separation.",
26140
26139
  requires_semantic_review: true
26141
26140
  });
26142
26141
  }
26143
26142
  for (const la of scoped) {
26144
26143
  if (!isCompletedWorkItem(la)) continue;
26145
- const learning = sectionBody(la.body, ["Learning", "Aprendizaje", "Aprendizajes", "Learnings"]);
26146
- if (!learning) continue;
26147
- if (!looksLikeDurableRule(learning)) continue;
26144
+ const learningRaw = sectionBody(la.body, ["Learning", "Aprendizaje", "Aprendizajes", "Learnings"]);
26145
+ if (!learningRaw) continue;
26146
+ const learning = stripNoise(learningRaw);
26147
+ const ruleFragment = firstRuleFragment(learning);
26148
+ if (!ruleFragment) continue;
26148
26149
  opportunities.push({
26149
26150
  id: stableOpportunityId("unincorporated_learning", [label(la)]),
26150
26151
  category: "unincorporated_learning",
@@ -26152,16 +26153,18 @@ function buildConsolidationPlan(dir, opts = {}) {
26152
26153
  confidence: "requires-review",
26153
26154
  title: `${label(la)} captured a learning that may belong in current knowledge`,
26154
26155
  source_artifacts: [label(la)],
26155
- target_artifacts: ["knowledge/tech/codebase.md"],
26156
- evidence: [`Completed Work Item records a rule-like learning: "${firstSentence(learning)}"`],
26157
- rationale: "A learning phrased as a durable rule MAY represent live technical knowledge not yet reflected in Tech Knowledge. This is a candidate, not a confirmed gap.",
26156
+ target_artifacts: [],
26157
+ // unresolved — determined in semantic review (never invent a destination)
26158
+ evidence: [`Completed Work Item records a rule-like learning (heuristic classification): "${redactSecrets3(ruleFragment)}"`],
26159
+ rationale: "A sentence phrased as a durable rule MAY represent live technical knowledge not yet reflected in current knowledge. The rule/result distinction is a heuristic, not a verified conclusion \u2014 this is a candidate, not a confirmed gap.",
26158
26160
  possible_impact: "A relevant constraint stays buried in delivery history instead of informing current work.",
26159
- suggested_action: "Semantic review: decide whether this learning is a live rule; if so, incorporate it into the right Tech artifact WITH a reference back to the Work Item. Do not delete or summarize the Work Item.",
26161
+ suggested_action: "Semantic review: confirm whether this is a live rule and determine the right destination artifact; if so, incorporate it WITH a reference back to the Work Item. Do not delete or summarize the Work Item.",
26160
26162
  requires_semantic_review: true
26161
26163
  });
26162
26164
  }
26163
26165
  const weakByFolder = /* @__PURE__ */ new Map();
26164
26166
  for (const la of scoped) {
26167
+ if (!isConsolidatableKnowledge(la)) continue;
26165
26168
  const quality = safeQuality(dir, la.rel);
26166
26169
  if (quality === "placeholder" || quality === "weak") {
26167
26170
  opportunities.push({
@@ -26172,11 +26175,11 @@ function buildConsolidationPlan(dir, opts = {}) {
26172
26175
  title: `${label(la)} is ${quality} and may need consolidation or expansion`,
26173
26176
  source_artifacts: [label(la)],
26174
26177
  target_artifacts: [label(la)],
26175
- evidence: [`Artifact quality analysis classifies this artifact as "${quality}".`],
26176
- rationale: "Low-signal artifacts reduce retrieval quality. This is an observed quality signal, not a judgement that the content is wrong.",
26178
+ evidence: [`Artifact quality analysis classifies this canonical knowledge artifact as "${quality}".`],
26179
+ rationale: "Observed: the quality heuristic rates this artifact low-signal. Whether it should be expanded, merged or cross-referenced is a judgement that needs semantic review \u2014 the quality signal alone does not decide it.",
26177
26180
  possible_impact: "Readers must open more files to assemble a complete picture.",
26178
- suggested_action: "Review whether to expand, merge into a stronger artifact, or cross-reference it.",
26179
- requires_semantic_review: false
26181
+ suggested_action: "Semantic review: decide whether to expand, merge into a stronger artifact, or cross-reference it.",
26182
+ requires_semantic_review: true
26180
26183
  });
26181
26184
  const folder = la.rel.split("/").slice(0, -1).join("/");
26182
26185
  const arr = weakByFolder.get(folder) ?? [];
@@ -26191,11 +26194,11 @@ function buildConsolidationPlan(dir, opts = {}) {
26191
26194
  category: "knowledge_fragmentation",
26192
26195
  classification: "suggested",
26193
26196
  confidence: "requires-review",
26194
- title: `${folder}/ holds ${arts.length} low-signal artifacts \u2014 possible fragmentation`,
26197
+ title: `${folder}/ holds ${arts.length} low-signal canonical artifacts \u2014 possible fragmentation`,
26195
26198
  source_artifacts: arts.map((a2) => label(a2)),
26196
26199
  target_artifacts: [folder],
26197
- evidence: [`${arts.length} placeholder/weak artifacts in the same folder: ${arts.map((a2) => a2.rel.split("/").pop()).join(", ")}.`],
26198
- rationale: "Several thin artifacts in one folder MAY be easier to consume if consolidated or cross-linked. Consolidation must preserve each distinct responsibility.",
26200
+ evidence: [`${arts.length} placeholder/weak canonical knowledge artifacts in the same folder: ${arts.map((a2) => a2.rel.split("/").pop()).join(", ")}.`],
26201
+ rationale: "Several thin canonical artifacts in one folder MAY be easier to consume if consolidated or cross-linked. Consolidation must preserve each distinct responsibility; Work Items and generated/lifecycle artifacts are not considered here.",
26199
26202
  possible_impact: "Related knowledge is spread across too many files to follow.",
26200
26203
  suggested_action: "Semantic review: evaluate whether cross-references or a consolidation would add clarity. Do not merge by file count alone.",
26201
26204
  requires_semantic_review: true
@@ -26287,7 +26290,9 @@ function renderConsolidationMarkdown(plan) {
26287
26290
  lines.push(`- Classification: **${o2.classification}**${o2.requires_semantic_review ? " (requires semantic review)" : ""}`);
26288
26291
  lines.push(`- Confidence: ${o2.confidence}`);
26289
26292
  lines.push(`- Source: ${o2.source_artifacts.join(", ") || "\u2014"}`);
26290
- lines.push(`- Suggested target: ${o2.target_artifacts.join(", ") || "\u2014"}`);
26293
+ lines.push(
26294
+ `- Suggested target: ${o2.target_artifacts.length > 0 ? o2.target_artifacts.join(", ") : "(unresolved \u2014 to be determined in semantic review)"}`
26295
+ );
26291
26296
  lines.push(`- Evidence:`);
26292
26297
  for (const e of o2.evidence) lines.push(` - ${e}`);
26293
26298
  lines.push(`- Rationale: ${o2.rationale}`);
@@ -26312,15 +26317,25 @@ function isCompletedWorkItem(la) {
26312
26317
  const p = toPosix8(la.artifact.filePath);
26313
26318
  return p.includes("/delivery/work-items/completed/") || isWorkItem(la) && la.artifact.status === "completed";
26314
26319
  }
26315
- function looksLikeDurableRule(text3) {
26316
- const lower = text3.toLowerCase();
26317
- return RULE_KEYWORDS.some((k2) => new RegExp(`(^|[^a-z\xE1\xE9\xED\xF3\xFA\xF1])${k2}([^a-z\xE1\xE9\xED\xF3\xFA\xF1]|$)`, "i").test(lower));
26320
+ function isScaffolding(la) {
26321
+ const p = toPosix8(la.artifact.filePath);
26322
+ return p.includes(`/${KNOWLEDGE7}/agents/`) || p.includes(`/${KNOWLEDGE7}/skills/`) || p.includes(`/${KNOWLEDGE7}/external/`) || la.artifact.type === "knowledge-capsule";
26323
+ }
26324
+ var NON_KNOWLEDGE_DOC_TYPES = /* @__PURE__ */ new Set([
26325
+ "roadmap",
26326
+ "initiative",
26327
+ "deprecation",
26328
+ "knowledge-capsule",
26329
+ "inventory",
26330
+ "project-resource"
26331
+ ]);
26332
+ function isComparableKnowledge(la) {
26333
+ return !isWorkItem(la) && la.artifact.type !== "roadmap" && !isScaffolding(la);
26318
26334
  }
26319
- function firstSentence(text3) {
26320
- const flat = text3.replace(/\s+/g, " ").trim();
26321
- const m2 = flat.match(/^(.{0,200}?[.!?])(\s|$)/);
26322
- const s = (m2 ? m2[1] : flat).slice(0, 200);
26323
- return redactSecrets3(s.trim());
26335
+ function isConsolidatableKnowledge(la) {
26336
+ if (isWorkItem(la) || isScaffolding(la)) return false;
26337
+ if (NON_KNOWLEDGE_DOC_TYPES.has(la.artifact.type)) return false;
26338
+ return la.layer === "Business" || la.layer === "Product" || la.layer === "Tech";
26324
26339
  }
26325
26340
  var SECRET_TOKEN_PATTERNS = [
26326
26341
  /\bgh[pours]_[A-Za-z0-9]{16,}\b/g,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.129.0",
3
+ "version": "3.129.2",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {