@plumpslabs/kuma 2.3.32 → 2.3.33
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/README.md +321 -184
- package/dist/index.js +224 -13
- package/package.json +1 -1
- package/packages/ide/studio/dist/index.js +31 -13
- package/packages/ide/studio/public/index.html +350 -75
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Kuma Studio</title>
|
|
7
|
-
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><circle cx='50' cy='50' r='48' fill='%23D97706'/><circle cx='50' cy='50' r='44' fill='%23F59E0B'/><circle cx='50' cy='45' r='30' fill='%2392400E'/><circle cx='35' cy='38' r='5' fill='%231F2937'/><circle cx='65' cy='38' r='5' fill='%231F2937'/><ellipse cx='50' cy='50' rx='10' ry='6' fill='%23B45309'/><path d='M35 58 Q50 72 65 58' stroke='%231F2937' stroke-width='3.5' fill='none' stroke-linecap='round'/></svg>">
|
|
8
8
|
<script src="https://unpkg.com/vis-network@9.1.9/dist/vis-network.min.js"></script>
|
|
9
9
|
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js"></script>
|
|
10
10
|
<style>
|
|
11
11
|
:root {
|
|
12
|
-
--bg: #
|
|
13
|
-
--text: #
|
|
14
|
-
--green: #
|
|
12
|
+
--bg: #0f172a; --surface: #1e293b; --border: #334155;
|
|
13
|
+
--text: #f1f5f9; --muted: #94a3b8; --accent: #a78bfa; --accent2: #22d3ee;
|
|
14
|
+
--green: #34d399; --yellow: #fbbf24; --orange: #fb923c; --red: #f87171;
|
|
15
|
+
--accent-bright: #c4b5fd; --accent2-bright: #67e8f9;
|
|
15
16
|
}
|
|
16
17
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
18
|
html, body {
|
|
@@ -20,46 +21,44 @@ html, body {
|
|
|
20
21
|
touch-action: none; -webkit-user-select: none; user-select: none;
|
|
21
22
|
}
|
|
22
23
|
header {
|
|
23
|
-
display: flex; align-items: center; gap:
|
|
24
|
+
display: flex; align-items: center; gap: 12px; padding: 8px 16px;
|
|
24
25
|
background: var(--surface); border-bottom: 1px solid var(--border);
|
|
25
26
|
-webkit-app-region: drag;
|
|
26
27
|
}
|
|
27
|
-
header {
|
|
28
|
-
display: flex; align-items: center; gap: 16px; padding: 12px 24px;
|
|
29
|
-
background: var(--surface); border-bottom: 1px solid var(--border);
|
|
30
|
-
-webkit-app-region: drag;
|
|
31
|
-
}
|
|
32
|
-
header h1 { font-size: 18px; font-weight: 700; color: var(--accent); letter-spacing: -0.5px; }
|
|
28
|
+
header h1 { font-size: 15px; font-weight: 700; color: var(--accent-bright); letter-spacing: -0.5px; text-shadow: 0 0 12px rgba(167,139,250,0.3); }
|
|
33
29
|
header .status { font-size: 12px; color: var(--muted); }
|
|
34
30
|
header .status .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
|
|
35
31
|
header .status .dot.on { background: var(--green); }
|
|
36
32
|
header .status .dot.off { background: var(--red); }
|
|
37
33
|
.stats-bar {
|
|
38
|
-
display: flex; gap:
|
|
39
|
-
border-bottom: 1px solid var(--border); font-size:
|
|
40
|
-
overflow-x: auto;
|
|
34
|
+
display: flex; gap: 6px; padding: 6px 16px; background: var(--surface);
|
|
35
|
+
border-bottom: 1px solid var(--border); font-size: 11px;
|
|
36
|
+
overflow-x: auto; flex-wrap: nowrap;
|
|
41
37
|
}
|
|
42
|
-
.stat { display: flex; align-items: center; gap:
|
|
43
|
-
.stat .num { font-weight: 700; color: var(--accent2); }
|
|
44
|
-
.stat .lbl { color: var(--muted); }
|
|
45
|
-
#main { display: flex; height: calc(100vh -
|
|
38
|
+
.stat { display: flex; align-items: center; gap: 3px; padding: 3px 8px; border-radius: 5px; background: var(--bg); white-space: nowrap; }
|
|
39
|
+
.stat .num { font-weight: 700; color: var(--accent2); font-size: 12px; }
|
|
40
|
+
.stat .lbl { color: var(--muted); font-size: 10px; }
|
|
41
|
+
#main { display: flex; height: calc(100vh - 80px); }
|
|
46
42
|
#graph-panel { flex: 1; position: relative; min-width: 0; overflow: hidden; }
|
|
47
43
|
#graph-container { width: 100%; height: 100%; background: radial-gradient(ellipse at center, #1e1e3a 0%, var(--bg) 70%); }
|
|
48
|
-
#sidebar { width:
|
|
49
|
-
.tabs { display: flex; border-bottom: 1px solid var(--border); }
|
|
44
|
+
#sidebar { width: 320px; min-width: 320px; background: var(--surface); border-left: 1px solid var(--border); display: flex; flex-direction: column; }
|
|
45
|
+
.tabs { display: flex; gap: 3px; padding: 8px 12px 4px; background: var(--surface); border-bottom: 1px solid var(--border); overflow-x: auto; flex-wrap: nowrap; }
|
|
50
46
|
.tab {
|
|
51
|
-
|
|
52
|
-
color: var(--muted); border-
|
|
47
|
+
padding: 5px 10px; text-align: center; cursor: pointer; font-size: 11px;
|
|
48
|
+
color: var(--muted); border-radius: 6px; transition: all 0.15s; white-space: nowrap;
|
|
49
|
+
display: flex; align-items: center; gap: 4px; border: 1px solid transparent;
|
|
53
50
|
}
|
|
54
|
-
.tab:hover { color: var(--text); }
|
|
55
|
-
.tab.active { color: var(--accent); border-
|
|
56
|
-
.tab-content { flex: 1; overflow-y: auto; padding: 12px; }
|
|
51
|
+
.tab:hover { color: var(--text); background: rgba(167,139,250,0.08); }
|
|
52
|
+
.tab.active { color: var(--accent-bright); background: rgba(167,139,250,0.12); border-color: rgba(167,139,250,0.25); }
|
|
53
|
+
.tab-content { flex: 1; overflow-y: auto; padding: 10px 12px; }
|
|
57
54
|
.panel { display: none; }
|
|
58
|
-
.panel.active { display: block; }
|
|
55
|
+
.panel.active { display: block; animation: fadeIn 0.15s; }
|
|
56
|
+
.tab-label { font-size: 11px; }
|
|
57
|
+
@media (max-width: 400px) { .tab-label { display: none; } .tab { padding: 5px 8px; } }
|
|
59
58
|
|
|
60
59
|
/* Gotcha items */
|
|
61
60
|
.gotcha-item {
|
|
62
|
-
padding: 10px
|
|
61
|
+
padding: 8px 10px; margin-bottom: 6px; border-radius: 6px;
|
|
63
62
|
background: var(--bg); border-left: 3px solid var(--muted); cursor: pointer;
|
|
64
63
|
transition: background 0.15s;
|
|
65
64
|
}
|
|
@@ -74,19 +73,19 @@ header .status .dot.off { background: var(--red); }
|
|
|
74
73
|
|
|
75
74
|
/* Feature items */
|
|
76
75
|
.feature-item {
|
|
77
|
-
padding: 10px
|
|
76
|
+
padding: 8px 10px; margin-bottom: 6px; border-radius: 6px;
|
|
78
77
|
background: var(--bg); border-left: 3px solid var(--accent); cursor: pointer;
|
|
79
78
|
transition: background 0.15s;
|
|
80
79
|
}
|
|
81
80
|
.feature-item:hover { background: #1e293b; }
|
|
82
|
-
.feature-item .name { font-size:
|
|
81
|
+
.feature-item .name { font-size: 13px; font-weight: 600; color: var(--accent); margin-bottom: 2px; }
|
|
83
82
|
.feature-item .meta { font-size: 11px; color: var(--muted); }
|
|
84
83
|
.feature-item .tags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px; }
|
|
85
|
-
.feature-item .tag { font-size: 10px; padding: 1px 6px; border-radius: 4px; background: rgba(
|
|
84
|
+
.feature-item .tag { font-size: 10px; padding: 1px 6px; border-radius: 4px; background: rgba(167,139,250,0.15); color: var(--accent-bright); }
|
|
86
85
|
|
|
87
86
|
/* Health items */
|
|
88
|
-
.health-item { padding:
|
|
89
|
-
.health-item .score { font-size:
|
|
87
|
+
.health-item { padding: 6px 10px; margin-bottom: 5px; background: var(--bg); border-radius: 5px; }
|
|
88
|
+
.health-item .score { font-size: 18px; font-weight: 700; }
|
|
90
89
|
.health-item .score.good { color: var(--green); }
|
|
91
90
|
.health-item .score.ok { color: var(--yellow); }
|
|
92
91
|
.health-item .score.bad { color: var(--red); }
|
|
@@ -96,7 +95,7 @@ header .status .dot.off { background: var(--red); }
|
|
|
96
95
|
|
|
97
96
|
/* Legend */
|
|
98
97
|
#legend {
|
|
99
|
-
position: fixed; bottom: 16px; left: 16px; background: rgba(
|
|
98
|
+
position: fixed; bottom: 16px; left: 16px; background: rgba(15,23,42,0.95);
|
|
100
99
|
border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px;
|
|
101
100
|
font-size: 11px; z-index: 10; max-height: 200px; overflow-y: auto;
|
|
102
101
|
backdrop-filter: blur(8px); color: #f8fafc;
|
|
@@ -130,45 +129,45 @@ header .status .dot.off { background: var(--red); }
|
|
|
130
129
|
border-radius: 6px; cursor: pointer; font-size: 12px; color: var(--text);
|
|
131
130
|
transition: background 0.1s;
|
|
132
131
|
}
|
|
133
|
-
#ctx-menu .ctx-item:hover { background: rgba(
|
|
132
|
+
#ctx-menu .ctx-item:hover { background: rgba(167,139,250,0.15); color: var(--accent-bright); }
|
|
134
133
|
#ctx-menu .ctx-item i { width: 14px; height: 14px; flex-shrink: 0; }
|
|
135
134
|
#ctx-menu .ctx-sep { height: 1px; background: var(--border); margin: 4px 8px; }
|
|
136
135
|
#search-box input {
|
|
137
|
-
background: rgba(
|
|
136
|
+
background: rgba(15,23,42,0.92); border: 1px solid var(--border);
|
|
138
137
|
border-radius: 8px; padding: 8px 12px; color: var(--text); font-size: 12px;
|
|
139
138
|
width: 200px; outline: none; backdrop-filter: blur(8px);
|
|
140
139
|
transition: border-color 0.2s;
|
|
141
140
|
}
|
|
142
|
-
#search-box input:focus { border-color: var(--accent); }
|
|
141
|
+
#search-box input:focus { border-color: var(--accent-bright); box-shadow: 0 0 8px rgba(167,139,250,0.3); }
|
|
143
142
|
#search-box input::placeholder { color: var(--muted); }
|
|
144
143
|
|
|
145
144
|
/* Graph controls */
|
|
146
145
|
#graph-controls {
|
|
147
|
-
position: fixed; bottom: 16px; right:
|
|
146
|
+
position: fixed; bottom: 16px; right: 336px; z-index: 10;
|
|
148
147
|
display: flex; gap: 6px;
|
|
149
148
|
}
|
|
150
149
|
#graph-controls button {
|
|
151
|
-
background: rgba(
|
|
150
|
+
background: rgba(15,23,42,0.92); border: 1px solid var(--border);
|
|
152
151
|
border-radius: 6px; color: var(--text); padding: 6px 10px;
|
|
153
152
|
font-size: 11px; cursor: pointer; backdrop-filter: blur(8px);
|
|
154
153
|
transition: background 0.2s;
|
|
155
154
|
}
|
|
156
|
-
#graph-controls button:hover { background: var(--accent); border-color: var(--accent); }
|
|
155
|
+
#graph-controls button:hover { background: var(--accent); border-color: var(--accent-bright); }
|
|
157
156
|
#graph-controls button.active {
|
|
158
|
-
background: var(--accent) !important; border-color: var(--accent) !important;
|
|
159
|
-
color: #ffffff !important; box-shadow: 0 0
|
|
157
|
+
background: var(--accent) !important; border-color: var(--accent-bright) !important;
|
|
158
|
+
color: #ffffff !important; box-shadow: 0 0 12px rgba(167,139,250,0.5);
|
|
160
159
|
}
|
|
161
160
|
#graph-controls .ctrl-sep { width: 1px; background: var(--border); margin: 0 2px; }
|
|
162
161
|
.depth-btn { min-width: 28px !important; padding: 4px 6px !important; font-size: 11px !important; font-weight: 600; }
|
|
163
|
-
.depth-btn.active { background: rgba(
|
|
162
|
+
.depth-btn.active { background: rgba(167,139,250,0.25) !important; border-color: var(--accent-bright) !important; color: var(--accent-bright) !important; }
|
|
164
163
|
|
|
165
164
|
/* Loading */
|
|
166
165
|
#loading {
|
|
167
166
|
position: fixed; inset: 0; background: var(--bg); display: flex;
|
|
168
167
|
align-items: center; justify-content: center; z-index: 100;
|
|
169
|
-
font-size: 18px; color: var(--accent); flex-direction: column; gap: 16px;
|
|
168
|
+
font-size: 18px; color: var(--accent-bright); flex-direction: column; gap: 16px;
|
|
170
169
|
}
|
|
171
|
-
#loading .spinner { width: 32px; height: 32px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; }
|
|
170
|
+
#loading .spinner { width: 32px; height: 32px; border: 3px solid var(--border); border-top-color: var(--accent-bright); border-radius: 50%; animation: spin 0.8s linear infinite; }
|
|
172
171
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
173
172
|
|
|
174
173
|
/* Node Detail Modal */
|
|
@@ -179,31 +178,31 @@ header .status .dot.off { background: var(--red); }
|
|
|
179
178
|
}
|
|
180
179
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
181
180
|
.modal {
|
|
182
|
-
background: var(--surface); border: 1px solid var(--border); border-radius:
|
|
183
|
-
width:
|
|
181
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
182
|
+
width: 520px; max-width: 90vw; max-height: 85vh; overflow: hidden; box-shadow: 0 16px 64px rgba(0,0,0,0.5);
|
|
184
183
|
display: flex; flex-direction: column; animation: slideUp 0.2s;
|
|
185
184
|
}
|
|
186
185
|
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
|
|
187
186
|
.modal-header {
|
|
188
187
|
display: flex; align-items: center; justify-content: space-between;
|
|
189
|
-
padding:
|
|
188
|
+
padding: 10px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0;
|
|
190
189
|
}
|
|
191
|
-
.modal-header h2 { font-size:
|
|
190
|
+
.modal-header h2 { font-size: 13px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
192
191
|
.modal-header .close {
|
|
193
192
|
background: none; border: none; color: var(--muted); font-size: 18px;
|
|
194
193
|
cursor: pointer; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;
|
|
195
194
|
border-radius: 6px; transition: all 0.15s; flex-shrink: 0;
|
|
196
195
|
}
|
|
197
196
|
.modal-header .close:hover { background: rgba(255,255,255,0.1); color: var(--text); }
|
|
198
|
-
.modal-body { padding: 16px
|
|
199
|
-
.modal-section { margin-bottom:
|
|
200
|
-
.modal-section h3 { font-size:
|
|
201
|
-
.modal-kv { display: flex; gap:
|
|
202
|
-
.modal-kv .key { color: var(--muted); min-width:
|
|
197
|
+
.modal-body { padding: 12px 16px; overflow-y: auto; flex: 1; min-height: 0; }
|
|
198
|
+
.modal-section { margin-bottom: 10px; }
|
|
199
|
+
.modal-section h3 { font-size: 10px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }
|
|
200
|
+
.modal-kv { display: flex; gap: 6px; margin-bottom: 3px; font-size: 11px; line-height: 1.3; }
|
|
201
|
+
.modal-kv .key { color: var(--muted); min-width: 64px; flex-shrink: 0; }
|
|
203
202
|
.modal-kv .val { color: var(--text); word-break: break-word; overflow-wrap: anywhere; min-width: 0; }
|
|
204
203
|
.relation-item {
|
|
205
|
-
display: flex; align-items: center; gap:
|
|
206
|
-
margin-bottom:
|
|
204
|
+
display: flex; align-items: center; gap: 5px; padding: 4px 7px;
|
|
205
|
+
margin-bottom: 2px; border-radius: 5px; background: var(--bg);
|
|
207
206
|
font-size: 11px; cursor: pointer; transition: background 0.15s;
|
|
208
207
|
}
|
|
209
208
|
.relation-item:hover { background: #1e293b; }
|
|
@@ -212,20 +211,20 @@ header .status .dot.off { background: var(--red); }
|
|
|
212
211
|
.relation-item .type { color: var(--muted); font-size: 10px; flex-shrink: 0; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
213
212
|
.relation-item .weight { color: var(--accent2); font-size: 10px; flex-shrink: 0; }
|
|
214
213
|
|
|
215
|
-
::-webkit-scrollbar { width:
|
|
214
|
+
::-webkit-scrollbar { width: 4px; height: 4px; }
|
|
216
215
|
::-webkit-scrollbar-track { background: transparent; }
|
|
217
|
-
::-webkit-scrollbar-thumb { background: var(--border); border-radius:
|
|
216
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
|
218
217
|
</style>
|
|
219
218
|
</head>
|
|
220
219
|
<body>
|
|
221
220
|
<div id="loading"><div class="spinner"></div>Connecting to Kuma...</div>
|
|
222
221
|
<header>
|
|
223
|
-
<h1><
|
|
222
|
+
<h1><svg width="22" height="22" viewBox="0 0 100 100" style="vertical-align:middle;margin-right:6px"><circle cx="50" cy="50" r="48" fill="#D97706"/><circle cx="50" cy="50" r="44" fill="#F59E0B"/><circle cx="50" cy="45" r="30" fill="#92400E"/><circle cx="35" cy="38" r="5" fill="#1F2937"/><circle cx="65" cy="38" r="5" fill="#1F2937"/><ellipse cx="50" cy="50" rx="10" ry="6" fill="#B45309"/><path d="M35 58 Q50 72 65 58" stroke="#1F2937" stroke-width="3.5" fill="none" stroke-linecap="round"/></svg> Kuma Studio</h1>
|
|
224
223
|
<div class="status"><span class="dot" id="status-dot"></span><span id="status-text">connecting...</span></div>
|
|
225
224
|
<div style="margin-left:auto;display:flex;gap:8px;-webkit-app-region:no-drag">
|
|
226
|
-
<button onclick="refetch()" id="refetch-btn" style="background:rgba(
|
|
227
|
-
<button onclick="resetKumaDb()" style="background:rgba(239,68,68,0.
|
|
228
|
-
<button onclick="stopKumaStudio()" style="background:rgba(148,163,184,0.
|
|
225
|
+
<button onclick="refetch()" id="refetch-btn" style="background:rgba(167,139,250,0.12);border:1px solid rgba(167,139,250,0.25);border-radius:5px;color:var(--accent-bright);padding:4px 10px;font-size:10px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:3px"><i data-lucide="refresh-cw" style="width:11px;height:11px"></i> Refetch</button>
|
|
226
|
+
<button onclick="resetKumaDb()" style="background:rgba(239,68,68,0.12);border:1px solid rgba(239,68,68,0.25);border-radius:5px;color:var(--red);padding:4px 10px;font-size:10px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:3px"><i data-lucide="trash-2" style="width:11px;height:11px"></i> Reset</button>
|
|
227
|
+
<button onclick="stopKumaStudio()" style="background:rgba(148,163,184,0.12);border:1px solid rgba(148,163,184,0.25);border-radius:5px;color:#94a3b8;padding:4px 10px;font-size:10px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:3px"><i data-lucide="square" style="width:11px;height:11px"></i> Stop</button>
|
|
229
228
|
</div>
|
|
230
229
|
</header>
|
|
231
230
|
<div class="stats-bar" id="stats-bar"></div>
|
|
@@ -249,11 +248,12 @@ header .status .dot.off { background: var(--red); }
|
|
|
249
248
|
</div>
|
|
250
249
|
<div id="sidebar">
|
|
251
250
|
<div class="tabs">
|
|
252
|
-
<div class="tab active" data-tab="features"><i data-lucide="star" style="width:
|
|
253
|
-
<div class="tab" data-tab="gotchas"><i data-lucide="alert-triangle" style="width:
|
|
254
|
-
<div class="tab" data-tab="health"><i data-lucide="heart-pulse" style="width:
|
|
255
|
-
<div class="tab" data-tab="efficiency"><i data-lucide="zap" style="width:
|
|
256
|
-
<div class="tab" data-tab="staleness"><i data-lucide="activity" style="width:
|
|
251
|
+
<div class="tab active" data-tab="features" title="Features"><i data-lucide="star" style="width:12px;height:12px"></i><span class="tab-label">Features</span></div>
|
|
252
|
+
<div class="tab" data-tab="gotchas" title="Gotchas"><i data-lucide="alert-triangle" style="width:12px;height:12px"></i><span class="tab-label">Gotchas</span></div>
|
|
253
|
+
<div class="tab" data-tab="health" title="Health"><i data-lucide="heart-pulse" style="width:12px;height:12px"></i><span class="tab-label">Health</span></div>
|
|
254
|
+
<div class="tab" data-tab="efficiency" title="Efficiency"><i data-lucide="zap" style="width:12px;height:12px"></i><span class="tab-label">Efficiency</span></div>
|
|
255
|
+
<div class="tab" data-tab="staleness" title="Staleness"><i data-lucide="activity" style="width:12px;height:12px"></i><span class="tab-label">Staleness</span></div>
|
|
256
|
+
<div class="tab" data-tab="activity" title="Activity"><i data-lucide="bar-chart-3" style="width:12px;height:12px"></i><span class="tab-label">Activity</span></div>
|
|
257
257
|
</div>
|
|
258
258
|
<div class="tab-content" id="tab-content"></div>
|
|
259
259
|
</div>
|
|
@@ -340,11 +340,14 @@ async function init() {
|
|
|
340
340
|
renderHealth(data);
|
|
341
341
|
renderEfficiency(data);
|
|
342
342
|
renderStaleness(data);
|
|
343
|
+
renderActivity(data);
|
|
343
344
|
setupSearch();
|
|
344
345
|
lucide.createIcons();
|
|
345
346
|
}
|
|
346
347
|
init();
|
|
347
348
|
|
|
349
|
+
|
|
350
|
+
|
|
348
351
|
function showError(msg) {
|
|
349
352
|
document.getElementById("graph-container").innerHTML = '<div class="empty"><i data-lucide="alert-circle" style="width:18px;height:18px;vertical-align:middle;margin-right:4px"></i> '+msg+'</div>';
|
|
350
353
|
lucide.createIcons();
|
|
@@ -357,7 +360,7 @@ function renderStats(data) {
|
|
|
357
360
|
document.getElementById("stats-bar").innerHTML =
|
|
358
361
|
'<div class="stat"><span class="num">'+(s.node_count||0)+'</span><span class="lbl">nodes</span></div>'+
|
|
359
362
|
'<div class="stat"><span class="num">'+(s.edge_count||0)+'</span><span class="lbl">edges</span></div>'+
|
|
360
|
-
'<div class="stat"><span class="num" style="color:var(--accent)">'+(s.feature_count||0)+'</span><span class="lbl">features</span></div>'+
|
|
363
|
+
'<div class="stat"><span class="num" style="color:var(--accent-bright)">'+(s.feature_count||0)+'</span><span class="lbl">features</span></div>'+
|
|
361
364
|
'<div class="stat"><span class="num">'+(s.gotcha_count||0)+'</span><span class="lbl">gotchas</span></div>'+
|
|
362
365
|
'<div class="stat"><span class="num" style="color:var(--accent)">'+currentDbSize+'</span><span class="lbl">kuma.db</span></div>'+
|
|
363
366
|
'<div class="stat"><span class="num" style="color:'+hcColor+'">'+(hc||0)+'</span><span class="lbl">health</span></div>';
|
|
@@ -439,7 +442,7 @@ function renderGraph(data) {
|
|
|
439
442
|
var color = isGotcha ? '#f97316' : (colors[n.type] || '#64748b');
|
|
440
443
|
return {
|
|
441
444
|
id: n.id, label: label,
|
|
442
|
-
color: { background: color, border: color, highlight: { background: color, border: '#
|
|
445
|
+
color: { background: color, border: color, highlight: { background: color, border: '#67e8f9' }, hover: { background: color, border: '#c4b5fd' } },
|
|
443
446
|
shape: shape,
|
|
444
447
|
font: { color: '#ffffff', size: Math.min(13, Math.max(10, size * 0.55)), face: 'sans-serif', multi: false, bold: true },
|
|
445
448
|
borderWidth: 0, size: size, mass: 1 + (size / 40),
|
|
@@ -469,7 +472,7 @@ function renderGraph(data) {
|
|
|
469
472
|
id: 'e'+idx, from: e.source, to: e.target,
|
|
470
473
|
label: e.relation || '',
|
|
471
474
|
arrows: { to: { enabled: true, scaleFactor: 0.7, type: 'arrow' } },
|
|
472
|
-
color: { color: edgeColor, highlight: '#
|
|
475
|
+
color: { color: edgeColor, highlight: '#c4b5fd', hover: '#67e8f9', opacity: 0.85 },
|
|
473
476
|
font: { size: 10, color: '#94a3b8', strokeWidth: 0, background: 'transparent' },
|
|
474
477
|
dashes: dashes,
|
|
475
478
|
smooth: { type: 'continuous', roundness: 0.3 },
|
|
@@ -486,7 +489,7 @@ function renderGraph(data) {
|
|
|
486
489
|
},
|
|
487
490
|
interaction: { hover: true, tooltipDelay: 300, zoomView: true, dragView: true, dragNodes: true, keyboard: true, multiselect: true, selectable: true, selectConnectedEdges: false },
|
|
488
491
|
nodes: { borderWidth: 0, font: { color: '#ffffff', size: 11, face: 'sans-serif' }, margin: { top: 6, bottom: 6, left: 10, right: 10 }, shapeProperties: { borderRadius: 6 } },
|
|
489
|
-
edges: { smooth: { type: 'continuous', roundness: 0.2 }, width: 1, color: { color: '#4a4a6a', highlight: '#
|
|
492
|
+
edges: { smooth: { type: 'continuous', roundness: 0.2 }, width: 1, color: { color: '#4a4a6a', highlight: '#a78bfa' } },
|
|
490
493
|
configure: { enabled: false },
|
|
491
494
|
});
|
|
492
495
|
|
|
@@ -610,7 +613,7 @@ function resetHighlight() {
|
|
|
610
613
|
network.body.data.nodes.update(nUp);
|
|
611
614
|
network.body.data.edges.forEach(function(e) {
|
|
612
615
|
var def = edgeDefaults[e.id];
|
|
613
|
-
eUp.push({ id: e.id, color: { color: def ? def.color : '#64748b', highlight: '#
|
|
616
|
+
eUp.push({ id: e.id, color: { color: def ? def.color : '#64748b', highlight: '#c4b5fd', hover: '#67e8f9', opacity: 0.85 }, width: def ? def.width : 1 });
|
|
614
617
|
});
|
|
615
618
|
network.body.data.edges.update(eUp);
|
|
616
619
|
document.getElementById("graph-tooltip").style.display = 'none';
|
|
@@ -788,7 +791,7 @@ async function refetch() {
|
|
|
788
791
|
if (status.ok) { dot.className = 'dot on'; txt.textContent = status.project || 'connected'; } else { dot.className = 'dot off'; txt.textContent = 'no kuma.db found'; }
|
|
789
792
|
var data = await fetch(API+'/dashboard').then(function(r){return r.json()});
|
|
790
793
|
if (data.error) { showError(data.error); return; }
|
|
791
|
-
renderStats(data); renderGraph(data); renderFeatures(data); renderGotchas(data); renderHealth(data); renderEfficiency(data); renderStaleness(data);
|
|
794
|
+
renderStats(data); renderGraph(data); renderFeatures(data); renderGotchas(data); renderHealth(data); renderEfficiency(data); renderStaleness(data); renderActivity(data);
|
|
792
795
|
lucide.createIcons();
|
|
793
796
|
} catch(e) { showError('Refetch failed: ' + e.message); }
|
|
794
797
|
btn.innerHTML = '<i data-lucide="refresh-cw" style="width:13px;height:13px;vertical-align:middle;margin-right:3px"></i> Refetch';
|
|
@@ -808,7 +811,8 @@ function setupTabs(){
|
|
|
808
811
|
'<div class="panel" id="panel-gotchas"><div class="empty">Loading...</div></div>' +
|
|
809
812
|
'<div class="panel" id="panel-health"><div class="empty">Loading...</div></div>' +
|
|
810
813
|
'<div class="panel" id="panel-efficiency"><div class="empty">Loading...</div></div>' +
|
|
811
|
-
'<div class="panel" id="panel-staleness"><div class="empty">Loading...</div></div>'
|
|
814
|
+
'<div class="panel" id="panel-staleness"><div class="empty">Loading...</div></div>' +
|
|
815
|
+
'<div class="panel" id="panel-activity"><div class="empty">Loading...</div></div>';
|
|
812
816
|
document.querySelectorAll('.tab').forEach(function(tab){
|
|
813
817
|
tab.onclick = function(){
|
|
814
818
|
document.querySelectorAll('.tab').forEach(function(t){t.classList.remove('active')});
|
|
@@ -892,7 +896,7 @@ function renderEfficiency(data){
|
|
|
892
896
|
var r = eff.recordings || {};
|
|
893
897
|
var savedSec = m.researchTimeSaved ? Math.round(m.researchTimeSaved/1000) : 0;
|
|
894
898
|
var passRate = eff.verificationPassRate;
|
|
895
|
-
var passColor = passRate
|
|
899
|
+
var passColor = passRate >= 80 ? 'var(--green)' : passRate >= 50 ? 'var(--yellow)' : 'var(--red)';
|
|
896
900
|
|
|
897
901
|
var stat = function(num, lbl, color){
|
|
898
902
|
return '<div style="flex:1;min-width:110px;padding:10px 12px;background:var(--bg);border-radius:8px;border:1px solid var(--border)"><div style="font-size:20px;font-weight:700;color:'+(color||'var(--accent2)')+'">'+num+'</div><div style="font-size:11px;color:var(--muted);margin-top:2px">'+lbl+'</div></div>';
|
|
@@ -902,7 +906,7 @@ function renderEfficiency(data){
|
|
|
902
906
|
html += '<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px">' +
|
|
903
907
|
stat(eff.sessions||0, 'sessions') +
|
|
904
908
|
stat(eff.toolCalls||0, 'tool calls') +
|
|
905
|
-
stat(eff.
|
|
909
|
+
stat(eff.gotchas||0, 'gotchas', 'var(--orange)') +
|
|
906
910
|
stat(eff.researchCacheScopes||0, 'research cached', 'var(--green)') +
|
|
907
911
|
stat(eff.decisions||0, 'decisions', 'var(--accent)') +
|
|
908
912
|
stat(eff.verifications||0, 'verifications', passRate==null?'var(--muted)':'var(--green)') +
|
|
@@ -1057,6 +1061,277 @@ function setupSearch() {
|
|
|
1057
1061
|
}, 150);
|
|
1058
1062
|
};
|
|
1059
1063
|
}
|
|
1064
|
+
|
|
1065
|
+
// ============ ACTIVITY PANEL — Agent Usage Intensity ============
|
|
1066
|
+
// Shows how intensely agents use Kuma: tool calls per day, sessions frequency,
|
|
1067
|
+
// and activity heatmap to understand adoption patterns.
|
|
1068
|
+
|
|
1069
|
+
function renderActivity(data) {
|
|
1070
|
+
var el = document.getElementById("panel-activity");
|
|
1071
|
+
if (!el) return;
|
|
1072
|
+
var eff = data.efficiency || {};
|
|
1073
|
+
var sess = eff.recentSessions || [];
|
|
1074
|
+
var totalSessions = eff.sessions || 0;
|
|
1075
|
+
var totalToolCalls = eff.toolCalls || 0;
|
|
1076
|
+
var totalGotchas = eff.gotchas || 0;
|
|
1077
|
+
var totalArchFlows = eff.archFlows || 0;
|
|
1078
|
+
var totalDecisions = eff.decisions || 0;
|
|
1079
|
+
var totalEdits = eff.metrics ? (eff.metrics.filesEdited || 0) : 0;
|
|
1080
|
+
|
|
1081
|
+
var html = '';
|
|
1082
|
+
|
|
1083
|
+
// === COPY REPORT BUTTON ===
|
|
1084
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">';
|
|
1085
|
+
html += '<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px">🤖 Agent Usage Intensity</div>';
|
|
1086
|
+
html += '<button onclick="copyActivityReport()" id="copy-report-btn" style="background:rgba(34,211,238,0.12);border:1px solid rgba(34,211,238,0.25);border-radius:6px;color:var(--accent2);padding:4px 10px;font-size:10px;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:4px"><i data-lucide="copy" style="width:11px;height:11px"></i> Copy Report</button>';
|
|
1087
|
+
html += '</div>';
|
|
1088
|
+
|
|
1089
|
+
// Intensity score: tool_calls per session
|
|
1090
|
+
var avgCallsPerSession = totalSessions > 0 ? (totalToolCalls / totalSessions).toFixed(1) : '0';
|
|
1091
|
+
var intensityLevel = totalToolCalls > 100 ? 'High' : totalToolCalls > 30 ? 'Medium' : totalToolCalls > 0 ? 'Low' : 'None';
|
|
1092
|
+
var intensityColor = totalToolCalls > 100 ? 'var(--green)' : totalToolCalls > 30 ? 'var(--yellow)' : totalToolCalls > 0 ? 'var(--orange)' : 'var(--muted)';
|
|
1093
|
+
var intensityIcon = totalToolCalls > 100 ? '🔥' : totalToolCalls > 30 ? '⚡' : totalToolCalls > 0 ? '💤' : '⚫';
|
|
1094
|
+
|
|
1095
|
+
html += '<div class="health-item" style="margin-bottom:12px;border-left:3px solid ' + intensityColor + '">';
|
|
1096
|
+
html += '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">';
|
|
1097
|
+
html += '<span style="font-size:24px">' + intensityIcon + '</span>';
|
|
1098
|
+
html += '<div><div style="font-size:16px;font-weight:700;color:' + intensityColor + '">' + intensityLevel + '</div>';
|
|
1099
|
+
html += '<div style="font-size:11px;color:var(--muted)">' + avgCallsPerSession + ' calls/session average</div></div>';
|
|
1100
|
+
html += '</div>';
|
|
1101
|
+
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:6px">';
|
|
1102
|
+
html += '<span style="font-size:10px;padding:2px 8px;border-radius:4px;background:rgba(34,211,238,0.15);color:var(--accent2)">' + totalToolCalls + ' total calls</span>';
|
|
1103
|
+
html += '<span style="font-size:10px;padding:2px 8px;border-radius:4px;background:rgba(52,211,153,0.15);color:var(--green)">' + totalSessions + ' sessions</span>';
|
|
1104
|
+
html += '<span style="font-size:10px;padding:2px 8px;border-radius:4px;background:rgba(251,191,36,0.15);color:var(--yellow)">' + totalEdits + ' edits</span>';
|
|
1105
|
+
html += '</div>';
|
|
1106
|
+
html += '</div>';
|
|
1107
|
+
|
|
1108
|
+
// === HEALTH SCORE TREND ===
|
|
1109
|
+
html += '<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin:10px 0 6px">📈 Activity Summary</div>';
|
|
1110
|
+
html += '<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px">';
|
|
1111
|
+
|
|
1112
|
+
var summaryCard = function(val, label, color) {
|
|
1113
|
+
return '<div style="flex:1;min-width:90px;padding:10px;background:var(--bg);border-radius:8px;border:1px solid var(--border);text-align:center">' +
|
|
1114
|
+
'<div style="font-size:20px;font-weight:700;color:' + (color || 'var(--accent2)') + '">' + val + '</div>' +
|
|
1115
|
+
'<div style="font-size:10px;color:var(--muted);margin-top:2px">' + label + '</div></div>';
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
html += summaryCard(totalSessions, 'Sessions', 'var(--accent2)');
|
|
1119
|
+
html += summaryCard(totalToolCalls, 'Tool Calls', 'var(--accent)');
|
|
1120
|
+
html += summaryCard(totalGotchas, 'Gotchas', 'var(--orange)');
|
|
1121
|
+
html += summaryCard(totalArchFlows, 'Arch Flows', 'var(--accent)');
|
|
1122
|
+
html += summaryCard(totalDecisions, 'Decisions', 'var(--accent2)');
|
|
1123
|
+
html += '</div>';
|
|
1124
|
+
|
|
1125
|
+
// === RECENT SESSION ACTIVITY (last 8) ===
|
|
1126
|
+
if (sess.length) {
|
|
1127
|
+
html += '<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin:10px 0 6px">🕐 Recent Activity</div>';
|
|
1128
|
+
html += '<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:12px">';
|
|
1129
|
+
|
|
1130
|
+
var maxCalls = Math.max.apply(null, sess.map(function(s) { return s.toolCalls || 0; }).concat([1]));
|
|
1131
|
+
|
|
1132
|
+
sess.forEach(function(s) {
|
|
1133
|
+
var calls = s.toolCalls || 0;
|
|
1134
|
+
var edits = s.edits || 0;
|
|
1135
|
+
var rollbacks = s.rollbacks || 0;
|
|
1136
|
+
var failures = s.failures || 0;
|
|
1137
|
+
var barWidth = Math.round((calls / maxCalls) * 100);
|
|
1138
|
+
var barColor = failures > 0 ? 'var(--red)' : rollbacks > 0 ? 'var(--yellow)' : 'var(--accent)';
|
|
1139
|
+
var goal = s.goal || 'No goal';
|
|
1140
|
+
var date = s.startedAt ? new Date(s.startedAt * 1000) : null;
|
|
1141
|
+
var dateStr = date ? date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'}) : '-';
|
|
1142
|
+
|
|
1143
|
+
html += '<div style="background:var(--bg);border-radius:6px;padding:8px 10px;border:1px solid var(--border)">';
|
|
1144
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">';
|
|
1145
|
+
html += '<span style="font-size:11px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px" title="' + escapeHtml(goal) + '">' + escapeHtml(goal) + '</span>';
|
|
1146
|
+
html += '<span style="font-size:10px;color:var(--muted);flex-shrink:0;margin-left:8px">' + dateStr + '</span>';
|
|
1147
|
+
html += '</div>';
|
|
1148
|
+
// Activity bar
|
|
1149
|
+
html += '<div style="height:6px;background:var(--border);border-radius:3px;overflow:hidden;margin-bottom:4px">';
|
|
1150
|
+
html += '<div style="height:100%;width:' + barWidth + '%;background:' + barColor + ';border-radius:3px;transition:width 0.3s"></div>';
|
|
1151
|
+
html += '</div>';
|
|
1152
|
+
// Metrics row
|
|
1153
|
+
html += '<div style="display:flex;gap:8px;font-size:10px;color:var(--muted)">';
|
|
1154
|
+
html += '<span>🔧 ' + calls + ' calls</span>';
|
|
1155
|
+
if (edits > 0) html += '<span>📝 ' + edits + ' edits</span>';
|
|
1156
|
+
if (rollbacks > 0) html += '<span style="color:var(--yellow)">↩ ' + rollbacks + '</span>';
|
|
1157
|
+
if (failures > 0) html += '<span style="color:var(--red)">❌ ' + failures + '</span>';
|
|
1158
|
+
if (s.safetyScore != null) html += '<span style="color:var(--green)">🛡 ' + s.safetyScore + '</span>';
|
|
1159
|
+
html += '</div>';
|
|
1160
|
+
html += '</div>';
|
|
1161
|
+
});
|
|
1162
|
+
html += '</div>';
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// === EFFICIENCY TRENDS ===
|
|
1166
|
+
var successRate = eff.verificationPassRate || 100;
|
|
1167
|
+
var passColor = successRate >= 90 ? 'var(--green)' : successRate >= 70 ? 'var(--yellow)' : 'var(--red)';
|
|
1168
|
+
var recordingRate = totalToolCalls > 0 ? Math.round(((totalGotchas + totalArchFlows + totalDecisions) / totalToolCalls) * 100) : 0;
|
|
1169
|
+
// Rollback rate from recent sessions (rollbacks / calls, %)
|
|
1170
|
+
var totalRollbacks = sess.reduce(function(a, s) { return a + (s.rollbacks || 0); }, 0);
|
|
1171
|
+
var totalCalls = sess.reduce(function(a, s) { return a + (s.toolCalls || 0); }, 0);
|
|
1172
|
+
var rollbackRate = totalCalls > 0 ? Math.round((totalRollbacks / totalCalls) * 100) : 0;
|
|
1173
|
+
|
|
1174
|
+
html += '<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:0.5px;margin:10px 0 6px">📊 Efficiency Trends</div>';
|
|
1175
|
+
html += '<div class="health-item" style="margin-bottom:8px">';
|
|
1176
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
|
|
1177
|
+
html += '<span style="font-size:12px;color:var(--text)">Verification Pass Rate</span>';
|
|
1178
|
+
html += '<span style="font-size:14px;font-weight:700;color:' + passColor + '">' + (successRate || '—') + '%</span>';
|
|
1179
|
+
html += '</div>';
|
|
1180
|
+
html += '<div style="height:8px;background:var(--border);border-radius:4px;overflow:hidden">';
|
|
1181
|
+
html += '<div style="height:100%;width:' + (successRate || 0) + '%;background:' + passColor + ';border-radius:4px"></div>';
|
|
1182
|
+
html += '</div>';
|
|
1183
|
+
html += '</div>';
|
|
1184
|
+
|
|
1185
|
+
html += '<div class="health-item" style="margin-bottom:8px">';
|
|
1186
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
|
|
1187
|
+
html += '<span style="font-size:12px;color:var(--text)">Recording Rate</span>';
|
|
1188
|
+
html += '<span style="font-size:14px;font-weight:700;color:' + (recordingRate >= 10 ? 'var(--green)' : recordingRate >= 5 ? 'var(--yellow)' : 'var(--orange)') + '">' + recordingRate + '%</span>';
|
|
1189
|
+
html += '</div>';
|
|
1190
|
+
html += '<div style="height:8px;background:var(--border);border-radius:4px;overflow:hidden">';
|
|
1191
|
+
html += '<div style="height:100%;width:' + Math.min(recordingRate, 100) + '%;background:' + (recordingRate >= 10 ? 'var(--green)' : recordingRate >= 5 ? 'var(--yellow)' : 'var(--orange)') + ';border-radius:4px"></div>';
|
|
1192
|
+
html += '</div>';
|
|
1193
|
+
html += '</div>';
|
|
1194
|
+
|
|
1195
|
+
// === INSIGHT ===
|
|
1196
|
+
html += '<div style="margin-top:12px;padding:10px 12px;background:rgba(167,139,250,0.1);border:1px solid rgba(167,139,250,0.2);border-radius:8px;font-size:11px;color:var(--accent-bright)">';
|
|
1197
|
+
html += '💡 <b>Activity Insight:</b> ';
|
|
1198
|
+
if (totalSessions === 0) {
|
|
1199
|
+
html += 'No sessions recorded yet. Start using Kuma tools to track activity!';
|
|
1200
|
+
} else if (totalToolCalls < 10) {
|
|
1201
|
+
html += 'Getting started! Kuma learns more with each tool call.';
|
|
1202
|
+
} else if (successRate >= 90) {
|
|
1203
|
+
html += 'Excellent! High success rate shows Kuma is well-calibrated for your workflow.';
|
|
1204
|
+
} else if (rollbackRate > 10) {
|
|
1205
|
+
html += 'High rollback rate — Kuma gotchas may help avoid repeated mistakes.';
|
|
1206
|
+
} else {
|
|
1207
|
+
html += 'Healthy usage pattern. The more you use Kuma, the smarter it gets!';
|
|
1208
|
+
}
|
|
1209
|
+
html += '</div>';
|
|
1210
|
+
|
|
1211
|
+
el.innerHTML = html;
|
|
1212
|
+
lucide.createIcons();
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// ============ COPY ACTIVITY REPORT ============
|
|
1216
|
+
function copyActivityReport() {
|
|
1217
|
+
var btn = document.getElementById('copy-report-btn');
|
|
1218
|
+
if (!btn) return;
|
|
1219
|
+
|
|
1220
|
+
// Find the data from the last render
|
|
1221
|
+
var panel = document.getElementById('panel-activity');
|
|
1222
|
+
if (!panel) return;
|
|
1223
|
+
|
|
1224
|
+
// Build a clean text report
|
|
1225
|
+
var report = [];
|
|
1226
|
+
report.push('=== KUMA STUDIO — ACTIVITY REPORT ===');
|
|
1227
|
+
report.push('Generated: ' + new Date().toLocaleString());
|
|
1228
|
+
report.push('');
|
|
1229
|
+
|
|
1230
|
+
// Get all stat cards
|
|
1231
|
+
var stats = panel.querySelectorAll('[style*="font-size:20px"]');
|
|
1232
|
+
var labels = panel.querySelectorAll('[style*="font-size:10px;color:var(--muted)"]');
|
|
1233
|
+
|
|
1234
|
+
// Extract intensity info
|
|
1235
|
+
var intensityEl = panel.querySelector('[style*="font-size:16px;font-weight:700"]');
|
|
1236
|
+
var intensity = intensityEl ? intensityEl.textContent : 'Unknown';
|
|
1237
|
+
var avgCallsEl = panel.querySelector('[style*="font-size:11px;color:var(--muted)"]');
|
|
1238
|
+
var avgCalls = avgCallsEl ? avgCallsEl.textContent : '';
|
|
1239
|
+
|
|
1240
|
+
report.push('INTENSITY: ' + intensity);
|
|
1241
|
+
if (avgCalls) report.push('Average: ' + avgCalls);
|
|
1242
|
+
report.push('');
|
|
1243
|
+
|
|
1244
|
+
// Get all section headers and content
|
|
1245
|
+
var sections = panel.querySelectorAll('[style*="text-transform:uppercase"]');
|
|
1246
|
+
sections.forEach(function(section) {
|
|
1247
|
+
var title = section.textContent.trim();
|
|
1248
|
+
report.push('--- ' + title + ' ---');
|
|
1249
|
+
|
|
1250
|
+
// Get next sibling content
|
|
1251
|
+
var next = section.nextElementSibling;
|
|
1252
|
+
if (next) {
|
|
1253
|
+
// Extract text content, cleaning up HTML
|
|
1254
|
+
var text = next.textContent.trim()
|
|
1255
|
+
.replace(/\s+/g, ' ')
|
|
1256
|
+
.replace(/([0-9]+) sessions/g, '$1 sessions')
|
|
1257
|
+
.replace(/([0-9]+) tool calls/g, '$1 tool calls')
|
|
1258
|
+
.replace(/([0-9]+) file edits/g, '$1 file edits')
|
|
1259
|
+
.replace(/([0-9]+) rollbacks/g, '$1 rollbacks')
|
|
1260
|
+
.replace(/([0-9]+) failures/g, '$1 failures')
|
|
1261
|
+
.replace(/([0-9]+) total calls/g, '$1 total calls');
|
|
1262
|
+
report.push(text);
|
|
1263
|
+
}
|
|
1264
|
+
report.push('');
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
// Get recent sessions
|
|
1268
|
+
var sessionItems = panel.querySelectorAll('[style*="background:var(--bg);border-radius:6px"]');
|
|
1269
|
+
if (sessionItems.length > 0) {
|
|
1270
|
+
report.push('--- RECENT SESSIONS ---');
|
|
1271
|
+
sessionItems.forEach(function(item) {
|
|
1272
|
+
var goal = item.querySelector('[style*="font-size:11px"]');
|
|
1273
|
+
var metrics = item.querySelector('[style*="font-size:10px"]');
|
|
1274
|
+
if (goal) report.push('• ' + goal.textContent.trim());
|
|
1275
|
+
if (metrics) report.push(' ' + metrics.textContent.trim());
|
|
1276
|
+
});
|
|
1277
|
+
report.push('');
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Get efficiency trends
|
|
1281
|
+
var trends = panel.querySelectorAll('.health-item');
|
|
1282
|
+
if (trends.length > 0) {
|
|
1283
|
+
report.push('--- EFFICIENCY TRENDS ---');
|
|
1284
|
+
trends.forEach(function(trend) {
|
|
1285
|
+
var label = trend.querySelector('[style*="font-size:12px"]');
|
|
1286
|
+
var value = trend.querySelector('[style*="font-size:14px"]');
|
|
1287
|
+
if (label && value) {
|
|
1288
|
+
report.push(label.textContent.trim() + ': ' + value.textContent.trim());
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
report.push('');
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// Get insight
|
|
1295
|
+
var insight = panel.querySelector('[style*="rgba(167,139,250,0.1)"]');
|
|
1296
|
+
if (insight) {
|
|
1297
|
+
report.push('--- INSIGHT ---');
|
|
1298
|
+
report.push(insight.textContent.trim());
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
var reportText = report.join('\n');
|
|
1302
|
+
|
|
1303
|
+
// Copy to clipboard
|
|
1304
|
+
navigator.clipboard.writeText(reportText).then(function() {
|
|
1305
|
+
btn.innerHTML = '<i data-lucide="check" style="width:11px;height:11px"></i> Copied!';
|
|
1306
|
+
btn.style.background = 'rgba(52,211,153,0.15)';
|
|
1307
|
+
btn.style.borderColor = 'rgba(52,211,153,0.3)';
|
|
1308
|
+
btn.style.color = 'var(--green)';
|
|
1309
|
+
lucide.createIcons();
|
|
1310
|
+
setTimeout(function() {
|
|
1311
|
+
btn.innerHTML = '<i data-lucide="copy" style="width:11px;height:11px"></i> Copy Report';
|
|
1312
|
+
btn.style.background = 'rgba(34,211,238,0.12)';
|
|
1313
|
+
btn.style.borderColor = 'rgba(34,211,238,0.25)';
|
|
1314
|
+
btn.style.color = 'var(--accent2)';
|
|
1315
|
+
lucide.createIcons();
|
|
1316
|
+
}, 2000);
|
|
1317
|
+
}).catch(function() {
|
|
1318
|
+
// Fallback: select text for manual copy
|
|
1319
|
+
var textarea = document.createElement('textarea');
|
|
1320
|
+
textarea.value = reportText;
|
|
1321
|
+
textarea.style.position = 'fixed';
|
|
1322
|
+
textarea.style.left = '-9999px';
|
|
1323
|
+
document.body.appendChild(textarea);
|
|
1324
|
+
textarea.select();
|
|
1325
|
+
document.execCommand('copy');
|
|
1326
|
+
document.body.removeChild(textarea);
|
|
1327
|
+
btn.innerHTML = '<i data-lucide="check" style="width:11px;height:11px"></i> Copied!';
|
|
1328
|
+
lucide.createIcons();
|
|
1329
|
+
setTimeout(function() {
|
|
1330
|
+
btn.innerHTML = '<i data-lucide="copy" style="width:11px;height:11px"></i> Copy Report';
|
|
1331
|
+
lucide.createIcons();
|
|
1332
|
+
}, 2000);
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1060
1335
|
</script>
|
|
1061
1336
|
</body>
|
|
1062
1337
|
</html>
|