@kage-core/kage-graph-mcp 1.1.37 → 1.2.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/cli.js +99 -4
- package/dist/daemon.js +31 -1
- package/dist/index.js +116 -5
- package/dist/kernel.js +896 -18
- package/package.json +1 -1
- package/viewer/app.js +216 -63
- package/viewer/data.html +6 -6
- package/viewer/graph.html +6 -6
- package/viewer/index.html +18 -7
- package/viewer/intel.html +6 -6
- package/viewer/memory.html +6 -6
- package/viewer/owners.html +6 -6
- package/viewer/review.html +7 -7
- package/viewer/styles.css +149 -1
package/package.json
CHANGED
package/viewer/app.js
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
risk: null,
|
|
38
38
|
moduleHealth: null,
|
|
39
39
|
graphInsights: null,
|
|
40
|
+
xray: null,
|
|
40
41
|
workspace: null,
|
|
41
42
|
sessions: null,
|
|
42
43
|
replay: null,
|
|
@@ -182,6 +183,10 @@
|
|
|
182
183
|
edgeCount: document.getElementById("edgeCount"),
|
|
183
184
|
reviewCount: document.getElementById("reviewCount"),
|
|
184
185
|
dashboardStats: document.getElementById("dashboardStats"),
|
|
186
|
+
repoXray: document.getElementById("repoXray"),
|
|
187
|
+
repoXrayStatus: document.getElementById("repoXrayStatus"),
|
|
188
|
+
repoXrayScript: document.getElementById("repoXrayScript"),
|
|
189
|
+
repoXrayLayers: document.getElementById("repoXrayLayers"),
|
|
185
190
|
dashboardCharts: document.getElementById("dashboardCharts"),
|
|
186
191
|
memoryStatus: document.getElementById("memoryStatus"),
|
|
187
192
|
memoryStats: document.getElementById("memoryStats"),
|
|
@@ -242,9 +247,9 @@
|
|
|
242
247
|
summary: "Find repo lore by file, feature, bug, command, or decision. Pick a packet to see linked code."
|
|
243
248
|
},
|
|
244
249
|
intel: {
|
|
245
|
-
eyebrow: "kage://
|
|
246
|
-
title: "
|
|
247
|
-
summary: "
|
|
250
|
+
eyebrow: "kage://before-edit",
|
|
251
|
+
title: "Before You Edit",
|
|
252
|
+
summary: "What can go wrong, why it matters, and the first safety step before an agent changes code."
|
|
248
253
|
},
|
|
249
254
|
review: {
|
|
250
255
|
eyebrow: "kage://review",
|
|
@@ -606,6 +611,7 @@
|
|
|
606
611
|
var riskPath = params.get("risk");
|
|
607
612
|
var moduleHealthPath = params.get("moduleHealth") || params.get("module-health");
|
|
608
613
|
var graphInsightsPath = params.get("graphInsights") || params.get("graph-insights");
|
|
614
|
+
var xrayPath = params.get("xray") || params.get("repoXray") || params.get("repo-xray");
|
|
609
615
|
var workspacePath = params.get("workspace");
|
|
610
616
|
var sessionsPath = params.get("sessions");
|
|
611
617
|
var replayPath = params.get("replay") || params.get("sessionReplay") || params.get("session-replay");
|
|
@@ -631,6 +637,7 @@
|
|
|
631
637
|
if (!riskPath) riskPath = inferredRoot + "/reports/risk.json";
|
|
632
638
|
if (!moduleHealthPath) moduleHealthPath = inferredRoot + "/reports/module-health.json";
|
|
633
639
|
if (!graphInsightsPath) graphInsightsPath = inferredRoot + "/reports/graph-insights.json";
|
|
640
|
+
if (!xrayPath) xrayPath = inferredRoot + "/reports/xray.json";
|
|
634
641
|
if (!workspacePath) workspacePath = inferredRoot + "/reports/workspace.json";
|
|
635
642
|
if (!sessionsPath) sessionsPath = inferredRoot + "/reports/sessions.json";
|
|
636
643
|
if (!replayPath) replayPath = inferredRoot + "/reports/replay.json";
|
|
@@ -657,6 +664,7 @@
|
|
|
657
664
|
if (riskPath) jobs.push(fetchJson(riskPath).then(function (report) { state.reports.risk = report; }).catch(function () { state.reports.risk = null; }));
|
|
658
665
|
if (moduleHealthPath) jobs.push(fetchJson(moduleHealthPath).then(function (report) { state.reports.moduleHealth = report; }).catch(function () { state.reports.moduleHealth = null; }));
|
|
659
666
|
if (graphInsightsPath) jobs.push(fetchJson(graphInsightsPath).then(function (report) { state.reports.graphInsights = report; }).catch(function () { state.reports.graphInsights = null; }));
|
|
667
|
+
if (xrayPath) jobs.push(fetchJson(xrayPath).then(function (report) { state.reports.xray = report; }).catch(function () { state.reports.xray = null; }));
|
|
660
668
|
if (workspacePath) jobs.push(fetchJson(workspacePath).then(function (report) { state.reports.workspace = report; }).catch(function () { state.reports.workspace = null; }));
|
|
661
669
|
if (sessionsPath) jobs.push(fetchJson(sessionsPath).then(function (report) { state.reports.sessions = report; }).catch(function () { state.reports.sessions = null; }));
|
|
662
670
|
if (replayPath) jobs.push(fetchJson(replayPath).then(function (report) { state.reports.replay = report; }).catch(function () { state.reports.replay = null; }));
|
|
@@ -705,6 +713,7 @@
|
|
|
705
713
|
fetchJson("./data/kage/reports/decisions.json").catch(function () { return null; }),
|
|
706
714
|
fetchJson("./data/kage/reports/module-health.json").catch(function () { return null; }),
|
|
707
715
|
fetchJson("./data/kage/reports/graph-insights.json").catch(function () { return null; }),
|
|
716
|
+
fetchJson("./data/kage/reports/xray.json").catch(function () { return null; }),
|
|
708
717
|
fetchJson("./data/kage/reports/workspace.json").catch(function () { return null; }),
|
|
709
718
|
fetchJson("./data/kage/reports/sessions.json").catch(function () { return null; }),
|
|
710
719
|
fetchJson("./data/kage/reports/replay.json").catch(function () { return null; }),
|
|
@@ -727,16 +736,17 @@
|
|
|
727
736
|
state.reports.decisions = items[9];
|
|
728
737
|
state.reports.moduleHealth = items[10];
|
|
729
738
|
state.reports.graphInsights = items[11];
|
|
730
|
-
state.reports.
|
|
731
|
-
state.reports.
|
|
732
|
-
state.reports.
|
|
733
|
-
state.reports.
|
|
734
|
-
state.reports.
|
|
735
|
-
state.reports.
|
|
736
|
-
state.reports.
|
|
737
|
-
state.reports.
|
|
738
|
-
state.reports.
|
|
739
|
-
state.reports.
|
|
739
|
+
state.reports.xray = items[12];
|
|
740
|
+
state.reports.workspace = items[13];
|
|
741
|
+
state.reports.sessions = items[14];
|
|
742
|
+
state.reports.replay = items[15];
|
|
743
|
+
state.reports.memoryAccess = items[16];
|
|
744
|
+
state.reports.memoryAudit = items[17];
|
|
745
|
+
state.reports.handoff = items[18];
|
|
746
|
+
state.reports.lifecycle = items[19];
|
|
747
|
+
state.reports.timeline = items[20];
|
|
748
|
+
state.reports.lineage = items[21];
|
|
749
|
+
state.reports.setup = items[22];
|
|
740
750
|
loadNormalizedGraph(merged, "Kage repo graph");
|
|
741
751
|
setAutoLoad("Kage repo graph loaded", true);
|
|
742
752
|
}).catch(function () {
|
|
@@ -2987,7 +2997,7 @@
|
|
|
2987
2997
|
var reports = state.reports || {};
|
|
2988
2998
|
var reportCount = Object.keys(reports).filter(function (key) { return reports[key]; }).length;
|
|
2989
2999
|
var risk = reports.risk || {};
|
|
2990
|
-
var riskTargets =
|
|
3000
|
+
var riskTargets = userFacingRiskTargets(risk);
|
|
2991
3001
|
var inboxCounts = state.inbox && state.inbox.counts ? state.inbox.counts : {};
|
|
2992
3002
|
var handoff = memoryHandoffSummary(reports.handoff);
|
|
2993
3003
|
var pendingReview = Number(firstNumber(inboxCounts.pending, memoryGraph.pending_packets, (state.pendingPackets || []).length, 0));
|
|
@@ -2995,14 +3005,14 @@
|
|
|
2995
3005
|
var duplicateFlags = Number(firstNumber(inboxCounts.duplicates, memoryGraph.duplicate_candidate_pairs, 0));
|
|
2996
3006
|
var missingContext = Number(firstNumber(inboxCounts.missing_context, 0));
|
|
2997
3007
|
var ownerSilos = Array.isArray(risk.ownership_silos) ? risk.ownership_silos.length : 0;
|
|
2998
|
-
var hotspots =
|
|
3008
|
+
var hotspots = userFacingRiskHotspots(risk).length;
|
|
2999
3009
|
var readiness = handoff || dashboardReadiness(metrics, pendingReview, staleFlags, duplicateFlags, missingContext);
|
|
3000
3010
|
var memoryCoverage = dashboardMemoryCoverage(reports, memoryCodeEdges, memoryGraph, memoryNodes);
|
|
3001
|
-
var riskHealth = riskTargets.length || hotspots ? (riskTargets.length + hotspots) + "
|
|
3011
|
+
var riskHealth = riskTargets.length || hotspots ? (riskTargets.length + hotspots) + " checks" : "No flags";
|
|
3002
3012
|
var statRows = [
|
|
3003
3013
|
["Handoff", readiness.label, readiness.detail, readiness.status],
|
|
3004
3014
|
["Memory", memoryCoverage.label, memoryCoverage.detail, memoryCoverage.status],
|
|
3005
|
-
["
|
|
3015
|
+
["Before edit", riskHealth, riskTargets.length + " edit areas, " + ownerSilos + " ownership silos", riskTargets.length || ownerSilos || hotspots ? "warn" : "ok"]
|
|
3006
3016
|
];
|
|
3007
3017
|
els.dashboardStats.textContent = "";
|
|
3008
3018
|
statRows.forEach(function (row) {
|
|
@@ -3026,7 +3036,7 @@
|
|
|
3026
3036
|
["Coverage", codeGraph.indexer_coverage_percent != null ? codeGraph.indexer_coverage_percent + "%" : "not loaded"]
|
|
3027
3037
|
]);
|
|
3028
3038
|
setDashboardRows("dashboardIntel", [
|
|
3029
|
-
["
|
|
3039
|
+
["Edit checks", riskTargets.length || "none"],
|
|
3030
3040
|
["Ownership silos", ownerSilos || "none"],
|
|
3031
3041
|
["Decision coverage", reports.decisions && reports.decisions.coverage_percent != null ? reports.decisions.coverage_percent + "%" : "not loaded"]
|
|
3032
3042
|
]);
|
|
@@ -3042,6 +3052,7 @@
|
|
|
3042
3052
|
["Stale / duplicate", staleFlags + " / " + duplicateFlags],
|
|
3043
3053
|
["Missing context", missingContext || "none"]
|
|
3044
3054
|
]);
|
|
3055
|
+
renderRepoXray(reports.xray);
|
|
3045
3056
|
renderDashboardCharts({
|
|
3046
3057
|
metrics: metrics,
|
|
3047
3058
|
reports: reports,
|
|
@@ -3061,6 +3072,61 @@
|
|
|
3061
3072
|
});
|
|
3062
3073
|
}
|
|
3063
3074
|
|
|
3075
|
+
function renderRepoXray(report) {
|
|
3076
|
+
if (!els.repoXray || !els.repoXrayLayers) return;
|
|
3077
|
+
if (!report || !Array.isArray(report.layers)) {
|
|
3078
|
+
if (els.repoXrayStatus) els.repoXrayStatus.textContent = "not loaded";
|
|
3079
|
+
if (els.repoXrayScript) els.repoXrayScript.textContent = "Open with `kage viewer --project <repo>` after refresh to see the first-use repo map.";
|
|
3080
|
+
els.repoXrayLayers.textContent = "";
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
var layers = report.layers.filter(function (layer) { return Array.isArray(layer.items) && layer.items.length; });
|
|
3084
|
+
if (els.repoXrayStatus) els.repoXrayStatus.textContent = layers.length ? layers.length + " layers" : "empty";
|
|
3085
|
+
if (els.repoXrayScript) {
|
|
3086
|
+
var script = Array.isArray(report.first_use_script) ? report.first_use_script : [];
|
|
3087
|
+
els.repoXrayScript.textContent = script[0] || report.summary || "Kage mapped the repo structure.";
|
|
3088
|
+
}
|
|
3089
|
+
els.repoXrayLayers.textContent = "";
|
|
3090
|
+
if (!layers.length) {
|
|
3091
|
+
els.repoXrayLayers.className = "repo-xray-layers details-empty";
|
|
3092
|
+
els.repoXrayLayers.textContent = "No X-Ray layers have items yet. Run kage refresh so code graph, risk, tests, and memory links are current.";
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
els.repoXrayLayers.className = "repo-xray-layers";
|
|
3096
|
+
layers.slice(0, 6).forEach(function (layer) {
|
|
3097
|
+
var card = document.createElement("article");
|
|
3098
|
+
card.className = "repo-xray-layer";
|
|
3099
|
+
card.innerHTML = [
|
|
3100
|
+
"<div class=\"repo-xray-layer-head\"><div><strong></strong><span></span></div><em></em></div>",
|
|
3101
|
+
"<div class=\"repo-xray-items\"></div>"
|
|
3102
|
+
].join("");
|
|
3103
|
+
card.querySelector("strong").textContent = layer.title || layer.id || "Layer";
|
|
3104
|
+
card.querySelector("span").textContent = layer.summary || "";
|
|
3105
|
+
card.querySelector("em").textContent = String(layer.items.length || 0);
|
|
3106
|
+
var list = card.querySelector(".repo-xray-items");
|
|
3107
|
+
layer.items.slice(0, 3).forEach(function (item) {
|
|
3108
|
+
var button = document.createElement("button");
|
|
3109
|
+
button.type = "button";
|
|
3110
|
+
button.className = classNames("repo-xray-item", item.status && "repo-xray-item-" + safeCssName(item.status));
|
|
3111
|
+
button.innerHTML = [
|
|
3112
|
+
"<span><strong></strong><em></em></span>",
|
|
3113
|
+
"<i></i>"
|
|
3114
|
+
].join("");
|
|
3115
|
+
button.querySelector("strong").textContent = item.label || item.path || "signal";
|
|
3116
|
+
button.querySelector("em").textContent = Array.isArray(item.evidence) && item.evidence.length ? item.evidence.slice(0, 2).join("; ") : item.action || "";
|
|
3117
|
+
button.querySelector("i").style.width = clamp(Number(item.strength || 0), 4, 100) + "%";
|
|
3118
|
+
if (item.path) {
|
|
3119
|
+
button.title = "Focus " + item.path + " in the graph";
|
|
3120
|
+
button.addEventListener("click", function () {
|
|
3121
|
+
focusGraphPath(item.path);
|
|
3122
|
+
});
|
|
3123
|
+
}
|
|
3124
|
+
list.appendChild(button);
|
|
3125
|
+
});
|
|
3126
|
+
els.repoXrayLayers.appendChild(card);
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
|
|
3064
3130
|
function renderDashboardCharts(data) {
|
|
3065
3131
|
if (!els.dashboardCharts) return;
|
|
3066
3132
|
var approvedPackets = Number(firstNumber(data.memoryGraph.approved_packets, data.memoryNodes, 0));
|
|
@@ -3190,11 +3256,11 @@
|
|
|
3190
3256
|
], blockers ? "Resolve Review before handing work to another agent." : "Memory is clean for handoff.", blockers ? "warn" : "ok"));
|
|
3191
3257
|
}
|
|
3192
3258
|
tailCards.push(
|
|
3193
|
-
metricBars("
|
|
3194
|
-
{ label: "
|
|
3259
|
+
metricBars("Before edit", riskSignals ? riskSignals + " checks" : "none", [
|
|
3260
|
+
{ label: "Edit areas", value: data.riskTargets.length, score: Math.min(100, data.riskTargets.length * 18), status: data.riskTargets.length ? "warn" : "ok" },
|
|
3195
3261
|
{ label: "Silos", value: data.ownerSilos, score: Math.min(100, data.ownerSilos * 18), status: data.ownerSilos ? "warn" : "ok" },
|
|
3196
3262
|
{ label: "Hotspots", value: data.hotspots, score: Math.min(100, data.hotspots * 18), status: data.hotspots ? "danger" : "ok" }
|
|
3197
|
-
], riskSignals ? "Open
|
|
3263
|
+
], riskSignals ? "Open Before Edit and do the listed safety step before changing code." : "No loaded risk flags.", riskSignals ? "warn" : "ok")
|
|
3198
3264
|
);
|
|
3199
3265
|
cards.concat(tailCards).slice(0, 3).forEach(function (card) { els.dashboardCharts.appendChild(card); });
|
|
3200
3266
|
}
|
|
@@ -4373,9 +4439,8 @@
|
|
|
4373
4439
|
var handoff = state.reports && state.reports.handoff;
|
|
4374
4440
|
var handoffItems = handoff && Array.isArray(handoff.items) ? handoff.items : [];
|
|
4375
4441
|
var counts = inbox && inbox.counts ? inbox.counts : {};
|
|
4376
|
-
var openCount = reviewOpenCount(counts, packets
|
|
4377
|
-
|
|
4378
|
-
els.reviewCount.textContent = String(openCount);
|
|
4442
|
+
var openCount = reviewOpenCount(counts, packets);
|
|
4443
|
+
els.reviewCount.textContent = openCount ? String(openCount) : "clear";
|
|
4379
4444
|
els.reviewList.textContent = "";
|
|
4380
4445
|
if (els.reviewOverview) renderReviewOverview(inbox, packets, inboxItems, handoff);
|
|
4381
4446
|
renderMemoryHandoff(handoff, handoffItems);
|
|
@@ -4412,7 +4477,7 @@
|
|
|
4412
4477
|
summary.querySelector(".review-summary").textContent = Array.isArray(inbox.recommendations) && inbox.recommendations.length
|
|
4413
4478
|
? inbox.recommendations.slice(0, 2).join(" ")
|
|
4414
4479
|
: "No inbox recommendations.";
|
|
4415
|
-
summary.querySelector(".review-risks").textContent = openCount ? "
|
|
4480
|
+
summary.querySelector(".review-risks").textContent = openCount ? "Inbox needs review before merge" : "Inbox: clear";
|
|
4416
4481
|
els.reviewList.appendChild(summary);
|
|
4417
4482
|
}
|
|
4418
4483
|
inboxItems.slice(0, 8).forEach(function (entry) {
|
|
@@ -4466,22 +4531,24 @@
|
|
|
4466
4531
|
var stale = Number(firstNumber(counts.stale, 0));
|
|
4467
4532
|
var duplicates = Number(firstNumber(counts.duplicates, 0));
|
|
4468
4533
|
var missingContext = Number(firstNumber(counts.missing_context, 0));
|
|
4469
|
-
var
|
|
4470
|
-
|
|
4534
|
+
var inboxBlockers = reviewOpenCount(counts, packets);
|
|
4535
|
+
var handoffReviews = handoffReviewCount(handoff);
|
|
4536
|
+
var blockers = handoff ? handoffReviews : inboxBlockers;
|
|
4471
4537
|
var mutations = handoff && handoff.totals ? Number(firstNumber(handoff.totals.recent_mutations, 0)) : 0;
|
|
4472
4538
|
els.reviewOverview.appendChild(metricDonut(
|
|
4473
4539
|
"Handoff readiness",
|
|
4474
4540
|
blockers ? 0 : 100,
|
|
4475
|
-
blockers ? blockers + "
|
|
4541
|
+
blockers ? blockers + " handoff review item(s) need attention" : "No pending, stale, or duplicate memory",
|
|
4476
4542
|
blockers ? "Resolve the handoff queue before trusting branch memory." : "Ready to hand work to another agent or teammate.",
|
|
4477
4543
|
blockers ? "warn" : "ok"
|
|
4478
4544
|
));
|
|
4479
|
-
els.reviewOverview.appendChild(metricBars(handoff ? "
|
|
4545
|
+
els.reviewOverview.appendChild(metricBars(handoff ? "Inbox and handoff" : "Inbox breakdown", inboxBlockers ? inboxBlockers + " inbox blocker(s)" : "Inbox: clear", [
|
|
4546
|
+
{ label: "Handoff review", value: handoffReviews || "none", score: Math.min(100, handoffReviews * 24), status: handoffReviews ? "warn" : "ok" },
|
|
4480
4547
|
{ label: "Pending", value: pending, score: Math.min(100, pending * 24), status: pending ? "warn" : "ok" },
|
|
4481
4548
|
{ label: "Stale", value: stale, score: Math.min(100, stale * 24), status: stale ? "warn" : "ok" },
|
|
4482
4549
|
{ label: "Duplicates", value: duplicates, score: Math.min(100, duplicates * 24), status: duplicates ? "warn" : "ok" },
|
|
4483
4550
|
{ label: "Mutations", value: mutations, score: Math.min(100, mutations * 16), status: mutations ? "ok" : "warn" }
|
|
4484
|
-
], handoff ? (handoff.summary || "
|
|
4551
|
+
], handoff ? (handoff.summary || "Handoff review combines lifecycle, audit, timeline, and lineage.") : "These inbox metrics should block merge or handoff.", blockers ? "warn" : "ok"));
|
|
4485
4552
|
}
|
|
4486
4553
|
|
|
4487
4554
|
function renderMemoryHandoff(handoff, items) {
|
|
@@ -4537,14 +4604,15 @@
|
|
|
4537
4604
|
return item;
|
|
4538
4605
|
}
|
|
4539
4606
|
|
|
4540
|
-
function
|
|
4607
|
+
function handoffReviewCount(handoff) {
|
|
4608
|
+
return handoff && handoff.totals ? Number(firstNumber(handoff.totals.open_items, 0)) : 0;
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
function reviewOpenCount(counts, packets) {
|
|
4541
4612
|
var pending = Number(firstNumber(counts && counts.pending, packets && packets.length, 0));
|
|
4542
4613
|
var stale = Number(firstNumber(counts && counts.stale, 0));
|
|
4543
4614
|
var duplicates = Number(firstNumber(counts && counts.duplicates, 0));
|
|
4544
|
-
|
|
4545
|
-
var counted = pending + stale + duplicates + missingContext;
|
|
4546
|
-
if (counted) return counted;
|
|
4547
|
-
return Array.isArray(inboxItems) ? inboxItems.length : 0;
|
|
4615
|
+
return pending + stale + duplicates;
|
|
4548
4616
|
}
|
|
4549
4617
|
|
|
4550
4618
|
function renderProof() {
|
|
@@ -4716,12 +4784,12 @@
|
|
|
4716
4784
|
els.intelligenceStatus.textContent = cards.length ? cards.length + " loaded" : "not loaded";
|
|
4717
4785
|
if (!cards.length) {
|
|
4718
4786
|
els.intelligenceList.className = "intelligence-list details-empty";
|
|
4719
|
-
els.intelligenceList.textContent = "No
|
|
4787
|
+
els.intelligenceList.textContent = "No before-edit reports loaded. Launch with `kage viewer --project <repo>` to load risk, module health, graph insights, and workspace reports.";
|
|
4720
4788
|
return;
|
|
4721
4789
|
}
|
|
4722
4790
|
els.intelligenceList.className = "intelligence-list";
|
|
4723
4791
|
var normalizedCards = normalizeIntelCards(cards);
|
|
4724
|
-
var riskFirst = new Set(["Change Risk", "Module Health", "Decision Memory", "Graph Insights", "Memory Quality"]);
|
|
4792
|
+
var riskFirst = new Set(["Before You Edit", "Change Risk", "Module Health", "Decision Memory", "Graph Insights", "Memory Quality"]);
|
|
4725
4793
|
var primaryCards = normalizedCards.filter(function (card) { return riskFirst.has(card.title); }).slice(0, 3);
|
|
4726
4794
|
if (!primaryCards.length) primaryCards = normalizedCards.slice(0, 3);
|
|
4727
4795
|
primaryCards.forEach(function (card) {
|
|
@@ -4741,11 +4809,11 @@
|
|
|
4741
4809
|
item.querySelector(".intel-highlight").textContent = card.highlight || card.summary || "";
|
|
4742
4810
|
item.querySelector(".intel-action span").textContent = card.action || "Review this signal before changing related code.";
|
|
4743
4811
|
var list = item.querySelector("ul");
|
|
4744
|
-
card.rows.slice(0, 2).forEach(function (row) {
|
|
4812
|
+
card.rows.slice(0, Number(card.rowLimit || (card.title === "Before You Edit" ? 3 : 2))).forEach(function (row) {
|
|
4745
4813
|
var li = document.createElement("li");
|
|
4746
4814
|
li.innerHTML = "<strong></strong> <span></span>";
|
|
4747
4815
|
li.querySelector("strong").textContent = row[0];
|
|
4748
|
-
li.querySelector("span").textContent = trimIntelText(row[1], 92);
|
|
4816
|
+
li.querySelector("span").textContent = card.title === "Before You Edit" ? row[1] : trimIntelText(row[1], 92);
|
|
4749
4817
|
list.appendChild(li);
|
|
4750
4818
|
});
|
|
4751
4819
|
els.intelligenceList.appendChild(item);
|
|
@@ -4817,6 +4885,7 @@
|
|
|
4817
4885
|
|
|
4818
4886
|
function intelligenceSectionPriority(section) {
|
|
4819
4887
|
var title = String(section && section.title || "").toLowerCase();
|
|
4888
|
+
if (title.indexOf("before you edit") !== -1 || title.indexOf("checklist") !== -1) return 0;
|
|
4820
4889
|
if (title.indexOf("blast") !== -1 || title.indexOf("risk") !== -1) return 0;
|
|
4821
4890
|
if (title.indexOf("onboarding") !== -1 || title.indexOf("decision") !== -1) return 1;
|
|
4822
4891
|
if (title.indexOf("module") !== -1 || title.indexOf("health") !== -1) return 2;
|
|
@@ -4824,6 +4893,81 @@
|
|
|
4824
4893
|
return 4;
|
|
4825
4894
|
}
|
|
4826
4895
|
|
|
4896
|
+
function riskTargetList(risk) {
|
|
4897
|
+
if (!risk) return [];
|
|
4898
|
+
return Array.isArray(risk.targets)
|
|
4899
|
+
? risk.targets
|
|
4900
|
+
: Object.keys(risk.targets || {}).map(function (key) { return risk.targets[key]; }).filter(Boolean);
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
function isGeneratedMemoryPathValue(path) {
|
|
4904
|
+
var normalized = String(path || "").replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
|
|
4905
|
+
return normalized.indexOf(".agent_memory/") === 0 ||
|
|
4906
|
+
normalized.indexOf("agent_memory/") === 0 ||
|
|
4907
|
+
normalized.indexOf("/.agent_memory/") !== -1 ||
|
|
4908
|
+
normalized.indexOf("/agent_memory/") !== -1;
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
function isUserFacingRiskPath(path) {
|
|
4912
|
+
var normalized = String(path || "").replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
|
|
4913
|
+
if (!normalized || normalized === "." || normalized === "root") return false;
|
|
4914
|
+
if (isGeneratedMemoryPathValue(normalized)) return false;
|
|
4915
|
+
if (normalized.indexOf("node_modules/") !== -1 || normalized.indexOf("dist/") === 0 || normalized.indexOf("build/") === 0) return false;
|
|
4916
|
+
return true;
|
|
4917
|
+
}
|
|
4918
|
+
|
|
4919
|
+
function userFacingRiskTargets(risk) {
|
|
4920
|
+
return riskTargetList(risk).filter(function (target) {
|
|
4921
|
+
return target && isUserFacingRiskPath(target.target);
|
|
4922
|
+
});
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
function userFacingRiskHotspots(risk) {
|
|
4926
|
+
return Array.isArray(risk && risk.global_hotspots)
|
|
4927
|
+
? risk.global_hotspots.filter(function (hotspot) { return hotspot && isUserFacingRiskPath(hotspot.file_path); })
|
|
4928
|
+
: [];
|
|
4929
|
+
}
|
|
4930
|
+
|
|
4931
|
+
function riskExplanation(item) {
|
|
4932
|
+
var dependents = Number(item && item.dependents_count || 0);
|
|
4933
|
+
var commits = Number(item && item.git && item.git.commit_count_90d || 0);
|
|
4934
|
+
var owner = item && item.git ? shortContributor(item.git.primary_owner || "") : "";
|
|
4935
|
+
if (item && item.test_gap) {
|
|
4936
|
+
return {
|
|
4937
|
+
why: "changes here are not protected by a direct test signal",
|
|
4938
|
+
action: "find or add the closest verification before handoff"
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
if (dependents >= 5) {
|
|
4942
|
+
return {
|
|
4943
|
+
why: "many other files depend on this path",
|
|
4944
|
+
action: "inspect dependents and run the full related test suite"
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
if (item && item.risk_type === "single-owner") {
|
|
4948
|
+
return {
|
|
4949
|
+
why: owner ? "most history belongs to " + owner : "ownership is concentrated in one person",
|
|
4950
|
+
action: "route review to the owner or write down assumptions before editing"
|
|
4951
|
+
};
|
|
4952
|
+
}
|
|
4953
|
+
if (commits >= 20 || item && item.risk_type === "churn-heavy") {
|
|
4954
|
+
return {
|
|
4955
|
+
why: "this area changed " + commits + " time(s) in the last 90 days",
|
|
4956
|
+
action: "recall recent memory and keep the change narrow"
|
|
4957
|
+
};
|
|
4958
|
+
}
|
|
4959
|
+
if (dependents > 0) {
|
|
4960
|
+
return {
|
|
4961
|
+
why: dependents + " file(s) depend on this path",
|
|
4962
|
+
action: "check the dependent paths before editing"
|
|
4963
|
+
};
|
|
4964
|
+
}
|
|
4965
|
+
return {
|
|
4966
|
+
why: item && item.risk_type ? "Kage sees a " + item.risk_type.replace(/-/g, " ") + " signal" : "Kage sees a local change-risk signal",
|
|
4967
|
+
action: "state the expected behavior and verify it after editing"
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
|
|
4827
4971
|
function buildIntelligenceSections(reports) {
|
|
4828
4972
|
var sections = [];
|
|
4829
4973
|
var contributors = reports.contributors;
|
|
@@ -5012,13 +5156,14 @@
|
|
|
5012
5156
|
}
|
|
5013
5157
|
|
|
5014
5158
|
if (risk) {
|
|
5015
|
-
var targets =
|
|
5016
|
-
var hotspots =
|
|
5159
|
+
var targets = userFacingRiskTargets(risk);
|
|
5160
|
+
var hotspots = userFacingRiskHotspots(risk);
|
|
5017
5161
|
var riskRows = targets.slice(0, 6).map(function (item) {
|
|
5162
|
+
var explanation = riskExplanation(item);
|
|
5018
5163
|
return {
|
|
5019
5164
|
label: item.target,
|
|
5020
|
-
value:
|
|
5021
|
-
meta:
|
|
5165
|
+
value: explanation.why,
|
|
5166
|
+
meta: "Do first: " + explanation.action,
|
|
5022
5167
|
score: Math.round(Number(item.hotspot_score || 0) * 100) || Math.min(100, Number(item.dependents_count || 0) * 12 + (item.test_gap ? 24 : 0)),
|
|
5023
5168
|
status: item.test_gap || item.risk_type === "single-owner" ? "warn" : "",
|
|
5024
5169
|
path: item.target,
|
|
@@ -5026,8 +5171,8 @@
|
|
|
5026
5171
|
}).concat(hotspots.slice(0, 4).map(function (hotspot) {
|
|
5027
5172
|
return {
|
|
5028
5173
|
label: hotspot.file_path,
|
|
5029
|
-
value:
|
|
5030
|
-
meta:
|
|
5174
|
+
value: "changed " + (hotspot.commit_count_90d || 0) + " time(s) in 90 days",
|
|
5175
|
+
meta: "Do first: recall recent repo memory and run the closest tests after editing.",
|
|
5031
5176
|
score: Math.round(Number(hotspot.hotspot_score || 0) * 100),
|
|
5032
5177
|
status: "danger",
|
|
5033
5178
|
path: hotspot.file_path,
|
|
@@ -5035,10 +5180,10 @@
|
|
|
5035
5180
|
}));
|
|
5036
5181
|
if (riskRows.length) {
|
|
5037
5182
|
sections.push({
|
|
5038
|
-
title: "
|
|
5039
|
-
kicker: "
|
|
5040
|
-
stat: riskRows.length + "
|
|
5041
|
-
summary: "
|
|
5183
|
+
title: "Before You Edit Checklist",
|
|
5184
|
+
kicker: "why risky / do first",
|
|
5185
|
+
stat: riskRows.length + " checks",
|
|
5186
|
+
summary: "Each row explains what can go wrong and the first safety step before an agent edits it.",
|
|
5042
5187
|
rows: riskRows,
|
|
5043
5188
|
limit: 10,
|
|
5044
5189
|
});
|
|
@@ -5100,16 +5245,24 @@
|
|
|
5100
5245
|
}
|
|
5101
5246
|
var risk = reports.risk;
|
|
5102
5247
|
if (risk) {
|
|
5103
|
-
var targets =
|
|
5248
|
+
var targets = userFacingRiskTargets(risk);
|
|
5104
5249
|
var silos = Array.isArray(risk.ownership_silos) ? risk.ownership_silos : [];
|
|
5250
|
+
var hotspots = userFacingRiskHotspots(risk);
|
|
5251
|
+
var riskRows = targets.slice(0, 4).map(function (item) {
|
|
5252
|
+
var explanation = riskExplanation(item);
|
|
5253
|
+
return [item.target || "edit area", "Why: " + explanation.why + " Do first: " + explanation.action];
|
|
5254
|
+
}).concat(targets.length ? [] : hotspots.slice(0, 2).map(function (hotspot) {
|
|
5255
|
+
return [hotspot.file_path || "hotspot", "Why: changed " + (hotspot.commit_count_90d || 0) + " time(s) in 90 days. Do first: recall recent memory and run closest tests after editing."];
|
|
5256
|
+
}));
|
|
5105
5257
|
cards.push({
|
|
5106
|
-
title: "
|
|
5107
|
-
kicker: "
|
|
5108
|
-
summary:
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5258
|
+
title: "Before You Edit",
|
|
5259
|
+
kicker: "risk checklist",
|
|
5260
|
+
summary: riskRows.length
|
|
5261
|
+
? "These are places where an agent is more likely to break behavior, miss tests, or rely on unstated knowledge."
|
|
5262
|
+
: "No user-facing risky edit areas were found in the loaded report.",
|
|
5263
|
+
rowLimit: 3,
|
|
5264
|
+
rows: (riskRows.length ? riskRows : [["Risk", "No code-level risk checks loaded"]])
|
|
5265
|
+
.concat(silos.length ? [["Reviewer signal", silos.length + " ownership concentration(s)"]] : [])
|
|
5113
5266
|
});
|
|
5114
5267
|
}
|
|
5115
5268
|
var contributors = reports.contributors;
|
|
@@ -5253,13 +5406,13 @@
|
|
|
5253
5406
|
normalized.metricLabel = "memory-code links";
|
|
5254
5407
|
normalized.highlight = "Shows whether saved repo knowledge is tied to actual files, symbols, routes, and tests.";
|
|
5255
5408
|
normalized.action = "If this is low, capture memory with concrete paths so agents can recall it during edits.";
|
|
5256
|
-
} else if (card.title === "Change Risk") {
|
|
5257
|
-
var siloText = row("Silos");
|
|
5409
|
+
} else if (card.title === "Before You Edit" || card.title === "Change Risk") {
|
|
5410
|
+
var siloText = row("Reviewer signal") || row("Silos");
|
|
5258
5411
|
var siloMatch = siloText && String(siloText).match(/\d+/);
|
|
5259
|
-
normalized.metric =
|
|
5260
|
-
normalized.metricLabel = "
|
|
5261
|
-
normalized.highlight = "
|
|
5262
|
-
normalized.action = "
|
|
5412
|
+
normalized.metric = (card.rows || []).length + " checks";
|
|
5413
|
+
normalized.metricLabel = siloMatch ? siloMatch[0] + " reviewer silo(s)" : "pre-edit checklist";
|
|
5414
|
+
normalized.highlight = card.summary || "Shows what can go wrong before an agent edits a file.";
|
|
5415
|
+
normalized.action = "Start with the first row: read why it is risky, then do the listed safety step before editing.";
|
|
5263
5416
|
} else if (card.title === "Contributors") {
|
|
5264
5417
|
normalized.metric = (card.rows || []).length + " profiles";
|
|
5265
5418
|
normalized.metricLabel = "review routing";
|
package/viewer/data.html
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<a class="viewer-section active" href="./" data-viewer-page="overview" aria-current="page">Overview</a>
|
|
22
22
|
<a class="viewer-section" href="./graph.html" data-viewer-page="graph">Graph</a>
|
|
23
23
|
<a class="viewer-section" href="./memory.html" data-viewer-page="memory">Memory</a>
|
|
24
|
-
<a class="viewer-section" href="./intel.html" data-viewer-page="intel">
|
|
24
|
+
<a class="viewer-section" href="./intel.html" data-viewer-page="intel">Before You Edit</a>
|
|
25
25
|
<a class="viewer-section" href="./review.html" data-viewer-page="review">Review</a>
|
|
26
26
|
</nav>
|
|
27
27
|
<nav class="sidebar-secondary" aria-label="Diagnostics">
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
<a href="./graph.html" data-viewer-page="graph">Explore graph</a>
|
|
71
71
|
</article>
|
|
72
72
|
<article class="dashboard-card primary" id="dashboardIntel">
|
|
73
|
-
<div class="dashboard-card-head"><span>
|
|
73
|
+
<div class="dashboard-card-head"><span>Before You Edit</span><strong>checklist</strong></div>
|
|
74
74
|
<h3>What needs attention</h3>
|
|
75
75
|
<ul></ul>
|
|
76
|
-
<a href="./intel.html" data-viewer-page="intel">Open
|
|
76
|
+
<a href="./intel.html" data-viewer-page="intel">Open edit checklist</a>
|
|
77
77
|
</article>
|
|
78
78
|
<article class="dashboard-card primary" id="dashboardReview">
|
|
79
79
|
<div class="dashboard-card-head"><span>Review</span><strong>handoff</strong></div>
|
|
@@ -259,9 +259,9 @@
|
|
|
259
259
|
<div id="proofList" class="proof-list"></div>
|
|
260
260
|
</section>
|
|
261
261
|
|
|
262
|
-
<section class="intelligence-panel" aria-label="
|
|
262
|
+
<section class="intelligence-panel" aria-label="Before edit risks and reports">
|
|
263
263
|
<div class="panel-heading">
|
|
264
|
-
<h2>
|
|
264
|
+
<h2>Before You Edit</h2>
|
|
265
265
|
<span id="intelligenceStatus">reports</span>
|
|
266
266
|
</div>
|
|
267
267
|
<div id="intelligenceList" class="intelligence-list"></div>
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
<span id="entityCount">0</span>
|
|
274
274
|
</div>
|
|
275
275
|
<div id="debugOverview" class="debug-overview"></div>
|
|
276
|
-
<div class="debug-guide">Use artifacts when the graph or recall output looks wrong. Normal repo work starts from Overview, Graph, Memory,
|
|
276
|
+
<div class="debug-guide">Use artifacts when the graph or recall output looks wrong. Normal repo work starts from Overview, Graph, Memory, Before You Edit, or Review.</div>
|
|
277
277
|
<div id="entityList" class="list"></div>
|
|
278
278
|
</section>
|
|
279
279
|
|
package/viewer/graph.html
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<a class="viewer-section active" href="./" data-viewer-page="overview" aria-current="page">Overview</a>
|
|
22
22
|
<a class="viewer-section" href="./graph.html" data-viewer-page="graph">Graph</a>
|
|
23
23
|
<a class="viewer-section" href="./memory.html" data-viewer-page="memory">Memory</a>
|
|
24
|
-
<a class="viewer-section" href="./intel.html" data-viewer-page="intel">
|
|
24
|
+
<a class="viewer-section" href="./intel.html" data-viewer-page="intel">Before You Edit</a>
|
|
25
25
|
<a class="viewer-section" href="./review.html" data-viewer-page="review">Review</a>
|
|
26
26
|
</nav>
|
|
27
27
|
<nav class="sidebar-secondary" aria-label="Diagnostics">
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
<a href="./graph.html" data-viewer-page="graph">Explore graph</a>
|
|
71
71
|
</article>
|
|
72
72
|
<article class="dashboard-card primary" id="dashboardIntel">
|
|
73
|
-
<div class="dashboard-card-head"><span>
|
|
73
|
+
<div class="dashboard-card-head"><span>Before You Edit</span><strong>checklist</strong></div>
|
|
74
74
|
<h3>What needs attention</h3>
|
|
75
75
|
<ul></ul>
|
|
76
|
-
<a href="./intel.html" data-viewer-page="intel">Open
|
|
76
|
+
<a href="./intel.html" data-viewer-page="intel">Open edit checklist</a>
|
|
77
77
|
</article>
|
|
78
78
|
<article class="dashboard-card primary" id="dashboardReview">
|
|
79
79
|
<div class="dashboard-card-head"><span>Review</span><strong>handoff</strong></div>
|
|
@@ -259,9 +259,9 @@
|
|
|
259
259
|
<div id="proofList" class="proof-list"></div>
|
|
260
260
|
</section>
|
|
261
261
|
|
|
262
|
-
<section class="intelligence-panel" aria-label="
|
|
262
|
+
<section class="intelligence-panel" aria-label="Before edit risks and reports">
|
|
263
263
|
<div class="panel-heading">
|
|
264
|
-
<h2>
|
|
264
|
+
<h2>Before You Edit</h2>
|
|
265
265
|
<span id="intelligenceStatus">reports</span>
|
|
266
266
|
</div>
|
|
267
267
|
<div id="intelligenceList" class="intelligence-list"></div>
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
<span id="entityCount">0</span>
|
|
274
274
|
</div>
|
|
275
275
|
<div id="debugOverview" class="debug-overview"></div>
|
|
276
|
-
<div class="debug-guide">Use artifacts when the graph or recall output looks wrong. Normal repo work starts from Overview, Graph, Memory,
|
|
276
|
+
<div class="debug-guide">Use artifacts when the graph or recall output looks wrong. Normal repo work starts from Overview, Graph, Memory, Before You Edit, or Review.</div>
|
|
277
277
|
<div id="entityList" class="list"></div>
|
|
278
278
|
</section>
|
|
279
279
|
|