@kage-core/kage-graph-mcp 2.2.7 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kage-core/kage-graph-mcp",
3
- "version": "2.2.7",
4
- "description": "Local-first repo memory, code graph, and recall MCP server for coding agents",
3
+ "version": "2.3.1",
4
+ "description": "Team memory for coding agents: captures the decisions, runbooks, and bug fixes that get lost, verified against your code and shared via git. MCP server, zero deps, no account.",
5
5
  "main": "dist/index.js",
6
6
  "files": [
7
7
  "dist/**/*.js",
package/viewer/console.js CHANGED
@@ -66,6 +66,7 @@
66
66
 
67
67
  // ---- nav ----
68
68
  var META = {
69
+ dashboard: ["kage://dashboard", "Dashboard", "Your team's captured knowledge — decisions, runbooks, and fixes — at a glance."],
69
70
  gains: ["kage://gains", "What Kage saved you", "Tokens, dollars, and bad memories caught — receipts, not vibes."],
70
71
  overview: ["kage://trust", "Memory trust", "Whether this repo's agent memory can be trusted — at a glance."],
71
72
  graph: ["kage://memory-map", "Memory ↔ code map", "Each packet anchored to the files it's grounded in. Hover a node to inspect."],
@@ -90,8 +91,29 @@
90
91
  });
91
92
 
92
93
  // ---- load ----
94
+ // Showcase mode: the bundled demo dataset (docs/viewer/data) carries showcase:true.
95
+ // Its timestamps are frozen, so we slide them forward to "now" on load — the daily
96
+ // chart and the feed stay current instead of aging into an empty 14-day window.
97
+ // Real daemon data has no showcase flag and is never touched.
98
+ function rebaseShowcase(activity, value) {
99
+ if (!activity || !activity.showcase) return;
100
+ var allAt = [];
101
+ (activity.events || []).forEach(function (e) { if (e.at) allAt.push(Date.parse(e.at)); });
102
+ if (value && value.events) value.events.forEach(function (e) { if (e.at) allAt.push(Date.parse(e.at)); });
103
+ var latest = allAt.length ? Math.max.apply(null, allAt) : 0;
104
+ if (!latest) return;
105
+ var delta = Date.now() - latest;
106
+ var dayDelta = Math.round(delta / 86400000);
107
+ function shift(e) { if (e && e.at) e.at = new Date(Date.parse(e.at) + delta).toISOString(); }
108
+ (activity.events || []).forEach(shift);
109
+ if (value && value.events) value.events.forEach(shift);
110
+ (activity.daily || []).forEach(function (d) {
111
+ if (d.day) d.day = new Date(Date.parse(d.day + "T00:00:00Z") + dayDelta * 86400000).toISOString().slice(0, 10);
112
+ });
113
+ }
114
+
93
115
  Promise.all([getJSON(paths.trust), getJSON(paths.suppressed), getJSON(paths.lifecycle), getJSON(paths.metrics), getJSON(paths.activity), getJSON(paths.value)])
94
- .then(function (r) { render(r[0], r[1], r[2], r[3], r[4], r[5]); })
116
+ .then(function (r) { rebaseShowcase(r[4], r[5]); render(r[0], r[1], r[2], r[3], r[4], r[5]); })
95
117
  .catch(function () { render(null, null, null, null, null, null); });
96
118
 
97
119
  function render(trust, suppressed, lifecycle, metrics, activity, value) {
@@ -102,12 +124,13 @@
102
124
  renderGains(value);
103
125
  renderHero(trust);
104
126
  renderTiles(metrics, state.items);
127
+ renderDashboard(metrics, state.items, value);
105
128
  renderAttention(state.items, suppressed);
106
129
  renderChips(); renderList();
107
130
  renderInsights(metrics, state.items);
108
131
  renderActivity(activity);
109
132
  var start = (location.hash || "").replace("#", "");
110
- show(META[start] ? start : "gains");
133
+ show(META[start] ? start : "dashboard");
111
134
  }
112
135
 
113
136
  // ---- gains (value ledger receipts) ----
@@ -320,6 +343,50 @@
320
343
  function counts(items) {
321
344
  var c = {}; items.forEach(function (i) { c[i.health] = (c[i.health] || 0) + 1; }); return c;
322
345
  }
346
+ // ---- dashboard (landing overview: what the team has captured, at a glance) ----
347
+ function renderDashboard(metrics, items, value) {
348
+ var cg = (metrics && metrics.code_graph) || {};
349
+ var c = counts(items);
350
+ var types = {}; items.forEach(function (i) { var t = i.type || "memory"; types[t] = (types[t] || 0) + 1; });
351
+ var ev = (value && value.events) || [];
352
+ var totals = (value && value.totals) || summarizeWindow(ev, 0);
353
+ var box = document.getElementById("dashTiles");
354
+ if (box) {
355
+ box.textContent = "";
356
+ [
357
+ { k: "Memory packets", v: fmt(items.length), s: (c.hot || 0) + " hot · " + (c.healthy || 0) + " healthy", cls: "memory" },
358
+ { k: "Decisions", v: fmt(types.decision || 0), s: "why the code is the way it is", cls: "code" },
359
+ { k: "Runbooks & fixes", v: fmt((types.runbook || 0) + (types.bug_fix || 0) + (types.workflow || 0)), s: "how to run it · how it broke", cls: "green" },
360
+ { k: "Recalls served", v: fmt(totals.recalls || 0), s: (totals.recalls ? "memory reused, not re-derived" : "recall to start the ledger"), cls: "green" },
361
+ ].forEach(function (d) { var t = el("div", "tile"); t.appendChild(el("div", "k", d.k)); t.appendChild(el("div", "v " + (d.cls || ""), d.v)); t.appendChild(el("div", "s", d.s)); box.appendChild(t); });
362
+ }
363
+ var cap = document.getElementById("dashCaptures");
364
+ if (cap) {
365
+ cap.textContent = "";
366
+ // Prefer human-readable captures: skip auto-distilled packets whose titles are
367
+ // raw ids / JSON fragments (start with a non-letter, or contain { } < >).
368
+ var clean = items.filter(function (i) { var t = (i.title || "").trim(); return /^[A-Za-z]/.test(t) && !/[{}<>]/.test(t); });
369
+ var pool = clean.length >= 5 ? clean : items;
370
+ var recent = pool.slice().sort(function (a, b) {
371
+ return (Date.parse(b.created_at || b.updated_at || 0) || 0) - (Date.parse(a.created_at || a.updated_at || 0) || 0);
372
+ }).slice(0, 7);
373
+ if (!recent.length) cap.appendChild(el("div", "empty", "No memory captured yet. As your agents work, decisions and fixes land here."));
374
+ else recent.forEach(function (i) { cap.appendChild(memoryRow(i)); });
375
+ }
376
+ var tb = document.getElementById("dashTypeBars");
377
+ if (tb) {
378
+ tb.textContent = "";
379
+ var arr = Object.keys(types).map(function (k) { return [k, types[k]]; }).sort(function (a, b) { return b[1] - a[1]; }).slice(0, 7);
380
+ var max = arr.length ? arr[0][1] : 1;
381
+ if (!arr.length) tb.appendChild(el("div", "empty", "No memory yet."));
382
+ arr.forEach(function (p) {
383
+ var row = el("div", "hbar"); row.appendChild(el("span", "n", p[0]));
384
+ var t = el("span", "t"), f = el("i"); t.appendChild(f); row.appendChild(t); row.appendChild(el("span", "c", String(p[1])));
385
+ tb.appendChild(row); setTimeout(function () { f.style.width = (p[1] / max * 100) + "%"; }, 80);
386
+ });
387
+ }
388
+ }
389
+
323
390
  function renderTiles(metrics, items) {
324
391
  var cg = (metrics && metrics.code_graph) || {};
325
392
  var act = (state.activity && state.activity.totals) || {};
package/viewer/index.html CHANGED
@@ -270,7 +270,8 @@
270
270
  <div class="brand"><span class="mark">K</span> Kage</div>
271
271
  <div class="repocard"><span class="eyebrow">Repository</span><strong id="repo">loading…</strong></div>
272
272
  <nav class="nav" id="nav">
273
- <button data-section="gains" aria-current="true"><span class="ic">⊕</span> Gains</button>
273
+ <button data-section="dashboard" aria-current="true"><span class="ic">⊞</span> Dashboard</button>
274
+ <button data-section="gains"><span class="ic">⊕</span> Gains</button>
274
275
  <button data-section="overview"><span class="ic">◎</span> Trust</button>
275
276
  <button data-section="graph"><span class="ic">⬡</span> Memory map</button>
276
277
  <button data-section="memory"><span class="ic">▤</span> Memory</button>
@@ -292,7 +293,15 @@
292
293
  <p id="subtitle">Tokens, dollars, and bad memories caught — receipts, not vibes.</p>
293
294
  </header>
294
295
  <div class="wrap">
295
- <section class="section active" id="section-gains">
296
+ <section class="section active" id="section-dashboard">
297
+ <div class="tiles" id="dashTiles"></div>
298
+ <div class="ins-grid">
299
+ <div class="panel"><h2>Recent captures <span class="sub">— newest knowledge your agents saved</span></h2><div id="dashCaptures"></div></div>
300
+ <div class="panel"><h2>Memory by type</h2><div class="hbars" id="dashTypeBars"></div></div>
301
+ </div>
302
+ </section>
303
+
304
+ <section class="section" id="section-gains">
296
305
  <div class="receipt" id="gainsHero"></div>
297
306
  <div class="tiles" id="gainsTiles"></div>
298
307
  <div class="panel" id="livePanel" hidden><h2><span class="livedot" aria-hidden="true"></span>Live <span class="sub">— memories and value events as they happen</span></h2><div id="liveFeed"></div></div>
@@ -359,6 +368,6 @@
359
368
  </div>
360
369
  <div class="drawer-backdrop" id="detailBackdrop"></div>
361
370
  <aside class="drawer" id="detail" aria-hidden="true"></aside>
362
- <script src="./console.js?v=17"></script>
371
+ <script src="./console.js?v=18"></script>
363
372
  </body>
364
373
  </html>