@kage-core/kage-graph-mcp 1.3.0 → 2.0.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/viewer/index.html CHANGED
@@ -1,309 +1,366 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Kage viewer</title>
7
- <link rel="stylesheet" href="./styles.css?v=39">
8
- </head>
9
- <body>
10
- <div class="viewer-shell">
11
- <aside class="repo-sidebar" aria-label="Repository navigation">
12
- <a class="sidebar-brand" href="../">
13
- <span class="brand-mark">K</span>
14
- <span>Kage</span>
15
- </a>
16
- <div class="repo-card">
17
- <span>Repository</span>
18
- <strong>kage-core/Kage</strong>
19
- </div>
20
- <nav class="viewer-sections" aria-label="Kage viewer sections">
21
- <a class="viewer-section active" href="./" data-viewer-page="overview" aria-current="page">Overview</a>
22
- <a class="viewer-section" href="./graph.html" data-viewer-page="graph">Graph</a>
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">Before You Edit</a>
25
- <a class="viewer-section" href="./review.html" data-viewer-page="review">Review</a>
26
- </nav>
27
- <nav class="sidebar-secondary" aria-label="Diagnostics">
28
- <span class="sidebar-secondary-label">Diagnostics</span>
29
- <a href="./owners.html" data-viewer-page="owners">Owners</a>
30
- <a href="./data.html" data-viewer-page="data">Artifacts</a>
31
- </nav>
32
- <nav class="sidebar-links" aria-label="Kage links">
33
- <a href="https://kage-core.com/">Home</a>
34
- <a href="https://kage-core.com/guide.html">Docs</a>
35
- <a href="https://kage-core.com/releases.html">Releases</a>
36
- <a href="https://github.com/kage-core/Kage">GitHub</a>
37
- </nav>
38
- </aside>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Kage — memory dashboard</title>
7
+ <style>
8
+ /* V2 "receipts" theme. Tokens mirror docs/assets/site.css so the dashboard
9
+ matches the site: light-first warm paper, editorial serif display type,
10
+ deep verified-green for gains, dark-capable via prefers-color-scheme. */
11
+ :root {
12
+ color-scheme: light dark;
13
+ --bg: #f6f4ef; --paper: #fffdf9; --paper-2: #efece4;
14
+ --line: #e2ded2; --line-strong: #c9c4b4;
15
+ --ink: #1c1e1a; --muted: #5d635b; --faint: #8b9088;
16
+ --gain: #0c7a4d; --gain-strong: #09935c; --gain-soft: rgba(12, 122, 77, 0.08);
17
+ --code: #155e9c; --memory: #6d49b8; --warn: #9a6b08; --danger: #b03048;
18
+ --warn-soft: rgba(154, 107, 8, 0.10);
19
+ --code-bg: #15181b; --code-text: #d7e2da;
20
+ --tip-bg: #fffdf9; --shadow: 0 14px 40px rgba(28, 30, 26, 0.12);
21
+ --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
22
+ --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
23
+ --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
24
+ --r-control: 4px; --r-panel: 6px; --r-card: 8px;
25
+ }
26
+ @media (prefers-color-scheme: dark) {
27
+ :root {
28
+ --bg: #121413; --paper: #1a1d1b; --paper-2: #212522;
29
+ --line: #2c302c; --line-strong: #41463f;
30
+ --ink: #edefe9; --muted: #a4aba1; --faint: #767d74;
31
+ --gain: #43c98a; --gain-strong: #5fdca0; --gain-soft: rgba(67, 201, 138, 0.12);
32
+ --code: #6fb4e8; --memory: #b095e8; --warn: #d9a93f; --danger: #e07a8c;
33
+ --warn-soft: rgba(217, 169, 63, 0.10);
34
+ --code-bg: #0e1110; --code-text: #cfe0d4;
35
+ --tip-bg: #212522; --shadow: 0 14px 40px rgba(0, 0, 0, 0.5);
36
+ }
37
+ }
38
+ * { box-sizing: border-box; }
39
+ html, body { margin: 0; }
40
+ body { background: var(--bg); color: var(--ink); font: 400 14px/1.55 var(--sans); -webkit-font-smoothing: antialiased; }
41
+ a { color: inherit; text-decoration: none; } a:hover { color: var(--gain); }
42
+ .eyebrow { color: var(--faint); font: 600 11px/1 var(--mono); text-transform: uppercase; letter-spacing: 0.1em; }
39
43
 
40
- <section class="viewer-main">
41
- <header class="app-header">
42
- <div class="brand-block">
43
- <span class="eyebrow" id="pageEyebrow">kage://overview</span>
44
- <h1 id="pageTitle">Repo dashboard</h1>
45
- <p id="graphSummary">What is safe to change next, what needs attention, and what is ready to hand off.</p>
46
- </div>
47
- <div id="statusStrip" class="status-strip" aria-label="Graph health"></div>
48
- <div id="autoLoadStatus" class="autoload-status">auto-load: waiting</div>
49
- <label class="file-picker">
50
- <span>Manual JSON</span>
51
- <input id="graphFile" type="file" accept=".json,application/json" multiple>
52
- </label>
53
- </header>
44
+ .app { display: grid; grid-template-columns: 240px minmax(0,1fr); min-height: 100vh; }
45
+ /* sidebar */
46
+ .side { position: sticky; top: 0; height: 100vh; display: flex; flex-direction: column;
47
+ padding: 20px 16px; border-right: 1px solid var(--line); background: var(--paper); }
48
+ .brand { display: inline-flex; align-items: center; gap: 10px; padding: 4px 6px 18px; font: 700 17px/1 var(--serif); letter-spacing: 0.01em; }
49
+ .brand .mark { width: 30px; height: 30px; display: grid; place-items: center; border: 1px solid var(--line-strong);
50
+ border-radius: var(--r-control); background: var(--ink); color: var(--paper); font: 700 15px/1 var(--serif); }
51
+ .repocard { margin: 0 2px 16px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--bg); }
52
+ .repocard .eyebrow { display: block; } .repocard strong { display: block; margin-top: 6px; font: 600 13px/1.3 var(--sans); overflow-wrap: anywhere; }
53
+ .nav { display: flex; flex-direction: column; gap: 2px; }
54
+ .nav button { display: flex; align-items: center; gap: 11px; width: 100%; text-align: left; cursor: pointer;
55
+ background: transparent; border: 1px solid transparent; color: var(--muted); font: 500 14px/1 var(--sans);
56
+ padding: 10px 11px; border-radius: var(--r-control); }
57
+ .nav button:hover { color: var(--ink); background: var(--paper-2); }
58
+ .nav button[aria-current="true"] { color: var(--gain); background: var(--gain-soft); border-color: var(--gain); font-weight: 600; }
59
+ .nav .ic { width: 15px; text-align: center; color: var(--faint); } .nav button[aria-current="true"] .ic { color: var(--gain); }
60
+ .side .grow { flex: 1; }
61
+ .side .links { display: flex; flex-direction: column; gap: 7px; padding-top: 14px; border-top: 1px solid var(--line); }
62
+ .side .links a { color: var(--faint); font: 500 12.5px/1 var(--sans); } .side .links a:hover { color: var(--ink); }
54
63
 
55
- <main class="layout">
56
- <section class="dashboard-panel" aria-label="Kage repo dashboard">
57
- <div id="trustHero" class="trust-hero" aria-label="Memory trust score"></div>
58
- <div id="suppressionShelf" class="suppression-shelf" aria-label="Memory withheld from recall" hidden></div>
59
- <div id="dashboardStats" class="dashboard-stats" aria-label="Repo dashboard stats"></div>
60
- <section id="repoXray" class="repo-xray" aria-label="Repository map">
61
- <div class="repo-xray-head">
62
- <div>
63
- <span>Repository map</span>
64
- <h2>What Kage understands about this repo</h2>
65
- </div>
66
- <strong id="repoXrayStatus">waiting</strong>
67
- </div>
68
- <p id="repoXrayScript">Entry points, core modules, change risk, tests, and memory overlays — mapped from the code graph.</p>
69
- <div id="repoXrayLayers" class="repo-xray-layers"></div>
70
- </section>
71
- <div id="dashboardCharts" class="dashboard-charts" aria-label="Repo health charts"></div>
72
- <div class="dashboard-grid">
73
- <article class="dashboard-card primary" id="dashboardMemory">
74
- <div class="dashboard-card-head"><span>Memory</span><strong>repo lore</strong></div>
75
- <h3>Reusable repo context</h3>
76
- <ul></ul>
77
- <a href="./memory.html" data-viewer-page="memory">Open memory</a>
78
- </article>
79
- <article class="dashboard-card primary" id="dashboardGraph">
80
- <div class="dashboard-card-head"><span>Graph</span><strong>source map</strong></div>
81
- <h3>What to inspect before editing</h3>
82
- <ul></ul>
83
- <a href="./graph.html" data-viewer-page="graph">Explore graph</a>
84
- </article>
85
- <article class="dashboard-card primary" id="dashboardIntel">
86
- <div class="dashboard-card-head"><span>Before You Edit</span><strong>checklist</strong></div>
87
- <h3>What needs attention</h3>
88
- <ul></ul>
89
- <a href="./intel.html" data-viewer-page="intel">Open edit checklist</a>
90
- </article>
91
- <article class="dashboard-card primary" id="dashboardReview">
92
- <div class="dashboard-card-head"><span>Review</span><strong>handoff</strong></div>
93
- <h3>Ready for handoff?</h3>
94
- <ul></ul>
95
- <a href="./review.html" data-viewer-page="review">Open review</a>
96
- </article>
97
- </div>
98
- </section>
64
+ .main { min-width: 0; }
65
+ .head { padding: 30px clamp(20px,3.4vw,44px) 6px; }
66
+ .head h1 { margin: 10px 0 0; font: 600 30px/1.12 var(--serif); letter-spacing: -0.005em; }
67
+ .head p { margin: 8px 0 0; color: var(--muted); font: 400 15px/1.5 var(--sans); max-width: 720px; }
68
+ .wrap { padding: 20px clamp(20px,3.4vw,44px) 90px; }
69
+ .section { display: none; } .section.active { display: block; animation: fade .25s ease; }
70
+ @keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
99
71
 
100
- <section class="graph-panel" aria-label="Graph rendering">
101
- <div class="graph-toolbar">
102
- <div>
103
- <h2>Dependency Graph</h2>
104
- <p id="graphSubhead">Combined repo memory and source graph.</p>
105
- </div>
106
- <div class="graph-actions" aria-label="Graph view controls">
107
- <span id="interactionHint" class="interaction-hint">drag canvas / wheel zoom / click node</span>
108
- <button id="zoomOut" type="button">-</button>
109
- <button id="fitView" type="button">Fit</button>
110
- <button id="zoomIn" type="button">+</button>
111
- </div>
112
- </div>
113
- <div id="graphCanvasWrap" class="graph-canvas-wrap">
114
- <canvas id="graphCanvas" aria-label="Interactive Kage memory and code graph"></canvas>
115
- <div id="threeGraph" class="three-graph" aria-label="Interactive 3D Kage memory and code graph"></div>
116
- <div id="graphTooltip" class="graph-tooltip" role="status"></div>
117
- </div>
118
- <svg id="graphSvg" class="fallback-graph" viewBox="0 0 1000 660" role="img" aria-labelledby="graphTitle graphDescription">
119
- <title id="graphTitle">Kage local memory and code graph terminal view</title>
120
- <desc id="graphDescription">Entities and relationships from loaded Kage memory and code graph JSON files.</desc>
121
- <defs>
122
- <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
123
- <path d="M 0 0 L 10 5 L 0 10 z"></path>
124
- </marker>
125
- </defs>
126
- <g id="edgeLayer"></g>
127
- <g id="nodeLayer"></g>
128
- </svg>
129
- <div id="emptyState" class="empty-state">
130
- <strong>No graph loaded</strong>
131
- <span>Choose Kage graph JSON files or open with graph, code, and metrics URL params.</span>
132
- </div>
133
- </section>
72
+ .panel { border: 1px solid var(--line); border-radius: var(--r-card); background: var(--paper); padding: 20px 22px; margin-bottom: 16px; }
73
+ .panel > h2 { margin: 0 0 16px; font: 600 14px/1.3 var(--sans); } .panel .sub { color: var(--faint); font-weight: 400; }
134
74
 
135
- <section class="workspace-shell" aria-label="Viewer workspace">
136
- <div class="workspace-body">
137
- <aside class="control-panel" aria-label="Graph controls">
138
- <div class="panel-heading compact">
139
- <h2>Find Context</h2>
140
- <span id="workspaceMode">Combined</span>
141
- </div>
142
- <div id="metricsSummary" class="metrics-grid"></div>
143
- <label>
144
- <span>File, symbol, route, test, or memory</span>
145
- <input id="searchInput" type="search" placeholder="Search before changing code...">
146
- </label>
147
- <div class="journey-actions" aria-label="Graph journeys">
148
- <button id="showUntrusted" type="button">Show untrusted edges</button>
149
- <button id="showUncovered" type="button">Show code without memory</button>
150
- <button id="showMemoryCode" type="button">Show memory-code links</button>
151
- </div>
152
- <details class="advanced-controls">
153
- <summary>More filters</summary>
154
- <label>
155
- <span>View</span>
156
- <select id="viewMode">
157
- <option value="combined">Combined</option>
158
- <option value="memory">Memory</option>
159
- <option value="code">Code</option>
160
- </select>
161
- </label>
162
- <label>
163
- <span>Node Type</span>
164
- <select id="typeFilter">
165
- <option value="">All types</option>
166
- </select>
167
- </label>
168
- <label>
169
- <span>Relation</span>
170
- <select id="relationFilter">
171
- <option value="">All relations</option>
172
- </select>
173
- </label>
174
- <label>
175
- <span>Max Nodes</span>
176
- <select id="maxNodes">
177
- <option value="60">60</option>
178
- <option value="90" selected>90</option>
179
- <option value="140">140</option>
180
- <option value="220">220</option>
181
- </select>
182
- </label>
183
- <label class="toggle-control">
184
- <input id="showDependencies" type="checkbox">
185
- <span>Include external dependencies</span>
186
- </label>
187
- <button id="resetView" type="button">Reset filters</button>
188
- </details>
189
- <input id="scopeFilter" type="hidden" value="signal">
190
- <div class="legend" aria-label="Legend">
191
- <span><i class="dot memory-dot"></i>memory packet</span>
192
- <span><i class="dot code-dot"></i>code artifact</span>
193
- <span><i class="line sample-line"></i>relation</span>
194
- </div>
195
- </aside>
75
+ /* ---- gains receipt: value numbers as heroes ---- */
76
+ .receipt { border: 1px solid var(--line-strong); border-radius: var(--r-card); background: var(--paper); margin-bottom: 16px; overflow: hidden; }
77
+ .receipt .r-head { display: flex; justify-content: space-between; gap: 12px; padding: 13px 24px;
78
+ border-bottom: 1px dashed var(--line-strong); color: var(--faint); font: 600 11px/1 var(--mono); text-transform: uppercase; letter-spacing: 0.12em; }
79
+ .receipt .r-hero { padding: 30px 24px 22px; }
80
+ .receipt .r-hero .big { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
81
+ .receipt .r-hero .big b { font: 600 64px/0.95 var(--serif); letter-spacing: -0.02em; color: var(--gain); font-variant-numeric: tabular-nums; }
82
+ .receipt .r-hero .big .unit { color: var(--muted); font: 500 16px/1 var(--sans); }
83
+ .receipt .r-hero .big .dollars { color: var(--ink); font: 600 22px/1 var(--serif); }
84
+ .receipt .r-hero .sub { margin-top: 10px; color: var(--muted); font: 400 13.5px/1.5 var(--sans); max-width: 560px; }
85
+ .receipt .r-windows { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px dashed var(--line-strong); }
86
+ .receipt .r-win { padding: 16px 24px; border-left: 1px dashed var(--line-strong); }
87
+ .receipt .r-win:first-child { border-left: 0; }
88
+ .receipt .r-win .k { color: var(--faint); font: 600 10px/1 var(--mono); text-transform: uppercase; letter-spacing: 0.1em; }
89
+ .receipt .r-win .v { margin-top: 8px; font: 600 24px/1 var(--serif); color: var(--ink); font-variant-numeric: tabular-nums; }
90
+ .receipt .r-win .d { margin-top: 5px; color: var(--gain); font: 600 12px/1 var(--mono); }
91
+ .receipt .r-lines { border-top: 1px dashed var(--line-strong); padding: 14px 24px 16px; }
92
+ .receipt .r-line { display: flex; align-items: baseline; gap: 10px; padding: 5px 0; font: 400 13.5px/1.5 var(--sans); color: var(--ink); }
93
+ .receipt .r-line .dots { flex: 1; border-bottom: 1px dotted var(--line-strong); transform: translateY(-4px); }
94
+ .receipt .r-line b { font: 600 14px/1 var(--mono); font-variant-numeric: tabular-nums; }
95
+ .receipt .r-line b.warn { color: var(--warn); } .receipt .r-line b.gain { color: var(--gain); }
96
+ .receipt .r-foot { border-top: 1px dashed var(--line-strong); padding: 11px 24px; color: var(--faint); font: 400 11px/1.5 var(--mono); }
196
97
 
197
- <aside class="graph-insights-panel" aria-label="Graph insights">
198
- <div class="panel-heading compact">
199
- <h2>Before You Change</h2>
200
- <span id="graphInsightStatus">signals</span>
201
- </div>
202
- <div id="graphInsights" class="graph-insights"></div>
203
- </aside>
98
+ /* gains timeline */
99
+ .vfeed { display: grid; }
100
+ .vev { display: grid; grid-template-columns: 20px 1fr auto; gap: 0 13px; align-items: baseline; padding: 11px 4px; border-top: 1px solid var(--line); }
101
+ .vev:first-child { border-top: 0; }
102
+ .vev .vi { font: 600 13px/1.5 var(--mono); text-align: center; }
103
+ .vev .vt { font: 400 13.5px/1.45 var(--sans); color: var(--ink); } .vev .vt b { font-weight: 600; }
104
+ .vev .when { color: var(--faint); font: 400 11px/1 var(--mono); white-space: nowrap; }
105
+ .vev.recall_served .vi { color: var(--gain); }
106
+ .vev.stale_withheld .vi { color: var(--warn); }
107
+ .vev.caller_answered .vi { color: var(--code); }
204
108
 
205
- <aside class="details-panel" aria-label="Selection details">
206
- <div class="panel-heading compact">
207
- <h2>Inspector</h2>
208
- <span id="selectionStatus">No selection</span>
209
- </div>
210
- <div id="selectionDetails" class="details-empty">Select an entity or edge.</div>
211
- <div class="path-finder inspector-path-finder" aria-label="Dependency path finder">
212
- <div class="path-finder-header">
213
- <span>Trace Code Path</span>
214
- <button id="clearPath" type="button">Clear</button>
215
- </div>
216
- <div class="path-finder-inputs">
217
- <input id="pathFromInput" type="search" list="pathNodeOptions" placeholder="From selected file or symbol...">
218
- <input id="pathToInput" type="search" list="pathNodeOptions" placeholder="To related test, route, or symbol...">
219
- <button id="findPath" type="button">Trace</button>
220
- </div>
221
- <datalist id="pathNodeOptions"></datalist>
222
- <div id="pathStatus" class="path-status">Select a code node, then trace to another code node when you need impact proof.</div>
223
- <div id="pathResult" class="path-result"></div>
224
- </div>
225
- </aside>
109
+ /* trust hero */
110
+ .hero { border: 1px solid var(--line); border-radius: var(--r-card); padding: 26px 28px; margin-bottom: 16px; background: var(--paper);
111
+ display: grid; grid-template-columns: minmax(190px,auto) 1fr; gap: 36px; align-items: center; }
112
+ .hero[data-status="ok"] { border-left: 3px solid var(--gain); }
113
+ .hero[data-status="warn"] { border-left: 3px solid var(--warn); }
114
+ .hero[data-status="alert"] { border-left: 3px solid var(--danger); }
115
+ .hero .score { display: flex; align-items: baseline; gap: 5px; margin-top: 12px; }
116
+ .hero .score b { font: 600 62px/0.9 var(--serif); letter-spacing: -0.02em; color: var(--gain); font-variant-numeric: tabular-nums; }
117
+ .hero[data-status="warn"] .score b { color: var(--warn); } .hero[data-status="alert"] .score b { color: var(--danger); }
118
+ .hero .score span { font: 500 17px/1 var(--sans); color: var(--faint); }
119
+ .hero .verdict { margin-top: 14px; color: var(--muted); font: 400 13px/1.55 var(--sans); max-width: 230px; }
120
+ .bars { display: grid; gap: 16px; }
121
+ .bar { display: grid; grid-template-columns: 1fr auto; gap: 6px 14px; align-items: center; }
122
+ .bar .lbl { font: 400 13.5px/1.3 var(--sans); } .bar .val { font: 600 13px/1 var(--mono); color: var(--gain); }
123
+ .bar .track { grid-column: 1/2; height: 5px; border-radius: 99px; background: var(--paper-2); overflow: hidden; }
124
+ .bar .track i { display: block; height: 100%; border-radius: 99px; background: var(--gain); width: 0; transition: width 1s cubic-bezier(.2,.7,.2,1); }
226
125
 
227
- <section class="memory-panel" aria-label="Memory library">
228
- <div class="panel-heading">
229
- <h2>Memory</h2>
230
- <span id="memoryStatus">packets</span>
231
- </div>
232
- <div id="memoryStats" class="memory-stats" aria-label="Memory summary"></div>
233
- <div id="memoryOverview" class="memory-overview" aria-label="Memory coverage chart"></div>
234
- <div class="memory-toolbar">
235
- <input id="memorySearch" type="search" placeholder="Search memory, path, command, bug, decision...">
236
- <select id="memoryFilter" aria-label="Memory filter">
237
- <option value="all">All memory</option>
238
- <option value="linked">Linked to code</option>
239
- <option value="needs-paths">Needs paths</option>
240
- <option value="decision">Decisions</option>
241
- <option value="runbook">Runbooks</option>
242
- <option value="bug_fix">Bug fixes</option>
243
- </select>
244
- </div>
245
- <div id="memoryList" class="memory-list"></div>
246
- </section>
126
+ /* stat tiles */
127
+ .tiles { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 12px; margin-bottom: 16px; }
128
+ .tile { border: 1px solid var(--line); border-radius: var(--r-card); padding: 16px 18px; background: var(--paper); }
129
+ .tile .k { color: var(--faint); font: 600 11px/1 var(--mono); text-transform: uppercase; letter-spacing: 0.06em; }
130
+ .tile .v { margin-top: 10px; font: 600 28px/1 var(--serif); letter-spacing: -0.01em; color: var(--ink); font-variant-numeric: tabular-nums; }
131
+ .tile .s { margin-top: 6px; color: var(--muted); font: 400 12.5px/1.3 var(--sans); }
132
+ .tile .v.green { color: var(--gain); } .tile .v.code { color: var(--code); } .tile .v.warn { color: var(--warn); } .tile .v.memory { color: var(--memory); }
247
133
 
248
- <section class="owners-panel" aria-label="Owners and contributors">
249
- <div class="panel-heading">
250
- <h2>Owners</h2>
251
- <span id="ownersStatus">git signals</span>
252
- </div>
253
- <div id="ownersSummary" class="owners-summary"></div>
254
- <div id="ownersList" class="owners-list"></div>
134
+ /* attention */
135
+ .alert-card { border: 1px solid var(--line); border-left: 3px solid var(--warn); border-radius: var(--r-card); overflow: hidden; margin-bottom: 16px; background: var(--paper); }
136
+ .alert-card .ah { display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid var(--line); background: var(--warn-soft); }
137
+ .alert-card .ah h2 { margin: 0; font: 600 14px/1 var(--sans); } .alert-card .ah .c { color: var(--warn); font: 600 12px/1 var(--mono); }
138
+ .att { display: grid; grid-template-columns: 1fr auto; gap: 4px 16px; padding: 13px 20px; border-top: 1px solid var(--line); }
139
+ .att:first-child { border-top: 0; }
140
+ .att .t { font: 500 14px/1.3 var(--sans); } .att .why { grid-column: 1/2; color: var(--warn); font: 400 12px/1.4 var(--sans); }
141
+ .att .tag { align-self: center; color: var(--faint); font: 500 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .04em; }
142
+
143
+ /* graph */
144
+ .graphwrap { position: relative; border: 1px solid var(--line); border-radius: var(--r-card); overflow: hidden; background: var(--paper-2); }
145
+ #graph { display: block; width: 100%; height: 580px; }
146
+ .glegend { position: absolute; left: 16px; bottom: 14px; display: flex; gap: 16px; color: var(--muted); font: 500 12px/1 var(--sans);
147
+ background: var(--paper); padding: 9px 13px; border-radius: var(--r-control); border: 1px solid var(--line); }
148
+ .glegend i { display: inline-block; width: 9px; height: 9px; border-radius: 99px; margin-right: 7px; vertical-align: middle; }
149
+ .glegend i.lg-memory { background: var(--memory); } .glegend i.lg-code { background: var(--code); } .glegend i.lg-warn { background: var(--warn); }
150
+ .gtip { position: absolute; pointer-events: none; background: var(--tip-bg); border: 1px solid var(--line-strong); border-radius: var(--r-control);
151
+ padding: 8px 11px; font: 400 12.5px/1.4 var(--sans); max-width: 270px; display: none; z-index: 5; box-shadow: var(--shadow); }
152
+ .gtip b { color: var(--ink); font-weight: 600; } .gtip .p { margin-top: 3px; color: var(--faint); font: 400 11px/1.3 var(--mono); }
153
+ .gdetail { position: absolute; right: 14px; top: 58px; width: 250px; display: none; z-index: 6; background: var(--paper);
154
+ border: 1px solid var(--line-strong); border-radius: var(--r-card); padding: 14px 15px; box-shadow: var(--shadow); }
155
+ .gdetail .gd-k { font: 600 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 7px; }
156
+ .gdetail .gd-k.k-file { color: var(--code); } .gdetail .gd-k.k-memory { color: var(--memory); }
157
+ .gdetail b.gd-t { display: block; color: var(--ink); font: 600 13.5px/1.4 var(--sans); padding-right: 16px; }
158
+ .gdetail .gd-row { margin-top: 9px; color: var(--muted); font: 400 12px/1.4 var(--sans); }
159
+ .gdetail .gd-row b { color: var(--ink); } .gdetail .gd-row b.hot, .gdetail .gd-row b.healthy { color: var(--gain); }
160
+ .gdetail .gd-row b.stale, .gdetail .gd-row b.disputed, .gdetail .gd-row b.ungrounded { color: var(--warn); }
161
+ .gdetail .gd-files { margin-top: 8px; padding-top: 9px; border-top: 1px solid var(--line); color: var(--faint); font: 400 11px/1.6 var(--mono); overflow-wrap: anywhere; }
162
+ .gdetail .gd-x { position: absolute; right: 8px; top: 6px; cursor: pointer; background: transparent; border: 0; color: var(--faint); font-size: 16px; line-height: 1; padding: 2px 5px; }
163
+ .gdetail .gd-x:hover { color: var(--ink); }
164
+ .ghint { position: absolute; left: 0; right: 0; bottom: 14px; text-align: center; pointer-events: none; color: var(--faint); font: 400 11.5px/1 var(--sans); }
165
+ .gtoolbar { position: absolute; left: 14px; top: 14px; right: 14px; display: flex; justify-content: space-between; gap: 10px; }
166
+ .gfilters, .gzoom { display: flex; gap: 4px; background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-control); padding: 4px; }
167
+ .gtoolbar button { cursor: pointer; background: transparent; border: 1px solid transparent; color: var(--muted); border-radius: 3px; font: 500 12px/1 var(--sans); padding: 6px 10px; }
168
+ .gtoolbar button:hover { color: var(--ink); background: var(--paper-2); }
169
+ .gfilters button[aria-pressed="true"] { color: var(--gain); background: var(--gain-soft); border-color: var(--gain); }
170
+ .gzoom button { width: 30px; padding: 6px 0; text-align: center; font-size: 14px; color: var(--ink); }
171
+
172
+ /* memory list */
173
+ .controls { margin-bottom: 12px; }
174
+ .controls input { width: 100%; background: var(--paper); border: 1px solid var(--line); color: var(--ink); border-radius: var(--r-control);
175
+ padding: 11px 14px; font: 400 14px/1 var(--sans); }
176
+ .controls input::placeholder { color: var(--faint); } .controls input:focus { outline: none; border-color: var(--gain); }
177
+ .chips { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 10px; }
178
+ .chip { font: 500 12.5px/1 var(--sans); padding: 8px 13px; border-radius: 99px; border: 1px solid var(--line); background: transparent; color: var(--muted); cursor: pointer; }
179
+ .chip[aria-pressed="true"] { border-color: var(--gain); background: var(--gain-soft); color: var(--ink); }
180
+ .chip b { color: var(--faint); font-weight: 600; } .chip[aria-pressed="true"] b { color: var(--gain); }
181
+ .memcount { color: var(--faint); font: 500 12px/1 var(--mono); margin: 2px 0 10px; }
182
+ .grouphead { display: flex; align-items: center; gap: 11px; padding: 18px 4px 9px; }
183
+ .grouphead:first-child { padding-top: 4px; }
184
+ .grouphead .gl { color: var(--muted); font: 600 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .09em; }
185
+ .grouphead .gc { color: var(--faint); font: 600 11px/1 var(--mono); }
186
+ .grouphead .gline { flex: 1; height: 1px; background: var(--line); }
187
+ .row { display: grid; grid-template-columns: 9px 1fr auto; gap: 0 14px; align-items: center; padding: 12px 8px; border-top: 1px solid var(--line); border-radius: var(--r-control); }
188
+ .grouphead + .row { border-top: 0; }
189
+ .row:hover { background: var(--paper-2); }
190
+ .dot { width: 8px; height: 8px; border-radius: 99px; background: var(--faint); }
191
+ .dot.hot { background: var(--gain-strong); } .dot.healthy { background: var(--gain); }
192
+ .dot.cold { background: var(--line-strong); } .dot.stale, .dot.disputed, .dot.ungrounded { background: var(--warn); }
193
+ .row .title { font: 500 14px/1.4 var(--sans); }
194
+ .row .meta { margin-top: 6px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
195
+ .type { color: var(--memory); font: 500 11px/1 var(--mono); padding: 3px 7px; border: 1px solid var(--memory); border-radius: var(--r-control); }
196
+ .paths { color: var(--faint); font: 400 11px/1.3 var(--mono); overflow-wrap: anywhere; }
197
+ .row .right { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; white-space: nowrap; }
198
+ .pill { font: 600 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .04em; padding: 4px 9px; border-radius: 99px; border: 1px solid var(--line); color: var(--muted); }
199
+ .pill.hot, .pill.healthy { color: var(--gain); border-color: var(--gain); background: var(--gain-soft); }
200
+ .pill.cold { color: var(--faint); }
201
+ .pill.stale, .pill.disputed, .pill.ungrounded { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }
202
+ .uses { color: var(--faint); font: 400 11px/1 var(--mono); }
203
+ .showmore { width: 100%; margin-top: 14px; padding: 12px; background: transparent; border: 1px solid var(--line); border-radius: var(--r-control); color: var(--muted); font: 500 13px/1 var(--sans); cursor: pointer; }
204
+ .showmore:hover { color: var(--ink); border-color: var(--line-strong); background: var(--paper-2); }
205
+ .row { cursor: pointer; }
206
+
207
+ /* activity */
208
+ .daybars { display: flex; align-items: flex-end; gap: 6px; height: 120px; padding-top: 8px; }
209
+ .daybars .col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 7px; min-width: 0; }
210
+ .daybars .col .bar { width: 100%; max-width: 30px; border-radius: 3px 3px 0 0; background: var(--gain); min-height: 3px; transition: height .8s cubic-bezier(.2,.7,.2,1); }
211
+ .daybars .col .bar.empty { background: var(--paper-2); }
212
+ .daybars .col .d { color: var(--faint); font: 400 9.5px/1 var(--mono); white-space: nowrap; }
213
+ .daybars .col .v { color: var(--muted); font: 600 11px/1 var(--mono); }
214
+ .feed { display: grid; }
215
+ .ev { display: grid; grid-template-columns: 18px 1fr auto; gap: 0 13px; align-items: baseline; padding: 11px 4px; border-top: 1px solid var(--line); }
216
+ .ev:first-child { border-top: 0; }
217
+ .ev .ei { font-size: 13px; line-height: 1.5; }
218
+ .ev .et { font: 500 13.5px/1.45 var(--sans); } .ev .ek { color: var(--faint); font: 500 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .04em; }
219
+ .ev .when { color: var(--faint); font: 400 11px/1 var(--mono); white-space: nowrap; }
220
+ .ev.recall .ei { color: var(--gain); } .ev.capture .ei { color: var(--memory); } .ev.supersede .ei, .ev.deprecate .ei { color: var(--warn); }
221
+
222
+ /* packet detail drawer */
223
+ .drawer-backdrop { position: fixed; inset: 0; background: rgba(28, 30, 26, 0.35); opacity: 0; pointer-events: none; transition: opacity .25s ease; z-index: 40; }
224
+ .drawer-backdrop.open { opacity: 1; pointer-events: auto; }
225
+ .drawer { position: fixed; top: 0; right: 0; height: 100vh; width: min(460px, 92vw); transform: translateX(102%); transition: transform .28s cubic-bezier(.2,.7,.2,1);
226
+ background: var(--paper); border-left: 1px solid var(--line-strong); z-index: 50; overflow-y: auto; padding: 24px 26px 60px; box-shadow: var(--shadow); }
227
+ .drawer.open { transform: translateX(0); }
228
+ .drawer .dr-x { position: absolute; right: 16px; top: 14px; cursor: pointer; background: transparent; border: 0; color: var(--faint); font-size: 22px; line-height: 1; padding: 2px 6px; }
229
+ .drawer .dr-x:hover { color: var(--ink); }
230
+ .drawer .dr-tags { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; margin: 4px 30px 0 0; }
231
+ .drawer .dr-title { margin: 14px 0 0; font: 600 20px/1.35 var(--serif); color: var(--ink); }
232
+ .drawer .dr-summary { margin: 10px 0 0; color: var(--muted); font: 400 14px/1.6 var(--sans); }
233
+ .drawer .dr-body { margin: 18px 0 0; padding: 16px; border: 1px solid var(--line); border-radius: var(--r-card); background: var(--code-bg);
234
+ color: var(--code-text); font: 400 13px/1.7 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; }
235
+ .drawer .dr-sec { margin-top: 20px; }
236
+ .drawer .dr-h { color: var(--faint); font: 600 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .08em; margin-bottom: 9px; }
237
+ .drawer .dr-file { color: var(--code); font: 400 12px/1.7 var(--mono); overflow-wrap: anywhere; }
238
+ .drawer .dr-tagrow { display: flex; gap: 6px; flex-wrap: wrap; }
239
+ .drawer .tg { color: var(--muted); font: 500 11px/1 var(--mono); padding: 4px 8px; border: 1px solid var(--line); border-radius: 99px; }
240
+ .drawer .dr-row { color: var(--muted); font: 400 13px/1.7 var(--sans); } .drawer .dr-row b { color: var(--ink); }
241
+ .drawer .dr-row.warn { color: var(--warn); }
242
+
243
+ /* insights */
244
+ .ins-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
245
+ .donut-row { display: flex; align-items: center; gap: 24px; }
246
+ .donut { width: 132px; height: 132px; border-radius: 99px; flex: none; position: relative; }
247
+ .donut::after { content: ""; position: absolute; inset: 21px; border-radius: 99px; background: var(--paper); }
248
+ .donut .center { position: absolute; inset: 0; display: grid; place-items: center; z-index: 1; text-align: center; }
249
+ .donut .center b { font: 600 26px/1 var(--serif); color: var(--gain); } .donut .center b.warn { color: var(--warn); } .donut .center b.danger { color: var(--danger); } .donut .center span { display: block; margin-top: 4px; color: var(--faint); font: 600 9px/1 var(--mono); text-transform: uppercase; letter-spacing: .04em; }
250
+ .donut-cap { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); color: var(--muted); font: 400 12.5px/1.5 var(--sans); }
251
+ .donut-cap b { color: var(--ink); font-weight: 600; }
252
+ .legend2 { display: grid; gap: 10px; flex: 1; }
253
+ .legend2 .li { display: flex; align-items: center; gap: 9px; font: 400 13px/1 var(--sans); }
254
+ .legend2 .li i { width: 9px; height: 9px; border-radius: 2px; } .legend2 .li b { margin-left: auto; color: var(--muted); font: 500 12px/1 var(--mono); }
255
+ .hbars { display: grid; gap: 11px; }
256
+ .hbar { display: grid; grid-template-columns: 116px 1fr 34px; gap: 12px; align-items: center; font: 400 13px/1 var(--sans); }
257
+ .hbar .n { color: var(--muted); } .hbar .t { height: 7px; border-radius: 99px; background: var(--paper-2); overflow: hidden; }
258
+ .hbar .t i { display: block; height: 100%; width: 0; min-width: 8px; border-radius: 99px; background: var(--memory); transition: width .9s cubic-bezier(.2,.7,.2,1); }
259
+ .hbar.code .t i { background: var(--code); }
260
+ .hbar .n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
261
+ .hbar .c { text-align: right; color: var(--faint); font: 500 12px/1 var(--mono); }
262
+ .facts { display: grid; gap: 13px; }
263
+ .fact { display: flex; gap: 12px; align-items: flex-start; color: var(--ink); font: 400 13.5px/1.5 var(--sans); }
264
+ .fact .em { font-size: 17px; line-height: 1.3; } .fact span { color: var(--muted); } .fact b { color: var(--ink); font-weight: 600; }
265
+ .fact code { padding: 1px 5px; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--paper-2); color: var(--code); font: 500 12px/1.4 var(--mono); }
266
+ .empty { color: var(--faint); padding: 22px 4px; font: 400 14px/1.5 var(--sans); }
267
+ @media (max-width: 760px) { .app { grid-template-columns: 1fr; } .side { position: static; height: auto; } .tiles { grid-template-columns: repeat(2,1fr); } .ins-grid { grid-template-columns: 1fr; } .hero { grid-template-columns: 1fr; gap: 22px; } .receipt .r-windows { grid-template-columns: 1fr; } .receipt .r-win { border-left: 0; border-top: 1px dashed var(--line-strong); } .receipt .r-win:first-child { border-top: 0; } }
268
+ </style>
269
+ </head>
270
+ <body>
271
+ <div class="app">
272
+ <aside class="side">
273
+ <div class="brand"><span class="mark">K</span> Kage</div>
274
+ <div class="repocard"><span class="eyebrow">Repository</span><strong id="repo">loading…</strong></div>
275
+ <nav class="nav" id="nav">
276
+ <button data-section="gains" aria-current="true"><span class="ic">⊕</span> Gains</button>
277
+ <button data-section="overview"><span class="ic">◎</span> Trust</button>
278
+ <button data-section="graph"><span class="ic">⬡</span> Memory map</button>
279
+ <button data-section="memory"><span class="ic">▤</span> Memory</button>
280
+ <button data-section="activity"><span class="ic">◷</span> Activity</button>
281
+ <button data-section="insights"><span class="ic">▦</span> Insights</button>
282
+ </nav>
283
+ <div class="grow"></div>
284
+ <div class="links">
285
+ <a href="https://kage-core.github.io/Kage/">Website ↗</a>
286
+ <a href="https://kage-core.github.io/Kage/guide.html">Docs ↗</a>
287
+ <a href="https://github.com/kage-core/Kage">GitHub ↗</a>
288
+ </div>
289
+ </aside>
290
+
291
+ <main class="main">
292
+ <header class="head">
293
+ <span class="eyebrow" id="eyebrow">kage://gains</span>
294
+ <h1 id="title">What Kage saved you</h1>
295
+ <p id="subtitle">Tokens, dollars, and bad memories caught — receipts, not vibes.</p>
296
+ </header>
297
+ <div class="wrap">
298
+ <section class="section active" id="section-gains">
299
+ <div class="receipt" id="gainsHero"></div>
300
+ <div class="tiles" id="gainsTiles"></div>
301
+ <div class="panel"><h2>Value timeline <span class="sub">— every saved recall and withheld stale memory, as it happened</span></h2><div id="gainsTimeline"></div></div>
255
302
  </section>
256
303
 
257
- <section class="review-panel" aria-label="Review queue">
258
- <div class="panel-heading">
259
- <h2>Memory Inbox</h2>
260
- <span id="reviewCount">0</span>
261
- </div>
262
- <div id="reviewOverview" class="review-overview"></div>
263
- <div id="reviewList" class="review-list"></div>
304
+ <section class="section" id="section-overview">
305
+ <div id="hero" class="hero" data-status="idle"></div>
306
+ <div class="tiles" id="tiles"></div>
307
+ <div id="attentionMount"></div>
264
308
  </section>
265
309
 
266
- <section class="proof-panel" aria-label="Quality and benchmark">
267
- <div class="panel-heading">
268
- <h2>Proof</h2>
269
- <span id="proofStatus">metrics</span>
310
+ <section class="section" id="section-graph">
311
+ <div class="panel" style="padding:16px 18px;">
312
+ <h2>Memory ↔ code map <span class="sub">— every memory packet linked to the files it's grounded in</span></h2>
313
+ <div class="graphwrap">
314
+ <canvas id="graph"></canvas>
315
+ <div class="gtoolbar">
316
+ <div class="gfilters" id="gfilters">
317
+ <button data-gfilter="all" aria-pressed="true">All</button>
318
+ <button data-gfilter="review">Needs review</button>
319
+ <button data-gfilter="hot">Hot</button>
320
+ </div>
321
+ <div class="gzoom">
322
+ <button id="zoomOut" title="Zoom out">−</button>
323
+ <button id="zoomIn" title="Zoom in">+</button>
324
+ <button id="resetView" title="Reset view">⤢</button>
325
+ </div>
326
+ </div>
327
+ <div class="ghint">scroll to zoom · drag a node to pin · click to focus · double-click to zoom in</div>
328
+ <div class="glegend"><span><i class="lg-memory"></i>memory</span><span><i class="lg-code"></i>code file</span><span><i class="lg-warn"></i>needs review</span></div>
329
+ <div class="gtip" id="gtip"></div>
330
+ <div class="gdetail" id="gdetail"></div>
331
+ </div>
270
332
  </div>
271
- <div id="proofOverview" class="proof-overview"></div>
272
- <div id="proofList" class="proof-list"></div>
273
333
  </section>
274
334
 
275
- <section class="intelligence-panel" aria-label="Before edit risks and reports">
276
- <div class="panel-heading">
277
- <h2>Before You Edit</h2>
278
- <span id="intelligenceStatus">reports</span>
279
- </div>
280
- <div id="intelligenceList" class="intelligence-list"></div>
335
+ <section class="section" id="section-memory">
336
+ <div class="controls"><input id="search" type="search" placeholder="Search memory by title, file, or type…" /></div>
337
+ <div class="chips" id="chips"></div>
338
+ <div class="memcount" id="memcount"></div>
339
+ <div class="panel" style="padding:6px 22px;"><div id="list"></div></div>
281
340
  </section>
282
341
 
283
- <section class="table-panel entities-panel" aria-label="Nodes">
284
- <div class="panel-heading">
285
- <h2>Artifact Nodes</h2>
286
- <span id="entityCount">0</span>
287
- </div>
288
- <div id="debugOverview" class="debug-overview"></div>
289
- <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>
290
- <div id="entityList" class="list"></div>
342
+ <section class="section" id="section-activity">
343
+ <div class="tiles" id="activityTiles"></div>
344
+ <div class="panel"><h2>Recalls per day <span class="sub">— how often agents pulled this repo's memory</span></h2><div class="daybars" id="activityDaily"></div></div>
345
+ <div class="panel"><h2>Recent activity</h2><div id="activityFeed"></div></div>
291
346
  </section>
292
347
 
293
- <section class="table-panel edges-panel" aria-label="Relations">
294
- <div class="panel-heading">
295
- <h2>Artifact Relations</h2>
296
- <span id="edgeCount">0</span>
348
+ <section class="section" id="section-insights">
349
+ <div class="ins-grid">
350
+ <div class="panel"><h2>Memory health</h2><div class="donut-row"><div class="donut" id="donut"><div class="center" id="donutCenter"></div></div><div class="legend2" id="healthLegend"></div></div><div class="donut-cap" id="healthCap"></div></div>
351
+ <div class="panel"><h2>Memory by type</h2><div class="hbars" id="typeBars"></div></div>
352
+ </div>
353
+ <div class="panel"><h2>Codebase Kage has mapped</h2><div class="tiles" id="codeTiles" style="margin:0;"></div></div>
354
+ <div class="ins-grid">
355
+ <div class="panel"><h2>Most-grounded files <span class="sub">— code your memory is anchored to</span></h2><div class="hbars" id="groundedFiles"></div></div>
356
+ <div class="panel"><h2>Worth knowing</h2><div class="facts" id="facts"></div></div>
297
357
  </div>
298
- <div class="debug-guide">Relations expose generation quality: evidence, confidence, invalidation, and memory-code linking.</div>
299
- <div id="edgeList" class="list"></div>
300
358
  </section>
301
359
  </div>
302
- </section>
303
- </main>
304
- </section>
360
+ </main>
305
361
  </div>
306
-
307
- <script src="./app.js?v=53"></script>
362
+ <div class="drawer-backdrop" id="detailBackdrop"></div>
363
+ <aside class="drawer" id="detail" aria-hidden="true"></aside>
364
+ <script src="./console.js?v=16"></script>
308
365
  </body>
309
366
  </html>