@kage-core/kage-graph-mcp 1.1.24 → 1.1.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kage-core/kage-graph-mcp",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
4
4
  "description": "Local-first repo memory, code graph, and recall MCP server for coding agents",
5
5
  "main": "dist/index.js",
6
6
  "files": [
package/viewer/app.js CHANGED
@@ -15,6 +15,16 @@
15
15
  selected: null,
16
16
  metrics: null,
17
17
  inbox: null,
18
+ reports: {
19
+ quality: null,
20
+ benchmark: null,
21
+ contributors: null,
22
+ decisions: null,
23
+ risk: null,
24
+ moduleHealth: null,
25
+ graphInsights: null,
26
+ workspace: null
27
+ },
18
28
  pendingPackets: [],
19
29
  reviewText: "",
20
30
  viewBox: { x: 0, y: 0, width: 1000, height: 660 },
@@ -138,7 +148,9 @@
138
148
  reviewCount: document.getElementById("reviewCount"),
139
149
  reviewList: document.getElementById("reviewList"),
140
150
  proofStatus: document.getElementById("proofStatus"),
141
- proofList: document.getElementById("proofList")
151
+ proofList: document.getElementById("proofList"),
152
+ intelligenceStatus: document.getElementById("intelligenceStatus"),
153
+ intelligenceList: document.getElementById("intelligenceList")
142
154
  };
143
155
 
144
156
  var MEMORY_CODE_RELATIONS = new Set(["explains_symbol", "informs_symbol", "fixes_symbol", "applies_to_route", "verified_by_test", "affects_code_path"]);
@@ -277,15 +289,41 @@
277
289
  var inboxPath = params.get("inbox");
278
290
  var reviewPath = params.get("review");
279
291
  var pendingPath = params.get("pending");
292
+ var qualityPath = params.get("quality");
293
+ var benchmarkPath = params.get("benchmark");
294
+ var contributorsPath = params.get("contributors");
295
+ var decisionsPath = params.get("decisions");
296
+ var riskPath = params.get("risk");
297
+ var moduleHealthPath = params.get("moduleHealth") || params.get("module-health");
298
+ var graphInsightsPath = params.get("graphInsights") || params.get("graph-insights");
299
+ var workspacePath = params.get("workspace");
280
300
  var inferredRoot = inferMemoryRoot(graphPaths[0] || "");
281
301
  if (!inboxPath && inferredRoot) inboxPath = inferredRoot + "/inbox.json";
282
302
  if (!reviewPath && inferredRoot) reviewPath = inferredRoot + "/review/memory-review.md";
283
303
  if (!pendingPath && inferredRoot) pendingPath = inferredRoot + "/pending";
304
+ if (inferredRoot) {
305
+ if (!qualityPath) qualityPath = inferredRoot + "/reports/quality.json";
306
+ if (!benchmarkPath) benchmarkPath = inferredRoot + "/reports/benchmark.json";
307
+ if (!contributorsPath) contributorsPath = inferredRoot + "/reports/contributors.json";
308
+ if (!decisionsPath) decisionsPath = inferredRoot + "/reports/decisions.json";
309
+ if (!riskPath) riskPath = inferredRoot + "/reports/risk.json";
310
+ if (!moduleHealthPath) moduleHealthPath = inferredRoot + "/reports/module-health.json";
311
+ if (!graphInsightsPath) graphInsightsPath = inferredRoot + "/reports/graph-insights.json";
312
+ if (!workspacePath) workspacePath = inferredRoot + "/reports/workspace.json";
313
+ }
284
314
  var jobs = [];
285
315
  if (metricsPath) jobs.push(fetchJson(metricsPath).then(function (metrics) { state.metrics = metrics; }));
286
316
  if (inboxPath) jobs.push(fetchJson(inboxPath).then(function (inbox) { state.inbox = inbox; }).catch(function () { state.inbox = null; }));
287
317
  if (reviewPath) jobs.push(fetchText(reviewPath).then(function (text) { state.reviewText = text; }).catch(function () { state.reviewText = ""; }));
288
318
  if (pendingPath) jobs.push(loadPending(pendingPath).then(function (packets) { state.pendingPackets = packets; }));
319
+ if (qualityPath) jobs.push(fetchJson(qualityPath).then(function (report) { state.reports.quality = report; }).catch(function () { state.reports.quality = null; }));
320
+ if (benchmarkPath) jobs.push(fetchJson(benchmarkPath).then(function (report) { state.reports.benchmark = report; }).catch(function () { state.reports.benchmark = null; }));
321
+ if (contributorsPath) jobs.push(fetchJson(contributorsPath).then(function (report) { state.reports.contributors = report; }).catch(function () { state.reports.contributors = null; }));
322
+ if (decisionsPath) jobs.push(fetchJson(decisionsPath).then(function (report) { state.reports.decisions = report; }).catch(function () { state.reports.decisions = null; }));
323
+ if (riskPath) jobs.push(fetchJson(riskPath).then(function (report) { state.reports.risk = report; }).catch(function () { state.reports.risk = null; }));
324
+ if (moduleHealthPath) jobs.push(fetchJson(moduleHealthPath).then(function (report) { state.reports.moduleHealth = report; }).catch(function () { state.reports.moduleHealth = null; }));
325
+ if (graphInsightsPath) jobs.push(fetchJson(graphInsightsPath).then(function (report) { state.reports.graphInsights = report; }).catch(function () { state.reports.graphInsights = null; }));
326
+ if (workspacePath) jobs.push(fetchJson(workspacePath).then(function (report) { state.reports.workspace = report; }).catch(function () { state.reports.workspace = null; }));
289
327
  if (!graphPaths.length && !jobs.length) {
290
328
  loadHostedDefault();
291
329
  return;
@@ -315,11 +353,23 @@
315
353
  loadGraphPath("./data/kage/graph.json"),
316
354
  loadGraphPath("./data/kage/code_graph/graph.json"),
317
355
  fetchJson("./data/kage/metrics.json").catch(function () { return null; }),
318
- fetchJson("./data/kage/inbox.json").catch(function () { return null; })
356
+ fetchJson("./data/kage/inbox.json").catch(function () { return null; }),
357
+ fetchJson("./data/kage/reports/risk.json").catch(function () { return null; }),
358
+ fetchJson("./data/kage/reports/contributors.json").catch(function () { return null; }),
359
+ fetchJson("./data/kage/reports/decisions.json").catch(function () { return null; }),
360
+ fetchJson("./data/kage/reports/module-health.json").catch(function () { return null; }),
361
+ fetchJson("./data/kage/reports/graph-insights.json").catch(function () { return null; }),
362
+ fetchJson("./data/kage/reports/workspace.json").catch(function () { return null; })
319
363
  ]).then(function (items) {
320
364
  var merged = mergeNormalizedGraphs([normalizeGraph(items[0]), normalizeGraph(items[1])]);
321
365
  state.metrics = items[2];
322
366
  state.inbox = items[3];
367
+ state.reports.risk = items[4];
368
+ state.reports.contributors = items[5];
369
+ state.reports.decisions = items[6];
370
+ state.reports.moduleHealth = items[7];
371
+ state.reports.graphInsights = items[8];
372
+ state.reports.workspace = items[9];
323
373
  loadNormalizedGraph(merged, "Kage repo graph");
324
374
  setAutoLoad("Kage repo graph loaded", true);
325
375
  }).catch(function () {
@@ -875,6 +925,7 @@
875
925
  renderMetrics();
876
926
  renderReviewQueue();
877
927
  renderProof();
928
+ renderIntelligence();
878
929
  }
879
930
 
880
931
  function scheduleRender() {
@@ -2167,6 +2218,191 @@
2167
2218
  });
2168
2219
  }
2169
2220
 
2221
+ function renderIntelligence() {
2222
+ if (!els.intelligenceList) return;
2223
+ var reports = state.reports || {};
2224
+ var cards = buildIntelligenceCards(reports);
2225
+ els.intelligenceList.textContent = "";
2226
+ els.intelligenceStatus.textContent = cards.length ? cards.length + " loaded" : "not loaded";
2227
+ if (!cards.length) {
2228
+ els.intelligenceList.className = "intelligence-list details-empty";
2229
+ els.intelligenceList.textContent = "No repo intelligence reports loaded. Launch with `kage viewer --project <repo>` to load risk, module health, graph insights, and workspace reports.";
2230
+ return;
2231
+ }
2232
+ els.intelligenceList.className = "intelligence-list";
2233
+ cards.forEach(function (card) {
2234
+ var item = document.createElement("article");
2235
+ item.className = "intel-card";
2236
+ item.innerHTML = [
2237
+ "<h3></h3>",
2238
+ "<div class=\"intel-kicker\"></div>",
2239
+ "<div class=\"intel-summary\"></div>",
2240
+ "<ul></ul>"
2241
+ ].join("");
2242
+ item.querySelector("h3").textContent = card.title;
2243
+ item.querySelector(".intel-kicker").textContent = card.kicker;
2244
+ item.querySelector(".intel-summary").textContent = card.summary;
2245
+ var list = item.querySelector("ul");
2246
+ card.rows.slice(0, 5).forEach(function (row) {
2247
+ var li = document.createElement("li");
2248
+ li.innerHTML = "<strong></strong> <span></span>";
2249
+ li.querySelector("strong").textContent = row[0];
2250
+ li.querySelector("span").textContent = row[1];
2251
+ list.appendChild(li);
2252
+ });
2253
+ els.intelligenceList.appendChild(item);
2254
+ });
2255
+ }
2256
+
2257
+ function buildIntelligenceCards(reports) {
2258
+ var cards = [];
2259
+ var memoryCodeEdges = state.edges.filter(isMemoryCodeEdge);
2260
+ if (state.edges.length) {
2261
+ var byRelation = new Map();
2262
+ memoryCodeEdges.forEach(function (edge) {
2263
+ byRelation.set(edge.relation, (byRelation.get(edge.relation) || 0) + 1);
2264
+ });
2265
+ cards.push({
2266
+ title: "Memory-Code Bridge",
2267
+ kicker: "shareable repo lore",
2268
+ summary: memoryCodeEdges.length
2269
+ ? "Approved memory is linked back to concrete code artifacts so future agents can recall why the code exists."
2270
+ : "No memory-code links are visible in the loaded graph.",
2271
+ rows: [
2272
+ ["Links", String(memoryCodeEdges.length)],
2273
+ ["Visible", String(memoryCodeEdges.filter(function (edge) { return state.visibleEdgeIds.has(edge.id); }).length)],
2274
+ ["Precise", String(memoryCodeEdges.filter(function (edge) { return edge.relation !== "affects_code_path"; }).length)]
2275
+ ].concat(Array.from(byRelation.entries()).sort(function (a, b) { return b[1] - a[1] || a[0].localeCompare(b[0]); }).slice(0, 2).map(function (entry) {
2276
+ return [entry[0], String(entry[1])];
2277
+ }))
2278
+ });
2279
+ }
2280
+ var risk = reports.risk;
2281
+ if (risk) {
2282
+ var targets = Array.isArray(risk.targets) ? risk.targets : Object.keys(risk.targets || {}).map(function (key) { return risk.targets[key]; });
2283
+ var silos = Array.isArray(risk.ownership_silos) ? risk.ownership_silos : [];
2284
+ cards.push({
2285
+ title: "Change Risk",
2286
+ kicker: "blast radius",
2287
+ summary: risk.summary || "Local risk report from code graph and git history.",
2288
+ rows: targets.slice(0, 5).map(function (item) {
2289
+ return [item.target || "target", item.risk_summary || [item.risk_type, item.dependents_count != null ? item.dependents_count + " dependents" : ""].filter(Boolean).join(", ")];
2290
+ }).concat(targets.length ? [] : [["Hotspots", Array.isArray(risk.global_hotspots) ? risk.global_hotspots.length + " global" : "none"]])
2291
+ .concat(silos.length ? [["Silos", silos.length + " ownership concentration(s)"]] : [])
2292
+ });
2293
+ }
2294
+ var contributors = reports.contributors;
2295
+ if (contributors) {
2296
+ var profiles = Array.isArray(contributors.contributors) ? contributors.contributors : [];
2297
+ cards.push({
2298
+ title: "Contributors",
2299
+ kicker: "local git profiles",
2300
+ summary: contributors.summary || "Contributor profiles from git history, ownership, modules, and hotspots.",
2301
+ rows: profiles.slice(0, 5).map(function (profile) {
2302
+ return [
2303
+ profile.contributor || "contributor",
2304
+ profile.commits_total + " commits, " + profile.commits_90d + " in 90d, " + profile.primary_owned_files + " owned file(s)"
2305
+ ];
2306
+ }).concat(profiles.length ? [] : [["Profiles", "No contributor profiles loaded"]])
2307
+ });
2308
+ }
2309
+ var decisions = reports.decisions;
2310
+ if (decisions) {
2311
+ var topDecisions = Array.isArray(decisions.top_decisions) ? decisions.top_decisions : [];
2312
+ var gaps = Array.isArray(decisions.coverage_gaps) ? decisions.coverage_gaps : [];
2313
+ cards.push({
2314
+ title: "Decision Memory",
2315
+ kicker: "why / gotchas / runbooks",
2316
+ summary: decisions.summary || "Decision memory connected to code paths, plus important uncovered files.",
2317
+ rows: [
2318
+ ["Coverage", (decisions.coverage_percent != null ? decisions.coverage_percent + "%" : "n/a") + " of code paths"],
2319
+ ["Why-memory", String(decisions.decision_memory_count || 0)],
2320
+ ["Coverage gaps", String(gaps.length)]
2321
+ ].concat(topDecisions.slice(0, 2).map(function (item) {
2322
+ return [item.type || "memory", item.title || item.summary || "decision memory"];
2323
+ })).concat(gaps.slice(0, 1).map(function (gap) {
2324
+ return ["Uncovered", gap.path + " - " + gap.reason];
2325
+ }))
2326
+ });
2327
+ }
2328
+ var health = reports.moduleHealth;
2329
+ if (health) {
2330
+ var modules = Array.isArray(health.modules) ? health.modules : [];
2331
+ cards.push({
2332
+ title: "Module Health",
2333
+ kicker: "churn / tests / ownership",
2334
+ summary: health.summary || "Module scorecards from local graph and git signals.",
2335
+ rows: modules.slice(0, 5).map(function (item) {
2336
+ return [item.module + " " + item.grade, "score " + item.score + " - " + (Array.isArray(item.reasons) ? item.reasons.slice(0, 2).join("; ") : "")];
2337
+ }).concat(modules.length ? [] : [["Modules", "No module scorecards loaded"]])
2338
+ });
2339
+ }
2340
+ var insights = reports.graphInsights;
2341
+ if (insights) {
2342
+ var central = Array.isArray(insights.central_files) ? insights.central_files : [];
2343
+ var cycles = Array.isArray(insights.dependency_cycles) ? insights.dependency_cycles : [];
2344
+ var communities = Array.isArray(insights.communities) ? insights.communities : [];
2345
+ var coverage = Array.isArray(insights.language_coverage) ? insights.language_coverage : [];
2346
+ var edgeMix = insights.edge_mix || {};
2347
+ cards.push({
2348
+ title: "Graph Insights",
2349
+ kicker: "centrality / cycles / communities",
2350
+ summary: insights.summary || "Deterministic source graph intelligence.",
2351
+ rows: [
2352
+ ["Central", central[0] ? central[0].path + " (" + central[0].dependents + " dependents)" : "none"],
2353
+ ["Cycles", String(cycles.length)],
2354
+ ["Communities", String(communities.length)],
2355
+ ["Edges", [edgeMix.imports || 0, "imports", edgeMix.calls || 0, "calls"].join(" ")]
2356
+ ].concat(central.slice(1, 3).map(function (item) { return ["Central", item.path]; }))
2357
+ .concat(coverage.slice(0, 1).map(function (item) { return [item.language, item.coverage_percent + "% indexed across " + item.files + " files"]; }))
2358
+ });
2359
+ }
2360
+ var workspace = reports.workspace;
2361
+ if (workspace) {
2362
+ var repos = Array.isArray(workspace.repos) ? workspace.repos : [];
2363
+ var deps = Array.isArray(workspace.package_dependencies) ? workspace.package_dependencies : [];
2364
+ var contracts = Array.isArray(workspace.route_contracts) ? workspace.route_contracts : [];
2365
+ cards.push({
2366
+ title: "Workspace",
2367
+ kicker: "multi-repo memory",
2368
+ summary: workspace.summary || "Workspace scan across local git repos.",
2369
+ rows: [
2370
+ ["Repos", String(repos.length)],
2371
+ ["Indexed", String(repos.filter(function (repo) { return repo.indexed; }).length)],
2372
+ ["Package deps", String(deps.length)],
2373
+ ["Route links", String(contracts.length)]
2374
+ ].concat(repos.slice(0, 2).map(function (repo) { return [repo.alias, repo.approved_packets + " packets, " + repo.code_files + " files"]; }))
2375
+ });
2376
+ }
2377
+ var quality = reports.quality;
2378
+ if (quality) {
2379
+ cards.push({
2380
+ title: "Memory Quality",
2381
+ kicker: "review gate",
2382
+ summary: quality.summary || "Packet quality, duplicates, staleness, and grounding.",
2383
+ rows: [
2384
+ ["Useful", quality.useful_memory_ratio_percent != null ? quality.useful_memory_ratio_percent + "%" : "n/a"],
2385
+ ["Evidence", quality.evidence_coverage_percent != null ? quality.evidence_coverage_percent + "%" : "n/a"],
2386
+ ["Path grounded", quality.path_grounding_coverage_percent != null ? quality.path_grounding_coverage_percent + "%" : "n/a"],
2387
+ ["Pending", quality.totals ? String(quality.totals.pending) : "n/a"]
2388
+ ]
2389
+ });
2390
+ }
2391
+ var benchmark = reports.benchmark;
2392
+ if (benchmark) {
2393
+ var checks = Array.isArray(benchmark.checks) ? benchmark.checks : [];
2394
+ cards.push({
2395
+ title: "Benchmark",
2396
+ kicker: "local proof",
2397
+ summary: benchmark.summary || "Local memory and graph benchmark signals.",
2398
+ rows: checks.slice(0, 5).map(function (item) {
2399
+ return [item.name || "check", (item.pass ? "pass" : "check") + " - " + item.actual + "/" + item.target];
2400
+ })
2401
+ });
2402
+ }
2403
+ return cards;
2404
+ }
2405
+
2170
2406
  function renderStatusStrip(visibleEntities, visibleEdges, official) {
2171
2407
  if (!els.statusStrip) return;
2172
2408
  var memoryCount = visibleEntities.filter(function (entity) { return entity.graph_kind === "memory"; }).length;
package/viewer/index.html CHANGED
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Kage Memory Terminal</title>
7
- <link rel="stylesheet" href="./styles.css?v=17">
7
+ <link rel="stylesheet" href="./styles.css?v=20">
8
8
  </head>
9
9
  <body>
10
10
  <header class="app-header">
@@ -13,6 +13,12 @@
13
13
  <h1>Memory Terminal</h1>
14
14
  <p id="graphSummary">Load memory, code, and metrics graphs to inspect what agents know and why.</p>
15
15
  </div>
16
+ <nav class="site-links" aria-label="Kage site links">
17
+ <a href="../">Home</a>
18
+ <a href="../guide.html">Docs</a>
19
+ <a href="../releases.html">Releases</a>
20
+ <a href="https://github.com/kage-core/Kage">GitHub</a>
21
+ </nav>
16
22
  <div id="statusStrip" class="status-strip" aria-label="Graph health"></div>
17
23
  <div id="autoLoadStatus" class="autoload-status">auto-load: waiting</div>
18
24
  <label class="file-picker">
@@ -140,6 +146,14 @@
140
146
  <div id="proofList" class="proof-list"></div>
141
147
  </section>
142
148
 
149
+ <section class="intelligence-panel" aria-label="Repo intelligence">
150
+ <div class="panel-heading">
151
+ <h2>Repo Intelligence</h2>
152
+ <span id="intelligenceStatus">reports</span>
153
+ </div>
154
+ <div id="intelligenceList" class="intelligence-list"></div>
155
+ </section>
156
+
143
157
  <section class="table-panel entities-panel" aria-label="Nodes">
144
158
  <div class="panel-heading">
145
159
  <h2>Nodes</h2>
@@ -157,6 +171,6 @@
157
171
  </section>
158
172
  </main>
159
173
 
160
- <script src="./app.js?v=17"></script>
174
+ <script src="./app.js?v=20"></script>
161
175
  </body>
162
176
  </html>
package/viewer/styles.css CHANGED
@@ -40,7 +40,10 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
40
40
 
41
41
  .app-header {
42
42
  display: grid;
43
- grid-template-columns: minmax(0, 1fr) auto auto auto;
43
+ grid-template-columns: minmax(360px, 1fr) auto auto;
44
+ grid-template-areas:
45
+ "brand links picker"
46
+ "status status autoload";
44
47
  gap: 16px;
45
48
  align-items: center;
46
49
  padding: 14px 18px;
@@ -52,7 +55,11 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
52
55
  z-index: 10;
53
56
  }
54
57
 
55
- .brand-block { min-width: 0; }
58
+ .brand-block {
59
+ grid-area: brand;
60
+ min-width: 280px;
61
+ max-width: 620px;
62
+ }
56
63
  .eyebrow {
57
64
  display: inline-flex;
58
65
  margin-bottom: 5px;
@@ -72,14 +79,42 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
72
79
  overflow-wrap: anywhere;
73
80
  }
74
81
 
82
+ .site-links {
83
+ grid-area: links;
84
+ display: flex;
85
+ flex-wrap: wrap;
86
+ gap: 10px;
87
+ justify-content: flex-end;
88
+ }
89
+ .site-links a {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ min-height: 28px;
93
+ padding: 4px 9px;
94
+ border: 1px solid var(--line);
95
+ border-radius: 4px;
96
+ background: rgba(13, 25, 19, 0.86);
97
+ color: var(--terminal-dim);
98
+ font-size: 11px;
99
+ font-weight: 780;
100
+ text-decoration: none;
101
+ white-space: nowrap;
102
+ }
103
+ .site-links a:hover {
104
+ border-color: var(--line-strong);
105
+ color: var(--terminal-strong);
106
+ }
107
+
75
108
  .status-strip {
109
+ grid-area: status;
76
110
  display: flex;
77
111
  flex-wrap: wrap;
78
112
  gap: 8px;
79
- justify-content: flex-end;
113
+ justify-content: flex-start;
80
114
  }
81
115
 
82
116
  .autoload-status {
117
+ grid-area: autoload;
83
118
  display: inline-flex;
84
119
  align-items: center;
85
120
  min-height: 28px;
@@ -131,6 +166,7 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
131
166
  font-weight: 780;
132
167
  box-shadow: inset 0 0 0 1px rgba(65, 255, 143, 0.10);
133
168
  }
169
+ .file-picker { grid-area: picker; }
134
170
  .file-picker:hover, button:hover { background: #0d1f15; }
135
171
  .file-picker input {
136
172
  position: absolute;
@@ -150,11 +186,12 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
150
186
  .layout {
151
187
  display: grid;
152
188
  grid-template-columns: minmax(0, 1fr) 380px;
153
- grid-template-rows: minmax(680px, calc(100vh - 108px)) auto minmax(220px, 30vh) minmax(270px, 34vh);
189
+ grid-template-rows: minmax(680px, calc(100vh - 108px)) auto minmax(220px, 30vh) minmax(260px, 32vh) minmax(270px, 34vh);
154
190
  grid-template-areas:
155
191
  "graph details"
156
192
  "controls details"
157
193
  "review proof"
194
+ "intelligence intelligence"
158
195
  "entities edges";
159
196
  gap: 12px;
160
197
  padding: 12px;
@@ -163,7 +200,7 @@ h2 { color: var(--terminal); font-size: 13px; letter-spacing: 0.04em; text-trans
163
200
 
164
201
  .layout > * { min-width: 0; }
165
202
 
166
- .control-panel, .graph-panel, .details-panel, .table-panel, .review-panel, .proof-panel {
203
+ .control-panel, .graph-panel, .details-panel, .table-panel, .review-panel, .proof-panel, .intelligence-panel {
167
204
  border: 1px solid var(--line);
168
205
  border-radius: 6px;
169
206
  background: rgba(8, 17, 13, 0.94);
@@ -553,14 +590,64 @@ input:focus, select:focus, button:focus, .file-picker:focus-within {
553
590
  .edges-panel { grid-area: edges; }
554
591
  .review-panel { grid-area: review; }
555
592
  .proof-panel { grid-area: proof; }
593
+ .intelligence-panel { grid-area: intelligence; }
556
594
  .table-panel { min-height: 0; overflow: hidden; }
557
- .review-panel, .proof-panel { min-height: 0; overflow: hidden; }
595
+ .review-panel, .proof-panel, .intelligence-panel { min-height: 0; overflow: hidden; }
558
596
  .list { height: calc(100% - 48px); overflow: auto; padding: 0 8px 10px; }
559
597
  .review-list, .proof-list {
560
598
  height: calc(100% - 48px);
561
599
  overflow: auto;
562
600
  padding: 0 10px 12px;
563
601
  }
602
+ .intelligence-list {
603
+ height: calc(100% - 48px);
604
+ overflow: auto;
605
+ padding: 0 10px 12px;
606
+ display: grid;
607
+ grid-template-columns: repeat(4, minmax(0, 1fr));
608
+ gap: 8px;
609
+ align-content: start;
610
+ }
611
+ .intel-card {
612
+ min-height: 160px;
613
+ padding: 11px;
614
+ border: 1px solid var(--line);
615
+ border-radius: 4px;
616
+ background: #06100b;
617
+ overflow: hidden;
618
+ }
619
+ .intel-card h3 {
620
+ margin: 0;
621
+ color: var(--terminal);
622
+ font-size: 12px;
623
+ letter-spacing: 0;
624
+ overflow-wrap: anywhere;
625
+ }
626
+ .intel-card .intel-kicker {
627
+ margin-top: 4px;
628
+ color: var(--terminal-dim);
629
+ font-size: 10px;
630
+ font-weight: 760;
631
+ text-transform: uppercase;
632
+ }
633
+ .intel-card .intel-summary {
634
+ margin-top: 8px;
635
+ color: var(--text);
636
+ font-size: 11px;
637
+ overflow-wrap: anywhere;
638
+ }
639
+ .intel-card ul {
640
+ margin: 9px 0 0;
641
+ padding: 0;
642
+ list-style: none;
643
+ }
644
+ .intel-card li {
645
+ padding-top: 6px;
646
+ color: var(--muted);
647
+ font-size: 11px;
648
+ overflow-wrap: anywhere;
649
+ }
650
+ .intel-card strong { color: var(--terminal-strong); }
564
651
  .review-item {
565
652
  padding: 10px 0;
566
653
  border-top: 1px solid var(--line);
@@ -702,6 +789,12 @@ input:focus, select:focus, button:focus, .file-picker:focus-within {
702
789
  @media (max-width: 1120px) {
703
790
  .app-header {
704
791
  grid-template-columns: 1fr;
792
+ grid-template-areas:
793
+ "brand"
794
+ "links"
795
+ "status"
796
+ "autoload"
797
+ "picker";
705
798
  align-items: stretch;
706
799
  padding: 12px 14px;
707
800
  }
@@ -711,13 +804,14 @@ input:focus, select:focus, button:focus, .file-picker:focus-within {
711
804
  .status-pill { min-height: 24px; padding: 3px 8px; }
712
805
  .layout {
713
806
  grid-template-columns: 1fr;
714
- grid-template-rows: minmax(620px, 78vh) auto auto minmax(220px, 36vh) minmax(220px, 36vh) minmax(220px, 36vh) minmax(220px, 36vh);
807
+ grid-template-rows: minmax(620px, 78vh) auto auto minmax(220px, 36vh) minmax(220px, 36vh) minmax(220px, 36vh) minmax(220px, 36vh) minmax(220px, 36vh);
715
808
  grid-template-areas:
716
809
  "graph"
717
810
  "controls"
718
811
  "details"
719
812
  "review"
720
813
  "proof"
814
+ "intelligence"
721
815
  "entities"
722
816
  "edges";
723
817
  }
@@ -740,6 +834,7 @@ input:focus, select:focus, button:focus, .file-picker:focus-within {
740
834
  .control-panel { grid-template-columns: 1fr; }
741
835
  .metrics-grid { grid-template-columns: 1fr 1fr; }
742
836
  .proof-list { grid-template-columns: 1fr 1fr; }
837
+ .intelligence-list { grid-template-columns: 1fr; }
743
838
  .graph-toolbar { align-items: flex-start; flex-direction: column; }
744
839
  .graph-actions { width: 100%; }
745
840
  .interaction-hint { flex: 1; white-space: normal; }