@kaddo/mcp 3.128.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.
- package/dist/index.js +959 -68
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -169,6 +169,8 @@ var DERIVED_WRITE_FILES = /* @__PURE__ */ new Set([
|
|
|
169
169
|
".kaddo/graph.mmd",
|
|
170
170
|
".kaddo/graph-hints.md",
|
|
171
171
|
".kaddo/graph-hints.json",
|
|
172
|
+
".kaddo/consolidation-plan.md",
|
|
173
|
+
".kaddo/consolidation-plan.json",
|
|
172
174
|
".kaddo/modules.yml"
|
|
173
175
|
]);
|
|
174
176
|
var DERIVED_EXPORTS_RE = /^\.kaddo\/exports\/[^/]+\.capsule\.(md|json)$/;
|
|
@@ -507,6 +509,21 @@ ${issues}`);
|
|
|
507
509
|
}
|
|
508
510
|
return parsed.data;
|
|
509
511
|
}
|
|
512
|
+
function requireConfig(dir) {
|
|
513
|
+
let config;
|
|
514
|
+
try {
|
|
515
|
+
config = loadConfig(dir);
|
|
516
|
+
} catch (err) {
|
|
517
|
+
const message = err instanceof ConfigError ? err.message : String(err);
|
|
518
|
+
console.error(message);
|
|
519
|
+
process.exit(1);
|
|
520
|
+
}
|
|
521
|
+
if (!config) {
|
|
522
|
+
console.error("No .kaddo/config.yml found. Run `kaddo init` first.");
|
|
523
|
+
process.exit(1);
|
|
524
|
+
}
|
|
525
|
+
return config;
|
|
526
|
+
}
|
|
510
527
|
function projectRole(config) {
|
|
511
528
|
return config.project.role ?? config.multirepo?.role;
|
|
512
529
|
}
|
|
@@ -4547,7 +4564,8 @@ var AGENT_GROUPS = {
|
|
|
4547
4564
|
"work-item-agent.md",
|
|
4548
4565
|
"implementation-agent.md",
|
|
4549
4566
|
"ownership-agent.md",
|
|
4550
|
-
"git-strategy-agent.md"
|
|
4567
|
+
"git-strategy-agent.md",
|
|
4568
|
+
"knowledge-consolidation-agent.md"
|
|
4551
4569
|
],
|
|
4552
4570
|
utilities: ["legacy-agent.md"]
|
|
4553
4571
|
};
|
|
@@ -5226,7 +5244,7 @@ var KNOWLEDGE_FILES = [
|
|
|
5226
5244
|
function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
5227
5245
|
const config = loadConfig(dir);
|
|
5228
5246
|
const rec = resolveNextStep(dir, now);
|
|
5229
|
-
const stub = (overall2,
|
|
5247
|
+
const stub = (overall2, label2, command) => ({
|
|
5230
5248
|
project_name: config?.project.name ?? "unknown",
|
|
5231
5249
|
project_type: config?.project.state ?? "unknown",
|
|
5232
5250
|
overall: overall2,
|
|
@@ -5249,7 +5267,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
5249
5267
|
resolved_questions: 0,
|
|
5250
5268
|
deferred_questions: 0
|
|
5251
5269
|
},
|
|
5252
|
-
recommended_next_step: { label, ...command ? { command } : {} },
|
|
5270
|
+
recommended_next_step: { label: label2, ...command ? { command } : {} },
|
|
5253
5271
|
nextStepRecommendation: rec
|
|
5254
5272
|
});
|
|
5255
5273
|
if (!config) return stub("not-initialized", rec.label, rec.command);
|
|
@@ -6124,6 +6142,69 @@ After a POC has a canonical conclusion and Core has prepared its deterministic r
|
|
|
6124
6142
|
15. Traceability and Sources
|
|
6125
6143
|
`
|
|
6126
6144
|
);
|
|
6145
|
+
var KNOWLEDGE_CONSOLIDATION = skill(
|
|
6146
|
+
"knowledge-consolidation",
|
|
6147
|
+
"Knowledge Consolidation Skill",
|
|
6148
|
+
"delivery",
|
|
6149
|
+
["knowledge-consolidation-agent", "work-item-agent", "architecture-agent"],
|
|
6150
|
+
`
|
|
6151
|
+
# Knowledge Consolidation Skill
|
|
6152
|
+
|
|
6153
|
+
## Purpose
|
|
6154
|
+
|
|
6155
|
+
Standardize the SEMANTIC review of a deterministic Consolidation Plan so canonical knowledge becomes
|
|
6156
|
+
more precise, connected, consistent and retrievable \u2014 without losing history, decisions or evidence.
|
|
6157
|
+
|
|
6158
|
+
## When to use
|
|
6159
|
+
|
|
6160
|
+
After \`kaddo knowledge consolidate\` (or the \`kaddo_generate_consolidation_plan\` tool) has produced
|
|
6161
|
+
\`.kaddo/consolidation-plan.{md,json}\`, and a human or agent wants to review the opportunities and
|
|
6162
|
+
prepare refinements. Never as an autonomous rewrite of \`knowledge/\`.
|
|
6163
|
+
|
|
6164
|
+
## Inputs
|
|
6165
|
+
|
|
6166
|
+
The Consolidation Plan (\`.kaddo/consolidation-plan.json\`), the referenced source artifacts, and the
|
|
6167
|
+
context pack. Each opportunity carries: category, classification, confidence, source/target, evidence,
|
|
6168
|
+
rationale, suggested action, and \`requires_semantic_review\`.
|
|
6169
|
+
|
|
6170
|
+
## Output
|
|
6171
|
+
|
|
6172
|
+
For each opportunity the agent chooses to act on: a reviewable proposal that states what would change,
|
|
6173
|
+
what content is added/moved/summarized, what must be preserved, and which claims still need
|
|
6174
|
+
confirmation \u2014 with a diff or equivalent. No canonical file is edited by this skill; application goes
|
|
6175
|
+
through the existing controlled-edit flows after human approval.
|
|
6176
|
+
|
|
6177
|
+
## Rules
|
|
6178
|
+
|
|
6179
|
+
- Distinguish \`observed\` (verifiable fact) from \`suggested\` (a candidate needing judgement). Never
|
|
6180
|
+
present a \`suggested\` candidate as a verified conclusion.
|
|
6181
|
+
- Classify every claim as Observed / Derived / Suggested / Unknown.
|
|
6182
|
+
- Do not merge Business/Product/Tech just because they share a topic \u2014 preserve layer responsibilities.
|
|
6183
|
+
- Do not move every historical learning into current knowledge; incorporate only live rules, WITH a
|
|
6184
|
+
reference back to the originating Work Item. Never summarize or delete the Work Item.
|
|
6185
|
+
- Do not invent relationships, decisions or business rules; a missing optional relationship is an
|
|
6186
|
+
opportunity, not an error.
|
|
6187
|
+
- For a potential inconsistency, present BOTH sources and say whether the conflict is verified or
|
|
6188
|
+
potential. Never pick a winner arbitrarily.
|
|
6189
|
+
- Preserve critical constraints, decisions and reasons, exceptions, known risks, technical contracts,
|
|
6190
|
+
implementation evidence, provenance and necessary history.
|
|
6191
|
+
- Never reveal secret values or resolve secret references; never connect to a Project Resource.
|
|
6192
|
+
- Do not commit, push or release automatically.
|
|
6193
|
+
|
|
6194
|
+
## Quality checklist
|
|
6195
|
+
|
|
6196
|
+
- Every proposal cites its source artifact(s) and evidence.
|
|
6197
|
+
- Facts are separated from interpretations.
|
|
6198
|
+
- Preserved information is named explicitly.
|
|
6199
|
+
- Claims needing confirmation are flagged.
|
|
6200
|
+
- No canonical artifact was modified by the analysis or the review.
|
|
6201
|
+
|
|
6202
|
+
## Example output
|
|
6203
|
+
|
|
6204
|
+
A short set of proposals, each with evidence, a before/after (or diff) and an explicit list of what
|
|
6205
|
+
must be preserved, ready for human approval.
|
|
6206
|
+
`
|
|
6207
|
+
);
|
|
6127
6208
|
var SKILLS = [
|
|
6128
6209
|
ADR_WRITING,
|
|
6129
6210
|
WORK_ITEM_REFINEMENT,
|
|
@@ -6135,10 +6216,11 @@ var SKILLS = [
|
|
|
6135
6216
|
MODULE_CONTEXT_REFINEMENT,
|
|
6136
6217
|
EVIDENCE_VERIFICATION,
|
|
6137
6218
|
LEGACY_RISK_ASSESSMENT,
|
|
6138
|
-
POC_REPORT_WRITING
|
|
6219
|
+
POC_REPORT_WRITING,
|
|
6220
|
+
KNOWLEDGE_CONSOLIDATION
|
|
6139
6221
|
];
|
|
6140
6222
|
var SKILL_GROUPS = {
|
|
6141
|
-
delivery: ["work-item-refinement", "implementation-planning", "learning-capture", "evidence-verification", "legacy-risk-assessment", "poc-report-writing"],
|
|
6223
|
+
delivery: ["work-item-refinement", "implementation-planning", "learning-capture", "evidence-verification", "legacy-risk-assessment", "poc-report-writing", "knowledge-consolidation"],
|
|
6142
6224
|
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
6143
6225
|
integration: ["capsule-writing"]
|
|
6144
6226
|
};
|
|
@@ -6334,6 +6416,24 @@ var RESPONSIBILITY_MATRIX = {
|
|
|
6334
6416
|
],
|
|
6335
6417
|
next: ["kaddo graph export"]
|
|
6336
6418
|
},
|
|
6419
|
+
"knowledge-consolidation-agent": {
|
|
6420
|
+
agent: "knowledge-consolidation-agent",
|
|
6421
|
+
responsibleFor: [
|
|
6422
|
+
"Semantic review of the deterministic Consolidation Plan",
|
|
6423
|
+
"Preparing reviewable knowledge refinements"
|
|
6424
|
+
],
|
|
6425
|
+
produces: ["proposed refinements (before/after) for human approval"],
|
|
6426
|
+
canSuggest: ["kaddo knowledge consolidate"],
|
|
6427
|
+
cannotSuggest: [
|
|
6428
|
+
"code",
|
|
6429
|
+
"git",
|
|
6430
|
+
"commits",
|
|
6431
|
+
"modifying canonical knowledge without confirmation",
|
|
6432
|
+
"inventing facts or relationships",
|
|
6433
|
+
"deleting history"
|
|
6434
|
+
],
|
|
6435
|
+
next: ["kaddo knowledge consolidate"]
|
|
6436
|
+
},
|
|
6337
6437
|
"ownership-agent": {
|
|
6338
6438
|
agent: "ownership-agent",
|
|
6339
6439
|
responsibleFor: ["Precise code: ownership for Work Items and artifacts"],
|
|
@@ -8494,6 +8594,78 @@ ADRs) and re-runs \`kaddo graph export\`.
|
|
|
8494
8594
|
- No files were modified; no Git was run.
|
|
8495
8595
|
- The human is asked to confirm and re-export the graph.
|
|
8496
8596
|
`;
|
|
8597
|
+
var KNOWLEDGE_CONSOLIDATION_AGENT = `# Knowledge Consolidation Agent
|
|
8598
|
+
|
|
8599
|
+
## Role
|
|
8600
|
+
|
|
8601
|
+
You are the Kaddo Knowledge Consolidation Agent. Your job is to perform the **semantic review** of
|
|
8602
|
+
the deterministic **Consolidation Plan** produced by \`kaddo knowledge consolidate\`, and to prepare
|
|
8603
|
+
**reviewable refinements** that make canonical knowledge more precise, connected, consistent and
|
|
8604
|
+
retrievable \u2014 without losing history, decisions or evidence.
|
|
8605
|
+
|
|
8606
|
+
You do not write code, you do not modify canonical files, and you never run Git. You propose; a human
|
|
8607
|
+
confirms, and application goes through Kaddo's existing controlled-edit flows.
|
|
8608
|
+
|
|
8609
|
+
## When to Use
|
|
8610
|
+
|
|
8611
|
+
Use this agent after \`kaddo knowledge consolidate\` (or the \`kaddo_generate_consolidation_plan\`
|
|
8612
|
+
tool) has produced \`.kaddo/consolidation-plan.md\` and \`.kaddo/consolidation-plan.json\`, and the
|
|
8613
|
+
plan contains opportunities flagged \`requires_semantic_review\`.
|
|
8614
|
+
|
|
8615
|
+
## Input Required
|
|
8616
|
+
|
|
8617
|
+
Provide \`.kaddo/context-pack.md\` and \`.kaddo/consolidation-plan.json\` as the primary inputs, plus
|
|
8618
|
+
the source artifacts each opportunity references under \`knowledge/\` (and completed Work Items under
|
|
8619
|
+
\`knowledge/delivery/work-items/completed/\` for learning opportunities).
|
|
8620
|
+
|
|
8621
|
+
## Expected Output
|
|
8622
|
+
|
|
8623
|
+
For each opportunity you choose to act on, a proposal that states what would change, what content is
|
|
8624
|
+
added / moved / summarized, what must be preserved, and which claims still need confirmation \u2014 with a
|
|
8625
|
+
diff or equivalent before/after.
|
|
8626
|
+
|
|
8627
|
+
## Instructions
|
|
8628
|
+
|
|
8629
|
+
1. Read the plan and work one opportunity at a time, highest-signal first.
|
|
8630
|
+
2. Separate what you **observe** in the files from what you **suggest** \u2014 never present a suggested
|
|
8631
|
+
candidate as a verified conclusion.
|
|
8632
|
+
3. For possible redundancy, compare the actual sections; propose a single reference location only if
|
|
8633
|
+
one genuinely restates the other. Preserve layer separation (Business / Product / Tech / Delivery).
|
|
8634
|
+
4. For an unincorporated learning, decide whether it is a live rule; if so, propose incorporating it
|
|
8635
|
+
into the right Tech artifact **with a reference back to the originating Work Item**. Never summarize
|
|
8636
|
+
or delete the Work Item.
|
|
8637
|
+
5. For a relationship opportunity, propose the relationship only when existing knowledge justifies it;
|
|
8638
|
+
a missing optional relationship is an opportunity, not an error.
|
|
8639
|
+
6. For a potential inconsistency, present **both** sources and say whether the conflict is verified or
|
|
8640
|
+
potential. Do not pick a winner arbitrarily.
|
|
8641
|
+
7. Classify every claim as Observed / Derived / Suggested / Unknown, and mark what needs confirmation.
|
|
8642
|
+
|
|
8643
|
+
## Constraints
|
|
8644
|
+
|
|
8645
|
+
- Do **not** modify canonical files \u2014 propose changes for a human to apply.
|
|
8646
|
+
- Do **not** invent facts, relationships, decisions or business rules.
|
|
8647
|
+
- Do **not** delete historical information, change Work Item states, or alter verification results.
|
|
8648
|
+
- Do **not** reveal secret values or resolve secret references; do **not** connect to a Project Resource.
|
|
8649
|
+
- Do **not** run Git, commit, push or release.
|
|
8650
|
+
|
|
8651
|
+
## Output Format
|
|
8652
|
+
|
|
8653
|
+
Per opportunity: the opportunity id, classification and confidence, the proposed before/after (or
|
|
8654
|
+
diff), the explicit list of what must be preserved, and the open questions that need confirmation.
|
|
8655
|
+
|
|
8656
|
+
## Where to Save the Result
|
|
8657
|
+
|
|
8658
|
+
Nothing is saved automatically. The human reviews the proposals and applies the approved ones through
|
|
8659
|
+
Kaddo's existing controlled-edit flows. Re-run \`kaddo knowledge consolidate\` afterwards to confirm.
|
|
8660
|
+
|
|
8661
|
+
## Quality Checklist
|
|
8662
|
+
|
|
8663
|
+
- Every proposal cites its source artifact(s) and evidence from the plan.
|
|
8664
|
+
- Facts are separated from interpretations; suggested candidates are never asserted as fact.
|
|
8665
|
+
- Preserved information (constraints, decisions, exceptions, risks, contracts, provenance) is named.
|
|
8666
|
+
- No canonical artifact was modified; no Git was run.
|
|
8667
|
+
- The human is asked to confirm before anything is applied.
|
|
8668
|
+
`;
|
|
8497
8669
|
var AGENT_PROMPTS = [
|
|
8498
8670
|
{ fileName: "capability-agent.md", content: CAPABILITY_AGENT },
|
|
8499
8671
|
{ fileName: "architecture-agent.md", content: ARCHITECTURE_AGENT },
|
|
@@ -8520,7 +8692,9 @@ var AGENT_PROMPTS = [
|
|
|
8520
8692
|
// Knowledge Capsule refinement (external context — VS-054)
|
|
8521
8693
|
{ fileName: "capsule-agent.md", content: CAPSULE_AGENT },
|
|
8522
8694
|
// Graph relationship quality (metadata hints → precise front matter — VS-056)
|
|
8523
|
-
{ fileName: "graph-agent.md", content: GRAPH_AGENT }
|
|
8695
|
+
{ fileName: "graph-agent.md", content: GRAPH_AGENT },
|
|
8696
|
+
// Knowledge Consolidation semantic review (deterministic plan → reviewable refinements — WI-070)
|
|
8697
|
+
{ fileName: "knowledge-consolidation-agent.md", content: KNOWLEDGE_CONSOLIDATION_AGENT }
|
|
8524
8698
|
// Every official prompt ends with its responsibility boundaries + Agent Trace footer.
|
|
8525
8699
|
].map((p) => ({ fileName: p.fileName, content: withResponsibilityTrace(p.fileName, p.content) }));
|
|
8526
8700
|
|
|
@@ -8727,9 +8901,9 @@ function installedAssetsSummary(dir) {
|
|
|
8727
8901
|
// ../cli/src/core/roadmap-quality.ts
|
|
8728
8902
|
var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
8729
8903
|
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
8730
|
-
function fieldPresent(lines,
|
|
8904
|
+
function fieldPresent(lines, label2) {
|
|
8731
8905
|
for (let i = 0; i < lines.length; i++) {
|
|
8732
|
-
const m2 = lines[i].match(new RegExp(`^\\s*[-*]?\\s*(?:\\*\\*)?\\s*(${
|
|
8906
|
+
const m2 = lines[i].match(new RegExp(`^\\s*[-*]?\\s*(?:\\*\\*)?\\s*(${label2.source})\\s*(?:\\*\\*)?\\s*:\\s*(.*)$`, "i"));
|
|
8733
8907
|
if (!m2) continue;
|
|
8734
8908
|
const inline = m2[2].trim();
|
|
8735
8909
|
if (inline) return true;
|
|
@@ -8831,13 +9005,13 @@ function renderSignalsCompact(signals) {
|
|
|
8831
9005
|
["external_integrations", "External integrations"],
|
|
8832
9006
|
["environment", "Environment"]
|
|
8833
9007
|
];
|
|
8834
|
-
for (const [key,
|
|
9008
|
+
for (const [key, label2] of CATEGORIES) {
|
|
8835
9009
|
const arr = signals[key];
|
|
8836
9010
|
if (arr.length === 0) continue;
|
|
8837
9011
|
if (arr.length === 1) {
|
|
8838
|
-
lines.push(`- ${
|
|
9012
|
+
lines.push(`- ${label2}: ${arr[0].label}`);
|
|
8839
9013
|
} else {
|
|
8840
|
-
lines.push(`- ${
|
|
9014
|
+
lines.push(`- ${label2}: ${arr.length}`);
|
|
8841
9015
|
}
|
|
8842
9016
|
}
|
|
8843
9017
|
return lines.length > 0 ? lines.join("\n") + "\n" : "No signals detected.\n";
|
|
@@ -11035,9 +11209,9 @@ function renderImpactMarkdown(r2, opts = {}) {
|
|
|
11035
11209
|
["validation section", gp.missing_validation]
|
|
11036
11210
|
];
|
|
11037
11211
|
L.push("## Historical Documentation Completeness", "");
|
|
11038
|
-
for (const [
|
|
11212
|
+
for (const [label2, items] of historical) {
|
|
11039
11213
|
const completed = items.filter((item) => item.status === "completed");
|
|
11040
|
-
if (completed.length > 0) L.push(`- Completed Work Items without detected ${
|
|
11214
|
+
if (completed.length > 0) L.push(`- Completed Work Items without detected ${label2}: ${completed.length}`);
|
|
11041
11215
|
}
|
|
11042
11216
|
if (!historical.some(([, items]) => items.some((item) => item.status === "completed"))) {
|
|
11043
11217
|
L.push("No historical documentation completeness gaps were detected.");
|
|
@@ -11812,6 +11986,27 @@ var RESOURCES = [
|
|
|
11812
11986
|
return parts;
|
|
11813
11987
|
}
|
|
11814
11988
|
},
|
|
11989
|
+
{
|
|
11990
|
+
uri: "kaddo://consolidation-plan",
|
|
11991
|
+
name: "Kaddo consolidation plan",
|
|
11992
|
+
description: "Knowledge Consolidation Plan (.kaddo/consolidation-plan.md + .json) \u2014 reviewable opportunities to optimize, connect and refine canonical knowledge. Read-only.",
|
|
11993
|
+
mimeType: "text/markdown",
|
|
11994
|
+
read: (root) => {
|
|
11995
|
+
const md = readText(root, ".kaddo/consolidation-plan.md");
|
|
11996
|
+
const json = readText(root, ".kaddo/consolidation-plan.json");
|
|
11997
|
+
if (!md && !json) {
|
|
11998
|
+
return text2(
|
|
11999
|
+
"kaddo://consolidation-plan",
|
|
12000
|
+
"Consolidation Plan not found. Run `kaddo knowledge consolidate` (or the kaddo_generate_consolidation_plan tool) first.",
|
|
12001
|
+
"text/plain"
|
|
12002
|
+
);
|
|
12003
|
+
}
|
|
12004
|
+
const parts = [];
|
|
12005
|
+
if (md) parts.push({ uri: "kaddo://consolidation-plan", text: md, mimeType: "text/markdown" });
|
|
12006
|
+
if (json) parts.push({ uri: "kaddo://consolidation-plan.json", text: json, mimeType: "application/json" });
|
|
12007
|
+
return parts;
|
|
12008
|
+
}
|
|
12009
|
+
},
|
|
11815
12010
|
{
|
|
11816
12011
|
uri: "kaddo://build-contract",
|
|
11817
12012
|
name: "Kaddo build contract",
|
|
@@ -12168,7 +12363,7 @@ function getPrompt(root, name) {
|
|
|
12168
12363
|
}
|
|
12169
12364
|
|
|
12170
12365
|
// src/tools.ts
|
|
12171
|
-
import
|
|
12366
|
+
import matter25 from "gray-matter";
|
|
12172
12367
|
|
|
12173
12368
|
// ../cli/dist/core.js
|
|
12174
12369
|
import fs3 from "fs";
|
|
@@ -12198,22 +12393,23 @@ import matter102 from "gray-matter";
|
|
|
12198
12393
|
import { parse as parseYaml82 } from "yaml";
|
|
12199
12394
|
import matter112 from "gray-matter";
|
|
12200
12395
|
import matter122 from "gray-matter";
|
|
12396
|
+
import matter132 from "gray-matter";
|
|
12201
12397
|
import { parse as parseYaml92, stringify as stringifyYaml52 } from "yaml";
|
|
12202
12398
|
import fs4 from "fs";
|
|
12203
12399
|
import path4 from "path";
|
|
12204
12400
|
import crypto2 from "crypto";
|
|
12205
|
-
import
|
|
12401
|
+
import matter142 from "gray-matter";
|
|
12206
12402
|
import crypto3 from "crypto";
|
|
12207
12403
|
import fs5 from "fs";
|
|
12208
|
-
import matter142 from "gray-matter";
|
|
12209
12404
|
import matter15 from "gray-matter";
|
|
12405
|
+
import matter16 from "gray-matter";
|
|
12210
12406
|
import { parse as parseYaml102, stringify as stringifyYaml6 } from "yaml";
|
|
12211
12407
|
import { parse as parseYaml11, stringify as stringifyYaml7 } from "yaml";
|
|
12212
|
-
import matter16 from "gray-matter";
|
|
12213
12408
|
import matter17 from "gray-matter";
|
|
12214
12409
|
import matter18 from "gray-matter";
|
|
12215
12410
|
import matter19 from "gray-matter";
|
|
12216
12411
|
import matter20 from "gray-matter";
|
|
12412
|
+
import matter21 from "gray-matter";
|
|
12217
12413
|
function exists2(p) {
|
|
12218
12414
|
return fs3.existsSync(p);
|
|
12219
12415
|
}
|
|
@@ -14688,7 +14884,8 @@ var AGENT_GROUPS2 = {
|
|
|
14688
14884
|
"work-item-agent.md",
|
|
14689
14885
|
"implementation-agent.md",
|
|
14690
14886
|
"ownership-agent.md",
|
|
14691
|
-
"git-strategy-agent.md"
|
|
14887
|
+
"git-strategy-agent.md",
|
|
14888
|
+
"knowledge-consolidation-agent.md"
|
|
14692
14889
|
],
|
|
14693
14890
|
utilities: ["legacy-agent.md"]
|
|
14694
14891
|
};
|
|
@@ -15718,6 +15915,69 @@ After a POC has a canonical conclusion and Core has prepared its deterministic r
|
|
|
15718
15915
|
15. Traceability and Sources
|
|
15719
15916
|
`
|
|
15720
15917
|
);
|
|
15918
|
+
var KNOWLEDGE_CONSOLIDATION2 = skill2(
|
|
15919
|
+
"knowledge-consolidation",
|
|
15920
|
+
"Knowledge Consolidation Skill",
|
|
15921
|
+
"delivery",
|
|
15922
|
+
["knowledge-consolidation-agent", "work-item-agent", "architecture-agent"],
|
|
15923
|
+
`
|
|
15924
|
+
# Knowledge Consolidation Skill
|
|
15925
|
+
|
|
15926
|
+
## Purpose
|
|
15927
|
+
|
|
15928
|
+
Standardize the SEMANTIC review of a deterministic Consolidation Plan so canonical knowledge becomes
|
|
15929
|
+
more precise, connected, consistent and retrievable \u2014 without losing history, decisions or evidence.
|
|
15930
|
+
|
|
15931
|
+
## When to use
|
|
15932
|
+
|
|
15933
|
+
After \`kaddo knowledge consolidate\` (or the \`kaddo_generate_consolidation_plan\` tool) has produced
|
|
15934
|
+
\`.kaddo/consolidation-plan.{md,json}\`, and a human or agent wants to review the opportunities and
|
|
15935
|
+
prepare refinements. Never as an autonomous rewrite of \`knowledge/\`.
|
|
15936
|
+
|
|
15937
|
+
## Inputs
|
|
15938
|
+
|
|
15939
|
+
The Consolidation Plan (\`.kaddo/consolidation-plan.json\`), the referenced source artifacts, and the
|
|
15940
|
+
context pack. Each opportunity carries: category, classification, confidence, source/target, evidence,
|
|
15941
|
+
rationale, suggested action, and \`requires_semantic_review\`.
|
|
15942
|
+
|
|
15943
|
+
## Output
|
|
15944
|
+
|
|
15945
|
+
For each opportunity the agent chooses to act on: a reviewable proposal that states what would change,
|
|
15946
|
+
what content is added/moved/summarized, what must be preserved, and which claims still need
|
|
15947
|
+
confirmation \u2014 with a diff or equivalent. No canonical file is edited by this skill; application goes
|
|
15948
|
+
through the existing controlled-edit flows after human approval.
|
|
15949
|
+
|
|
15950
|
+
## Rules
|
|
15951
|
+
|
|
15952
|
+
- Distinguish \`observed\` (verifiable fact) from \`suggested\` (a candidate needing judgement). Never
|
|
15953
|
+
present a \`suggested\` candidate as a verified conclusion.
|
|
15954
|
+
- Classify every claim as Observed / Derived / Suggested / Unknown.
|
|
15955
|
+
- Do not merge Business/Product/Tech just because they share a topic \u2014 preserve layer responsibilities.
|
|
15956
|
+
- Do not move every historical learning into current knowledge; incorporate only live rules, WITH a
|
|
15957
|
+
reference back to the originating Work Item. Never summarize or delete the Work Item.
|
|
15958
|
+
- Do not invent relationships, decisions or business rules; a missing optional relationship is an
|
|
15959
|
+
opportunity, not an error.
|
|
15960
|
+
- For a potential inconsistency, present BOTH sources and say whether the conflict is verified or
|
|
15961
|
+
potential. Never pick a winner arbitrarily.
|
|
15962
|
+
- Preserve critical constraints, decisions and reasons, exceptions, known risks, technical contracts,
|
|
15963
|
+
implementation evidence, provenance and necessary history.
|
|
15964
|
+
- Never reveal secret values or resolve secret references; never connect to a Project Resource.
|
|
15965
|
+
- Do not commit, push or release automatically.
|
|
15966
|
+
|
|
15967
|
+
## Quality checklist
|
|
15968
|
+
|
|
15969
|
+
- Every proposal cites its source artifact(s) and evidence.
|
|
15970
|
+
- Facts are separated from interpretations.
|
|
15971
|
+
- Preserved information is named explicitly.
|
|
15972
|
+
- Claims needing confirmation are flagged.
|
|
15973
|
+
- No canonical artifact was modified by the analysis or the review.
|
|
15974
|
+
|
|
15975
|
+
## Example output
|
|
15976
|
+
|
|
15977
|
+
A short set of proposals, each with evidence, a before/after (or diff) and an explicit list of what
|
|
15978
|
+
must be preserved, ready for human approval.
|
|
15979
|
+
`
|
|
15980
|
+
);
|
|
15721
15981
|
var SKILLS2 = [
|
|
15722
15982
|
ADR_WRITING2,
|
|
15723
15983
|
WORK_ITEM_REFINEMENT2,
|
|
@@ -15729,10 +15989,11 @@ var SKILLS2 = [
|
|
|
15729
15989
|
MODULE_CONTEXT_REFINEMENT2,
|
|
15730
15990
|
EVIDENCE_VERIFICATION2,
|
|
15731
15991
|
LEGACY_RISK_ASSESSMENT2,
|
|
15732
|
-
POC_REPORT_WRITING2
|
|
15992
|
+
POC_REPORT_WRITING2,
|
|
15993
|
+
KNOWLEDGE_CONSOLIDATION2
|
|
15733
15994
|
];
|
|
15734
15995
|
var SKILL_GROUPS2 = {
|
|
15735
|
-
delivery: ["work-item-refinement", "implementation-planning", "learning-capture", "evidence-verification", "legacy-risk-assessment", "poc-report-writing"],
|
|
15996
|
+
delivery: ["work-item-refinement", "implementation-planning", "learning-capture", "evidence-verification", "legacy-risk-assessment", "poc-report-writing", "knowledge-consolidation"],
|
|
15736
15997
|
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
15737
15998
|
integration: ["capsule-writing"]
|
|
15738
15999
|
};
|
|
@@ -15923,6 +16184,24 @@ var RESPONSIBILITY_MATRIX2 = {
|
|
|
15923
16184
|
],
|
|
15924
16185
|
next: ["kaddo graph export"]
|
|
15925
16186
|
},
|
|
16187
|
+
"knowledge-consolidation-agent": {
|
|
16188
|
+
agent: "knowledge-consolidation-agent",
|
|
16189
|
+
responsibleFor: [
|
|
16190
|
+
"Semantic review of the deterministic Consolidation Plan",
|
|
16191
|
+
"Preparing reviewable knowledge refinements"
|
|
16192
|
+
],
|
|
16193
|
+
produces: ["proposed refinements (before/after) for human approval"],
|
|
16194
|
+
canSuggest: ["kaddo knowledge consolidate"],
|
|
16195
|
+
cannotSuggest: [
|
|
16196
|
+
"code",
|
|
16197
|
+
"git",
|
|
16198
|
+
"commits",
|
|
16199
|
+
"modifying canonical knowledge without confirmation",
|
|
16200
|
+
"inventing facts or relationships",
|
|
16201
|
+
"deleting history"
|
|
16202
|
+
],
|
|
16203
|
+
next: ["kaddo knowledge consolidate"]
|
|
16204
|
+
},
|
|
15926
16205
|
"ownership-agent": {
|
|
15927
16206
|
agent: "ownership-agent",
|
|
15928
16207
|
responsibleFor: ["Precise code: ownership for Work Items and artifacts"],
|
|
@@ -18081,6 +18360,78 @@ ADRs) and re-runs \`kaddo graph export\`.
|
|
|
18081
18360
|
- No files were modified; no Git was run.
|
|
18082
18361
|
- The human is asked to confirm and re-export the graph.
|
|
18083
18362
|
`;
|
|
18363
|
+
var KNOWLEDGE_CONSOLIDATION_AGENT2 = `# Knowledge Consolidation Agent
|
|
18364
|
+
|
|
18365
|
+
## Role
|
|
18366
|
+
|
|
18367
|
+
You are the Kaddo Knowledge Consolidation Agent. Your job is to perform the **semantic review** of
|
|
18368
|
+
the deterministic **Consolidation Plan** produced by \`kaddo knowledge consolidate\`, and to prepare
|
|
18369
|
+
**reviewable refinements** that make canonical knowledge more precise, connected, consistent and
|
|
18370
|
+
retrievable \u2014 without losing history, decisions or evidence.
|
|
18371
|
+
|
|
18372
|
+
You do not write code, you do not modify canonical files, and you never run Git. You propose; a human
|
|
18373
|
+
confirms, and application goes through Kaddo's existing controlled-edit flows.
|
|
18374
|
+
|
|
18375
|
+
## When to Use
|
|
18376
|
+
|
|
18377
|
+
Use this agent after \`kaddo knowledge consolidate\` (or the \`kaddo_generate_consolidation_plan\`
|
|
18378
|
+
tool) has produced \`.kaddo/consolidation-plan.md\` and \`.kaddo/consolidation-plan.json\`, and the
|
|
18379
|
+
plan contains opportunities flagged \`requires_semantic_review\`.
|
|
18380
|
+
|
|
18381
|
+
## Input Required
|
|
18382
|
+
|
|
18383
|
+
Provide \`.kaddo/context-pack.md\` and \`.kaddo/consolidation-plan.json\` as the primary inputs, plus
|
|
18384
|
+
the source artifacts each opportunity references under \`knowledge/\` (and completed Work Items under
|
|
18385
|
+
\`knowledge/delivery/work-items/completed/\` for learning opportunities).
|
|
18386
|
+
|
|
18387
|
+
## Expected Output
|
|
18388
|
+
|
|
18389
|
+
For each opportunity you choose to act on, a proposal that states what would change, what content is
|
|
18390
|
+
added / moved / summarized, what must be preserved, and which claims still need confirmation \u2014 with a
|
|
18391
|
+
diff or equivalent before/after.
|
|
18392
|
+
|
|
18393
|
+
## Instructions
|
|
18394
|
+
|
|
18395
|
+
1. Read the plan and work one opportunity at a time, highest-signal first.
|
|
18396
|
+
2. Separate what you **observe** in the files from what you **suggest** \u2014 never present a suggested
|
|
18397
|
+
candidate as a verified conclusion.
|
|
18398
|
+
3. For possible redundancy, compare the actual sections; propose a single reference location only if
|
|
18399
|
+
one genuinely restates the other. Preserve layer separation (Business / Product / Tech / Delivery).
|
|
18400
|
+
4. For an unincorporated learning, decide whether it is a live rule; if so, propose incorporating it
|
|
18401
|
+
into the right Tech artifact **with a reference back to the originating Work Item**. Never summarize
|
|
18402
|
+
or delete the Work Item.
|
|
18403
|
+
5. For a relationship opportunity, propose the relationship only when existing knowledge justifies it;
|
|
18404
|
+
a missing optional relationship is an opportunity, not an error.
|
|
18405
|
+
6. For a potential inconsistency, present **both** sources and say whether the conflict is verified or
|
|
18406
|
+
potential. Do not pick a winner arbitrarily.
|
|
18407
|
+
7. Classify every claim as Observed / Derived / Suggested / Unknown, and mark what needs confirmation.
|
|
18408
|
+
|
|
18409
|
+
## Constraints
|
|
18410
|
+
|
|
18411
|
+
- Do **not** modify canonical files \u2014 propose changes for a human to apply.
|
|
18412
|
+
- Do **not** invent facts, relationships, decisions or business rules.
|
|
18413
|
+
- Do **not** delete historical information, change Work Item states, or alter verification results.
|
|
18414
|
+
- Do **not** reveal secret values or resolve secret references; do **not** connect to a Project Resource.
|
|
18415
|
+
- Do **not** run Git, commit, push or release.
|
|
18416
|
+
|
|
18417
|
+
## Output Format
|
|
18418
|
+
|
|
18419
|
+
Per opportunity: the opportunity id, classification and confidence, the proposed before/after (or
|
|
18420
|
+
diff), the explicit list of what must be preserved, and the open questions that need confirmation.
|
|
18421
|
+
|
|
18422
|
+
## Where to Save the Result
|
|
18423
|
+
|
|
18424
|
+
Nothing is saved automatically. The human reviews the proposals and applies the approved ones through
|
|
18425
|
+
Kaddo's existing controlled-edit flows. Re-run \`kaddo knowledge consolidate\` afterwards to confirm.
|
|
18426
|
+
|
|
18427
|
+
## Quality Checklist
|
|
18428
|
+
|
|
18429
|
+
- Every proposal cites its source artifact(s) and evidence from the plan.
|
|
18430
|
+
- Facts are separated from interpretations; suggested candidates are never asserted as fact.
|
|
18431
|
+
- Preserved information (constraints, decisions, exceptions, risks, contracts, provenance) is named.
|
|
18432
|
+
- No canonical artifact was modified; no Git was run.
|
|
18433
|
+
- The human is asked to confirm before anything is applied.
|
|
18434
|
+
`;
|
|
18084
18435
|
var AGENT_PROMPTS2 = [
|
|
18085
18436
|
{ fileName: "capability-agent.md", content: CAPABILITY_AGENT2 },
|
|
18086
18437
|
{ fileName: "architecture-agent.md", content: ARCHITECTURE_AGENT2 },
|
|
@@ -18107,7 +18458,9 @@ var AGENT_PROMPTS2 = [
|
|
|
18107
18458
|
// Knowledge Capsule refinement (external context — VS-054)
|
|
18108
18459
|
{ fileName: "capsule-agent.md", content: CAPSULE_AGENT2 },
|
|
18109
18460
|
// Graph relationship quality (metadata hints → precise front matter — VS-056)
|
|
18110
|
-
{ fileName: "graph-agent.md", content: GRAPH_AGENT2 }
|
|
18461
|
+
{ fileName: "graph-agent.md", content: GRAPH_AGENT2 },
|
|
18462
|
+
// Knowledge Consolidation semantic review (deterministic plan → reviewable refinements — WI-070)
|
|
18463
|
+
{ fileName: "knowledge-consolidation-agent.md", content: KNOWLEDGE_CONSOLIDATION_AGENT2 }
|
|
18111
18464
|
// Every official prompt ends with its responsibility boundaries + Agent Trace footer.
|
|
18112
18465
|
].map((p) => ({ fileName: p.fileName, content: withResponsibilityTrace2(p.fileName, p.content) }));
|
|
18113
18466
|
function withAgentFrontMatter2(fileName, content) {
|
|
@@ -18985,7 +19338,7 @@ function parseOriginalSnapshot(fm) {
|
|
|
18985
19338
|
function readBody(filePath) {
|
|
18986
19339
|
try {
|
|
18987
19340
|
const raw = readFile2(filePath);
|
|
18988
|
-
return
|
|
19341
|
+
return matter132(raw).content;
|
|
18989
19342
|
} catch {
|
|
18990
19343
|
return "";
|
|
18991
19344
|
}
|
|
@@ -19270,7 +19623,7 @@ function ensureH1(body, title) {
|
|
|
19270
19623
|
${trimmed}`;
|
|
19271
19624
|
}
|
|
19272
19625
|
function serialize2(data, body) {
|
|
19273
|
-
return
|
|
19626
|
+
return matter142.stringify(`
|
|
19274
19627
|
${body.trim()}
|
|
19275
19628
|
`, data);
|
|
19276
19629
|
}
|
|
@@ -20184,7 +20537,7 @@ function detectFormat(raw) {
|
|
|
20184
20537
|
if (!trimmed) throw new ImportError("EMPTY_INPUT", "Import content is empty.");
|
|
20185
20538
|
if (trimmed.startsWith("---")) {
|
|
20186
20539
|
try {
|
|
20187
|
-
const { data } =
|
|
20540
|
+
const { data } = matter15(trimmed);
|
|
20188
20541
|
if (data && typeof data === "object" && Object.keys(data).length > 0) {
|
|
20189
20542
|
const d3 = data;
|
|
20190
20543
|
if (d3.type === "work-item" || d3.id && typeof d3.id === "string" && /^WI-\d+/.test(d3.id)) {
|
|
@@ -20206,7 +20559,7 @@ function parseContent(raw) {
|
|
|
20206
20559
|
let bodyText = trimmed;
|
|
20207
20560
|
if (format === "kaddo-frontmatter" || format === "markdown-frontmatter") {
|
|
20208
20561
|
try {
|
|
20209
|
-
const parsed =
|
|
20562
|
+
const parsed = matter15(trimmed);
|
|
20210
20563
|
frontmatterFields = parsed.data ?? {};
|
|
20211
20564
|
bodyText = parsed.content.trim();
|
|
20212
20565
|
} catch {
|
|
@@ -20303,7 +20656,7 @@ function findDuplicateByHash(dir, hash) {
|
|
|
20303
20656
|
const raw = readFile2(item.filePath);
|
|
20304
20657
|
if (!raw) continue;
|
|
20305
20658
|
try {
|
|
20306
|
-
const { data } =
|
|
20659
|
+
const { data } = matter15(raw);
|
|
20307
20660
|
const source22 = data?.source;
|
|
20308
20661
|
if (source22 && typeof source22 === "object" && !Array.isArray(source22)) {
|
|
20309
20662
|
const s = source22;
|
|
@@ -21198,7 +21551,7 @@ function buildInitiativeContent(id, input) {
|
|
|
21198
21551
|
if (input.priority) data.priority = input.priority;
|
|
21199
21552
|
if (input.source) data.source = input.source;
|
|
21200
21553
|
if (input.sourceId) data.source_id = input.sourceId;
|
|
21201
|
-
return
|
|
21554
|
+
return matter17.stringify("\n" + (input.body ?? defaultBody(input.title.trim())), data);
|
|
21202
21555
|
}
|
|
21203
21556
|
function createInitiative(dir, input) {
|
|
21204
21557
|
if (!input.title?.trim()) throw new InitiativeWriteError("Initiative title is required.");
|
|
@@ -21222,10 +21575,10 @@ function transitionInitiative(dir, id, to) {
|
|
|
21222
21575
|
throw new InitiativeWriteError(`Invalid transition ${ini.status} \u2192 ${to}.`);
|
|
21223
21576
|
}
|
|
21224
21577
|
const raw = readFile2(ini.filePath);
|
|
21225
|
-
const { data, content } =
|
|
21578
|
+
const { data, content } = matter17(raw, {});
|
|
21226
21579
|
data.status = to;
|
|
21227
21580
|
if (to === "completed") data.completed_at = today2();
|
|
21228
|
-
const newContent =
|
|
21581
|
+
const newContent = matter17.stringify(content, data);
|
|
21229
21582
|
writeFile2(ini.filePath, newContent);
|
|
21230
21583
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21231
21584
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after transition.");
|
|
@@ -21235,7 +21588,7 @@ function addCandidate(dir, id, candidate) {
|
|
|
21235
21588
|
const ini = getInitiative(dir, id);
|
|
21236
21589
|
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
21237
21590
|
const raw = readFile2(ini.filePath);
|
|
21238
|
-
const { data, content } =
|
|
21591
|
+
const { data, content } = matter17(raw, {});
|
|
21239
21592
|
const existing = Array.isArray(data.candidates) ? data.candidates : [];
|
|
21240
21593
|
const fallbackId = `WI-CANDIDATE-${String(existing.length + 1).padStart(3, "0")}`;
|
|
21241
21594
|
const normalized = normalizeCandidate(candidate, fallbackId);
|
|
@@ -21243,7 +21596,7 @@ function addCandidate(dir, id, candidate) {
|
|
|
21243
21596
|
throw new InitiativeWriteError(`Candidate ${normalized.id} already exists in ${id}.`);
|
|
21244
21597
|
}
|
|
21245
21598
|
data.candidates = [...existing, candidateToData(normalized)];
|
|
21246
|
-
const newContent =
|
|
21599
|
+
const newContent = matter17.stringify(content, data);
|
|
21247
21600
|
writeFile2(ini.filePath, newContent);
|
|
21248
21601
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21249
21602
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after adding a candidate.");
|
|
@@ -21253,7 +21606,7 @@ function updateInitiative(dir, id, patch) {
|
|
|
21253
21606
|
const ini = getInitiative(dir, id);
|
|
21254
21607
|
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
21255
21608
|
const raw = readFile2(ini.filePath);
|
|
21256
|
-
const { data, content } =
|
|
21609
|
+
const { data, content } = matter17(raw, {});
|
|
21257
21610
|
if (patch.title !== void 0) {
|
|
21258
21611
|
if (!patch.title.trim()) throw new InitiativeWriteError("Initiative title cannot be empty.");
|
|
21259
21612
|
data.title = patch.title.trim();
|
|
@@ -21263,7 +21616,7 @@ function updateInitiative(dir, id, patch) {
|
|
|
21263
21616
|
if (patch.knowledgeLevel !== void 0) data.knowledge_level = patch.knowledgeLevel;
|
|
21264
21617
|
if (patch.domains !== void 0) data.domains = patch.domains;
|
|
21265
21618
|
if (patch.relatedCapabilities !== void 0) data.related_capabilities = patch.relatedCapabilities;
|
|
21266
|
-
const newContent =
|
|
21619
|
+
const newContent = matter17.stringify(content, data);
|
|
21267
21620
|
writeFile2(ini.filePath, newContent);
|
|
21268
21621
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21269
21622
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after update.");
|
|
@@ -21281,10 +21634,10 @@ function addExternalLink(dir, id, link) {
|
|
|
21281
21634
|
throw new InitiativeWriteError(`External link ${link.integration}:${link.externalId} already exists on ${id}.`);
|
|
21282
21635
|
}
|
|
21283
21636
|
const raw = readFile2(ini.filePath);
|
|
21284
|
-
const { data, content } =
|
|
21637
|
+
const { data, content } = matter17(raw, {});
|
|
21285
21638
|
const existing = Array.isArray(data.external_links) ? data.external_links : [];
|
|
21286
21639
|
data.external_links = [...existing, externalLinkToData(link)];
|
|
21287
|
-
const newContent =
|
|
21640
|
+
const newContent = matter17.stringify(content, data);
|
|
21288
21641
|
writeFile2(ini.filePath, newContent);
|
|
21289
21642
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21290
21643
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after adding an external link.");
|
|
@@ -21353,7 +21706,7 @@ function buildWorkItemContent(wiId, iniId, candidate) {
|
|
|
21353
21706
|
"_What did we learn? Update after completion._",
|
|
21354
21707
|
""
|
|
21355
21708
|
].join("\n");
|
|
21356
|
-
return
|
|
21709
|
+
return matter17.stringify("\n" + body, data);
|
|
21357
21710
|
}
|
|
21358
21711
|
function materializeCandidate(dir, id, candidateId) {
|
|
21359
21712
|
const ini = getInitiative(dir, id);
|
|
@@ -21370,13 +21723,13 @@ function materializeCandidate(dir, id, candidateId) {
|
|
|
21370
21723
|
ensureDir2(join3(dir, DRAFT_DIR));
|
|
21371
21724
|
writeFile2(join3(dir, DRAFT_DIR, fileName), buildWorkItemContent(wiId, ini.id, candidate));
|
|
21372
21725
|
const raw = readFile2(ini.filePath);
|
|
21373
|
-
const { data, content } =
|
|
21726
|
+
const { data, content } = matter17(raw, {});
|
|
21374
21727
|
const cands = Array.isArray(data.candidates) ? data.candidates : [];
|
|
21375
21728
|
for (const c of cands) {
|
|
21376
21729
|
if (c && typeof c === "object" && String(c.id) === candidateId) c.materialized_as = wiId;
|
|
21377
21730
|
}
|
|
21378
21731
|
data.candidates = cands;
|
|
21379
|
-
const newContent =
|
|
21732
|
+
const newContent = matter17.stringify(content, data);
|
|
21380
21733
|
writeFile2(ini.filePath, newContent);
|
|
21381
21734
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21382
21735
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after materialization.");
|
|
@@ -21490,7 +21843,7 @@ function evaluateInitiativeCompletion(dir, ini) {
|
|
|
21490
21843
|
// ../cli/src/core/resource-write.ts
|
|
21491
21844
|
import fs6 from "fs";
|
|
21492
21845
|
import path5 from "path";
|
|
21493
|
-
import
|
|
21846
|
+
import matter23 from "gray-matter";
|
|
21494
21847
|
var RESOURCES_DIR = "knowledge/tech/resources";
|
|
21495
21848
|
var ResourceWriteError = class extends Error {
|
|
21496
21849
|
constructor(code, message) {
|
|
@@ -21600,7 +21953,7 @@ function buildFrontmatter(id, input, base = {}) {
|
|
|
21600
21953
|
return data;
|
|
21601
21954
|
}
|
|
21602
21955
|
function serialize(data, body) {
|
|
21603
|
-
return
|
|
21956
|
+
return matter23.stringify(`
|
|
21604
21957
|
${body.trim()}
|
|
21605
21958
|
`, data);
|
|
21606
21959
|
}
|
|
@@ -21640,7 +21993,7 @@ function updateResource(dir, id, input) {
|
|
|
21640
21993
|
throw new ResourceWriteError("VALIDATION_FAILED", findings.filter((f3) => f3.level === "error").map((f3) => f3.message).join("; "));
|
|
21641
21994
|
}
|
|
21642
21995
|
const raw = readFile(match.filePath);
|
|
21643
|
-
const parsed =
|
|
21996
|
+
const parsed = matter23(raw);
|
|
21644
21997
|
const base = parsed.data ?? {};
|
|
21645
21998
|
const data = buildFrontmatter(match.id || id, input, base);
|
|
21646
21999
|
let body = parsed.content.trim();
|
|
@@ -21873,7 +22226,7 @@ var CANDIDATE_DISCOVERY_GUIDANCE2 = [
|
|
|
21873
22226
|
// ../cli/src/core/deprecation-write.ts
|
|
21874
22227
|
import fs7 from "fs";
|
|
21875
22228
|
import path6 from "path";
|
|
21876
|
-
import
|
|
22229
|
+
import matter24 from "gray-matter";
|
|
21877
22230
|
var DeprecationWriteError = class extends Error {
|
|
21878
22231
|
constructor(code, message) {
|
|
21879
22232
|
super(message);
|
|
@@ -21891,7 +22244,7 @@ function atomicWrite2(filePath, content) {
|
|
|
21891
22244
|
fs7.renameSync(tmp, filePath);
|
|
21892
22245
|
}
|
|
21893
22246
|
function serialize3(data, body) {
|
|
21894
|
-
return
|
|
22247
|
+
return matter24.stringify(`
|
|
21895
22248
|
${body.trim()}
|
|
21896
22249
|
`, data);
|
|
21897
22250
|
}
|
|
@@ -21957,7 +22310,7 @@ function validateTargetInput(dir, raw) {
|
|
|
21957
22310
|
function loadPlanRaw(dir, planId) {
|
|
21958
22311
|
const match = allPlanArtifacts(dir).find((a2) => a2.id === planId || a2.title === planId);
|
|
21959
22312
|
if (!match) throw new DeprecationWriteError("NOT_FOUND", `Deprecation Plan "${planId}" not found.`);
|
|
21960
|
-
const parsed =
|
|
22313
|
+
const parsed = matter24(readFile(match.filePath));
|
|
21961
22314
|
const data = { ...parsed.data ?? {} };
|
|
21962
22315
|
return { filePath: match.filePath, data, body: parsed.content.trim() };
|
|
21963
22316
|
}
|
|
@@ -22145,12 +22498,12 @@ function markWorkItemReady(root, id, confirm2) {
|
|
|
22145
22498
|
}
|
|
22146
22499
|
const raw = readText(root, item.path);
|
|
22147
22500
|
if (!raw) return fail(`Could not read Work Item file: ${item.path}`);
|
|
22148
|
-
const parsed =
|
|
22501
|
+
const parsed = matter25(raw);
|
|
22149
22502
|
const data = { ...parsed.data };
|
|
22150
22503
|
const today3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
22151
22504
|
data.status = "ready";
|
|
22152
22505
|
data.ready_at = today3;
|
|
22153
|
-
const newContent =
|
|
22506
|
+
const newContent = matter25.stringify(parsed.content, data);
|
|
22154
22507
|
const posixPath = item.path.replace(/\\/g, "/");
|
|
22155
22508
|
let newRelPath = item.path;
|
|
22156
22509
|
if (posixPath.includes("/work-items/draft/")) {
|
|
@@ -22445,7 +22798,7 @@ function removeDeprecationTargetTool(root, planId, targetId, confirm2) {
|
|
|
22445
22798
|
// src/multirepo.ts
|
|
22446
22799
|
import fs8 from "fs";
|
|
22447
22800
|
import path7 from "path";
|
|
22448
|
-
import
|
|
22801
|
+
import matter26 from "gray-matter";
|
|
22449
22802
|
import { parse as parseYaml12, stringify as stringifyYaml8 } from "yaml";
|
|
22450
22803
|
var ok2 = (data) => ({ ok: true, data });
|
|
22451
22804
|
var fail2 = (message) => ({ ok: false, message });
|
|
@@ -22597,7 +22950,7 @@ function validateWorkItemModulesTool(root, args) {
|
|
|
22597
22950
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22598
22951
|
const raw = readText(root, wi.path);
|
|
22599
22952
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22600
|
-
const parsed =
|
|
22953
|
+
const parsed = matter26(raw);
|
|
22601
22954
|
const data = parsed.data;
|
|
22602
22955
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22603
22956
|
const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
|
|
@@ -22650,7 +23003,7 @@ function getWorkItemContextTool(root, args) {
|
|
|
22650
23003
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22651
23004
|
const raw = readText(root, wi.path);
|
|
22652
23005
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22653
|
-
const parsed =
|
|
23006
|
+
const parsed = matter26(raw);
|
|
22654
23007
|
const data = parsed.data;
|
|
22655
23008
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22656
23009
|
const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
|
|
@@ -22736,7 +23089,7 @@ function suggestBranchStrategyTool(root, args) {
|
|
|
22736
23089
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22737
23090
|
const raw = readText(root, wi.path);
|
|
22738
23091
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22739
|
-
const parsed =
|
|
23092
|
+
const parsed = matter26(raw);
|
|
22740
23093
|
const data = parsed.data;
|
|
22741
23094
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22742
23095
|
const codeEntries = Array.isArray(data.code) ? data.code.filter((c) => typeof c === "object" && c !== null).map((c) => ({ repo: typeof c.repo === "string" ? c.repo : void 0, paths: Array.isArray(c.paths) ? c.paths.map(String) : [] })) : [];
|
|
@@ -23496,14 +23849,14 @@ function systemImpactCandidatesTool(root, args) {
|
|
|
23496
23849
|
}
|
|
23497
23850
|
|
|
23498
23851
|
// ../cli/src/services/integrations.ts
|
|
23499
|
-
import
|
|
23852
|
+
import matter28 from "gray-matter";
|
|
23500
23853
|
import { parse as parseYaml14, stringify as stringifyYaml10 } from "yaml";
|
|
23501
23854
|
|
|
23502
23855
|
// ../cli/src/core/work-item-write.ts
|
|
23503
23856
|
import fs10 from "fs";
|
|
23504
23857
|
import path9 from "path";
|
|
23505
23858
|
import crypto4 from "crypto";
|
|
23506
|
-
import
|
|
23859
|
+
import matter27 from "gray-matter";
|
|
23507
23860
|
var SECTION_ORDER2 = [
|
|
23508
23861
|
"Actor",
|
|
23509
23862
|
"Outcome",
|
|
@@ -24551,7 +24904,7 @@ async function integrationsWorkItemTool(root, args) {
|
|
|
24551
24904
|
}
|
|
24552
24905
|
|
|
24553
24906
|
// ../cli/src/core/context-pack.ts
|
|
24554
|
-
import
|
|
24907
|
+
import matter29 from "gray-matter";
|
|
24555
24908
|
var CONTEXT_PACK_VERSION = "1";
|
|
24556
24909
|
var ARCH_DIR4 = "knowledge";
|
|
24557
24910
|
function readScanJson(dir) {
|
|
@@ -24564,7 +24917,7 @@ function readScanJson(dir) {
|
|
|
24564
24917
|
}
|
|
24565
24918
|
}
|
|
24566
24919
|
function firstParagraph4(markdown) {
|
|
24567
|
-
const body =
|
|
24920
|
+
const body = matter29(markdown).content.trim();
|
|
24568
24921
|
const para = body.split("\n\n").map((p) => p.trim()).find((p) => p && !p.startsWith("#"));
|
|
24569
24922
|
return para ?? "";
|
|
24570
24923
|
}
|
|
@@ -25065,11 +25418,11 @@ function renderContextPack(pack) {
|
|
|
25065
25418
|
if (mixEntries.length > 0) {
|
|
25066
25419
|
parts.push("## Delivery Mix\n");
|
|
25067
25420
|
parts.push("Active Work Items by type:\n");
|
|
25068
|
-
const
|
|
25421
|
+
const label2 = (t) => {
|
|
25069
25422
|
const c = t.charAt(0).toUpperCase() + t.slice(1);
|
|
25070
25423
|
return c.endsWith("s") ? c : `${c}s`;
|
|
25071
25424
|
};
|
|
25072
|
-
parts.push(mixEntries.map(([t, n]) => `- ${
|
|
25425
|
+
parts.push(mixEntries.map(([t, n]) => `- ${label2(t)}: ${n}`).join("\n") + "\n");
|
|
25073
25426
|
}
|
|
25074
25427
|
parts.push("## Artifacts and Ownership\n");
|
|
25075
25428
|
if (knowledge.artifacts.length > 0) {
|
|
@@ -25545,8 +25898,502 @@ function renderUnderstand(plan) {
|
|
|
25545
25898
|
return parts.join("\n");
|
|
25546
25899
|
}
|
|
25547
25900
|
|
|
25901
|
+
// ../cli/src/core/knowledge-consolidation.ts
|
|
25902
|
+
import { createHash as createHash3 } from "crypto";
|
|
25903
|
+
import matter30 from "gray-matter";
|
|
25904
|
+
var KNOWLEDGE7 = "knowledge";
|
|
25905
|
+
var CONSOLIDATION_CATEGORIES = [
|
|
25906
|
+
"knowledge_redundancy",
|
|
25907
|
+
"unincorporated_learning",
|
|
25908
|
+
"knowledge_fragmentation",
|
|
25909
|
+
"relationship_opportunity",
|
|
25910
|
+
"potentially_outdated",
|
|
25911
|
+
"knowledge_organization"
|
|
25912
|
+
];
|
|
25913
|
+
function toPosix8(p) {
|
|
25914
|
+
return p.replace(/\\/g, "/");
|
|
25915
|
+
}
|
|
25916
|
+
function relFromDir(dir, filePath) {
|
|
25917
|
+
const d3 = toPosix8(dir).replace(/\/+$/, "");
|
|
25918
|
+
const f3 = toPosix8(filePath);
|
|
25919
|
+
return f3.startsWith(d3 + "/") ? f3.slice(d3.length + 1) : f3;
|
|
25920
|
+
}
|
|
25921
|
+
function sha256(content) {
|
|
25922
|
+
return createHash3("sha256").update(content, "utf-8").digest("hex");
|
|
25923
|
+
}
|
|
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;
|
|
25999
|
+
}
|
|
26000
|
+
return null;
|
|
26001
|
+
}
|
|
26002
|
+
function sectionBody(body, titles) {
|
|
26003
|
+
const lines = body.split(/\r?\n/);
|
|
26004
|
+
const re = new RegExp(`^#{1,3}\\s+(${titles.join("|")})\\s*$`, "i");
|
|
26005
|
+
const start = lines.findIndex((l2) => re.test(l2));
|
|
26006
|
+
if (start < 0) return null;
|
|
26007
|
+
const collected = [];
|
|
26008
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
26009
|
+
if (/^#{1,3}\s+/.test(lines[i])) break;
|
|
26010
|
+
collected.push(lines[i]);
|
|
26011
|
+
}
|
|
26012
|
+
const text3 = collected.join("\n").trim();
|
|
26013
|
+
return text3.length > 0 ? text3 : null;
|
|
26014
|
+
}
|
|
26015
|
+
function stableOpportunityId(category, sources) {
|
|
26016
|
+
const key = [category, ...[...sources].sort()].join("|");
|
|
26017
|
+
return `${category}:${sha256(key).slice(0, 12)}`;
|
|
26018
|
+
}
|
|
26019
|
+
function layerOf(a2) {
|
|
26020
|
+
const byType = layerForType(a2.type);
|
|
26021
|
+
if (byType) return byType;
|
|
26022
|
+
const p = toPosix8(a2.filePath);
|
|
26023
|
+
if (p.includes(`/${KNOWLEDGE7}/business/`)) return "Business";
|
|
26024
|
+
if (p.includes(`/${KNOWLEDGE7}/product/`)) return "Product";
|
|
26025
|
+
if (p.includes(`/${KNOWLEDGE7}/tech/`)) return "Tech";
|
|
26026
|
+
if (p.includes(`/${KNOWLEDGE7}/delivery/`)) return "Delivery";
|
|
26027
|
+
return null;
|
|
26028
|
+
}
|
|
26029
|
+
function inScope(la, scope) {
|
|
26030
|
+
if (scope.kind === "all") return true;
|
|
26031
|
+
if (scope.kind === "layer") return la.layer === scope.layer;
|
|
26032
|
+
return la.artifact.affectedModules.includes(scope.module);
|
|
26033
|
+
}
|
|
26034
|
+
function label(la) {
|
|
26035
|
+
return la.artifact.id || la.rel;
|
|
26036
|
+
}
|
|
26037
|
+
function buildConsolidationPlan(dir, opts = {}) {
|
|
26038
|
+
requireConfig(dir);
|
|
26039
|
+
const scope = opts.scope ?? { kind: "all" };
|
|
26040
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
26041
|
+
const archDir = join(dir, KNOWLEDGE7);
|
|
26042
|
+
const rawArtifacts = exists(archDir) ? readArtifacts(archDir) : [];
|
|
26043
|
+
const loaded = rawArtifacts.map((a2) => {
|
|
26044
|
+
let body = "";
|
|
26045
|
+
try {
|
|
26046
|
+
body = matter30(readFile(a2.filePath)).content;
|
|
26047
|
+
} catch {
|
|
26048
|
+
body = "";
|
|
26049
|
+
}
|
|
26050
|
+
return { artifact: a2, rel: relFromDir(dir, a2.filePath), body, layer: layerOf(a2) };
|
|
26051
|
+
});
|
|
26052
|
+
const scoped = loaded.filter((la) => inScope(la, scope));
|
|
26053
|
+
const scopedRels = new Set(scoped.map((la) => la.rel));
|
|
26054
|
+
const knownIds = new Set(loaded.map((la) => la.artifact.id).filter(Boolean));
|
|
26055
|
+
const opportunities = [];
|
|
26056
|
+
try {
|
|
26057
|
+
const config = requireConfig(dir);
|
|
26058
|
+
const graph = buildGraph(dir, config, { scope: "all" }, now);
|
|
26059
|
+
const hints = buildGraphHints(dir, graph, now);
|
|
26060
|
+
for (const hint of hints.hints) {
|
|
26061
|
+
if (!hintInScope(hint, scoped)) continue;
|
|
26062
|
+
opportunities.push(relationshipOpportunityFromHint(hint));
|
|
26063
|
+
}
|
|
26064
|
+
} catch {
|
|
26065
|
+
}
|
|
26066
|
+
for (const la of scoped) {
|
|
26067
|
+
const dangling = la.artifact.decisions.filter((d3) => d3 && !knownIds.has(d3) && !decisionFileExists(dir, d3));
|
|
26068
|
+
if (dangling.length === 0) continue;
|
|
26069
|
+
opportunities.push({
|
|
26070
|
+
id: stableOpportunityId("potentially_outdated", [label(la), ...dangling]),
|
|
26071
|
+
category: "potentially_outdated",
|
|
26072
|
+
classification: "observed",
|
|
26073
|
+
confidence: "requires-review",
|
|
26074
|
+
title: `${label(la)} references decision(s) that no longer exist`,
|
|
26075
|
+
source_artifacts: [label(la)],
|
|
26076
|
+
target_artifacts: [label(la)],
|
|
26077
|
+
evidence: dangling.map((d3) => `Declared decision \`${d3}\` has no matching artifact in the project.`),
|
|
26078
|
+
rationale: "A reference to a missing decision is a verifiable inconsistency: either the decision artifact was removed/renamed or the reference is stale.",
|
|
26079
|
+
possible_impact: "Broken traceability between a Work Item/artifact and its decisions.",
|
|
26080
|
+
suggested_action: "Review and update or remove the dangling decision reference.",
|
|
26081
|
+
requires_semantic_review: false
|
|
26082
|
+
});
|
|
26083
|
+
}
|
|
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) ?? [];
|
|
26092
|
+
arr.push(la);
|
|
26093
|
+
shingleIndex.set(key, arr);
|
|
26094
|
+
}
|
|
26095
|
+
}
|
|
26096
|
+
const candidatePairs = /* @__PURE__ */ new Map();
|
|
26097
|
+
for (const arts of shingleIndex.values()) {
|
|
26098
|
+
if (arts.length < 2) continue;
|
|
26099
|
+
for (let i = 0; i < arts.length; i++) {
|
|
26100
|
+
for (let j2 = i + 1; j2 < arts.length; j2++) {
|
|
26101
|
+
if (arts[i].rel === arts[j2].rel) continue;
|
|
26102
|
+
const key = [arts[i].rel, arts[j2].rel].sort().join("||");
|
|
26103
|
+
if (!candidatePairs.has(key)) candidatePairs.set(key, { a: arts[i], b: arts[j2] });
|
|
26104
|
+
}
|
|
26105
|
+
}
|
|
26106
|
+
}
|
|
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;
|
|
26111
|
+
opportunities.push({
|
|
26112
|
+
id: stableOpportunityId("knowledge_redundancy", [label(a2), label(b2)]),
|
|
26113
|
+
category: "knowledge_redundancy",
|
|
26114
|
+
classification: "suggested",
|
|
26115
|
+
confidence: "requires-review",
|
|
26116
|
+
title: `Possible overlapping content between ${label(a2)} and ${label(b2)}`,
|
|
26117
|
+
source_artifacts: [label(a2), label(b2)],
|
|
26118
|
+
target_artifacts: [label(a2), label(b2)],
|
|
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.",
|
|
26123
|
+
possible_impact: "If genuinely duplicated, the same fact can drift out of sync across files.",
|
|
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.",
|
|
26125
|
+
requires_semantic_review: true
|
|
26126
|
+
});
|
|
26127
|
+
}
|
|
26128
|
+
for (const la of scoped) {
|
|
26129
|
+
if (!isCompletedWorkItem(la)) continue;
|
|
26130
|
+
const learning = sectionBody(la.body, ["Learning", "Aprendizaje", "Aprendizajes", "Learnings"]);
|
|
26131
|
+
if (!learning) continue;
|
|
26132
|
+
const ruleFragment = firstRuleFragment(learning);
|
|
26133
|
+
if (!ruleFragment) continue;
|
|
26134
|
+
opportunities.push({
|
|
26135
|
+
id: stableOpportunityId("unincorporated_learning", [label(la)]),
|
|
26136
|
+
category: "unincorporated_learning",
|
|
26137
|
+
classification: "suggested",
|
|
26138
|
+
confidence: "requires-review",
|
|
26139
|
+
title: `${label(la)} captured a learning that may belong in current knowledge`,
|
|
26140
|
+
source_artifacts: [label(la)],
|
|
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.",
|
|
26145
|
+
possible_impact: "A relevant constraint stays buried in delivery history instead of informing current work.",
|
|
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.",
|
|
26147
|
+
requires_semantic_review: true
|
|
26148
|
+
});
|
|
26149
|
+
}
|
|
26150
|
+
const weakByFolder = /* @__PURE__ */ new Map();
|
|
26151
|
+
for (const la of scoped) {
|
|
26152
|
+
if (!isConsolidatableKnowledge(la)) continue;
|
|
26153
|
+
const quality = safeQuality(dir, la.rel);
|
|
26154
|
+
if (quality === "placeholder" || quality === "weak") {
|
|
26155
|
+
opportunities.push({
|
|
26156
|
+
id: stableOpportunityId("knowledge_organization", [la.rel]),
|
|
26157
|
+
category: "knowledge_organization",
|
|
26158
|
+
classification: "observed",
|
|
26159
|
+
confidence: "requires-review",
|
|
26160
|
+
title: `${label(la)} is ${quality} and may need consolidation or expansion`,
|
|
26161
|
+
source_artifacts: [label(la)],
|
|
26162
|
+
target_artifacts: [label(la)],
|
|
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.",
|
|
26165
|
+
possible_impact: "Readers must open more files to assemble a complete picture.",
|
|
26166
|
+
suggested_action: "Semantic review: decide whether to expand, merge into a stronger artifact, or cross-reference it.",
|
|
26167
|
+
requires_semantic_review: true
|
|
26168
|
+
});
|
|
26169
|
+
const folder = la.rel.split("/").slice(0, -1).join("/");
|
|
26170
|
+
const arr = weakByFolder.get(folder) ?? [];
|
|
26171
|
+
arr.push(la);
|
|
26172
|
+
weakByFolder.set(folder, arr);
|
|
26173
|
+
}
|
|
26174
|
+
}
|
|
26175
|
+
for (const [folder, arts] of weakByFolder) {
|
|
26176
|
+
if (arts.length < 3) continue;
|
|
26177
|
+
opportunities.push({
|
|
26178
|
+
id: stableOpportunityId("knowledge_fragmentation", arts.map((a2) => a2.rel)),
|
|
26179
|
+
category: "knowledge_fragmentation",
|
|
26180
|
+
classification: "suggested",
|
|
26181
|
+
confidence: "requires-review",
|
|
26182
|
+
title: `${folder}/ holds ${arts.length} low-signal canonical artifacts \u2014 possible fragmentation`,
|
|
26183
|
+
source_artifacts: arts.map((a2) => label(a2)),
|
|
26184
|
+
target_artifacts: [folder],
|
|
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.",
|
|
26187
|
+
possible_impact: "Related knowledge is spread across too many files to follow.",
|
|
26188
|
+
suggested_action: "Semantic review: evaluate whether cross-references or a consolidation would add clarity. Do not merge by file count alone.",
|
|
26189
|
+
requires_semantic_review: true
|
|
26190
|
+
});
|
|
26191
|
+
}
|
|
26192
|
+
opportunities.sort((x2, y) => {
|
|
26193
|
+
const ci = CONSOLIDATION_CATEGORIES.indexOf(x2.category) - CONSOLIDATION_CATEGORIES.indexOf(y.category);
|
|
26194
|
+
return ci !== 0 ? ci : x2.id.localeCompare(y.id);
|
|
26195
|
+
});
|
|
26196
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26197
|
+
const deduped = opportunities.filter((o2) => seen.has(o2.id) ? false : (seen.add(o2.id), true));
|
|
26198
|
+
const layers = discoverLayers(dir);
|
|
26199
|
+
const layersEvaluated = scope.kind === "layer" ? [scope.layer] : layers.map((l2) => l2.layer);
|
|
26200
|
+
const workItemsEvaluated = scoped.filter(isWorkItem).length;
|
|
26201
|
+
const sourceFiles = [...scopedRels].sort().map((rel) => ({ path: rel, hash: sha256(readFileSafe(join(dir, rel))) }));
|
|
26202
|
+
const byCategory = Object.fromEntries(
|
|
26203
|
+
CONSOLIDATION_CATEGORIES.map((c) => [c, deduped.filter((o2) => o2.category === c).length])
|
|
26204
|
+
);
|
|
26205
|
+
return {
|
|
26206
|
+
generated_at: now.toISOString(),
|
|
26207
|
+
scope: describeScope(scope),
|
|
26208
|
+
project_context: reportingProjectContext(dir),
|
|
26209
|
+
coverage: {
|
|
26210
|
+
scope: describeScope(scope),
|
|
26211
|
+
layers_evaluated: layersEvaluated,
|
|
26212
|
+
artifacts_evaluated: scoped.length,
|
|
26213
|
+
work_items_evaluated: workItemsEvaluated,
|
|
26214
|
+
excluded_sources: scope.kind === "all" ? [] : [...loaded.map((l2) => l2.rel)].filter((r2) => !scopedRels.has(r2)).sort()
|
|
26215
|
+
},
|
|
26216
|
+
source_files: sourceFiles,
|
|
26217
|
+
opportunities: deduped,
|
|
26218
|
+
summary: {
|
|
26219
|
+
total: deduped.length,
|
|
26220
|
+
by_category: byCategory,
|
|
26221
|
+
requires_semantic_review: deduped.filter((o2) => o2.requires_semantic_review).length
|
|
26222
|
+
}
|
|
26223
|
+
};
|
|
26224
|
+
}
|
|
26225
|
+
var CATEGORY_LABELS = {
|
|
26226
|
+
knowledge_redundancy: "Possible redundancy",
|
|
26227
|
+
unincorporated_learning: "Learning integration opportunity",
|
|
26228
|
+
knowledge_fragmentation: "Possible fragmentation",
|
|
26229
|
+
relationship_opportunity: "Relationship review hint",
|
|
26230
|
+
potentially_outdated: "Potential inconsistency",
|
|
26231
|
+
knowledge_organization: "Organization opportunity"
|
|
26232
|
+
};
|
|
26233
|
+
function renderConsolidationMarkdown(plan) {
|
|
26234
|
+
const lines = [];
|
|
26235
|
+
lines.push("# Knowledge Consolidation Plan");
|
|
26236
|
+
lines.push("");
|
|
26237
|
+
lines.push("> Derived, review-only projection. No canonical knowledge was modified by this analysis.");
|
|
26238
|
+
lines.push("");
|
|
26239
|
+
lines.push(`- Generated at: ${plan.generated_at}`);
|
|
26240
|
+
lines.push(`- Scope: ${plan.scope}`);
|
|
26241
|
+
lines.push(`- Project: state=${plan.project_context.state}, mode=${plan.project_context.mode}, structure=${plan.project_context.repository_structure}`);
|
|
26242
|
+
lines.push("");
|
|
26243
|
+
lines.push("## Coverage");
|
|
26244
|
+
lines.push("");
|
|
26245
|
+
lines.push(`- Layers evaluated: ${plan.coverage.layers_evaluated.join(", ") || "\u2014"}`);
|
|
26246
|
+
lines.push(`- Artifacts evaluated: ${plan.coverage.artifacts_evaluated}`);
|
|
26247
|
+
lines.push(`- Work Items evaluated: ${plan.coverage.work_items_evaluated}`);
|
|
26248
|
+
if (plan.coverage.excluded_sources.length > 0) {
|
|
26249
|
+
lines.push(`- Excluded from this scope: ${plan.coverage.excluded_sources.length} artifact(s)`);
|
|
26250
|
+
}
|
|
26251
|
+
lines.push("");
|
|
26252
|
+
lines.push("## Findings");
|
|
26253
|
+
lines.push("");
|
|
26254
|
+
if (plan.summary.total === 0) {
|
|
26255
|
+
lines.push("No consolidation opportunities were detected by the available deterministic analyses within this scope.");
|
|
26256
|
+
lines.push("");
|
|
26257
|
+
lines.push("This is not a claim that the knowledge is perfect \u2014 only that no opportunity was found with the current signals.");
|
|
26258
|
+
lines.push("");
|
|
26259
|
+
return lines.join("\n") + "\n";
|
|
26260
|
+
}
|
|
26261
|
+
for (const cat of CONSOLIDATION_CATEGORIES) {
|
|
26262
|
+
const n = plan.summary.by_category[cat];
|
|
26263
|
+
if (n > 0) lines.push(`- ${n} \xD7 ${CATEGORY_LABELS[cat]}`);
|
|
26264
|
+
}
|
|
26265
|
+
lines.push("");
|
|
26266
|
+
lines.push(`${plan.summary.requires_semantic_review} finding(s) require semantic (agent/human) review before acting.`);
|
|
26267
|
+
lines.push("");
|
|
26268
|
+
lines.push("## Opportunities");
|
|
26269
|
+
lines.push("");
|
|
26270
|
+
for (const o2 of plan.opportunities) {
|
|
26271
|
+
lines.push(`### ${o2.title}`);
|
|
26272
|
+
lines.push("");
|
|
26273
|
+
lines.push(`- Id: \`${o2.id}\``);
|
|
26274
|
+
lines.push(`- Category: ${o2.category}`);
|
|
26275
|
+
lines.push(`- Classification: **${o2.classification}**${o2.requires_semantic_review ? " (requires semantic review)" : ""}`);
|
|
26276
|
+
lines.push(`- Confidence: ${o2.confidence}`);
|
|
26277
|
+
lines.push(`- Source: ${o2.source_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
|
+
);
|
|
26281
|
+
lines.push(`- Evidence:`);
|
|
26282
|
+
for (const e of o2.evidence) lines.push(` - ${e}`);
|
|
26283
|
+
lines.push(`- Rationale: ${o2.rationale}`);
|
|
26284
|
+
lines.push(`- Possible impact: ${o2.possible_impact}`);
|
|
26285
|
+
lines.push(`- Suggested action: ${o2.suggested_action}`);
|
|
26286
|
+
lines.push("");
|
|
26287
|
+
}
|
|
26288
|
+
return lines.join("\n") + "\n";
|
|
26289
|
+
}
|
|
26290
|
+
function serializeConsolidationJson(plan) {
|
|
26291
|
+
return JSON.stringify(plan, null, 2) + "\n";
|
|
26292
|
+
}
|
|
26293
|
+
function describeScope(scope) {
|
|
26294
|
+
if (scope.kind === "all") return "all";
|
|
26295
|
+
if (scope.kind === "layer") return `layer:${scope.layer}`;
|
|
26296
|
+
return `module:${scope.module}`;
|
|
26297
|
+
}
|
|
26298
|
+
function isWorkItem(la) {
|
|
26299
|
+
return toPosix8(la.artifact.filePath).includes("/delivery/work-items/");
|
|
26300
|
+
}
|
|
26301
|
+
function isCompletedWorkItem(la) {
|
|
26302
|
+
const p = toPosix8(la.artifact.filePath);
|
|
26303
|
+
return p.includes("/delivery/work-items/completed/") || isWorkItem(la) && la.artifact.status === "completed";
|
|
26304
|
+
}
|
|
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);
|
|
26319
|
+
}
|
|
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
|
+
}
|
|
26325
|
+
var SECRET_TOKEN_PATTERNS = [
|
|
26326
|
+
/\bgh[pours]_[A-Za-z0-9]{16,}\b/g,
|
|
26327
|
+
// GitHub tokens
|
|
26328
|
+
/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
|
|
26329
|
+
// AWS access key ids
|
|
26330
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,
|
|
26331
|
+
// Slack tokens
|
|
26332
|
+
/\bsk-[A-Za-z0-9]{16,}\b/g,
|
|
26333
|
+
// OpenAI-style keys
|
|
26334
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g,
|
|
26335
|
+
// JWTs
|
|
26336
|
+
/\b[A-Za-z0-9+/]{40,}={0,2}\b/g
|
|
26337
|
+
// long base64 / opaque blobs
|
|
26338
|
+
];
|
|
26339
|
+
function redactSecrets3(text3) {
|
|
26340
|
+
let out = text3;
|
|
26341
|
+
for (const re of SECRET_TOKEN_PATTERNS) out = out.replace(re, "[redacted]");
|
|
26342
|
+
return out;
|
|
26343
|
+
}
|
|
26344
|
+
function safeQuality(dir, rel) {
|
|
26345
|
+
try {
|
|
26346
|
+
return analyzeKnowledgeArtifact(dir, rel);
|
|
26347
|
+
} catch {
|
|
26348
|
+
return "useful";
|
|
26349
|
+
}
|
|
26350
|
+
}
|
|
26351
|
+
function readFileSafe(abs) {
|
|
26352
|
+
try {
|
|
26353
|
+
return readFile(abs);
|
|
26354
|
+
} catch {
|
|
26355
|
+
return "";
|
|
26356
|
+
}
|
|
26357
|
+
}
|
|
26358
|
+
function decisionFileExists(dir, decisionId) {
|
|
26359
|
+
const decisionsDir = join(dir, KNOWLEDGE7, "tech", "decisions");
|
|
26360
|
+
if (!exists(decisionsDir)) return false;
|
|
26361
|
+
try {
|
|
26362
|
+
return readDir(decisionsDir).some((e) => {
|
|
26363
|
+
const full = join(decisionsDir, e);
|
|
26364
|
+
if (!isFile(full) || !e.endsWith(".md")) return false;
|
|
26365
|
+
return e.toLowerCase().includes(decisionId.toLowerCase());
|
|
26366
|
+
});
|
|
26367
|
+
} catch {
|
|
26368
|
+
return false;
|
|
26369
|
+
}
|
|
26370
|
+
}
|
|
26371
|
+
function hintInScope(hint, scoped) {
|
|
26372
|
+
if (scoped.length === 0) return false;
|
|
26373
|
+
return scoped.some(
|
|
26374
|
+
(la) => la.artifact.id === hint.artifact_id || hint.path && toPosix8(la.artifact.filePath).endsWith(toPosix8(hint.path))
|
|
26375
|
+
);
|
|
26376
|
+
}
|
|
26377
|
+
function relationshipOpportunityFromHint(hint) {
|
|
26378
|
+
const finding = graphHintFinding(hint);
|
|
26379
|
+
return {
|
|
26380
|
+
id: stableOpportunityId("relationship_opportunity", [hint.artifact_id, ...hint.missing]),
|
|
26381
|
+
category: "relationship_opportunity",
|
|
26382
|
+
classification: "observed",
|
|
26383
|
+
confidence: "requires-review",
|
|
26384
|
+
title: hint.message,
|
|
26385
|
+
source_artifacts: [hint.artifact_id],
|
|
26386
|
+
target_artifacts: [hint.artifact_id],
|
|
26387
|
+
evidence: [finding.evidence],
|
|
26388
|
+
rationale: "A missing OPTIONAL relationship is an opportunity to review, not an error or a verified inconsistency. Kaddo never invents the relationship.",
|
|
26389
|
+
possible_impact: "Weaker traceability in the knowledge graph.",
|
|
26390
|
+
suggested_action: finding.suggested_action,
|
|
26391
|
+
requires_semantic_review: false
|
|
26392
|
+
};
|
|
26393
|
+
}
|
|
26394
|
+
|
|
25548
26395
|
// src/generate.ts
|
|
25549
|
-
function
|
|
26396
|
+
function requireConfig2(root) {
|
|
25550
26397
|
const config = loadConfig(root);
|
|
25551
26398
|
if (!config) throw new KaddoMcpError("Kaddo project not found. Run `kaddo init` first.");
|
|
25552
26399
|
return config;
|
|
@@ -25560,7 +26407,7 @@ function slug6(s) {
|
|
|
25560
26407
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
|
|
25561
26408
|
}
|
|
25562
26409
|
function generateContext(root) {
|
|
25563
|
-
const config =
|
|
26410
|
+
const config = requireConfig2(root);
|
|
25564
26411
|
requireKnowledge(root);
|
|
25565
26412
|
const pack = buildContextPack(root, config);
|
|
25566
26413
|
writeDerived(root, ".kaddo/context-pack.md", renderContextPack(pack));
|
|
@@ -25574,7 +26421,7 @@ function generateContext(root) {
|
|
|
25574
26421
|
};
|
|
25575
26422
|
}
|
|
25576
26423
|
function generateExplain(root) {
|
|
25577
|
-
|
|
26424
|
+
requireConfig2(root);
|
|
25578
26425
|
requireKnowledge(root);
|
|
25579
26426
|
const exp = buildProjectExplanation(root);
|
|
25580
26427
|
writeDerived(root, ".kaddo/explain.md", renderExplanationHuman(exp));
|
|
@@ -25588,7 +26435,7 @@ function generateExplain(root) {
|
|
|
25588
26435
|
};
|
|
25589
26436
|
}
|
|
25590
26437
|
function generateUnderstand(root) {
|
|
25591
|
-
const config =
|
|
26438
|
+
const config = requireConfig2(root);
|
|
25592
26439
|
requireKnowledge(root);
|
|
25593
26440
|
const plan = buildUnderstandPlan(root, config);
|
|
25594
26441
|
writeDerived(root, ".kaddo/understand.md", renderUnderstand(plan));
|
|
@@ -25601,7 +26448,7 @@ function generateUnderstand(root) {
|
|
|
25601
26448
|
};
|
|
25602
26449
|
}
|
|
25603
26450
|
function generateGraph(root, scope = "active") {
|
|
25604
|
-
const config =
|
|
26451
|
+
const config = requireConfig2(root);
|
|
25605
26452
|
requireKnowledge(root);
|
|
25606
26453
|
const graph = buildGraph(root, config, { scope });
|
|
25607
26454
|
const hints = buildGraphHints(root, graph);
|
|
@@ -25623,8 +26470,39 @@ function generateGraph(root, scope = "active") {
|
|
|
25623
26470
|
next_suggested_resources: ["kaddo://graph", "kaddo://graph-hints"]
|
|
25624
26471
|
};
|
|
25625
26472
|
}
|
|
26473
|
+
var LAYER_BY_FLAG = {
|
|
26474
|
+
business: "Business",
|
|
26475
|
+
product: "Product",
|
|
26476
|
+
tech: "Tech",
|
|
26477
|
+
delivery: "Delivery"
|
|
26478
|
+
};
|
|
26479
|
+
function generateConsolidationPlan(root, opts = {}) {
|
|
26480
|
+
requireConfig2(root);
|
|
26481
|
+
requireKnowledge(root);
|
|
26482
|
+
let scope = { kind: "all" };
|
|
26483
|
+
if (opts.module) {
|
|
26484
|
+
scope = { kind: "module", module: opts.module };
|
|
26485
|
+
} else if (opts.layer) {
|
|
26486
|
+
const layer2 = LAYER_BY_FLAG[opts.layer.toLowerCase()];
|
|
26487
|
+
if (!layer2) {
|
|
26488
|
+
throw new KaddoMcpError(`Unknown layer "${opts.layer}". Use one of: business, product, tech, delivery.`);
|
|
26489
|
+
}
|
|
26490
|
+
scope = { kind: "layer", layer: layer2 };
|
|
26491
|
+
}
|
|
26492
|
+
const plan = buildConsolidationPlan(root, { scope });
|
|
26493
|
+
writeDerived(root, ".kaddo/consolidation-plan.md", renderConsolidationMarkdown(plan));
|
|
26494
|
+
writeDerived(root, ".kaddo/consolidation-plan.json", serializeConsolidationJson(plan));
|
|
26495
|
+
const warnings = plan.summary.requires_semantic_review > 0 ? [`${plan.summary.requires_semantic_review} finding(s) require semantic review before acting \u2014 nothing was changed automatically.`] : [];
|
|
26496
|
+
return {
|
|
26497
|
+
status: "ok",
|
|
26498
|
+
files_written: [".kaddo/consolidation-plan.md", ".kaddo/consolidation-plan.json"],
|
|
26499
|
+
summary: `Consolidation Plan generated (scope: ${plan.scope}, ${plan.summary.total} opportunity/opportunities).`,
|
|
26500
|
+
warnings,
|
|
26501
|
+
next_suggested_resources: ["kaddo://consolidation-plan"]
|
|
26502
|
+
};
|
|
26503
|
+
}
|
|
25626
26504
|
function generateImpactReport(root, opts = {}) {
|
|
25627
|
-
|
|
26505
|
+
requireConfig2(root);
|
|
25628
26506
|
requireKnowledge(root);
|
|
25629
26507
|
const format = opts.format ?? "markdown";
|
|
25630
26508
|
const report = buildImpactReport(root, { scope: opts.scope ?? "all", scopeSource: opts.scope ? "explicit" : "default" });
|
|
@@ -25640,7 +26518,7 @@ function generateImpactReport(root, opts = {}) {
|
|
|
25640
26518
|
};
|
|
25641
26519
|
}
|
|
25642
26520
|
function generateSavingsReport(root, opts = {}) {
|
|
25643
|
-
|
|
26521
|
+
requireConfig2(root);
|
|
25644
26522
|
requireKnowledge(root);
|
|
25645
26523
|
const format = opts.format ?? "markdown";
|
|
25646
26524
|
const report = buildSavingsReport(root, { scope: opts.scope ?? "all", scopeSource: opts.scope ? "explicit" : "default" });
|
|
@@ -25656,7 +26534,7 @@ function generateSavingsReport(root, opts = {}) {
|
|
|
25656
26534
|
};
|
|
25657
26535
|
}
|
|
25658
26536
|
function generateDriftReport(root, opts = {}) {
|
|
25659
|
-
|
|
26537
|
+
requireConfig2(root);
|
|
25660
26538
|
const format = opts.format ?? "markdown";
|
|
25661
26539
|
const report = buildDriftReport(root);
|
|
25662
26540
|
const content = format === "json" ? serializeDriftJson(report) : renderDriftMarkdown(report);
|
|
@@ -25671,7 +26549,7 @@ function generateDriftReport(root, opts = {}) {
|
|
|
25671
26549
|
};
|
|
25672
26550
|
}
|
|
25673
26551
|
function generateQuestionsReport(root, opts = {}) {
|
|
25674
|
-
|
|
26552
|
+
requireConfig2(root);
|
|
25675
26553
|
const format = opts.format ?? "markdown";
|
|
25676
26554
|
const report = buildOpenQuestionsReport(root);
|
|
25677
26555
|
const content = format === "json" ? serializeOpenQuestionsJson(report) : renderOpenQuestionsMarkdown(report);
|
|
@@ -25686,7 +26564,7 @@ function generateQuestionsReport(root, opts = {}) {
|
|
|
25686
26564
|
};
|
|
25687
26565
|
}
|
|
25688
26566
|
function generateCapsuleDraft(root) {
|
|
25689
|
-
const config =
|
|
26567
|
+
const config = requireConfig2(root);
|
|
25690
26568
|
requireKnowledge(root);
|
|
25691
26569
|
const capsule = buildCapsule(root, config);
|
|
25692
26570
|
const name = slug6(config.project.name);
|
|
@@ -25906,13 +26784,13 @@ async function guardedAsync(root, fn) {
|
|
|
25906
26784
|
throw err;
|
|
25907
26785
|
}
|
|
25908
26786
|
}
|
|
25909
|
-
function generated(root,
|
|
26787
|
+
function generated(root, label2, fn) {
|
|
25910
26788
|
try {
|
|
25911
26789
|
assertKaddoProject(root);
|
|
25912
26790
|
const result = fn();
|
|
25913
26791
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25914
26792
|
} catch (err) {
|
|
25915
|
-
const message = err instanceof KaddoMcpError ? err.message : `Could not ${
|
|
26793
|
+
const message = err instanceof KaddoMcpError ? err.message : `Could not ${label2}. ${String(err)}`;
|
|
25916
26794
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
25917
26795
|
}
|
|
25918
26796
|
}
|
|
@@ -26613,6 +27491,19 @@ function createServer(root) {
|
|
|
26613
27491
|
},
|
|
26614
27492
|
async (args) => generated(root, "generate knowledge graph", () => generateGraph(root, args.scope ?? "active"))
|
|
26615
27493
|
);
|
|
27494
|
+
server.registerTool(
|
|
27495
|
+
"kaddo_generate_consolidation_plan",
|
|
27496
|
+
{
|
|
27497
|
+
title: "Generate knowledge consolidation plan",
|
|
27498
|
+
description: `Analyze canonical knowledge and write .kaddo/consolidation-plan.md/.json \u2014 a reviewable projection of consolidation opportunities (redundancy, unincorporated learning, fragmentation, relationships, potential inconsistencies, organization). Deterministic: facts are "observed"; anything needing judgement is a "suggested" candidate flagged for semantic review. Optional layer (business|product|tech|delivery) or module scope. ${DERIVED_NOTE}`,
|
|
27499
|
+
inputSchema: { layer: z4.string().optional(), module: z4.string().optional() }
|
|
27500
|
+
},
|
|
27501
|
+
async (args) => generated(
|
|
27502
|
+
root,
|
|
27503
|
+
"generate consolidation plan",
|
|
27504
|
+
() => generateConsolidationPlan(root, { layer: args.layer, module: args.module })
|
|
27505
|
+
)
|
|
27506
|
+
);
|
|
26616
27507
|
server.registerTool(
|
|
26617
27508
|
"kaddo_generate_impact_report",
|
|
26618
27509
|
{
|