crg-dev-kit 2.0.4 → 2.0.7
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/assets/setup-crg.sh +12 -1
- package/lib/actions.js +4 -3
- package/package.json +1 -1
- package/server.js +147 -71
package/assets/setup-crg.sh
CHANGED
|
@@ -180,7 +180,18 @@ fi
|
|
|
180
180
|
|
|
181
181
|
# ── Step 6: Add .gitignore entries ──
|
|
182
182
|
if [ -f ".gitignore" ]; then
|
|
183
|
-
IGNORE_ENTRIES=(
|
|
183
|
+
IGNORE_ENTRIES=(
|
|
184
|
+
".code-review-graph/"
|
|
185
|
+
"setup-crg.sh"
|
|
186
|
+
"setup-crg.ps1"
|
|
187
|
+
"check-crg.sh"
|
|
188
|
+
"crg-cheatsheet.pdf"
|
|
189
|
+
"CRG-README.md"
|
|
190
|
+
".cursorrules"
|
|
191
|
+
".opencode.json"
|
|
192
|
+
".windsurfrules"
|
|
193
|
+
"GEMINI.md"
|
|
194
|
+
)
|
|
184
195
|
ADDED=0
|
|
185
196
|
for entry in "${IGNORE_ENTRIES[@]}"; do
|
|
186
197
|
if ! grep -qxF "$entry" .gitignore 2>/dev/null; then
|
package/lib/actions.js
CHANGED
|
@@ -41,12 +41,13 @@ function install(targetDir, trackROI = true) {
|
|
|
41
41
|
// Add copied files to .gitignore
|
|
42
42
|
if (copied > 0) {
|
|
43
43
|
const gitignorePath = path.join(targetDir, '.gitignore');
|
|
44
|
+
const filesToIgnore = [...INSTALL_FILES.map(f => f.name), '.cursorrules', '.opencode.json', '.windsurfrules', 'GEMINI.md'];
|
|
44
45
|
if (fs.existsSync(gitignorePath)) {
|
|
45
46
|
let content = fs.readFileSync(gitignorePath, 'utf8');
|
|
46
|
-
const
|
|
47
|
+
const newFiles = filesToIgnore
|
|
47
48
|
.filter(name => !content.split('\n').some(line => line.trim() === name));
|
|
48
|
-
if (
|
|
49
|
-
const block = '\n#
|
|
49
|
+
if (newFiles.length > 0) {
|
|
50
|
+
const block = '\n# code-review-graph\n' + newFiles.join('\n') + '\n';
|
|
50
51
|
fs.appendFileSync(gitignorePath, block);
|
|
51
52
|
}
|
|
52
53
|
}
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -113,7 +113,7 @@ function buildPage() {
|
|
|
113
113
|
];
|
|
114
114
|
|
|
115
115
|
const navLinks = tabs.map(t =>
|
|
116
|
-
`<a href="#" hx-get="/tab/${t.id}" hx-target="#
|
|
116
|
+
`<a href="#content" hx-get="/tab/${t.id}" hx-target="#main" hx-swap="innerHTML" class="${t.id === 'dashboard' ? 'active' : ''}" aria-current="${t.id === 'dashboard' ? 'page' : 'false'}" onclick="document.querySelectorAll('.nk a').forEach(a=>a.removeAttribute('aria-current'));this.setAttribute('aria-current','page');return true">${t.label}</a>`
|
|
117
117
|
).join('');
|
|
118
118
|
|
|
119
119
|
return `<!DOCTYPE html>
|
|
@@ -121,31 +121,40 @@ function buildPage() {
|
|
|
121
121
|
<head>
|
|
122
122
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
123
123
|
<title>code-review-graph Dev Kit</title>
|
|
124
|
+
<meta name="description" content="One-click setup for AI-powered code review with knowledge graph">
|
|
124
125
|
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
|
125
126
|
<style>
|
|
126
|
-
@import url('https://fonts.googleapis.com/css2?family=
|
|
127
|
+
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
127
128
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
128
|
-
:root{--bg:#fafaf9;--s:#fff;--b:#e7e5e4;--t:#1c1917;--t2:#
|
|
129
|
-
body{font-family:
|
|
130
|
-
|
|
131
|
-
.
|
|
132
|
-
|
|
133
|
-
.
|
|
134
|
-
.
|
|
129
|
+
:root{--bg:#fafaf9;--s:#fff;--b:#e7e5e4;--t:#1c1917;--t2:#57534e;--t3:#78716c;--t4:#a8a29e;--a:#ea580c;--al:#fff7ed;--ab:#fed7aa;--m:'JetBrains Mono',monospace;--f:'DM Sans',system-ui,-apple-system,sans-serif}
|
|
130
|
+
body{font-family:var(--f);background:var(--bg);color:var(--t);line-height:1.5;-webkit-font-smoothing:antialiased}
|
|
131
|
+
.skip-link{position:absolute;left:-9999px;top:0;background:var(--a);color:#fff;padding:8px 16px;z-index:999}
|
|
132
|
+
.skip-link:focus{left:0}
|
|
133
|
+
nav{background:var(--s);border-bottom:1px solid var(--b);padding:0 clamp(16px,4vw,40px);display:flex;align-items:center;height:56px;position:sticky;top:0;z-index:100;gap:8px}
|
|
134
|
+
.nb{display:flex;align-items:center;gap:10px;font-weight:700;font-size:15px;letter-spacing:-0.02em}
|
|
135
|
+
.nl{width:28px;height:28px;background:var(--a);border-radius:6px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:14px}
|
|
136
|
+
.nk{margin-left:auto;display:flex;gap:clamp(8px,2vw,24px);align-items:center}
|
|
137
|
+
.nk a{color:var(--t3);text-decoration:none;font-size:13px;font-weight:500;transition:color .15s;padding:16px 0;border-bottom:2px solid transparent}
|
|
135
138
|
.nk a:hover{color:var(--a)}
|
|
136
|
-
.nk a.active{color:var(--a);border-bottom:
|
|
139
|
+
.nk a.active,.nk a[aria-current="page"]{color:var(--a);border-bottom-color:var(--a)}
|
|
137
140
|
.badge{background:var(--al);color:var(--a);padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700;border:1px solid var(--ab)}
|
|
138
|
-
|
|
139
|
-
.hero
|
|
141
|
+
main{max-width:100%;overflow-x:hidden}
|
|
142
|
+
.hero{text-align:center;padding:clamp(32px,6vw,64px) clamp(16px,4vw,40px) clamp(24px,4vw,48px);max-width:720px;margin:0 auto}
|
|
143
|
+
.hero h1{font-size:clamp(28px,5vw,42px);font-weight:700;letter-spacing:-0.03em;line-height:1.15;margin-bottom:12px}
|
|
140
144
|
.hero h1 span{color:var(--a)}
|
|
141
|
-
.hero
|
|
142
|
-
.
|
|
143
|
-
.
|
|
144
|
-
.
|
|
145
|
-
|
|
145
|
+
.hero-sub{font-size:clamp(14px,1.5vw,16px);color:var(--t3);max-width:520px;margin:0 auto}
|
|
146
|
+
.hero-metrics{display:flex;justify-content:center;gap:clamp(16px,3vw,32px);margin-top:28px;flex-wrap:wrap}
|
|
147
|
+
.metric-card{text-align:center;min-width:100px}
|
|
148
|
+
.metric-value{font-size:clamp(24px,3vw,32px);font-weight:700;letter-spacing:-0.02em}
|
|
149
|
+
.metric-label{font-size:11px;color:var(--t4);text-transform:uppercase;letter-spacing:.06em;font-weight:600;margin-top:4px}
|
|
150
|
+
section{max-width:clamp(320px,90vw,780px);margin:0 auto;padding:0 clamp(16px,4vw,40px) 48px}
|
|
146
151
|
.st{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--a);margin-bottom:16px;padding-bottom:8px;border-bottom:2px solid var(--a);display:inline-block}
|
|
152
|
+
.status-banner{display:flex;align-items:center;gap:10px;padding:12px 16px;background:var(--s);border:1px solid var(--b);border-radius:8px;margin-bottom:16px}
|
|
153
|
+
.status-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
154
|
+
.status-label{font-weight:600;font-size:14px}
|
|
155
|
+
.status-count{font-size:13px;color:var(--t3);margin-left:auto}
|
|
147
156
|
.step{display:flex;gap:16px;padding:20px 0;border-bottom:1px solid var(--b)}.step:last-child{border-bottom:none}
|
|
148
|
-
.step-num{width:32px;height:32px;background:var(--a);color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:
|
|
157
|
+
.step-num{width:32px;height:32px;background:var(--a);color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;flex-shrink:0}
|
|
149
158
|
.step-body h3{font-size:15px;font-weight:700;margin-bottom:4px}
|
|
150
159
|
.step-desc{font-size:13px;color:var(--t3)}
|
|
151
160
|
.step-cmds{display:flex;gap:12px;margin-top:8px;flex-wrap:wrap}
|
|
@@ -155,14 +164,15 @@ section{max-width:780px;margin:0 auto;padding:0 40px 48px}
|
|
|
155
164
|
.dl-grid{display:flex;flex-direction:column;gap:8px}
|
|
156
165
|
.dl-card{display:flex;align-items:center;gap:12px;padding:14px 16px;background:var(--s);border:1px solid var(--b);border-radius:8px;text-decoration:none;color:var(--t);transition:border-color .15s,box-shadow .15s}
|
|
157
166
|
.dl-card:hover{border-color:var(--a);box-shadow:0 2px 8px rgba(234,88,12,.08)}
|
|
158
|
-
.dl-
|
|
167
|
+
.dl-card:focus-visible{outline:2px solid var(--a);outline-offset:2px}
|
|
168
|
+
.dl-icon{font-size:22px;flex-shrink:0}.dl-info{flex:1;min-width:0}
|
|
159
169
|
.dl-name{font-weight:700;font-size:14px;display:block}
|
|
160
170
|
.dl-desc{font-size:12px;color:var(--t3);display:block;margin-top:1px}
|
|
161
171
|
.dl-size{font-family:var(--m);font-size:11px;color:var(--t4);flex-shrink:0}
|
|
162
172
|
.dl-btn{background:var(--a);color:#fff;padding:6px 14px;border-radius:5px;font-size:12px;font-weight:700;flex-shrink:0;transition:background .15s}
|
|
163
173
|
.dl-card:hover .dl-btn{background:#c2410c}
|
|
164
|
-
.rc{background:var(--s);border:1px solid var(--b);border-radius:8px;padding:32px}
|
|
165
|
-
.rc h1{font-size:22px;font-weight:
|
|
174
|
+
.rc{background:var(--s);border:1px solid var(--b);border-radius:8px;padding:clamp(16px,3vw,32px)}
|
|
175
|
+
.rc h1{font-size:22px;font-weight:700;margin-bottom:16px;letter-spacing:-0.02em}
|
|
166
176
|
.rc h2{font-size:17px;font-weight:700;margin:24px 0 8px}
|
|
167
177
|
.rc h3{font-size:14px;font-weight:700;margin:16px 0 6px}
|
|
168
178
|
.rc p{font-size:14px;color:var(--t2);margin-bottom:8px}
|
|
@@ -174,7 +184,7 @@ section{max-width:780px;margin:0 auto;padding:0 40px 48px}
|
|
|
174
184
|
.rc td{padding:8px 12px;border-bottom:1px solid var(--b);color:var(--t2)}
|
|
175
185
|
.rc li{font-size:14px;color:var(--t2);margin-bottom:4px;margin-left:20px}
|
|
176
186
|
.rc a{color:var(--a)}
|
|
177
|
-
footer{text-align:center;padding:32px 40px;font-size:12px;color:var(--t4);border-top:1px solid var(--b);margin-top:24px}
|
|
187
|
+
footer{text-align:center;padding:32px clamp(16px,4vw,40px);font-size:12px;color:var(--t4);border-top:1px solid var(--b);margin-top:24px}
|
|
178
188
|
footer a{color:var(--a);text-decoration:none;font-weight:600}
|
|
179
189
|
.npx-banner{background:#1c1917;border-radius:8px;padding:16px 20px;margin-bottom:24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
|
|
180
190
|
.npx-banner code{font-family:var(--m);font-size:15px;color:#a6e3a1;font-weight:600}
|
|
@@ -188,10 +198,10 @@ footer a{color:var(--a);text-decoration:none;font-weight:600}
|
|
|
188
198
|
.roi-installed{font-size:13px;color:var(--t3)}
|
|
189
199
|
.roi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}
|
|
190
200
|
.roi-card{background:var(--s);border:1px solid var(--b);border-radius:8px;padding:20px;text-align:center}
|
|
191
|
-
.roi-value{font-size:28px;font-weight:
|
|
201
|
+
.roi-value{font-size:28px;font-weight:700;letter-spacing:-0.02em}
|
|
192
202
|
.roi-label{font-size:11px;color:var(--t3);margin-top:4px;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
|
|
193
|
-
.roi-compare{display:flex;align-items:center;gap:24px;background:var(--s);border:1px solid var(--b);border-radius:8px;padding:24px;margin-bottom:16px}
|
|
194
|
-
.roi-compare-col{flex:1}
|
|
203
|
+
.roi-compare{display:flex;align-items:center;gap:24px;background:var(--s);border:1px solid var(--b);border-radius:8px;padding:24px;margin-bottom:16px;flex-wrap:wrap}
|
|
204
|
+
.roi-compare-col{flex:1;min-width:180px}
|
|
195
205
|
.roi-compare-col h4{font-size:12px;color:var(--t4);text-transform:uppercase;letter-spacing:.06em;margin-bottom:12px}
|
|
196
206
|
.roi-compare-stat{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--b)}
|
|
197
207
|
.roi-compare-stat:last-child{border-bottom:none}
|
|
@@ -202,10 +212,10 @@ footer a{color:var(--a);text-decoration:none;font-weight:600}
|
|
|
202
212
|
.roi-cta code{background:var(--bg);padding:4px 8px;border-radius:4px;font-size:12px}
|
|
203
213
|
.stat-card{background:var(--s);border:1px solid var(--b);border-radius:8px;padding:24px;text-align:center}
|
|
204
214
|
.stat-card.primary{border-color:var(--a);background:var(--al)}
|
|
205
|
-
.stat-value{font-size:32px;font-weight:
|
|
215
|
+
.stat-value{font-size:32px;font-weight:700;letter-spacing:-0.03em}
|
|
206
216
|
.stat-label{font-size:12px;color:var(--t3);margin-top:4px;font-weight:600}
|
|
207
217
|
.stat-sub{font-size:11px;color:var(--t4);margin-top:2px}
|
|
208
|
-
.project-table{margin-bottom:24px}
|
|
218
|
+
.project-table{margin-bottom:24px;overflow-x:auto}
|
|
209
219
|
.project-table table{width:100%;border-collapse:collapse;background:var(--s);border:1px solid var(--b);border-radius:8px;overflow:hidden}
|
|
210
220
|
.project-table th{text-align:left;padding:12px 16px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--t4);background:var(--bg);border-bottom:1px solid var(--b)}
|
|
211
221
|
.project-table td{padding:12px 16px;font-size:13px;color:var(--t2);border-bottom:1px solid var(--b)}
|
|
@@ -217,76 +227,118 @@ footer a{color:var(--a);text-decoration:none;font-weight:600}
|
|
|
217
227
|
.tool-bars{display:flex;flex-direction:column;gap:12px}
|
|
218
228
|
.tool-bar{display:flex;align-items:center;gap:12px}
|
|
219
229
|
.tool-bar-name{font-family:var(--m);font-size:11px;color:var(--t3);width:180px;flex-shrink:0;text-align:right}
|
|
220
|
-
.tool-bar-track{flex:1;height:8px;background:var(--bg);border-radius:4px;overflow:hidden}
|
|
230
|
+
.tool-bar-track{flex:1;height:8px;background:var(--bg);border-radius:4px;overflow:hidden;min-width:0}
|
|
221
231
|
.tool-bar-fill{height:100%;background:var(--a);border-radius:4px;transition:width .3s}
|
|
222
232
|
.tool-bar-count{font-family:var(--m);font-size:11px;color:var(--t4);width:30px;flex-shrink:0}
|
|
223
|
-
.tools-grid{display:grid;grid-template-columns:repeat(
|
|
224
|
-
.tool-card{background:var(--s);border:1px solid var(--b);border-radius:6px;padding:
|
|
233
|
+
.tools-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}
|
|
234
|
+
.tool-card{background:var(--s);border:1px solid var(--b);border-radius:6px;padding:16px;display:flex;flex-direction:column;gap:4px}
|
|
235
|
+
.tool-card:focus-visible{outline:2px solid var(--a);outline-offset:2px}
|
|
225
236
|
.tool-name{font-family:var(--m);font-size:11px;color:var(--a);font-weight:600}
|
|
226
|
-
.tool-label{font-size:
|
|
227
|
-
.tool-desc{font-size:
|
|
228
|
-
|
|
229
|
-
.nk a.active{color:var(--a);border-bottom:2px solid var(--a)}
|
|
230
|
-
/* Action buttons */
|
|
231
|
-
.btn{background:var(--a);color:#fff;padding:10px 20px;border:none;border-radius:6px;font-weight:700;font-size:13px;cursor:pointer;font-family:inherit}
|
|
237
|
+
.tool-label{font-size:14px;font-weight:600;color:var(--t)}
|
|
238
|
+
.tool-desc{font-size:12px;color:var(--t3);line-height:1.4}
|
|
239
|
+
.btn{background:var(--a);color:#fff;padding:10px 20px;border:none;border-radius:6px;font-weight:700;font-size:13px;cursor:pointer;font-family:inherit;transition:background .15s}
|
|
232
240
|
.btn:hover{background:#c2410c}
|
|
241
|
+
.btn:focus-visible{outline:2px solid var(--a);outline-offset:2px}
|
|
242
|
+
.btn:disabled{opacity:.6;cursor:not-allowed}
|
|
233
243
|
.btn-danger{background:#dc2626}
|
|
234
244
|
.btn-danger:hover{background:#b91c1c}
|
|
235
245
|
.btn-secondary{background:var(--bg);color:var(--t2);border:1px solid var(--b)}
|
|
236
|
-
/* Status checks */
|
|
237
246
|
.check-pass{color:#16a34a}
|
|
238
247
|
.check-fail{color:#dc2626}
|
|
239
248
|
.check-item{display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid var(--b)}
|
|
240
249
|
.check-item:last-child{border-bottom:none}
|
|
241
|
-
/* Result messages */
|
|
242
250
|
.result-box{background:var(--s);border:1px solid var(--b);border-radius:8px;padding:20px;margin-top:16px}
|
|
243
251
|
.result-success{border-color:#16a34a;background:#f0fdf4}
|
|
244
252
|
.result-error{border-color:#dc2626;background:#fef2f2}
|
|
245
|
-
|
|
246
|
-
.input{font-family:var(--m);font-size:13px;padding:8px 12px;border:1px solid var(--b);border-radius:6px;width:100%;background:var(--s)}
|
|
253
|
+
.input{font-family:var(--m);font-size:13px;padding:8px 12px;border:1px solid var(--b);border-radius:6px;width:100%;background:var(--s);color:var(--t)}
|
|
247
254
|
.input:focus{outline:none;border-color:var(--a)}
|
|
248
|
-
|
|
255
|
+
.input::placeholder{color:var(--t4)}
|
|
249
256
|
.htmx-indicator{display:none}
|
|
250
257
|
.htmx-request .htmx-indicator{display:inline-block}
|
|
251
258
|
.spinner{width:16px;height:16px;border:2px solid var(--b);border-top-color:var(--a);border-radius:50%;animation:spin .6s linear infinite;display:inline-block}
|
|
252
259
|
@keyframes spin{to{transform:rotate(360deg)}}
|
|
260
|
+
:focus-visible{outline:2px solid var(--a);outline-offset:2px}
|
|
261
|
+
@media(prefers-color-scheme:dark){
|
|
262
|
+
:root{--bg:#1c1917;--s:#292524;--b:#44403c;--t:#fafaf9;--t2:#d6d3d1;--t3:#a8a29e;--t4:#78716c;--al:#292524;--ab:#44403c}
|
|
263
|
+
.dl-card:hover,.roi-card,.stat-card,.tool-card,.project-table table,.roi-compare{background:var(--s)}
|
|
264
|
+
}
|
|
265
|
+
@media(prefers-color-scheme:light){
|
|
266
|
+
:root{--bg:#fafaf9;--s:#fff;--b:#e7e5e4;--t:#1c1917;--t2:#57534e;--t3:#78716c;--t4:#a8a29e;--al:#fff7ed;--ab:#fed7aa}
|
|
267
|
+
}
|
|
253
268
|
@media(max-width:768px){
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
269
|
+
.analytics-grid,.roi-grid{grid-template-columns:repeat(2,1fr)}
|
|
270
|
+
.tools-grid{grid-template-columns:1fr}
|
|
271
|
+
.hero-metrics{gap:16px}
|
|
272
|
+
.nk{gap:8px;overflow-x:auto;padding-bottom:4px}
|
|
273
|
+
.nk a{font-size:12px;padding:12px 8px;white-space:nowrap}
|
|
274
|
+
section{padding:0 16px 32px}
|
|
275
|
+
.roi-compare{flex-direction:column}
|
|
276
|
+
.roi-arrow{transform:rotate(90deg)}
|
|
261
277
|
}
|
|
262
278
|
</style>
|
|
263
279
|
</head>
|
|
264
280
|
<body>
|
|
265
|
-
<
|
|
281
|
+
<a href="#content" class="skip-link">Skip to main content</a>
|
|
282
|
+
<nav role="navigation" aria-label="Main navigation">
|
|
266
283
|
<div class="nb"><div class="nl">G</div>code-review-graph</div>
|
|
267
284
|
<div class="nk">${navLinks}<span class="badge">v2.1.0</span></div>
|
|
268
285
|
</nav>
|
|
269
|
-
<main id="
|
|
270
|
-
<footer><a href="https://github.com/tirth8205/code-review-graph">github.com/tirth8205/code-review-graph</a>
|
|
286
|
+
<main id="main" hx-get="/tab/dashboard" hx-trigger="load" hx-swap="innerHTML"></main>
|
|
287
|
+
<footer><a href="https://github.com/tirth8205/code-review-graph">github.com/tirth8205/code-review-graph</a> · MIT License · All data stays local</footer>
|
|
271
288
|
</body></html>`;
|
|
272
289
|
}
|
|
273
290
|
|
|
274
291
|
/* ── Tab fragments ────────────────────────────────────────────────────── */
|
|
275
292
|
|
|
276
|
-
function tabDashboard() {
|
|
293
|
+
function tabDashboard(cwd) {
|
|
294
|
+
let statusHtml = '';
|
|
295
|
+
try {
|
|
296
|
+
const statusData = actions.getStatusSync(cwd);
|
|
297
|
+
const verdictColors = { ready: '#16a34a', partial: '#ea580c', not_setup: '#dc2626' };
|
|
298
|
+
const verdictLabels = { ready: 'Ready', partial: 'Partial Setup', not_setup: 'Not Set Up' };
|
|
299
|
+
const color = verdictColors[statusData.verdict] || '#dc2626';
|
|
300
|
+
const label = verdictLabels[statusData.verdict] || statusData.verdict;
|
|
301
|
+
statusHtml = `
|
|
302
|
+
<div class="status-banner" style="border-color:${color}">
|
|
303
|
+
<span class="status-dot" style="background:${color}"></span>
|
|
304
|
+
<span class="status-label" style="color:${color}">${label}</span>
|
|
305
|
+
<span class="status-count">${statusData.found}/${statusData.total} files</span>
|
|
306
|
+
</div>`;
|
|
307
|
+
} catch (e) {
|
|
308
|
+
statusHtml = '';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let analyticsHtml = '';
|
|
312
|
+
try {
|
|
313
|
+
const analyticsData = analytics.getAllStats(cwd);
|
|
314
|
+
if (analyticsData) {
|
|
315
|
+
analyticsHtml = `
|
|
316
|
+
<div class="hero-metrics">
|
|
317
|
+
<div class="metric-card">
|
|
318
|
+
<div class="metric-value">${analyticsData.totalSessions}</div>
|
|
319
|
+
<div class="metric-label">Sessions</div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="metric-card">
|
|
322
|
+
<div class="metric-value">${analyticsData.avgSavingsPercent}%</div>
|
|
323
|
+
<div class="metric-label">Avg Savings</div>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="metric-card">
|
|
326
|
+
<div class="metric-value">${formatTokens(analyticsData.totalTokensSaved)}</div>
|
|
327
|
+
<div class="metric-label">Tokens Saved</div>
|
|
328
|
+
</div>
|
|
329
|
+
</div>`;
|
|
330
|
+
}
|
|
331
|
+
} catch (e) {}
|
|
332
|
+
|
|
277
333
|
return `
|
|
278
334
|
<div class="hero">
|
|
279
335
|
<h1>Ship code with a <span>knowledge graph</span></h1>
|
|
280
|
-
<p>One command to set up AI-powered code review, impact analysis, and codebase navigation
|
|
281
|
-
|
|
282
|
-
<div><div class="sv">22</div><div class="sl">MCP Tools</div></div>
|
|
283
|
-
<div><div class="sv">19</div><div class="sl">Languages</div></div>
|
|
284
|
-
<div><div class="sv">8.2x</div><div class="sl">Token Reduction</div></div>
|
|
285
|
-
<div><div class="sv">0</div><div class="sl">Telemetry</div></div>
|
|
286
|
-
</div>
|
|
336
|
+
<p class="hero-sub">One command to set up AI-powered code review, impact analysis, and codebase navigation.</p>
|
|
337
|
+
${analyticsHtml}
|
|
287
338
|
</div>
|
|
288
339
|
<section>
|
|
289
340
|
<div class="st">Quick Status</div>
|
|
341
|
+
${statusHtml}
|
|
290
342
|
<div id="dashboard-status" hx-get="/api/health?fragment=1" hx-trigger="load" hx-swap="innerHTML">
|
|
291
343
|
<span class="spinner"></span> Loading status...
|
|
292
344
|
</div>
|
|
@@ -299,10 +351,10 @@ function tabInstall(cwd) {
|
|
|
299
351
|
<div class="st">Install CRG Dev Kit</div>
|
|
300
352
|
<p style="color:var(--t2);font-size:14px;margin-bottom:16px">Copy setup scripts, CLAUDE.md, and health check to your project directory.</p>
|
|
301
353
|
<div style="margin-bottom:16px">
|
|
302
|
-
<label style="font-size:12px;font-weight:600;color:var(--t3);display:block;margin-bottom:6px">Target Directory</label>
|
|
354
|
+
<label for="install-dir" style="font-size:12px;font-weight:600;color:var(--t3);display:block;margin-bottom:6px">Target Directory</label>
|
|
303
355
|
<input class="input" id="install-dir" name="targetDir" value="${esc(cwd)}" />
|
|
304
356
|
</div>
|
|
305
|
-
<div style="display:flex;gap:12px">
|
|
357
|
+
<div style="display:flex;gap:12px;flex-wrap:wrap">
|
|
306
358
|
<button class="btn"
|
|
307
359
|
hx-post="/api/install"
|
|
308
360
|
hx-target="#install-result"
|
|
@@ -365,11 +417,11 @@ function tabAnalytics(cwd) {
|
|
|
365
417
|
const roiData = roi.getAllProjectsROI(cwd);
|
|
366
418
|
if (roiData.installed) {
|
|
367
419
|
const verdictColor = roiData.roi.verdict === 'positive' ? '#16a34a' : roiData.roi.verdict === 'neutral' ? '#ea580c' : '#dc2626';
|
|
368
|
-
const verdictIcon = roiData.roi.verdict === 'positive' ? '
|
|
420
|
+
const verdictIcon = roiData.roi.verdict === 'positive' ? '✓' : roiData.roi.verdict === 'neutral' ? '−' : '⚠';
|
|
369
421
|
roiHtml = `
|
|
370
422
|
<div class="st">ROI Calculator</div>
|
|
371
423
|
<div class="roi-banner">
|
|
372
|
-
<div class="roi-verdict" style="background:${verdictColor}20;border-color:${verdictColor}">
|
|
424
|
+
<div class="roi-verdict" style="background:${verdictColor}20;border-color:${verdictColor};color:${verdictColor}">
|
|
373
425
|
<span class="roi-verdict-icon">${verdictIcon}</span>
|
|
374
426
|
<span class="roi-verdict-text">${roiData.roi.verdict === 'positive' ? 'CRG is helping' : roiData.roi.verdict === 'neutral' ? 'No significant change' : 'CRG may not be helping'}</span>
|
|
375
427
|
</div>
|
|
@@ -405,7 +457,7 @@ function tabAnalytics(cwd) {
|
|
|
405
457
|
<span class="roi-compare-value">${roiData.baseline.totalPrompts}</span>
|
|
406
458
|
</div>
|
|
407
459
|
</div>
|
|
408
|
-
<div class="roi-arrow"
|
|
460
|
+
<div class="roi-arrow" aria-hidden="true">→</div>
|
|
409
461
|
<div class="roi-compare-col">
|
|
410
462
|
<h4>After CRG</h4>
|
|
411
463
|
<div class="roi-compare-stat">
|
|
@@ -419,8 +471,10 @@ function tabAnalytics(cwd) {
|
|
|
419
471
|
</div>
|
|
420
472
|
</div>
|
|
421
473
|
<div class="roi-cta">
|
|
422
|
-
<
|
|
474
|
+
<button class="btn btn-secondary" hx-get="/api/roi-report" hx-target="#report-modal" hx-swap="innerHTML" style="margin-right:8px">View ROI Report</button>
|
|
475
|
+
<button class="btn btn-secondary" hx-get="/api/daily-breakdown" hx-target="#report-modal" hx-swap="innerHTML">Daily Breakdown</button>
|
|
423
476
|
</div>
|
|
477
|
+
<div id="report-modal" style="margin-top:16px"></div>
|
|
424
478
|
<div style="margin-bottom:32px"></div>`;
|
|
425
479
|
}
|
|
426
480
|
} catch (e) {
|
|
@@ -483,7 +537,11 @@ function tabAnalytics(cwd) {
|
|
|
483
537
|
</div>`;
|
|
484
538
|
}).join('')}
|
|
485
539
|
</div>
|
|
486
|
-
</div
|
|
540
|
+
</div>
|
|
541
|
+
<div class="roi-cta" style="margin-top:16px">
|
|
542
|
+
<button class="btn btn-secondary" hx-get="/api/report" hx-target="#analytics-report" hx-swap="innerHTML">View Full Report</button>
|
|
543
|
+
</div>
|
|
544
|
+
<div id="analytics-report"></div>` : ''}`;
|
|
487
545
|
} else {
|
|
488
546
|
tokenHtml = `<div class="st">Token Analytics</div><p style="color:var(--t3);font-size:14px">No analytics data yet. Use CRG tools in a project to start tracking.</p>`;
|
|
489
547
|
}
|
|
@@ -493,23 +551,31 @@ function tabAnalytics(cwd) {
|
|
|
493
551
|
|
|
494
552
|
function tabTools() {
|
|
495
553
|
const toolCards = CRG_TOOLS.map(t => `
|
|
496
|
-
<div class="tool-card">
|
|
554
|
+
<div class="tool-card" tabindex="0">
|
|
497
555
|
<span class="tool-name">${t.name}</span>
|
|
498
556
|
<span class="tool-label">${t.label}</span>
|
|
499
557
|
<span class="tool-desc">${t.desc}</span>
|
|
500
558
|
</div>`).join('');
|
|
501
|
-
return `<section
|
|
559
|
+
return `<section>
|
|
560
|
+
<div class="st">Available Tools</div>
|
|
561
|
+
<p style="font-size:14px;color:var(--t3);margin-bottom:16px">These MCP tools are available in your projects after setup. They provide token-efficient code review and analysis.</p>
|
|
562
|
+
<div class="tools-grid">${toolCards}</div>
|
|
563
|
+
</section>`;
|
|
502
564
|
}
|
|
503
565
|
|
|
504
566
|
function tabDownloads() {
|
|
505
567
|
const dlCards = DOWNLOADS.map(d => `
|
|
506
|
-
<a href="/download/${d.file}" class="dl-card" download>
|
|
507
|
-
<span class="dl-icon">${d.icon}</span>
|
|
568
|
+
<a href="/download/${d.file}" class="dl-card" download aria-label="Download ${d.label}">
|
|
569
|
+
<span class="dl-icon" aria-hidden="true">${d.icon}</span>
|
|
508
570
|
<div class="dl-info"><span class="dl-name">${d.label}</span><span class="dl-desc">${d.desc}</span></div>
|
|
509
571
|
<span class="dl-size">${fileSize(d.file)}</span>
|
|
510
572
|
<span class="dl-btn">Download</span>
|
|
511
573
|
</a>`).join('');
|
|
512
|
-
return `<section
|
|
574
|
+
return `<section>
|
|
575
|
+
<div class="st">Downloads</div>
|
|
576
|
+
<p style="font-size:14px;color:var(--t3);margin-bottom:16px">Download setup scripts for different platforms. All files are open source and stay local.</p>
|
|
577
|
+
<div class="dl-grid">${dlCards}</div>
|
|
578
|
+
</section>`;
|
|
513
579
|
}
|
|
514
580
|
|
|
515
581
|
function tabDocs() {
|
|
@@ -681,6 +747,16 @@ function start(port, noOpen) {
|
|
|
681
747
|
res.writeHead(200, { 'Content-Type': 'text/markdown' });
|
|
682
748
|
res.end(report);
|
|
683
749
|
|
|
750
|
+
} else if (url.pathname === '/api/roi-report') {
|
|
751
|
+
const report = roi.generateROIReport(cwd);
|
|
752
|
+
res.writeHead(200, { 'Content-Type': 'text/markdown' });
|
|
753
|
+
res.end(report);
|
|
754
|
+
|
|
755
|
+
} else if (url.pathname === '/api/daily-breakdown') {
|
|
756
|
+
const breakdown = roi.generateDailyBreakdown();
|
|
757
|
+
res.writeHead(200, { 'Content-Type': 'text/markdown' });
|
|
758
|
+
res.end(breakdown);
|
|
759
|
+
|
|
684
760
|
} else if (url.pathname === '/api/session' && req.method === 'POST') {
|
|
685
761
|
readBody(req, res, (data) => {
|
|
686
762
|
const session = analytics.createSession(data.project, data.operation);
|