@kaddo/mcp 3.127.0 → 3.129.0
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 +1083 -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
|
}
|
|
@@ -2619,6 +2636,29 @@ var RESOURCE_TYPES = [
|
|
|
2619
2636
|
"other"
|
|
2620
2637
|
];
|
|
2621
2638
|
var INTERFACE_TYPES = ["cli", "mcp", "api", "sql", "sdk", "iac", "console", "other"];
|
|
2639
|
+
var REDACTED_COORDINATE = "\u2022\u2022\u2022\u2022 (hidden \u2014 store as an authentication reference)";
|
|
2640
|
+
var SECRET_KEY_RE = /(pass(word|phrase)?|secret|token|api[_-]?key|\bkey\b|credential|private|auth[_-]?token|access[_-]?key)/i;
|
|
2641
|
+
var SECRET_VALUE_PATTERNS = [
|
|
2642
|
+
/\b(AKIA|ASIA)[A-Z0-9]{8,}/,
|
|
2643
|
+
// AWS access key id
|
|
2644
|
+
/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}/,
|
|
2645
|
+
// GitHub tokens
|
|
2646
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}/,
|
|
2647
|
+
// Slack tokens
|
|
2648
|
+
/\bsk-[A-Za-z0-9]{16,}/,
|
|
2649
|
+
// OpenAI-style secret keys
|
|
2650
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\./,
|
|
2651
|
+
// JWT
|
|
2652
|
+
/\w+=[^;\s]{6,}/,
|
|
2653
|
+
// key=value credential fragments
|
|
2654
|
+
/^[A-Za-z0-9+/]{40,}={0,2}$/
|
|
2655
|
+
// long opaque base64 blob
|
|
2656
|
+
];
|
|
2657
|
+
function looksLikeSecretCoordinate(key, value) {
|
|
2658
|
+
if (SECRET_KEY_RE.test(key)) return true;
|
|
2659
|
+
const v = value.trim();
|
|
2660
|
+
return SECRET_VALUE_PATTERNS.some((re) => re.test(v));
|
|
2661
|
+
}
|
|
2622
2662
|
function str(v) {
|
|
2623
2663
|
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
2624
2664
|
}
|
|
@@ -2647,6 +2687,29 @@ function parseInterfaces(v) {
|
|
|
2647
2687
|
}
|
|
2648
2688
|
return out;
|
|
2649
2689
|
}
|
|
2690
|
+
function parseConnectionProfiles(v) {
|
|
2691
|
+
if (!Array.isArray(v)) return [];
|
|
2692
|
+
const out = [];
|
|
2693
|
+
for (const raw of v) {
|
|
2694
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
2695
|
+
const o2 = raw;
|
|
2696
|
+
const coords = [];
|
|
2697
|
+
const rawCoords = o2.coordinates;
|
|
2698
|
+
if (rawCoords && typeof rawCoords === "object" && !Array.isArray(rawCoords)) {
|
|
2699
|
+
for (const [key, val] of Object.entries(rawCoords)) {
|
|
2700
|
+
const k2 = key.trim();
|
|
2701
|
+
const value = val == null ? "" : String(val).trim();
|
|
2702
|
+
if (!k2 || !value) continue;
|
|
2703
|
+
coords.push({ key: k2, value: looksLikeSecretCoordinate(k2, value) ? REDACTED_COORDINATE : value });
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
const environment = str(o2.environment);
|
|
2707
|
+
const iface = str(o2.interface);
|
|
2708
|
+
if (!environment && !iface && coords.length === 0) continue;
|
|
2709
|
+
out.push({ environment, interface: iface, coordinates: coords });
|
|
2710
|
+
}
|
|
2711
|
+
return out;
|
|
2712
|
+
}
|
|
2650
2713
|
function parseBoundaries(v) {
|
|
2651
2714
|
if (!v || typeof v !== "object" || Array.isArray(v)) return {};
|
|
2652
2715
|
const out = {};
|
|
@@ -2695,6 +2758,7 @@ function toDetail(filePath, relPath, raw) {
|
|
|
2695
2758
|
const a2 = parseAuth(fm.authentication);
|
|
2696
2759
|
return { authRefs: a2.refs, authMode: a2.mode };
|
|
2697
2760
|
})(),
|
|
2761
|
+
connectionProfiles: parseConnectionProfiles(fm.connection_profiles),
|
|
2698
2762
|
markdownBody: body
|
|
2699
2763
|
};
|
|
2700
2764
|
}
|
|
@@ -4500,7 +4564,8 @@ var AGENT_GROUPS = {
|
|
|
4500
4564
|
"work-item-agent.md",
|
|
4501
4565
|
"implementation-agent.md",
|
|
4502
4566
|
"ownership-agent.md",
|
|
4503
|
-
"git-strategy-agent.md"
|
|
4567
|
+
"git-strategy-agent.md",
|
|
4568
|
+
"knowledge-consolidation-agent.md"
|
|
4504
4569
|
],
|
|
4505
4570
|
utilities: ["legacy-agent.md"]
|
|
4506
4571
|
};
|
|
@@ -5179,7 +5244,7 @@ var KNOWLEDGE_FILES = [
|
|
|
5179
5244
|
function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
5180
5245
|
const config = loadConfig(dir);
|
|
5181
5246
|
const rec = resolveNextStep(dir, now);
|
|
5182
|
-
const stub = (overall2,
|
|
5247
|
+
const stub = (overall2, label2, command) => ({
|
|
5183
5248
|
project_name: config?.project.name ?? "unknown",
|
|
5184
5249
|
project_type: config?.project.state ?? "unknown",
|
|
5185
5250
|
overall: overall2,
|
|
@@ -5202,7 +5267,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
5202
5267
|
resolved_questions: 0,
|
|
5203
5268
|
deferred_questions: 0
|
|
5204
5269
|
},
|
|
5205
|
-
recommended_next_step: { label, ...command ? { command } : {} },
|
|
5270
|
+
recommended_next_step: { label: label2, ...command ? { command } : {} },
|
|
5206
5271
|
nextStepRecommendation: rec
|
|
5207
5272
|
});
|
|
5208
5273
|
if (!config) return stub("not-initialized", rec.label, rec.command);
|
|
@@ -6077,6 +6142,69 @@ After a POC has a canonical conclusion and Core has prepared its deterministic r
|
|
|
6077
6142
|
15. Traceability and Sources
|
|
6078
6143
|
`
|
|
6079
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
|
+
);
|
|
6080
6208
|
var SKILLS = [
|
|
6081
6209
|
ADR_WRITING,
|
|
6082
6210
|
WORK_ITEM_REFINEMENT,
|
|
@@ -6088,10 +6216,11 @@ var SKILLS = [
|
|
|
6088
6216
|
MODULE_CONTEXT_REFINEMENT,
|
|
6089
6217
|
EVIDENCE_VERIFICATION,
|
|
6090
6218
|
LEGACY_RISK_ASSESSMENT,
|
|
6091
|
-
POC_REPORT_WRITING
|
|
6219
|
+
POC_REPORT_WRITING,
|
|
6220
|
+
KNOWLEDGE_CONSOLIDATION
|
|
6092
6221
|
];
|
|
6093
6222
|
var SKILL_GROUPS = {
|
|
6094
|
-
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"],
|
|
6095
6224
|
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
6096
6225
|
integration: ["capsule-writing"]
|
|
6097
6226
|
};
|
|
@@ -6287,6 +6416,24 @@ var RESPONSIBILITY_MATRIX = {
|
|
|
6287
6416
|
],
|
|
6288
6417
|
next: ["kaddo graph export"]
|
|
6289
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
|
+
},
|
|
6290
6437
|
"ownership-agent": {
|
|
6291
6438
|
agent: "ownership-agent",
|
|
6292
6439
|
responsibleFor: ["Precise code: ownership for Work Items and artifacts"],
|
|
@@ -8447,6 +8594,78 @@ ADRs) and re-runs \`kaddo graph export\`.
|
|
|
8447
8594
|
- No files were modified; no Git was run.
|
|
8448
8595
|
- The human is asked to confirm and re-export the graph.
|
|
8449
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
|
+
`;
|
|
8450
8669
|
var AGENT_PROMPTS = [
|
|
8451
8670
|
{ fileName: "capability-agent.md", content: CAPABILITY_AGENT },
|
|
8452
8671
|
{ fileName: "architecture-agent.md", content: ARCHITECTURE_AGENT },
|
|
@@ -8473,7 +8692,9 @@ var AGENT_PROMPTS = [
|
|
|
8473
8692
|
// Knowledge Capsule refinement (external context — VS-054)
|
|
8474
8693
|
{ fileName: "capsule-agent.md", content: CAPSULE_AGENT },
|
|
8475
8694
|
// Graph relationship quality (metadata hints → precise front matter — VS-056)
|
|
8476
|
-
{ 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 }
|
|
8477
8698
|
// Every official prompt ends with its responsibility boundaries + Agent Trace footer.
|
|
8478
8699
|
].map((p) => ({ fileName: p.fileName, content: withResponsibilityTrace(p.fileName, p.content) }));
|
|
8479
8700
|
|
|
@@ -8680,9 +8901,9 @@ function installedAssetsSummary(dir) {
|
|
|
8680
8901
|
// ../cli/src/core/roadmap-quality.ts
|
|
8681
8902
|
var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
8682
8903
|
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
8683
|
-
function fieldPresent(lines,
|
|
8904
|
+
function fieldPresent(lines, label2) {
|
|
8684
8905
|
for (let i = 0; i < lines.length; i++) {
|
|
8685
|
-
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"));
|
|
8686
8907
|
if (!m2) continue;
|
|
8687
8908
|
const inline = m2[2].trim();
|
|
8688
8909
|
if (inline) return true;
|
|
@@ -8784,13 +9005,13 @@ function renderSignalsCompact(signals) {
|
|
|
8784
9005
|
["external_integrations", "External integrations"],
|
|
8785
9006
|
["environment", "Environment"]
|
|
8786
9007
|
];
|
|
8787
|
-
for (const [key,
|
|
9008
|
+
for (const [key, label2] of CATEGORIES) {
|
|
8788
9009
|
const arr = signals[key];
|
|
8789
9010
|
if (arr.length === 0) continue;
|
|
8790
9011
|
if (arr.length === 1) {
|
|
8791
|
-
lines.push(`- ${
|
|
9012
|
+
lines.push(`- ${label2}: ${arr[0].label}`);
|
|
8792
9013
|
} else {
|
|
8793
|
-
lines.push(`- ${
|
|
9014
|
+
lines.push(`- ${label2}: ${arr.length}`);
|
|
8794
9015
|
}
|
|
8795
9016
|
}
|
|
8796
9017
|
return lines.length > 0 ? lines.join("\n") + "\n" : "No signals detected.\n";
|
|
@@ -10988,9 +11209,9 @@ function renderImpactMarkdown(r2, opts = {}) {
|
|
|
10988
11209
|
["validation section", gp.missing_validation]
|
|
10989
11210
|
];
|
|
10990
11211
|
L.push("## Historical Documentation Completeness", "");
|
|
10991
|
-
for (const [
|
|
11212
|
+
for (const [label2, items] of historical) {
|
|
10992
11213
|
const completed = items.filter((item) => item.status === "completed");
|
|
10993
|
-
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}`);
|
|
10994
11215
|
}
|
|
10995
11216
|
if (!historical.some(([, items]) => items.some((item) => item.status === "completed"))) {
|
|
10996
11217
|
L.push("No historical documentation completeness gaps were detected.");
|
|
@@ -11765,6 +11986,27 @@ var RESOURCES = [
|
|
|
11765
11986
|
return parts;
|
|
11766
11987
|
}
|
|
11767
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
|
+
},
|
|
11768
12010
|
{
|
|
11769
12011
|
uri: "kaddo://build-contract",
|
|
11770
12012
|
name: "Kaddo build contract",
|
|
@@ -12121,7 +12363,7 @@ function getPrompt(root, name) {
|
|
|
12121
12363
|
}
|
|
12122
12364
|
|
|
12123
12365
|
// src/tools.ts
|
|
12124
|
-
import
|
|
12366
|
+
import matter25 from "gray-matter";
|
|
12125
12367
|
|
|
12126
12368
|
// ../cli/dist/core.js
|
|
12127
12369
|
import fs3 from "fs";
|
|
@@ -12151,22 +12393,23 @@ import matter102 from "gray-matter";
|
|
|
12151
12393
|
import { parse as parseYaml82 } from "yaml";
|
|
12152
12394
|
import matter112 from "gray-matter";
|
|
12153
12395
|
import matter122 from "gray-matter";
|
|
12396
|
+
import matter132 from "gray-matter";
|
|
12154
12397
|
import { parse as parseYaml92, stringify as stringifyYaml52 } from "yaml";
|
|
12155
12398
|
import fs4 from "fs";
|
|
12156
12399
|
import path4 from "path";
|
|
12157
12400
|
import crypto2 from "crypto";
|
|
12158
|
-
import
|
|
12401
|
+
import matter142 from "gray-matter";
|
|
12159
12402
|
import crypto3 from "crypto";
|
|
12160
12403
|
import fs5 from "fs";
|
|
12161
|
-
import matter142 from "gray-matter";
|
|
12162
12404
|
import matter15 from "gray-matter";
|
|
12405
|
+
import matter16 from "gray-matter";
|
|
12163
12406
|
import { parse as parseYaml102, stringify as stringifyYaml6 } from "yaml";
|
|
12164
12407
|
import { parse as parseYaml11, stringify as stringifyYaml7 } from "yaml";
|
|
12165
|
-
import matter16 from "gray-matter";
|
|
12166
12408
|
import matter17 from "gray-matter";
|
|
12167
12409
|
import matter18 from "gray-matter";
|
|
12168
12410
|
import matter19 from "gray-matter";
|
|
12169
12411
|
import matter20 from "gray-matter";
|
|
12412
|
+
import matter21 from "gray-matter";
|
|
12170
12413
|
function exists2(p) {
|
|
12171
12414
|
return fs3.existsSync(p);
|
|
12172
12415
|
}
|
|
@@ -13897,6 +14140,29 @@ function suggestInitiativesForExternalItem(dir, integration, externalId) {
|
|
|
13897
14140
|
);
|
|
13898
14141
|
}
|
|
13899
14142
|
var RESOURCE_ARTIFACT_TYPE2 = "project-resource";
|
|
14143
|
+
var REDACTED_COORDINATE2 = "\u2022\u2022\u2022\u2022 (hidden \u2014 store as an authentication reference)";
|
|
14144
|
+
var SECRET_KEY_RE2 = /(pass(word|phrase)?|secret|token|api[_-]?key|\bkey\b|credential|private|auth[_-]?token|access[_-]?key)/i;
|
|
14145
|
+
var SECRET_VALUE_PATTERNS2 = [
|
|
14146
|
+
/\b(AKIA|ASIA)[A-Z0-9]{8,}/,
|
|
14147
|
+
// AWS access key id
|
|
14148
|
+
/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}/,
|
|
14149
|
+
// GitHub tokens
|
|
14150
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}/,
|
|
14151
|
+
// Slack tokens
|
|
14152
|
+
/\bsk-[A-Za-z0-9]{16,}/,
|
|
14153
|
+
// OpenAI-style secret keys
|
|
14154
|
+
/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\./,
|
|
14155
|
+
// JWT
|
|
14156
|
+
/\w+=[^;\s]{6,}/,
|
|
14157
|
+
// key=value credential fragments
|
|
14158
|
+
/^[A-Za-z0-9+/]{40,}={0,2}$/
|
|
14159
|
+
// long opaque base64 blob
|
|
14160
|
+
];
|
|
14161
|
+
function looksLikeSecretCoordinate2(key, value) {
|
|
14162
|
+
if (SECRET_KEY_RE2.test(key)) return true;
|
|
14163
|
+
const v = value.trim();
|
|
14164
|
+
return SECRET_VALUE_PATTERNS2.some((re) => re.test(v));
|
|
14165
|
+
}
|
|
13900
14166
|
function str3(v) {
|
|
13901
14167
|
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
13902
14168
|
}
|
|
@@ -13925,6 +14191,29 @@ function parseInterfaces2(v) {
|
|
|
13925
14191
|
}
|
|
13926
14192
|
return out;
|
|
13927
14193
|
}
|
|
14194
|
+
function parseConnectionProfiles2(v) {
|
|
14195
|
+
if (!Array.isArray(v)) return [];
|
|
14196
|
+
const out = [];
|
|
14197
|
+
for (const raw of v) {
|
|
14198
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
14199
|
+
const o2 = raw;
|
|
14200
|
+
const coords = [];
|
|
14201
|
+
const rawCoords = o2.coordinates;
|
|
14202
|
+
if (rawCoords && typeof rawCoords === "object" && !Array.isArray(rawCoords)) {
|
|
14203
|
+
for (const [key, val] of Object.entries(rawCoords)) {
|
|
14204
|
+
const k2 = key.trim();
|
|
14205
|
+
const value = val == null ? "" : String(val).trim();
|
|
14206
|
+
if (!k2 || !value) continue;
|
|
14207
|
+
coords.push({ key: k2, value: looksLikeSecretCoordinate2(k2, value) ? REDACTED_COORDINATE2 : value });
|
|
14208
|
+
}
|
|
14209
|
+
}
|
|
14210
|
+
const environment = str3(o2.environment);
|
|
14211
|
+
const iface = str3(o2.interface);
|
|
14212
|
+
if (!environment && !iface && coords.length === 0) continue;
|
|
14213
|
+
out.push({ environment, interface: iface, coordinates: coords });
|
|
14214
|
+
}
|
|
14215
|
+
return out;
|
|
14216
|
+
}
|
|
13928
14217
|
function parseBoundaries2(v) {
|
|
13929
14218
|
if (!v || typeof v !== "object" || Array.isArray(v)) return {};
|
|
13930
14219
|
const out = {};
|
|
@@ -13973,6 +14262,7 @@ function toDetail2(filePath, relPath, raw) {
|
|
|
13973
14262
|
const a2 = parseAuth2(fm.authentication);
|
|
13974
14263
|
return { authRefs: a2.refs, authMode: a2.mode };
|
|
13975
14264
|
})(),
|
|
14265
|
+
connectionProfiles: parseConnectionProfiles2(fm.connection_profiles),
|
|
13976
14266
|
markdownBody: body
|
|
13977
14267
|
};
|
|
13978
14268
|
}
|
|
@@ -14594,7 +14884,8 @@ var AGENT_GROUPS2 = {
|
|
|
14594
14884
|
"work-item-agent.md",
|
|
14595
14885
|
"implementation-agent.md",
|
|
14596
14886
|
"ownership-agent.md",
|
|
14597
|
-
"git-strategy-agent.md"
|
|
14887
|
+
"git-strategy-agent.md",
|
|
14888
|
+
"knowledge-consolidation-agent.md"
|
|
14598
14889
|
],
|
|
14599
14890
|
utilities: ["legacy-agent.md"]
|
|
14600
14891
|
};
|
|
@@ -15624,6 +15915,69 @@ After a POC has a canonical conclusion and Core has prepared its deterministic r
|
|
|
15624
15915
|
15. Traceability and Sources
|
|
15625
15916
|
`
|
|
15626
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
|
+
);
|
|
15627
15981
|
var SKILLS2 = [
|
|
15628
15982
|
ADR_WRITING2,
|
|
15629
15983
|
WORK_ITEM_REFINEMENT2,
|
|
@@ -15635,10 +15989,11 @@ var SKILLS2 = [
|
|
|
15635
15989
|
MODULE_CONTEXT_REFINEMENT2,
|
|
15636
15990
|
EVIDENCE_VERIFICATION2,
|
|
15637
15991
|
LEGACY_RISK_ASSESSMENT2,
|
|
15638
|
-
POC_REPORT_WRITING2
|
|
15992
|
+
POC_REPORT_WRITING2,
|
|
15993
|
+
KNOWLEDGE_CONSOLIDATION2
|
|
15639
15994
|
];
|
|
15640
15995
|
var SKILL_GROUPS2 = {
|
|
15641
|
-
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"],
|
|
15642
15997
|
tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review", "module-context-refinement"],
|
|
15643
15998
|
integration: ["capsule-writing"]
|
|
15644
15999
|
};
|
|
@@ -15829,6 +16184,24 @@ var RESPONSIBILITY_MATRIX2 = {
|
|
|
15829
16184
|
],
|
|
15830
16185
|
next: ["kaddo graph export"]
|
|
15831
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
|
+
},
|
|
15832
16205
|
"ownership-agent": {
|
|
15833
16206
|
agent: "ownership-agent",
|
|
15834
16207
|
responsibleFor: ["Precise code: ownership for Work Items and artifacts"],
|
|
@@ -17987,6 +18360,78 @@ ADRs) and re-runs \`kaddo graph export\`.
|
|
|
17987
18360
|
- No files were modified; no Git was run.
|
|
17988
18361
|
- The human is asked to confirm and re-export the graph.
|
|
17989
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
|
+
`;
|
|
17990
18435
|
var AGENT_PROMPTS2 = [
|
|
17991
18436
|
{ fileName: "capability-agent.md", content: CAPABILITY_AGENT2 },
|
|
17992
18437
|
{ fileName: "architecture-agent.md", content: ARCHITECTURE_AGENT2 },
|
|
@@ -18013,7 +18458,9 @@ var AGENT_PROMPTS2 = [
|
|
|
18013
18458
|
// Knowledge Capsule refinement (external context — VS-054)
|
|
18014
18459
|
{ fileName: "capsule-agent.md", content: CAPSULE_AGENT2 },
|
|
18015
18460
|
// Graph relationship quality (metadata hints → precise front matter — VS-056)
|
|
18016
|
-
{ 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 }
|
|
18017
18464
|
// Every official prompt ends with its responsibility boundaries + Agent Trace footer.
|
|
18018
18465
|
].map((p) => ({ fileName: p.fileName, content: withResponsibilityTrace2(p.fileName, p.content) }));
|
|
18019
18466
|
function withAgentFrontMatter2(fileName, content) {
|
|
@@ -18891,7 +19338,7 @@ function parseOriginalSnapshot(fm) {
|
|
|
18891
19338
|
function readBody(filePath) {
|
|
18892
19339
|
try {
|
|
18893
19340
|
const raw = readFile2(filePath);
|
|
18894
|
-
return
|
|
19341
|
+
return matter132(raw).content;
|
|
18895
19342
|
} catch {
|
|
18896
19343
|
return "";
|
|
18897
19344
|
}
|
|
@@ -19176,7 +19623,7 @@ function ensureH1(body, title) {
|
|
|
19176
19623
|
${trimmed}`;
|
|
19177
19624
|
}
|
|
19178
19625
|
function serialize2(data, body) {
|
|
19179
|
-
return
|
|
19626
|
+
return matter142.stringify(`
|
|
19180
19627
|
${body.trim()}
|
|
19181
19628
|
`, data);
|
|
19182
19629
|
}
|
|
@@ -20090,7 +20537,7 @@ function detectFormat(raw) {
|
|
|
20090
20537
|
if (!trimmed) throw new ImportError("EMPTY_INPUT", "Import content is empty.");
|
|
20091
20538
|
if (trimmed.startsWith("---")) {
|
|
20092
20539
|
try {
|
|
20093
|
-
const { data } =
|
|
20540
|
+
const { data } = matter15(trimmed);
|
|
20094
20541
|
if (data && typeof data === "object" && Object.keys(data).length > 0) {
|
|
20095
20542
|
const d3 = data;
|
|
20096
20543
|
if (d3.type === "work-item" || d3.id && typeof d3.id === "string" && /^WI-\d+/.test(d3.id)) {
|
|
@@ -20112,7 +20559,7 @@ function parseContent(raw) {
|
|
|
20112
20559
|
let bodyText = trimmed;
|
|
20113
20560
|
if (format === "kaddo-frontmatter" || format === "markdown-frontmatter") {
|
|
20114
20561
|
try {
|
|
20115
|
-
const parsed =
|
|
20562
|
+
const parsed = matter15(trimmed);
|
|
20116
20563
|
frontmatterFields = parsed.data ?? {};
|
|
20117
20564
|
bodyText = parsed.content.trim();
|
|
20118
20565
|
} catch {
|
|
@@ -20209,7 +20656,7 @@ function findDuplicateByHash(dir, hash) {
|
|
|
20209
20656
|
const raw = readFile2(item.filePath);
|
|
20210
20657
|
if (!raw) continue;
|
|
20211
20658
|
try {
|
|
20212
|
-
const { data } =
|
|
20659
|
+
const { data } = matter15(raw);
|
|
20213
20660
|
const source22 = data?.source;
|
|
20214
20661
|
if (source22 && typeof source22 === "object" && !Array.isArray(source22)) {
|
|
20215
20662
|
const s = source22;
|
|
@@ -21104,7 +21551,7 @@ function buildInitiativeContent(id, input) {
|
|
|
21104
21551
|
if (input.priority) data.priority = input.priority;
|
|
21105
21552
|
if (input.source) data.source = input.source;
|
|
21106
21553
|
if (input.sourceId) data.source_id = input.sourceId;
|
|
21107
|
-
return
|
|
21554
|
+
return matter17.stringify("\n" + (input.body ?? defaultBody(input.title.trim())), data);
|
|
21108
21555
|
}
|
|
21109
21556
|
function createInitiative(dir, input) {
|
|
21110
21557
|
if (!input.title?.trim()) throw new InitiativeWriteError("Initiative title is required.");
|
|
@@ -21128,10 +21575,10 @@ function transitionInitiative(dir, id, to) {
|
|
|
21128
21575
|
throw new InitiativeWriteError(`Invalid transition ${ini.status} \u2192 ${to}.`);
|
|
21129
21576
|
}
|
|
21130
21577
|
const raw = readFile2(ini.filePath);
|
|
21131
|
-
const { data, content } =
|
|
21578
|
+
const { data, content } = matter17(raw, {});
|
|
21132
21579
|
data.status = to;
|
|
21133
21580
|
if (to === "completed") data.completed_at = today2();
|
|
21134
|
-
const newContent =
|
|
21581
|
+
const newContent = matter17.stringify(content, data);
|
|
21135
21582
|
writeFile2(ini.filePath, newContent);
|
|
21136
21583
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21137
21584
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after transition.");
|
|
@@ -21141,7 +21588,7 @@ function addCandidate(dir, id, candidate) {
|
|
|
21141
21588
|
const ini = getInitiative(dir, id);
|
|
21142
21589
|
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
21143
21590
|
const raw = readFile2(ini.filePath);
|
|
21144
|
-
const { data, content } =
|
|
21591
|
+
const { data, content } = matter17(raw, {});
|
|
21145
21592
|
const existing = Array.isArray(data.candidates) ? data.candidates : [];
|
|
21146
21593
|
const fallbackId = `WI-CANDIDATE-${String(existing.length + 1).padStart(3, "0")}`;
|
|
21147
21594
|
const normalized = normalizeCandidate(candidate, fallbackId);
|
|
@@ -21149,7 +21596,7 @@ function addCandidate(dir, id, candidate) {
|
|
|
21149
21596
|
throw new InitiativeWriteError(`Candidate ${normalized.id} already exists in ${id}.`);
|
|
21150
21597
|
}
|
|
21151
21598
|
data.candidates = [...existing, candidateToData(normalized)];
|
|
21152
|
-
const newContent =
|
|
21599
|
+
const newContent = matter17.stringify(content, data);
|
|
21153
21600
|
writeFile2(ini.filePath, newContent);
|
|
21154
21601
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21155
21602
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after adding a candidate.");
|
|
@@ -21159,7 +21606,7 @@ function updateInitiative(dir, id, patch) {
|
|
|
21159
21606
|
const ini = getInitiative(dir, id);
|
|
21160
21607
|
if (!ini) throw new InitiativeWriteError(`Initiative ${id} not found.`);
|
|
21161
21608
|
const raw = readFile2(ini.filePath);
|
|
21162
|
-
const { data, content } =
|
|
21609
|
+
const { data, content } = matter17(raw, {});
|
|
21163
21610
|
if (patch.title !== void 0) {
|
|
21164
21611
|
if (!patch.title.trim()) throw new InitiativeWriteError("Initiative title cannot be empty.");
|
|
21165
21612
|
data.title = patch.title.trim();
|
|
@@ -21169,7 +21616,7 @@ function updateInitiative(dir, id, patch) {
|
|
|
21169
21616
|
if (patch.knowledgeLevel !== void 0) data.knowledge_level = patch.knowledgeLevel;
|
|
21170
21617
|
if (patch.domains !== void 0) data.domains = patch.domains;
|
|
21171
21618
|
if (patch.relatedCapabilities !== void 0) data.related_capabilities = patch.relatedCapabilities;
|
|
21172
|
-
const newContent =
|
|
21619
|
+
const newContent = matter17.stringify(content, data);
|
|
21173
21620
|
writeFile2(ini.filePath, newContent);
|
|
21174
21621
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21175
21622
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after update.");
|
|
@@ -21187,10 +21634,10 @@ function addExternalLink(dir, id, link) {
|
|
|
21187
21634
|
throw new InitiativeWriteError(`External link ${link.integration}:${link.externalId} already exists on ${id}.`);
|
|
21188
21635
|
}
|
|
21189
21636
|
const raw = readFile2(ini.filePath);
|
|
21190
|
-
const { data, content } =
|
|
21637
|
+
const { data, content } = matter17(raw, {});
|
|
21191
21638
|
const existing = Array.isArray(data.external_links) ? data.external_links : [];
|
|
21192
21639
|
data.external_links = [...existing, externalLinkToData(link)];
|
|
21193
|
-
const newContent =
|
|
21640
|
+
const newContent = matter17.stringify(content, data);
|
|
21194
21641
|
writeFile2(ini.filePath, newContent);
|
|
21195
21642
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21196
21643
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after adding an external link.");
|
|
@@ -21259,7 +21706,7 @@ function buildWorkItemContent(wiId, iniId, candidate) {
|
|
|
21259
21706
|
"_What did we learn? Update after completion._",
|
|
21260
21707
|
""
|
|
21261
21708
|
].join("\n");
|
|
21262
|
-
return
|
|
21709
|
+
return matter17.stringify("\n" + body, data);
|
|
21263
21710
|
}
|
|
21264
21711
|
function materializeCandidate(dir, id, candidateId) {
|
|
21265
21712
|
const ini = getInitiative(dir, id);
|
|
@@ -21276,13 +21723,13 @@ function materializeCandidate(dir, id, candidateId) {
|
|
|
21276
21723
|
ensureDir2(join3(dir, DRAFT_DIR));
|
|
21277
21724
|
writeFile2(join3(dir, DRAFT_DIR, fileName), buildWorkItemContent(wiId, ini.id, candidate));
|
|
21278
21725
|
const raw = readFile2(ini.filePath);
|
|
21279
|
-
const { data, content } =
|
|
21726
|
+
const { data, content } = matter17(raw, {});
|
|
21280
21727
|
const cands = Array.isArray(data.candidates) ? data.candidates : [];
|
|
21281
21728
|
for (const c of cands) {
|
|
21282
21729
|
if (c && typeof c === "object" && String(c.id) === candidateId) c.materialized_as = wiId;
|
|
21283
21730
|
}
|
|
21284
21731
|
data.candidates = cands;
|
|
21285
|
-
const newContent =
|
|
21732
|
+
const newContent = matter17.stringify(content, data);
|
|
21286
21733
|
writeFile2(ini.filePath, newContent);
|
|
21287
21734
|
const updated = parseInitiative2(dir, ini.filePath, newContent);
|
|
21288
21735
|
if (!updated) throw new InitiativeWriteError("Failed to parse the Initiative after materialization.");
|
|
@@ -21396,7 +21843,7 @@ function evaluateInitiativeCompletion(dir, ini) {
|
|
|
21396
21843
|
// ../cli/src/core/resource-write.ts
|
|
21397
21844
|
import fs6 from "fs";
|
|
21398
21845
|
import path5 from "path";
|
|
21399
|
-
import
|
|
21846
|
+
import matter23 from "gray-matter";
|
|
21400
21847
|
var RESOURCES_DIR = "knowledge/tech/resources";
|
|
21401
21848
|
var ResourceWriteError = class extends Error {
|
|
21402
21849
|
constructor(code, message) {
|
|
@@ -21442,6 +21889,20 @@ function validateResource(dir, input) {
|
|
|
21442
21889
|
findings.push({ level: "warning", message: `Unknown access interface type "${i.type}".` });
|
|
21443
21890
|
}
|
|
21444
21891
|
}
|
|
21892
|
+
for (const p of input.connectionProfiles ?? []) {
|
|
21893
|
+
const where = p.environment ? ` in environment "${p.environment}"` : "";
|
|
21894
|
+
for (const c of p.coordinates ?? []) {
|
|
21895
|
+
const key = (c?.key ?? "").trim();
|
|
21896
|
+
const value = (c?.value ?? "").trim();
|
|
21897
|
+
if (!key || !value) continue;
|
|
21898
|
+
if (looksLikeSecretCoordinate(key, value)) {
|
|
21899
|
+
findings.push({
|
|
21900
|
+
level: "error",
|
|
21901
|
+
message: `Connection coordinate "${key}"${where} looks like a secret value. Store credentials as authentication references, not connection coordinates.`
|
|
21902
|
+
});
|
|
21903
|
+
}
|
|
21904
|
+
}
|
|
21905
|
+
}
|
|
21445
21906
|
const mapped = loadMappedModules(dir).map((m2) => m2.id);
|
|
21446
21907
|
if (mapped.length > 0) {
|
|
21447
21908
|
const refs = /* @__PURE__ */ new Set();
|
|
@@ -21468,6 +21929,22 @@ function buildFrontmatter(id, input, base = {}) {
|
|
|
21468
21929
|
if (input.modules != null) data.modules = input.modules;
|
|
21469
21930
|
if (input.accessInterfaces != null) data.access_interfaces = input.accessInterfaces;
|
|
21470
21931
|
if (input.accessBoundaries != null) data.access_boundaries = input.accessBoundaries;
|
|
21932
|
+
if (input.connectionProfiles != null) {
|
|
21933
|
+
data.connection_profiles = input.connectionProfiles.map((p) => {
|
|
21934
|
+
const coordinates = {};
|
|
21935
|
+
for (const c of p.coordinates ?? []) {
|
|
21936
|
+
const key = (c?.key ?? "").trim();
|
|
21937
|
+
const value = (c?.value ?? "").trim();
|
|
21938
|
+
if (!key || !value || looksLikeSecretCoordinate(key, value)) continue;
|
|
21939
|
+
coordinates[key] = value;
|
|
21940
|
+
}
|
|
21941
|
+
const entry = {};
|
|
21942
|
+
if (p.environment?.trim()) entry.environment = p.environment.trim();
|
|
21943
|
+
if (p.interface?.trim()) entry.interface = p.interface.trim();
|
|
21944
|
+
if (Object.keys(coordinates).length) entry.coordinates = coordinates;
|
|
21945
|
+
return entry;
|
|
21946
|
+
}).filter((e) => Object.keys(e).length > 0);
|
|
21947
|
+
}
|
|
21471
21948
|
if (input.authentication != null) {
|
|
21472
21949
|
const mode = input.authentication.mode;
|
|
21473
21950
|
const refs = sanitizeRefs(input.authentication.refs);
|
|
@@ -21476,7 +21953,7 @@ function buildFrontmatter(id, input, base = {}) {
|
|
|
21476
21953
|
return data;
|
|
21477
21954
|
}
|
|
21478
21955
|
function serialize(data, body) {
|
|
21479
|
-
return
|
|
21956
|
+
return matter23.stringify(`
|
|
21480
21957
|
${body.trim()}
|
|
21481
21958
|
`, data);
|
|
21482
21959
|
}
|
|
@@ -21516,7 +21993,7 @@ function updateResource(dir, id, input) {
|
|
|
21516
21993
|
throw new ResourceWriteError("VALIDATION_FAILED", findings.filter((f3) => f3.level === "error").map((f3) => f3.message).join("; "));
|
|
21517
21994
|
}
|
|
21518
21995
|
const raw = readFile(match.filePath);
|
|
21519
|
-
const parsed =
|
|
21996
|
+
const parsed = matter23(raw);
|
|
21520
21997
|
const base = parsed.data ?? {};
|
|
21521
21998
|
const data = buildFrontmatter(match.id || id, input, base);
|
|
21522
21999
|
let body = parsed.content.trim();
|
|
@@ -21749,7 +22226,7 @@ var CANDIDATE_DISCOVERY_GUIDANCE2 = [
|
|
|
21749
22226
|
// ../cli/src/core/deprecation-write.ts
|
|
21750
22227
|
import fs7 from "fs";
|
|
21751
22228
|
import path6 from "path";
|
|
21752
|
-
import
|
|
22229
|
+
import matter24 from "gray-matter";
|
|
21753
22230
|
var DeprecationWriteError = class extends Error {
|
|
21754
22231
|
constructor(code, message) {
|
|
21755
22232
|
super(message);
|
|
@@ -21767,7 +22244,7 @@ function atomicWrite2(filePath, content) {
|
|
|
21767
22244
|
fs7.renameSync(tmp, filePath);
|
|
21768
22245
|
}
|
|
21769
22246
|
function serialize3(data, body) {
|
|
21770
|
-
return
|
|
22247
|
+
return matter24.stringify(`
|
|
21771
22248
|
${body.trim()}
|
|
21772
22249
|
`, data);
|
|
21773
22250
|
}
|
|
@@ -21833,7 +22310,7 @@ function validateTargetInput(dir, raw) {
|
|
|
21833
22310
|
function loadPlanRaw(dir, planId) {
|
|
21834
22311
|
const match = allPlanArtifacts(dir).find((a2) => a2.id === planId || a2.title === planId);
|
|
21835
22312
|
if (!match) throw new DeprecationWriteError("NOT_FOUND", `Deprecation Plan "${planId}" not found.`);
|
|
21836
|
-
const parsed =
|
|
22313
|
+
const parsed = matter24(readFile(match.filePath));
|
|
21837
22314
|
const data = { ...parsed.data ?? {} };
|
|
21838
22315
|
return { filePath: match.filePath, data, body: parsed.content.trim() };
|
|
21839
22316
|
}
|
|
@@ -22021,12 +22498,12 @@ function markWorkItemReady(root, id, confirm2) {
|
|
|
22021
22498
|
}
|
|
22022
22499
|
const raw = readText(root, item.path);
|
|
22023
22500
|
if (!raw) return fail(`Could not read Work Item file: ${item.path}`);
|
|
22024
|
-
const parsed =
|
|
22501
|
+
const parsed = matter25(raw);
|
|
22025
22502
|
const data = { ...parsed.data };
|
|
22026
22503
|
const today3 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
22027
22504
|
data.status = "ready";
|
|
22028
22505
|
data.ready_at = today3;
|
|
22029
|
-
const newContent =
|
|
22506
|
+
const newContent = matter25.stringify(parsed.content, data);
|
|
22030
22507
|
const posixPath = item.path.replace(/\\/g, "/");
|
|
22031
22508
|
let newRelPath = item.path;
|
|
22032
22509
|
if (posixPath.includes("/work-items/draft/")) {
|
|
@@ -22321,7 +22798,7 @@ function removeDeprecationTargetTool(root, planId, targetId, confirm2) {
|
|
|
22321
22798
|
// src/multirepo.ts
|
|
22322
22799
|
import fs8 from "fs";
|
|
22323
22800
|
import path7 from "path";
|
|
22324
|
-
import
|
|
22801
|
+
import matter26 from "gray-matter";
|
|
22325
22802
|
import { parse as parseYaml12, stringify as stringifyYaml8 } from "yaml";
|
|
22326
22803
|
var ok2 = (data) => ({ ok: true, data });
|
|
22327
22804
|
var fail2 = (message) => ({ ok: false, message });
|
|
@@ -22473,7 +22950,7 @@ function validateWorkItemModulesTool(root, args) {
|
|
|
22473
22950
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22474
22951
|
const raw = readText(root, wi.path);
|
|
22475
22952
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22476
|
-
const parsed =
|
|
22953
|
+
const parsed = matter26(raw);
|
|
22477
22954
|
const data = parsed.data;
|
|
22478
22955
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22479
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) : [] })) : [];
|
|
@@ -22526,7 +23003,7 @@ function getWorkItemContextTool(root, args) {
|
|
|
22526
23003
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22527
23004
|
const raw = readText(root, wi.path);
|
|
22528
23005
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22529
|
-
const parsed =
|
|
23006
|
+
const parsed = matter26(raw);
|
|
22530
23007
|
const data = parsed.data;
|
|
22531
23008
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22532
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) : [] })) : [];
|
|
@@ -22612,7 +23089,7 @@ function suggestBranchStrategyTool(root, args) {
|
|
|
22612
23089
|
if (!wi) return fail2(`Work Item "${args.workItemId}" not found.`);
|
|
22613
23090
|
const raw = readText(root, wi.path);
|
|
22614
23091
|
if (!raw) return fail2(`Could not read Work Item file.`);
|
|
22615
|
-
const parsed =
|
|
23092
|
+
const parsed = matter26(raw);
|
|
22616
23093
|
const data = parsed.data;
|
|
22617
23094
|
const affectedModules = Array.isArray(data.affected_modules) ? data.affected_modules.map(String) : [];
|
|
22618
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) : [] })) : [];
|
|
@@ -23372,14 +23849,14 @@ function systemImpactCandidatesTool(root, args) {
|
|
|
23372
23849
|
}
|
|
23373
23850
|
|
|
23374
23851
|
// ../cli/src/services/integrations.ts
|
|
23375
|
-
import
|
|
23852
|
+
import matter28 from "gray-matter";
|
|
23376
23853
|
import { parse as parseYaml14, stringify as stringifyYaml10 } from "yaml";
|
|
23377
23854
|
|
|
23378
23855
|
// ../cli/src/core/work-item-write.ts
|
|
23379
23856
|
import fs10 from "fs";
|
|
23380
23857
|
import path9 from "path";
|
|
23381
23858
|
import crypto4 from "crypto";
|
|
23382
|
-
import
|
|
23859
|
+
import matter27 from "gray-matter";
|
|
23383
23860
|
var SECTION_ORDER2 = [
|
|
23384
23861
|
"Actor",
|
|
23385
23862
|
"Outcome",
|
|
@@ -24427,7 +24904,7 @@ async function integrationsWorkItemTool(root, args) {
|
|
|
24427
24904
|
}
|
|
24428
24905
|
|
|
24429
24906
|
// ../cli/src/core/context-pack.ts
|
|
24430
|
-
import
|
|
24907
|
+
import matter29 from "gray-matter";
|
|
24431
24908
|
var CONTEXT_PACK_VERSION = "1";
|
|
24432
24909
|
var ARCH_DIR4 = "knowledge";
|
|
24433
24910
|
function readScanJson(dir) {
|
|
@@ -24440,7 +24917,7 @@ function readScanJson(dir) {
|
|
|
24440
24917
|
}
|
|
24441
24918
|
}
|
|
24442
24919
|
function firstParagraph4(markdown) {
|
|
24443
|
-
const body =
|
|
24920
|
+
const body = matter29(markdown).content.trim();
|
|
24444
24921
|
const para = body.split("\n\n").map((p) => p.trim()).find((p) => p && !p.startsWith("#"));
|
|
24445
24922
|
return para ?? "";
|
|
24446
24923
|
}
|
|
@@ -24941,11 +25418,11 @@ function renderContextPack(pack) {
|
|
|
24941
25418
|
if (mixEntries.length > 0) {
|
|
24942
25419
|
parts.push("## Delivery Mix\n");
|
|
24943
25420
|
parts.push("Active Work Items by type:\n");
|
|
24944
|
-
const
|
|
25421
|
+
const label2 = (t) => {
|
|
24945
25422
|
const c = t.charAt(0).toUpperCase() + t.slice(1);
|
|
24946
25423
|
return c.endsWith("s") ? c : `${c}s`;
|
|
24947
25424
|
};
|
|
24948
|
-
parts.push(mixEntries.map(([t, n]) => `- ${
|
|
25425
|
+
parts.push(mixEntries.map(([t, n]) => `- ${label2(t)}: ${n}`).join("\n") + "\n");
|
|
24949
25426
|
}
|
|
24950
25427
|
parts.push("## Artifacts and Ownership\n");
|
|
24951
25428
|
if (knowledge.artifacts.length > 0) {
|
|
@@ -25421,8 +25898,502 @@ function renderUnderstand(plan) {
|
|
|
25421
25898
|
return parts.join("\n");
|
|
25422
25899
|
}
|
|
25423
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 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);
|
|
26017
|
+
}
|
|
26018
|
+
return [...new Set(out)];
|
|
26019
|
+
}
|
|
26020
|
+
function sectionBody(body, titles) {
|
|
26021
|
+
const lines = body.split(/\r?\n/);
|
|
26022
|
+
const re = new RegExp(`^#{1,3}\\s+(${titles.join("|")})\\s*$`, "i");
|
|
26023
|
+
const start = lines.findIndex((l2) => re.test(l2));
|
|
26024
|
+
if (start < 0) return null;
|
|
26025
|
+
const collected = [];
|
|
26026
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
26027
|
+
if (/^#{1,3}\s+/.test(lines[i])) break;
|
|
26028
|
+
collected.push(lines[i]);
|
|
26029
|
+
}
|
|
26030
|
+
const text3 = collected.join("\n").trim();
|
|
26031
|
+
return text3.length > 0 ? text3 : null;
|
|
26032
|
+
}
|
|
26033
|
+
function stableOpportunityId(category, sources) {
|
|
26034
|
+
const key = [category, ...[...sources].sort()].join("|");
|
|
26035
|
+
return `${category}:${sha256(key).slice(0, 12)}`;
|
|
26036
|
+
}
|
|
26037
|
+
function layerOf(a2) {
|
|
26038
|
+
const byType = layerForType(a2.type);
|
|
26039
|
+
if (byType) return byType;
|
|
26040
|
+
const p = toPosix8(a2.filePath);
|
|
26041
|
+
if (p.includes(`/${KNOWLEDGE7}/business/`)) return "Business";
|
|
26042
|
+
if (p.includes(`/${KNOWLEDGE7}/product/`)) return "Product";
|
|
26043
|
+
if (p.includes(`/${KNOWLEDGE7}/tech/`)) return "Tech";
|
|
26044
|
+
if (p.includes(`/${KNOWLEDGE7}/delivery/`)) return "Delivery";
|
|
26045
|
+
return null;
|
|
26046
|
+
}
|
|
26047
|
+
function inScope(la, scope) {
|
|
26048
|
+
if (scope.kind === "all") return true;
|
|
26049
|
+
if (scope.kind === "layer") return la.layer === scope.layer;
|
|
26050
|
+
return la.artifact.affectedModules.includes(scope.module);
|
|
26051
|
+
}
|
|
26052
|
+
function label(la) {
|
|
26053
|
+
return la.artifact.id || la.rel;
|
|
26054
|
+
}
|
|
26055
|
+
function buildConsolidationPlan(dir, opts = {}) {
|
|
26056
|
+
requireConfig(dir);
|
|
26057
|
+
const scope = opts.scope ?? { kind: "all" };
|
|
26058
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
26059
|
+
const archDir = join(dir, KNOWLEDGE7);
|
|
26060
|
+
const rawArtifacts = exists(archDir) ? readArtifacts(archDir) : [];
|
|
26061
|
+
const loaded = rawArtifacts.map((a2) => {
|
|
26062
|
+
let body = "";
|
|
26063
|
+
try {
|
|
26064
|
+
body = matter30(readFile(a2.filePath)).content;
|
|
26065
|
+
} catch {
|
|
26066
|
+
body = "";
|
|
26067
|
+
}
|
|
26068
|
+
return { artifact: a2, rel: relFromDir(dir, a2.filePath), body, layer: layerOf(a2) };
|
|
26069
|
+
});
|
|
26070
|
+
const scoped = loaded.filter((la) => inScope(la, scope));
|
|
26071
|
+
const scopedRels = new Set(scoped.map((la) => la.rel));
|
|
26072
|
+
const knownIds = new Set(loaded.map((la) => la.artifact.id).filter(Boolean));
|
|
26073
|
+
const opportunities = [];
|
|
26074
|
+
try {
|
|
26075
|
+
const config = requireConfig(dir);
|
|
26076
|
+
const graph = buildGraph(dir, config, { scope: "all" }, now);
|
|
26077
|
+
const hints = buildGraphHints(dir, graph, now);
|
|
26078
|
+
for (const hint of hints.hints) {
|
|
26079
|
+
if (!hintInScope(hint, scoped)) continue;
|
|
26080
|
+
opportunities.push(relationshipOpportunityFromHint(hint));
|
|
26081
|
+
}
|
|
26082
|
+
} catch {
|
|
26083
|
+
}
|
|
26084
|
+
for (const la of scoped) {
|
|
26085
|
+
const dangling = la.artifact.decisions.filter((d3) => d3 && !knownIds.has(d3) && !decisionFileExists(dir, d3));
|
|
26086
|
+
if (dangling.length === 0) continue;
|
|
26087
|
+
opportunities.push({
|
|
26088
|
+
id: stableOpportunityId("potentially_outdated", [label(la), ...dangling]),
|
|
26089
|
+
category: "potentially_outdated",
|
|
26090
|
+
classification: "observed",
|
|
26091
|
+
confidence: "requires-review",
|
|
26092
|
+
title: `${label(la)} references decision(s) that no longer exist`,
|
|
26093
|
+
source_artifacts: [label(la)],
|
|
26094
|
+
target_artifacts: [label(la)],
|
|
26095
|
+
evidence: dangling.map((d3) => `Declared decision \`${d3}\` has no matching artifact in the project.`),
|
|
26096
|
+
rationale: "A reference to a missing decision is a verifiable inconsistency: either the decision artifact was removed/renamed or the reference is stale.",
|
|
26097
|
+
possible_impact: "Broken traceability between a Work Item/artifact and its decisions.",
|
|
26098
|
+
suggested_action: "Review and update or remove the dangling decision reference.",
|
|
26099
|
+
requires_semantic_review: false
|
|
26100
|
+
});
|
|
26101
|
+
}
|
|
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) ?? [];
|
|
26109
|
+
arr.push(la);
|
|
26110
|
+
byHeading.set(h2, arr);
|
|
26111
|
+
}
|
|
26112
|
+
}
|
|
26113
|
+
const pairHeadings = /* @__PURE__ */ new Map();
|
|
26114
|
+
for (const [heading, arts] of byHeading) {
|
|
26115
|
+
if (arts.length < 2) continue;
|
|
26116
|
+
for (let i = 0; i < arts.length; i++) {
|
|
26117
|
+
for (let j2 = i + 1; j2 < arts.length; j2++) {
|
|
26118
|
+
if (arts[i].rel === arts[j2].rel) continue;
|
|
26119
|
+
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);
|
|
26123
|
+
}
|
|
26124
|
+
}
|
|
26125
|
+
}
|
|
26126
|
+
for (const { a: a2, b: b2, shared } of pairHeadings.values()) {
|
|
26127
|
+
if (shared.size < 2) continue;
|
|
26128
|
+
opportunities.push({
|
|
26129
|
+
id: stableOpportunityId("knowledge_redundancy", [label(a2), label(b2)]),
|
|
26130
|
+
category: "knowledge_redundancy",
|
|
26131
|
+
classification: "suggested",
|
|
26132
|
+
confidence: "requires-review",
|
|
26133
|
+
title: `Possible overlapping content between ${label(a2)} and ${label(b2)}`,
|
|
26134
|
+
source_artifacts: [label(a2), label(b2)],
|
|
26135
|
+
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.",
|
|
26138
|
+
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.",
|
|
26140
|
+
requires_semantic_review: true
|
|
26141
|
+
});
|
|
26142
|
+
}
|
|
26143
|
+
for (const la of scoped) {
|
|
26144
|
+
if (!isCompletedWorkItem(la)) continue;
|
|
26145
|
+
const learning = sectionBody(la.body, ["Learning", "Aprendizaje", "Aprendizajes", "Learnings"]);
|
|
26146
|
+
if (!learning) continue;
|
|
26147
|
+
if (!looksLikeDurableRule(learning)) continue;
|
|
26148
|
+
opportunities.push({
|
|
26149
|
+
id: stableOpportunityId("unincorporated_learning", [label(la)]),
|
|
26150
|
+
category: "unincorporated_learning",
|
|
26151
|
+
classification: "suggested",
|
|
26152
|
+
confidence: "requires-review",
|
|
26153
|
+
title: `${label(la)} captured a learning that may belong in current knowledge`,
|
|
26154
|
+
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.",
|
|
26158
|
+
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.",
|
|
26160
|
+
requires_semantic_review: true
|
|
26161
|
+
});
|
|
26162
|
+
}
|
|
26163
|
+
const weakByFolder = /* @__PURE__ */ new Map();
|
|
26164
|
+
for (const la of scoped) {
|
|
26165
|
+
const quality = safeQuality(dir, la.rel);
|
|
26166
|
+
if (quality === "placeholder" || quality === "weak") {
|
|
26167
|
+
opportunities.push({
|
|
26168
|
+
id: stableOpportunityId("knowledge_organization", [la.rel]),
|
|
26169
|
+
category: "knowledge_organization",
|
|
26170
|
+
classification: "observed",
|
|
26171
|
+
confidence: "requires-review",
|
|
26172
|
+
title: `${label(la)} is ${quality} and may need consolidation or expansion`,
|
|
26173
|
+
source_artifacts: [label(la)],
|
|
26174
|
+
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.",
|
|
26177
|
+
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
|
|
26180
|
+
});
|
|
26181
|
+
const folder = la.rel.split("/").slice(0, -1).join("/");
|
|
26182
|
+
const arr = weakByFolder.get(folder) ?? [];
|
|
26183
|
+
arr.push(la);
|
|
26184
|
+
weakByFolder.set(folder, arr);
|
|
26185
|
+
}
|
|
26186
|
+
}
|
|
26187
|
+
for (const [folder, arts] of weakByFolder) {
|
|
26188
|
+
if (arts.length < 3) continue;
|
|
26189
|
+
opportunities.push({
|
|
26190
|
+
id: stableOpportunityId("knowledge_fragmentation", arts.map((a2) => a2.rel)),
|
|
26191
|
+
category: "knowledge_fragmentation",
|
|
26192
|
+
classification: "suggested",
|
|
26193
|
+
confidence: "requires-review",
|
|
26194
|
+
title: `${folder}/ holds ${arts.length} low-signal artifacts \u2014 possible fragmentation`,
|
|
26195
|
+
source_artifacts: arts.map((a2) => label(a2)),
|
|
26196
|
+
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.",
|
|
26199
|
+
possible_impact: "Related knowledge is spread across too many files to follow.",
|
|
26200
|
+
suggested_action: "Semantic review: evaluate whether cross-references or a consolidation would add clarity. Do not merge by file count alone.",
|
|
26201
|
+
requires_semantic_review: true
|
|
26202
|
+
});
|
|
26203
|
+
}
|
|
26204
|
+
opportunities.sort((x2, y) => {
|
|
26205
|
+
const ci = CONSOLIDATION_CATEGORIES.indexOf(x2.category) - CONSOLIDATION_CATEGORIES.indexOf(y.category);
|
|
26206
|
+
return ci !== 0 ? ci : x2.id.localeCompare(y.id);
|
|
26207
|
+
});
|
|
26208
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26209
|
+
const deduped = opportunities.filter((o2) => seen.has(o2.id) ? false : (seen.add(o2.id), true));
|
|
26210
|
+
const layers = discoverLayers(dir);
|
|
26211
|
+
const layersEvaluated = scope.kind === "layer" ? [scope.layer] : layers.map((l2) => l2.layer);
|
|
26212
|
+
const workItemsEvaluated = scoped.filter(isWorkItem).length;
|
|
26213
|
+
const sourceFiles = [...scopedRels].sort().map((rel) => ({ path: rel, hash: sha256(readFileSafe(join(dir, rel))) }));
|
|
26214
|
+
const byCategory = Object.fromEntries(
|
|
26215
|
+
CONSOLIDATION_CATEGORIES.map((c) => [c, deduped.filter((o2) => o2.category === c).length])
|
|
26216
|
+
);
|
|
26217
|
+
return {
|
|
26218
|
+
generated_at: now.toISOString(),
|
|
26219
|
+
scope: describeScope(scope),
|
|
26220
|
+
project_context: reportingProjectContext(dir),
|
|
26221
|
+
coverage: {
|
|
26222
|
+
scope: describeScope(scope),
|
|
26223
|
+
layers_evaluated: layersEvaluated,
|
|
26224
|
+
artifacts_evaluated: scoped.length,
|
|
26225
|
+
work_items_evaluated: workItemsEvaluated,
|
|
26226
|
+
excluded_sources: scope.kind === "all" ? [] : [...loaded.map((l2) => l2.rel)].filter((r2) => !scopedRels.has(r2)).sort()
|
|
26227
|
+
},
|
|
26228
|
+
source_files: sourceFiles,
|
|
26229
|
+
opportunities: deduped,
|
|
26230
|
+
summary: {
|
|
26231
|
+
total: deduped.length,
|
|
26232
|
+
by_category: byCategory,
|
|
26233
|
+
requires_semantic_review: deduped.filter((o2) => o2.requires_semantic_review).length
|
|
26234
|
+
}
|
|
26235
|
+
};
|
|
26236
|
+
}
|
|
26237
|
+
var CATEGORY_LABELS = {
|
|
26238
|
+
knowledge_redundancy: "Possible redundancy",
|
|
26239
|
+
unincorporated_learning: "Learning integration opportunity",
|
|
26240
|
+
knowledge_fragmentation: "Possible fragmentation",
|
|
26241
|
+
relationship_opportunity: "Relationship review hint",
|
|
26242
|
+
potentially_outdated: "Potential inconsistency",
|
|
26243
|
+
knowledge_organization: "Organization opportunity"
|
|
26244
|
+
};
|
|
26245
|
+
function renderConsolidationMarkdown(plan) {
|
|
26246
|
+
const lines = [];
|
|
26247
|
+
lines.push("# Knowledge Consolidation Plan");
|
|
26248
|
+
lines.push("");
|
|
26249
|
+
lines.push("> Derived, review-only projection. No canonical knowledge was modified by this analysis.");
|
|
26250
|
+
lines.push("");
|
|
26251
|
+
lines.push(`- Generated at: ${plan.generated_at}`);
|
|
26252
|
+
lines.push(`- Scope: ${plan.scope}`);
|
|
26253
|
+
lines.push(`- Project: state=${plan.project_context.state}, mode=${plan.project_context.mode}, structure=${plan.project_context.repository_structure}`);
|
|
26254
|
+
lines.push("");
|
|
26255
|
+
lines.push("## Coverage");
|
|
26256
|
+
lines.push("");
|
|
26257
|
+
lines.push(`- Layers evaluated: ${plan.coverage.layers_evaluated.join(", ") || "\u2014"}`);
|
|
26258
|
+
lines.push(`- Artifacts evaluated: ${plan.coverage.artifacts_evaluated}`);
|
|
26259
|
+
lines.push(`- Work Items evaluated: ${plan.coverage.work_items_evaluated}`);
|
|
26260
|
+
if (plan.coverage.excluded_sources.length > 0) {
|
|
26261
|
+
lines.push(`- Excluded from this scope: ${plan.coverage.excluded_sources.length} artifact(s)`);
|
|
26262
|
+
}
|
|
26263
|
+
lines.push("");
|
|
26264
|
+
lines.push("## Findings");
|
|
26265
|
+
lines.push("");
|
|
26266
|
+
if (plan.summary.total === 0) {
|
|
26267
|
+
lines.push("No consolidation opportunities were detected by the available deterministic analyses within this scope.");
|
|
26268
|
+
lines.push("");
|
|
26269
|
+
lines.push("This is not a claim that the knowledge is perfect \u2014 only that no opportunity was found with the current signals.");
|
|
26270
|
+
lines.push("");
|
|
26271
|
+
return lines.join("\n") + "\n";
|
|
26272
|
+
}
|
|
26273
|
+
for (const cat of CONSOLIDATION_CATEGORIES) {
|
|
26274
|
+
const n = plan.summary.by_category[cat];
|
|
26275
|
+
if (n > 0) lines.push(`- ${n} \xD7 ${CATEGORY_LABELS[cat]}`);
|
|
26276
|
+
}
|
|
26277
|
+
lines.push("");
|
|
26278
|
+
lines.push(`${plan.summary.requires_semantic_review} finding(s) require semantic (agent/human) review before acting.`);
|
|
26279
|
+
lines.push("");
|
|
26280
|
+
lines.push("## Opportunities");
|
|
26281
|
+
lines.push("");
|
|
26282
|
+
for (const o2 of plan.opportunities) {
|
|
26283
|
+
lines.push(`### ${o2.title}`);
|
|
26284
|
+
lines.push("");
|
|
26285
|
+
lines.push(`- Id: \`${o2.id}\``);
|
|
26286
|
+
lines.push(`- Category: ${o2.category}`);
|
|
26287
|
+
lines.push(`- Classification: **${o2.classification}**${o2.requires_semantic_review ? " (requires semantic review)" : ""}`);
|
|
26288
|
+
lines.push(`- Confidence: ${o2.confidence}`);
|
|
26289
|
+
lines.push(`- Source: ${o2.source_artifacts.join(", ") || "\u2014"}`);
|
|
26290
|
+
lines.push(`- Suggested target: ${o2.target_artifacts.join(", ") || "\u2014"}`);
|
|
26291
|
+
lines.push(`- Evidence:`);
|
|
26292
|
+
for (const e of o2.evidence) lines.push(` - ${e}`);
|
|
26293
|
+
lines.push(`- Rationale: ${o2.rationale}`);
|
|
26294
|
+
lines.push(`- Possible impact: ${o2.possible_impact}`);
|
|
26295
|
+
lines.push(`- Suggested action: ${o2.suggested_action}`);
|
|
26296
|
+
lines.push("");
|
|
26297
|
+
}
|
|
26298
|
+
return lines.join("\n") + "\n";
|
|
26299
|
+
}
|
|
26300
|
+
function serializeConsolidationJson(plan) {
|
|
26301
|
+
return JSON.stringify(plan, null, 2) + "\n";
|
|
26302
|
+
}
|
|
26303
|
+
function describeScope(scope) {
|
|
26304
|
+
if (scope.kind === "all") return "all";
|
|
26305
|
+
if (scope.kind === "layer") return `layer:${scope.layer}`;
|
|
26306
|
+
return `module:${scope.module}`;
|
|
26307
|
+
}
|
|
26308
|
+
function isWorkItem(la) {
|
|
26309
|
+
return toPosix8(la.artifact.filePath).includes("/delivery/work-items/");
|
|
26310
|
+
}
|
|
26311
|
+
function isCompletedWorkItem(la) {
|
|
26312
|
+
const p = toPosix8(la.artifact.filePath);
|
|
26313
|
+
return p.includes("/delivery/work-items/completed/") || isWorkItem(la) && la.artifact.status === "completed";
|
|
26314
|
+
}
|
|
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));
|
|
26318
|
+
}
|
|
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());
|
|
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
|
+
|
|
25424
26395
|
// src/generate.ts
|
|
25425
|
-
function
|
|
26396
|
+
function requireConfig2(root) {
|
|
25426
26397
|
const config = loadConfig(root);
|
|
25427
26398
|
if (!config) throw new KaddoMcpError("Kaddo project not found. Run `kaddo init` first.");
|
|
25428
26399
|
return config;
|
|
@@ -25436,7 +26407,7 @@ function slug6(s) {
|
|
|
25436
26407
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
|
|
25437
26408
|
}
|
|
25438
26409
|
function generateContext(root) {
|
|
25439
|
-
const config =
|
|
26410
|
+
const config = requireConfig2(root);
|
|
25440
26411
|
requireKnowledge(root);
|
|
25441
26412
|
const pack = buildContextPack(root, config);
|
|
25442
26413
|
writeDerived(root, ".kaddo/context-pack.md", renderContextPack(pack));
|
|
@@ -25450,7 +26421,7 @@ function generateContext(root) {
|
|
|
25450
26421
|
};
|
|
25451
26422
|
}
|
|
25452
26423
|
function generateExplain(root) {
|
|
25453
|
-
|
|
26424
|
+
requireConfig2(root);
|
|
25454
26425
|
requireKnowledge(root);
|
|
25455
26426
|
const exp = buildProjectExplanation(root);
|
|
25456
26427
|
writeDerived(root, ".kaddo/explain.md", renderExplanationHuman(exp));
|
|
@@ -25464,7 +26435,7 @@ function generateExplain(root) {
|
|
|
25464
26435
|
};
|
|
25465
26436
|
}
|
|
25466
26437
|
function generateUnderstand(root) {
|
|
25467
|
-
const config =
|
|
26438
|
+
const config = requireConfig2(root);
|
|
25468
26439
|
requireKnowledge(root);
|
|
25469
26440
|
const plan = buildUnderstandPlan(root, config);
|
|
25470
26441
|
writeDerived(root, ".kaddo/understand.md", renderUnderstand(plan));
|
|
@@ -25477,7 +26448,7 @@ function generateUnderstand(root) {
|
|
|
25477
26448
|
};
|
|
25478
26449
|
}
|
|
25479
26450
|
function generateGraph(root, scope = "active") {
|
|
25480
|
-
const config =
|
|
26451
|
+
const config = requireConfig2(root);
|
|
25481
26452
|
requireKnowledge(root);
|
|
25482
26453
|
const graph = buildGraph(root, config, { scope });
|
|
25483
26454
|
const hints = buildGraphHints(root, graph);
|
|
@@ -25499,8 +26470,39 @@ function generateGraph(root, scope = "active") {
|
|
|
25499
26470
|
next_suggested_resources: ["kaddo://graph", "kaddo://graph-hints"]
|
|
25500
26471
|
};
|
|
25501
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
|
+
}
|
|
25502
26504
|
function generateImpactReport(root, opts = {}) {
|
|
25503
|
-
|
|
26505
|
+
requireConfig2(root);
|
|
25504
26506
|
requireKnowledge(root);
|
|
25505
26507
|
const format = opts.format ?? "markdown";
|
|
25506
26508
|
const report = buildImpactReport(root, { scope: opts.scope ?? "all", scopeSource: opts.scope ? "explicit" : "default" });
|
|
@@ -25516,7 +26518,7 @@ function generateImpactReport(root, opts = {}) {
|
|
|
25516
26518
|
};
|
|
25517
26519
|
}
|
|
25518
26520
|
function generateSavingsReport(root, opts = {}) {
|
|
25519
|
-
|
|
26521
|
+
requireConfig2(root);
|
|
25520
26522
|
requireKnowledge(root);
|
|
25521
26523
|
const format = opts.format ?? "markdown";
|
|
25522
26524
|
const report = buildSavingsReport(root, { scope: opts.scope ?? "all", scopeSource: opts.scope ? "explicit" : "default" });
|
|
@@ -25532,7 +26534,7 @@ function generateSavingsReport(root, opts = {}) {
|
|
|
25532
26534
|
};
|
|
25533
26535
|
}
|
|
25534
26536
|
function generateDriftReport(root, opts = {}) {
|
|
25535
|
-
|
|
26537
|
+
requireConfig2(root);
|
|
25536
26538
|
const format = opts.format ?? "markdown";
|
|
25537
26539
|
const report = buildDriftReport(root);
|
|
25538
26540
|
const content = format === "json" ? serializeDriftJson(report) : renderDriftMarkdown(report);
|
|
@@ -25547,7 +26549,7 @@ function generateDriftReport(root, opts = {}) {
|
|
|
25547
26549
|
};
|
|
25548
26550
|
}
|
|
25549
26551
|
function generateQuestionsReport(root, opts = {}) {
|
|
25550
|
-
|
|
26552
|
+
requireConfig2(root);
|
|
25551
26553
|
const format = opts.format ?? "markdown";
|
|
25552
26554
|
const report = buildOpenQuestionsReport(root);
|
|
25553
26555
|
const content = format === "json" ? serializeOpenQuestionsJson(report) : renderOpenQuestionsMarkdown(report);
|
|
@@ -25562,7 +26564,7 @@ function generateQuestionsReport(root, opts = {}) {
|
|
|
25562
26564
|
};
|
|
25563
26565
|
}
|
|
25564
26566
|
function generateCapsuleDraft(root) {
|
|
25565
|
-
const config =
|
|
26567
|
+
const config = requireConfig2(root);
|
|
25566
26568
|
requireKnowledge(root);
|
|
25567
26569
|
const capsule = buildCapsule(root, config);
|
|
25568
26570
|
const name = slug6(config.project.name);
|
|
@@ -25782,13 +26784,13 @@ async function guardedAsync(root, fn) {
|
|
|
25782
26784
|
throw err;
|
|
25783
26785
|
}
|
|
25784
26786
|
}
|
|
25785
|
-
function generated(root,
|
|
26787
|
+
function generated(root, label2, fn) {
|
|
25786
26788
|
try {
|
|
25787
26789
|
assertKaddoProject(root);
|
|
25788
26790
|
const result = fn();
|
|
25789
26791
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
25790
26792
|
} catch (err) {
|
|
25791
|
-
const message = err instanceof KaddoMcpError ? err.message : `Could not ${
|
|
26793
|
+
const message = err instanceof KaddoMcpError ? err.message : `Could not ${label2}. ${String(err)}`;
|
|
25792
26794
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
25793
26795
|
}
|
|
25794
26796
|
}
|
|
@@ -26489,6 +27491,19 @@ function createServer(root) {
|
|
|
26489
27491
|
},
|
|
26490
27492
|
async (args) => generated(root, "generate knowledge graph", () => generateGraph(root, args.scope ?? "active"))
|
|
26491
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
|
+
);
|
|
26492
27507
|
server.registerTool(
|
|
26493
27508
|
"kaddo_generate_impact_report",
|
|
26494
27509
|
{
|