@kaddo/mcp 3.129.0 → 3.129.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.
Files changed (2) hide show
  1. package/dist/index.js +133 -133
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25921,101 +25921,83 @@ 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, " ");
26008
- }
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);
25924
+ var SHINGLE_SIZE = 6;
25925
+ var MIN_SHARED_RUN = 6;
25926
+ function contentWords(body) {
25927
+ const words = [];
25928
+ let inFence = false;
25929
+ for (const raw of body.split(/\r?\n/)) {
25930
+ const t = raw.trim();
25931
+ if (/^```/.test(t)) {
25932
+ inFence = !inFence;
25933
+ continue;
25934
+ }
25935
+ if (inFence) continue;
25936
+ if (/^#{1,6}\s/.test(t)) continue;
25937
+ if (/^>/.test(t)) continue;
25938
+ const text3 = t.replace(/^([-*+]\s+|\d+\.\s+)/, "");
25939
+ const matched = text3.toLowerCase().match(/[a-záéíóúñü0-9]+/gi);
25940
+ if (matched) words.push(...matched);
25941
+ }
25942
+ return words;
25943
+ }
25944
+ function buildShingles(body) {
25945
+ const words = contentWords(body);
25946
+ const keys = [];
25947
+ const set = /* @__PURE__ */ new Set();
25948
+ for (let i = 0; i + SHINGLE_SIZE <= words.length; i++) {
25949
+ const key = words.slice(i, i + SHINGLE_SIZE).join(" ");
25950
+ keys.push(key);
25951
+ set.add(key);
25952
+ }
25953
+ return { words, keys, set };
25954
+ }
25955
+ function longestSharedRun(a2, b2) {
25956
+ let best = 0;
25957
+ let bestStart = -1;
25958
+ let run = 0;
25959
+ let runStart = 0;
25960
+ for (let i = 0; i < a2.keys.length; i++) {
25961
+ if (b2.set.has(a2.keys[i])) {
25962
+ if (run === 0) runStart = i;
25963
+ run += 1;
25964
+ if (run > best) {
25965
+ best = run;
25966
+ bestStart = runStart;
25967
+ }
25968
+ } else {
25969
+ run = 0;
25970
+ }
25971
+ }
25972
+ if (best === 0) return { length: 0, snippet: "" };
25973
+ const snippet = a2.words.slice(bestStart, bestStart + SHINGLE_SIZE + best - 1).join(" ");
25974
+ return { length: best, snippet };
25975
+ }
25976
+ 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;
25977
+ 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;
25978
+ var TEST_RE = /(\btest\w*|\bpruebas?\b|coverage|cobertura|verde[s]?|green\b|assert\w*)/i;
25979
+ var BENCH_RE = /(benchmark\w*|ns\/op|µs\b|throughput|latenc\w*|ops\/s|\d+\s*%|faster|slower|baseline)/i;
25980
+ var EXPERIMENT_RE = /(experiment\w*|experiment[oa]\w*|prototyp\w*|prototip\w*|spike\b|probamos|probé|intentamos)/i;
25981
+ function splitSentences(text3) {
25982
+ return text3.replace(/\s+/g, " ").split(/(?<=[.!?;])\s+/).map((s) => s.trim()).filter(Boolean);
25983
+ }
25984
+ function classifyLearningSentence(sentence) {
25985
+ const s = sentence.trim();
25986
+ if (!s) return "none";
25987
+ const normative = NORMATIVE_RE.test(s);
25988
+ const pastResult = PAST_RESULT_RE.test(s);
25989
+ if (normative && !pastResult) return "durable-rule";
25990
+ if (BENCH_RE.test(s)) return "benchmark-evidence";
25991
+ if (pastResult) return "historical-result";
25992
+ if (TEST_RE.test(s)) return "test-observation";
25993
+ if (EXPERIMENT_RE.test(s)) return "experimental-result";
25994
+ return "none";
25995
+ }
25996
+ function firstRuleFragment(learning) {
25997
+ for (const sentence of splitSentences(learning)) {
25998
+ if (classifyLearningSentence(sentence) === "durable-rule") return sentence;
26017
25999
  }
26018
- return [...new Set(out)];
26000
+ return null;
26019
26001
  }
26020
26002
  function sectionBody(body, titles) {
26021
26003
  const lines = body.split(/\r?\n/);
@@ -26099,32 +26081,33 @@ function buildConsolidationPlan(dir, opts = {}) {
26099
26081
  requires_semantic_review: false
26100
26082
  });
26101
26083
  }
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) ?? [];
26084
+ const comparable = scoped.filter(isComparableKnowledge);
26085
+ const shingleIndex = /* @__PURE__ */ new Map();
26086
+ const shinglesByRel = /* @__PURE__ */ new Map();
26087
+ for (const la of comparable) {
26088
+ const shingles = buildShingles(la.body);
26089
+ shinglesByRel.set(la.rel, shingles);
26090
+ for (const key of shingles.set) {
26091
+ const arr = shingleIndex.get(key) ?? [];
26109
26092
  arr.push(la);
26110
- byHeading.set(h2, arr);
26093
+ shingleIndex.set(key, arr);
26111
26094
  }
26112
26095
  }
26113
- const pairHeadings = /* @__PURE__ */ new Map();
26114
- for (const [heading, arts] of byHeading) {
26096
+ const candidatePairs = /* @__PURE__ */ new Map();
26097
+ for (const arts of shingleIndex.values()) {
26115
26098
  if (arts.length < 2) continue;
26116
26099
  for (let i = 0; i < arts.length; i++) {
26117
26100
  for (let j2 = i + 1; j2 < arts.length; j2++) {
26118
26101
  if (arts[i].rel === arts[j2].rel) continue;
26119
26102
  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);
26103
+ if (!candidatePairs.has(key)) candidatePairs.set(key, { a: arts[i], b: arts[j2] });
26123
26104
  }
26124
26105
  }
26125
26106
  }
26126
- for (const { a: a2, b: b2, shared } of pairHeadings.values()) {
26127
- if (shared.size < 2) continue;
26107
+ for (const { a: a2, b: b2 } of candidatePairs.values()) {
26108
+ const run = longestSharedRun(shinglesByRel.get(a2.rel), shinglesByRel.get(b2.rel));
26109
+ if (run.length < MIN_SHARED_RUN) continue;
26110
+ const passageWords = SHINGLE_SIZE + run.length - 1;
26128
26111
  opportunities.push({
26129
26112
  id: stableOpportunityId("knowledge_redundancy", [label(a2), label(b2)]),
26130
26113
  category: "knowledge_redundancy",
@@ -26133,10 +26116,12 @@ function buildConsolidationPlan(dir, opts = {}) {
26133
26116
  title: `Possible overlapping content between ${label(a2)} and ${label(b2)}`,
26134
26117
  source_artifacts: [label(a2), label(b2)],
26135
26118
  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.",
26119
+ evidence: [
26120
+ `A ${passageWords}-word passage appears verbatim in both artifacts: "${redactSecrets3(run.snippet)}".`
26121
+ ],
26122
+ 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
26123
  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.",
26124
+ 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
26125
  requires_semantic_review: true
26141
26126
  });
26142
26127
  }
@@ -26144,7 +26129,8 @@ function buildConsolidationPlan(dir, opts = {}) {
26144
26129
  if (!isCompletedWorkItem(la)) continue;
26145
26130
  const learning = sectionBody(la.body, ["Learning", "Aprendizaje", "Aprendizajes", "Learnings"]);
26146
26131
  if (!learning) continue;
26147
- if (!looksLikeDurableRule(learning)) continue;
26132
+ const ruleFragment = firstRuleFragment(learning);
26133
+ if (!ruleFragment) continue;
26148
26134
  opportunities.push({
26149
26135
  id: stableOpportunityId("unincorporated_learning", [label(la)]),
26150
26136
  category: "unincorporated_learning",
@@ -26152,16 +26138,18 @@ function buildConsolidationPlan(dir, opts = {}) {
26152
26138
  confidence: "requires-review",
26153
26139
  title: `${label(la)} captured a learning that may belong in current knowledge`,
26154
26140
  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.",
26141
+ target_artifacts: [],
26142
+ // unresolved — determined in semantic review (never invent a destination)
26143
+ evidence: [`Completed Work Item records a rule-like learning (heuristic classification): "${redactSecrets3(ruleFragment)}"`],
26144
+ 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
26145
  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.",
26146
+ 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
26147
  requires_semantic_review: true
26161
26148
  });
26162
26149
  }
26163
26150
  const weakByFolder = /* @__PURE__ */ new Map();
26164
26151
  for (const la of scoped) {
26152
+ if (!isConsolidatableKnowledge(la)) continue;
26165
26153
  const quality = safeQuality(dir, la.rel);
26166
26154
  if (quality === "placeholder" || quality === "weak") {
26167
26155
  opportunities.push({
@@ -26172,11 +26160,11 @@ function buildConsolidationPlan(dir, opts = {}) {
26172
26160
  title: `${label(la)} is ${quality} and may need consolidation or expansion`,
26173
26161
  source_artifacts: [label(la)],
26174
26162
  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.",
26163
+ evidence: [`Artifact quality analysis classifies this canonical knowledge artifact as "${quality}".`],
26164
+ 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
26165
  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
26166
+ suggested_action: "Semantic review: decide whether to expand, merge into a stronger artifact, or cross-reference it.",
26167
+ requires_semantic_review: true
26180
26168
  });
26181
26169
  const folder = la.rel.split("/").slice(0, -1).join("/");
26182
26170
  const arr = weakByFolder.get(folder) ?? [];
@@ -26191,11 +26179,11 @@ function buildConsolidationPlan(dir, opts = {}) {
26191
26179
  category: "knowledge_fragmentation",
26192
26180
  classification: "suggested",
26193
26181
  confidence: "requires-review",
26194
- title: `${folder}/ holds ${arts.length} low-signal artifacts \u2014 possible fragmentation`,
26182
+ title: `${folder}/ holds ${arts.length} low-signal canonical artifacts \u2014 possible fragmentation`,
26195
26183
  source_artifacts: arts.map((a2) => label(a2)),
26196
26184
  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.",
26185
+ evidence: [`${arts.length} placeholder/weak canonical knowledge artifacts in the same folder: ${arts.map((a2) => a2.rel.split("/").pop()).join(", ")}.`],
26186
+ 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
26187
  possible_impact: "Related knowledge is spread across too many files to follow.",
26200
26188
  suggested_action: "Semantic review: evaluate whether cross-references or a consolidation would add clarity. Do not merge by file count alone.",
26201
26189
  requires_semantic_review: true
@@ -26287,7 +26275,9 @@ function renderConsolidationMarkdown(plan) {
26287
26275
  lines.push(`- Classification: **${o2.classification}**${o2.requires_semantic_review ? " (requires semantic review)" : ""}`);
26288
26276
  lines.push(`- Confidence: ${o2.confidence}`);
26289
26277
  lines.push(`- Source: ${o2.source_artifacts.join(", ") || "\u2014"}`);
26290
- lines.push(`- Suggested target: ${o2.target_artifacts.join(", ") || "\u2014"}`);
26278
+ lines.push(
26279
+ `- Suggested target: ${o2.target_artifacts.length > 0 ? o2.target_artifacts.join(", ") : "(unresolved \u2014 to be determined in semantic review)"}`
26280
+ );
26291
26281
  lines.push(`- Evidence:`);
26292
26282
  for (const e of o2.evidence) lines.push(` - ${e}`);
26293
26283
  lines.push(`- Rationale: ${o2.rationale}`);
@@ -26312,15 +26302,25 @@ function isCompletedWorkItem(la) {
26312
26302
  const p = toPosix8(la.artifact.filePath);
26313
26303
  return p.includes("/delivery/work-items/completed/") || isWorkItem(la) && la.artifact.status === "completed";
26314
26304
  }
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));
26305
+ function isScaffolding(la) {
26306
+ const p = toPosix8(la.artifact.filePath);
26307
+ return p.includes(`/${KNOWLEDGE7}/agents/`) || p.includes(`/${KNOWLEDGE7}/skills/`) || p.includes(`/${KNOWLEDGE7}/external/`) || la.artifact.type === "knowledge-capsule";
26308
+ }
26309
+ var NON_KNOWLEDGE_DOC_TYPES = /* @__PURE__ */ new Set([
26310
+ "roadmap",
26311
+ "initiative",
26312
+ "deprecation",
26313
+ "knowledge-capsule",
26314
+ "inventory",
26315
+ "project-resource"
26316
+ ]);
26317
+ function isComparableKnowledge(la) {
26318
+ return !isWorkItem(la) && la.artifact.type !== "roadmap" && !isScaffolding(la);
26318
26319
  }
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());
26320
+ function isConsolidatableKnowledge(la) {
26321
+ if (isWorkItem(la) || isScaffolding(la)) return false;
26322
+ if (NON_KNOWLEDGE_DOC_TYPES.has(la.artifact.type)) return false;
26323
+ return la.layer === "Business" || la.layer === "Product" || la.layer === "Tech";
26324
26324
  }
26325
26325
  var SECRET_TOKEN_PATTERNS = [
26326
26326
  /\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.1",
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": {