brainforge-ai 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +863 -420
- package/dist/cli.js +47 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/defensePack.d.ts +2 -0
- package/dist/commands/defensePack.d.ts.map +1 -0
- package/dist/commands/defensePack.js +269 -0
- package/dist/commands/defensePack.js.map +1 -0
- package/dist/commands/difficulty.d.ts +2 -0
- package/dist/commands/difficulty.d.ts.map +1 -0
- package/dist/commands/difficulty.js +177 -0
- package/dist/commands/difficulty.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +53 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +24 -1
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/init.d.ts +6 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +64 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/professorCheck.d.ts +2 -0
- package/dist/commands/professorCheck.d.ts.map +1 -0
- package/dist/commands/professorCheck.js +203 -0
- package/dist/commands/professorCheck.js.map +1 -0
- package/dist/commands/serve.js +16 -16
- package/dist/commands/simplify.d.ts +2 -0
- package/dist/commands/simplify.d.ts.map +1 -0
- package/dist/commands/simplify.js +174 -0
- package/dist/commands/simplify.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +105 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/study.d.ts +2 -0
- package/dist/commands/study.d.ts.map +1 -0
- package/dist/commands/study.js +193 -0
- package/dist/commands/study.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +11 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/core/dashboard.d.ts +41 -0
- package/dist/core/dashboard.d.ts.map +1 -1
- package/dist/core/dashboard.js +121 -0
- package/dist/core/dashboard.js.map +1 -1
- package/dist/core/dashboardTemplate.d.ts.map +1 -1
- package/dist/core/dashboardTemplate.js +523 -92
- package/dist/core/dashboardTemplate.js.map +1 -1
- package/dist/core/fileSystem.d.ts.map +1 -1
- package/dist/core/fileSystem.js +491 -309
- package/dist/core/fileSystem.js.map +1 -1
- package/dist/core/templates.d.ts +1 -0
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +8720 -1129
- package/dist/core/templates.js.map +1 -1
- package/package.json +58 -54
|
@@ -27,46 +27,162 @@ function getDashboardHtml() {
|
|
|
27
27
|
<div class="meta-item"><span class="label">User Level</span><span id="user-level"></span></div>
|
|
28
28
|
<div class="meta-item"><span class="label">Code Level</span><span id="code-level" class="badge"></span></div>
|
|
29
29
|
<div class="meta-item"><span class="label">Git</span><span id="git-status"></span></div>
|
|
30
|
+
<div class="meta-item"><span class="label">Complexity</span><span id="complexity"></span></div>
|
|
31
|
+
<div class="meta-item"><span class="label">Academic Readiness</span><span id="academic-readiness"></span></div>
|
|
30
32
|
</div>
|
|
31
33
|
</section>
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</
|
|
38
|
-
<
|
|
39
|
-
|
|
35
|
+
<!-- Tab Navigation -->
|
|
36
|
+
<nav class="tab-nav">
|
|
37
|
+
<button class="tab-btn active" data-tab="overview">Overview</button>
|
|
38
|
+
<button class="tab-btn" data-tab="phases">Phases</button>
|
|
39
|
+
<button class="tab-btn" data-tab="memory">Memory</button>
|
|
40
|
+
<button class="tab-btn" data-tab="study">Study</button>
|
|
41
|
+
<button class="tab-btn" data-tab="defense">Defense</button>
|
|
42
|
+
<button class="tab-btn" data-tab="docs">Docs Hub</button>
|
|
43
|
+
<button class="tab-btn" data-tab="agents">Agents</button>
|
|
44
|
+
<button class="tab-btn" data-tab="reports">Reports</button>
|
|
45
|
+
</nav>
|
|
46
|
+
|
|
47
|
+
<!-- Overview Tab -->
|
|
48
|
+
<div class="tab-content active" id="tab-overview">
|
|
49
|
+
<section class="progress-section card">
|
|
50
|
+
<div class="section-header">
|
|
51
|
+
<h2>Progress</h2>
|
|
52
|
+
<span id="phase-counter" class="counter"></span>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="progress-bar-wrap">
|
|
55
|
+
<div id="progress-bar" class="progress-bar"></div>
|
|
56
|
+
</div>
|
|
57
|
+
<div id="phases-list-overview" class="phases-list"></div>
|
|
58
|
+
</section>
|
|
59
|
+
|
|
60
|
+
<div class="two-col">
|
|
61
|
+
<section class="card">
|
|
62
|
+
<h2>Recent Commits</h2>
|
|
63
|
+
<ul id="commits-list" class="list"></ul>
|
|
64
|
+
</section>
|
|
65
|
+
<section class="card">
|
|
66
|
+
<h2>Known Bugs</h2>
|
|
67
|
+
<ul id="bugs-list" class="list"></ul>
|
|
68
|
+
</section>
|
|
40
69
|
</div>
|
|
41
|
-
<div id="phases-list" class="phases-list"></div>
|
|
42
|
-
</section>
|
|
43
70
|
|
|
44
|
-
<div class="two-col">
|
|
45
71
|
<section class="card">
|
|
46
|
-
<h2>
|
|
47
|
-
<ul id="
|
|
72
|
+
<h2>Last Decisions</h2>
|
|
73
|
+
<ul id="decisions-list" class="list"></ul>
|
|
48
74
|
</section>
|
|
49
75
|
|
|
50
76
|
<section class="card">
|
|
51
|
-
<h2>
|
|
52
|
-
<
|
|
77
|
+
<h2>Project Depth</h2>
|
|
78
|
+
<div id="depth-grid" class="depth-grid"></div>
|
|
53
79
|
</section>
|
|
54
80
|
</div>
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<
|
|
59
|
-
|
|
82
|
+
<!-- Phases Tab -->
|
|
83
|
+
<div class="tab-content" id="tab-phases">
|
|
84
|
+
<section class="card">
|
|
85
|
+
<h2>All Phases</h2>
|
|
86
|
+
<div id="phases-list-full" class="phases-list"></div>
|
|
87
|
+
</section>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- Memory Tab -->
|
|
91
|
+
<div class="tab-content" id="tab-memory">
|
|
92
|
+
<section class="card">
|
|
93
|
+
<h2>Memory Files</h2>
|
|
94
|
+
<p class="tab-hint">These files keep your project context. Run <code>brainforge serve</code> to read them.</p>
|
|
95
|
+
<div id="memory-docs-grid" class="docs-grid"></div>
|
|
96
|
+
</section>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<!-- Study Tab -->
|
|
100
|
+
<div class="tab-content" id="tab-study">
|
|
101
|
+
<section class="card">
|
|
102
|
+
<h2>Study Mode</h2>
|
|
103
|
+
<div id="study-status" class="status-banner"></div>
|
|
104
|
+
<div id="study-docs-grid" class="docs-grid"></div>
|
|
105
|
+
<div class="cmd-hint">
|
|
106
|
+
<span class="cmd-label">Run to enable:</span>
|
|
107
|
+
<code>brainforge study</code>
|
|
108
|
+
<span class="cmd-label">then:</span>
|
|
109
|
+
<code>/study-phase 1</code>
|
|
110
|
+
</div>
|
|
111
|
+
</section>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<!-- Defense Tab -->
|
|
115
|
+
<div class="tab-content" id="tab-defense">
|
|
116
|
+
<section class="card">
|
|
117
|
+
<h2>Defense Pack</h2>
|
|
118
|
+
<div id="defense-checklist" class="checklist"></div>
|
|
119
|
+
<div class="cmd-hint">
|
|
120
|
+
<span class="cmd-label">Run:</span>
|
|
121
|
+
<code>brainforge defense-pack</code>
|
|
122
|
+
<span class="cmd-label">then:</span>
|
|
123
|
+
<code>/defense-pack</code>
|
|
124
|
+
</div>
|
|
125
|
+
</section>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<!-- Docs Hub Tab -->
|
|
129
|
+
<div class="tab-content" id="tab-docs">
|
|
130
|
+
<section class="card">
|
|
131
|
+
<h2>Docs Hub</h2>
|
|
132
|
+
<p class="tab-hint">Click a card to preview the file. Run <code>brainforge serve</code> for full file reading.</p>
|
|
133
|
+
<div id="doc-viewer" class="doc-viewer hidden">
|
|
134
|
+
<div class="doc-viewer-header">
|
|
135
|
+
<span id="doc-viewer-title"></span>
|
|
136
|
+
<button id="doc-viewer-close" class="close-btn">✕</button>
|
|
137
|
+
</div>
|
|
138
|
+
<pre id="doc-viewer-content" class="doc-viewer-content"></pre>
|
|
139
|
+
</div>
|
|
140
|
+
<div id="docs-by-category"></div>
|
|
141
|
+
</section>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<!-- Agents Tab -->
|
|
145
|
+
<div class="tab-content" id="tab-agents">
|
|
146
|
+
<section class="card">
|
|
147
|
+
<h2>Agent Families</h2>
|
|
148
|
+
<p class="tab-hint">Use <code>/router</code> to find the right agent for your task.</p>
|
|
149
|
+
<div id="agents-grid" class="agents-grid"></div>
|
|
150
|
+
</section>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<!-- Reports Tab -->
|
|
154
|
+
<div class="tab-content" id="tab-reports">
|
|
155
|
+
<section class="card">
|
|
156
|
+
<h2>Reports</h2>
|
|
157
|
+
<div id="reports-docs-grid" class="docs-grid"></div>
|
|
158
|
+
<div class="cmd-hint">
|
|
159
|
+
<span class="cmd-label">Generate:</span>
|
|
160
|
+
<code>brainforge professor-check</code>
|
|
161
|
+
<code>brainforge difficulty</code>
|
|
162
|
+
<code>brainforge defense-pack</code>
|
|
163
|
+
</div>
|
|
164
|
+
</section>
|
|
165
|
+
</div>
|
|
60
166
|
|
|
61
167
|
<footer class="footer">
|
|
62
|
-
Powered by <strong>BrainForge</strong> — structured AI development
|
|
168
|
+
Powered by <strong>BrainForge v1.2</strong> — structured AI development
|
|
63
169
|
</footer>
|
|
64
170
|
</div>
|
|
65
171
|
|
|
66
172
|
<script>
|
|
173
|
+
// Tab navigation
|
|
174
|
+
document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
175
|
+
btn.addEventListener('click', () => {
|
|
176
|
+
const tab = btn.dataset.tab;
|
|
177
|
+
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
178
|
+
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
|
179
|
+
btn.classList.add('active');
|
|
180
|
+
document.getElementById('tab-' + tab).classList.add('active');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
67
184
|
async function loadData() {
|
|
68
185
|
try {
|
|
69
|
-
// Use inlined data (file:// mode) or fetch (http:// mode via brainforge serve)
|
|
70
186
|
let d = window.__BRAINFORGE_DATA__;
|
|
71
187
|
if (!d) {
|
|
72
188
|
const res = await fetch('data.json?t=' + Date.now());
|
|
@@ -74,42 +190,57 @@ function getDashboardHtml() {
|
|
|
74
190
|
}
|
|
75
191
|
|
|
76
192
|
document.title = 'BrainForge — ' + d.projectName;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
193
|
+
setText('project-name', d.projectName);
|
|
194
|
+
setText('project-description', d.description || 'No description yet.');
|
|
195
|
+
setText('project-type', d.projectType || '—');
|
|
196
|
+
setText('project-stack', (d.stack || []).join(', ') || '—');
|
|
197
|
+
setText('user-level', d.userLevel || '—');
|
|
198
|
+
setText('code-level', d.codeLevel || '—');
|
|
199
|
+
setText('git-status', d.gitStatus || '—');
|
|
200
|
+
setText('updated-at', 'Updated: ' + new Date(d.updatedAt).toLocaleString());
|
|
201
|
+
|
|
202
|
+
const pd = d.projectDepth || {};
|
|
203
|
+
setText('complexity', pd.estimatedComplexity || '—');
|
|
204
|
+
setText('academic-readiness', pd.academicReadiness || '—');
|
|
205
|
+
|
|
206
|
+
// Progress
|
|
86
207
|
const done = (d.phases || []).filter(p => p.status === 'done').length;
|
|
87
208
|
const total = d.totalPhases || d.phases?.length || 0;
|
|
88
|
-
|
|
209
|
+
setText('phase-counter', done + ' / ' + total + ' done');
|
|
89
210
|
const pct = total > 0 ? Math.round((done / total) * 100) : 0;
|
|
90
|
-
document.getElementById('progress-bar')
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
(d.phases || [])
|
|
95
|
-
|
|
96
|
-
div.className = 'phase-item ' + p.status;
|
|
97
|
-
div.innerHTML = '<span class="phase-num">' + String(p.id).padStart(2,'0') + '</span>'
|
|
98
|
-
+ '<span class="phase-title">' + p.title + '</span>'
|
|
99
|
-
+ '<span class="phase-status ' + p.status + '">' + p.status + '</span>';
|
|
100
|
-
phasesList.appendChild(div);
|
|
101
|
-
});
|
|
211
|
+
const pb = document.getElementById('progress-bar');
|
|
212
|
+
pb.style.width = pct + '%';
|
|
213
|
+
pb.textContent = pct + '%';
|
|
214
|
+
|
|
215
|
+
renderPhases('phases-list-overview', d.phases || []);
|
|
216
|
+
renderPhases('phases-list-full', d.phases || []);
|
|
102
217
|
|
|
103
218
|
renderList('commits-list', d.recentCommits, 'No commits yet.');
|
|
104
219
|
renderList('bugs-list', d.knownBugs, 'No bugs tracked.');
|
|
105
220
|
renderList('decisions-list', d.decisions, 'No decisions recorded.');
|
|
221
|
+
|
|
222
|
+
renderDepthGrid(pd);
|
|
223
|
+
renderDocsByCategory('docs-by-category', d.docs || []);
|
|
224
|
+
renderDocsByCategory('memory-docs-grid', (d.docs || []).filter(dc => dc.category === 'Memory'), true);
|
|
225
|
+
renderDocsByCategory('study-docs-grid', (d.docs || []).filter(dc => dc.category === 'Study'), true);
|
|
226
|
+
renderDocsByCategory('reports-docs-grid', (d.docs || []).filter(dc => dc.category === 'Reports'), true);
|
|
227
|
+
renderStudyStatus(d.study || {});
|
|
228
|
+
renderDefenseChecklist(d.defense || {});
|
|
229
|
+
renderAgentsGrid(d.agents || []);
|
|
230
|
+
|
|
106
231
|
} catch (e) {
|
|
107
|
-
document.body.innerHTML += '<p style="color:red;padding:1rem">Error loading data.json: ' + e.message + '
|
|
232
|
+
document.body.innerHTML += '<p style="color:red;padding:1rem">Error loading data.json: ' + e.message + '. Run brainforge serve for live loading.</p>';
|
|
108
233
|
}
|
|
109
234
|
}
|
|
110
235
|
|
|
236
|
+
function setText(id, val) {
|
|
237
|
+
const el = document.getElementById(id);
|
|
238
|
+
if (el) el.textContent = val;
|
|
239
|
+
}
|
|
240
|
+
|
|
111
241
|
function renderList(id, items, empty) {
|
|
112
242
|
const el = document.getElementById(id);
|
|
243
|
+
if (!el) return;
|
|
113
244
|
if (!items || items.length === 0) {
|
|
114
245
|
el.innerHTML = '<li class="empty">' + empty + '</li>';
|
|
115
246
|
return;
|
|
@@ -117,6 +248,142 @@ function getDashboardHtml() {
|
|
|
117
248
|
el.innerHTML = items.map(i => '<li>' + i + '</li>').join('');
|
|
118
249
|
}
|
|
119
250
|
|
|
251
|
+
function renderPhases(id, phases) {
|
|
252
|
+
const el = document.getElementById(id);
|
|
253
|
+
if (!el) return;
|
|
254
|
+
if (!phases.length) { el.innerHTML = '<p class="empty">No phases yet.</p>'; return; }
|
|
255
|
+
el.innerHTML = phases.map(p =>
|
|
256
|
+
'<div class="phase-item ' + p.status + '">'
|
|
257
|
+
+ '<span class="phase-num">' + String(p.id).padStart(2,'0') + '</span>'
|
|
258
|
+
+ '<span class="phase-title">' + p.title + '</span>'
|
|
259
|
+
+ '<span class="phase-status ' + p.status + '">' + p.status + '</span>'
|
|
260
|
+
+ '</div>'
|
|
261
|
+
).join('');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function renderDepthGrid(pd) {
|
|
265
|
+
const el = document.getElementById('depth-grid');
|
|
266
|
+
if (!el) return;
|
|
267
|
+
const items = [
|
|
268
|
+
{ label: 'Agents', value: pd.totalAgents || 0 },
|
|
269
|
+
{ label: 'Commands', value: pd.totalCommands || 0 },
|
|
270
|
+
{ label: 'Phases', value: pd.totalPhases || 0 },
|
|
271
|
+
{ label: 'Memory Files', value: pd.totalMemoryFiles || 0 },
|
|
272
|
+
{ label: 'Reports', value: pd.totalReports || 0 },
|
|
273
|
+
{ label: 'Total MD Files', value: pd.totalMarkdownFiles || 0 },
|
|
274
|
+
];
|
|
275
|
+
el.innerHTML = items.map(i =>
|
|
276
|
+
'<div class="depth-item"><span class="depth-value">' + i.value + '</span><span class="label">' + i.label + '</span></div>'
|
|
277
|
+
).join('');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function renderDocsByCategory(id, docs, flat) {
|
|
281
|
+
const el = document.getElementById(id);
|
|
282
|
+
if (!el) return;
|
|
283
|
+
if (!docs.length) { el.innerHTML = '<p class="empty">No docs found.</p>'; return; }
|
|
284
|
+
|
|
285
|
+
if (flat) {
|
|
286
|
+
el.innerHTML = docs.map(doc => docCard(doc)).join('');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const cats = {};
|
|
291
|
+
docs.forEach(doc => {
|
|
292
|
+
if (!cats[doc.category]) cats[doc.category] = [];
|
|
293
|
+
cats[doc.category].push(doc);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
el.innerHTML = Object.entries(cats).map(([cat, catDocs]) =>
|
|
297
|
+
'<div class="doc-category">'
|
|
298
|
+
+ '<h3 class="doc-cat-title">' + cat + '</h3>'
|
|
299
|
+
+ '<div class="doc-cat-grid">' + catDocs.map(doc => docCard(doc)).join('') + '</div>'
|
|
300
|
+
+ '</div>'
|
|
301
|
+
).join('');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function docCard(doc) {
|
|
305
|
+
const cls = doc.exists ? 'doc-card' : 'doc-card missing';
|
|
306
|
+
const badge = doc.exists ? '<span class="doc-badge exists">exists</span>' : '<span class="doc-badge missing">missing</span>';
|
|
307
|
+
return '<div class="' + cls + '" data-path="' + doc.path + '" onclick="openDoc(this)">'
|
|
308
|
+
+ '<div class="doc-card-title">' + doc.title + '</div>'
|
|
309
|
+
+ '<div class="doc-card-path">' + doc.path + '</div>'
|
|
310
|
+
+ badge
|
|
311
|
+
+ '</div>';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function openDoc(el) {
|
|
315
|
+
const p = el.dataset.path;
|
|
316
|
+
const viewer = document.getElementById('doc-viewer');
|
|
317
|
+
const title = document.getElementById('doc-viewer-title');
|
|
318
|
+
const content = document.getElementById('doc-viewer-content');
|
|
319
|
+
title.textContent = p;
|
|
320
|
+
content.textContent = 'Loading...';
|
|
321
|
+
viewer.classList.remove('hidden');
|
|
322
|
+
try {
|
|
323
|
+
const res = await fetch('../' + p.replace('.brainforge/', '') + '?t=' + Date.now());
|
|
324
|
+
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
325
|
+
content.textContent = await res.text();
|
|
326
|
+
} catch {
|
|
327
|
+
content.textContent = 'Cannot read file in file:// mode.\\nRun: brainforge serve';
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
document.getElementById('doc-viewer-close').addEventListener('click', () => {
|
|
332
|
+
document.getElementById('doc-viewer').classList.add('hidden');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
function renderStudyStatus(study) {
|
|
336
|
+
const el = document.getElementById('study-status');
|
|
337
|
+
if (!el) return;
|
|
338
|
+
if (study.enabled) {
|
|
339
|
+
el.className = 'status-banner success';
|
|
340
|
+
el.textContent = 'Study Mode enabled — ' + (study.files || []).length + ' file(s)';
|
|
341
|
+
} else {
|
|
342
|
+
el.className = 'status-banner warn';
|
|
343
|
+
el.textContent = 'Study Mode not initialized. Run: brainforge study';
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function renderDefenseChecklist(defense) {
|
|
348
|
+
const el = document.getElementById('defense-checklist');
|
|
349
|
+
if (!el) return;
|
|
350
|
+
const items = [
|
|
351
|
+
{ label: 'Defense Pack report', ok: defense.reportExists },
|
|
352
|
+
{ label: 'Professor Check report', ok: defense.professorCheckExists },
|
|
353
|
+
{ label: 'Difficulty Report', ok: defense.difficultyReportExists },
|
|
354
|
+
];
|
|
355
|
+
el.innerHTML = items.map(item =>
|
|
356
|
+
'<div class="check-item ' + (item.ok ? 'ok' : 'missing') + '">'
|
|
357
|
+
+ '<span class="check-icon">' + (item.ok ? '✔' : '✖') + '</span>'
|
|
358
|
+
+ '<span>' + item.label + '</span>'
|
|
359
|
+
+ '</div>'
|
|
360
|
+
).join('');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function renderAgentsGrid(agents) {
|
|
364
|
+
const el = document.getElementById('agents-grid');
|
|
365
|
+
if (!el) return;
|
|
366
|
+
if (!agents.length) { el.innerHTML = '<p class="empty">No agents found. Run brainforge update.</p>'; return; }
|
|
367
|
+
|
|
368
|
+
const families = {};
|
|
369
|
+
agents.forEach(a => {
|
|
370
|
+
if (!families[a.family]) families[a.family] = [];
|
|
371
|
+
families[a.family].push(a);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
el.innerHTML = Object.entries(families).map(([fam, agts]) =>
|
|
375
|
+
'<div class="agent-family">'
|
|
376
|
+
+ '<h3 class="agent-family-title">' + fam + '</h3>'
|
|
377
|
+
+ agts.map(a =>
|
|
378
|
+
'<div class="agent-card">'
|
|
379
|
+
+ '<div class="agent-title">' + a.title + '</div>'
|
|
380
|
+
+ '<div class="agent-summary">' + a.summary + '</div>'
|
|
381
|
+
+ '</div>'
|
|
382
|
+
).join('')
|
|
383
|
+
+ '</div>'
|
|
384
|
+
).join('');
|
|
385
|
+
}
|
|
386
|
+
|
|
120
387
|
loadData();
|
|
121
388
|
</script>
|
|
122
389
|
</body>
|
|
@@ -149,11 +416,7 @@ body {
|
|
|
149
416
|
min-height: 100vh;
|
|
150
417
|
}
|
|
151
418
|
|
|
152
|
-
.container {
|
|
153
|
-
max-width: 1100px;
|
|
154
|
-
margin: 0 auto;
|
|
155
|
-
padding: 2rem 1.5rem;
|
|
156
|
-
}
|
|
419
|
+
.container { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem; }
|
|
157
420
|
|
|
158
421
|
.header {
|
|
159
422
|
display: flex;
|
|
@@ -162,13 +425,7 @@ body {
|
|
|
162
425
|
margin-bottom: 2rem;
|
|
163
426
|
}
|
|
164
427
|
|
|
165
|
-
.logo {
|
|
166
|
-
font-size: 1.4rem;
|
|
167
|
-
font-weight: 700;
|
|
168
|
-
color: var(--primary-light);
|
|
169
|
-
letter-spacing: -0.5px;
|
|
170
|
-
}
|
|
171
|
-
|
|
428
|
+
.logo { font-size: 1.4rem; font-weight: 700; color: var(--primary-light); letter-spacing: -0.5px; }
|
|
172
429
|
.updated-at { color: var(--muted); font-size: 0.8rem; }
|
|
173
430
|
|
|
174
431
|
.project-card {
|
|
@@ -181,12 +438,13 @@ body {
|
|
|
181
438
|
|
|
182
439
|
h1 { font-size: 1.6rem; font-weight: 700; margin-bottom: 0.4rem; }
|
|
183
440
|
h2 { font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem; color: var(--primary-light); }
|
|
441
|
+
h3 { font-size: 0.95rem; font-weight: 600; margin-bottom: 0.75rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
|
|
184
442
|
|
|
185
443
|
.description { color: var(--muted); margin-bottom: 1.25rem; }
|
|
186
444
|
|
|
187
445
|
.meta-grid {
|
|
188
446
|
display: grid;
|
|
189
|
-
grid-template-columns: repeat(auto-fill, minmax(
|
|
447
|
+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
190
448
|
gap: 0.75rem;
|
|
191
449
|
}
|
|
192
450
|
|
|
@@ -212,7 +470,41 @@ h2 { font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem; color: var(--pri
|
|
|
212
470
|
width: fit-content;
|
|
213
471
|
}
|
|
214
472
|
|
|
215
|
-
|
|
473
|
+
/* Tab Navigation */
|
|
474
|
+
.tab-nav {
|
|
475
|
+
display: flex;
|
|
476
|
+
gap: 0.25rem;
|
|
477
|
+
margin-bottom: 1.5rem;
|
|
478
|
+
background: var(--surface);
|
|
479
|
+
border: 1px solid var(--border);
|
|
480
|
+
border-radius: var(--radius);
|
|
481
|
+
padding: 0.4rem;
|
|
482
|
+
flex-wrap: wrap;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.tab-btn {
|
|
486
|
+
background: none;
|
|
487
|
+
border: none;
|
|
488
|
+
color: var(--muted);
|
|
489
|
+
cursor: pointer;
|
|
490
|
+
padding: 0.45rem 0.9rem;
|
|
491
|
+
border-radius: 7px;
|
|
492
|
+
font-size: 0.85rem;
|
|
493
|
+
font-weight: 500;
|
|
494
|
+
transition: all 0.15s;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.tab-btn:hover { background: var(--surface2); color: var(--text); }
|
|
498
|
+
.tab-btn.active { background: var(--primary); color: #fff; }
|
|
499
|
+
|
|
500
|
+
.tab-content { display: none; }
|
|
501
|
+
.tab-content.active { display: block; }
|
|
502
|
+
|
|
503
|
+
.tab-hint { color: var(--muted); font-size: 0.85rem; margin-bottom: 1rem; }
|
|
504
|
+
.tab-hint code { background: var(--surface2); padding: 1px 6px; border-radius: 4px; font-size: 0.8rem; }
|
|
505
|
+
|
|
506
|
+
/* Cards */
|
|
507
|
+
.card {
|
|
216
508
|
background: var(--surface);
|
|
217
509
|
border: 1px solid var(--border);
|
|
218
510
|
border-radius: var(--radius);
|
|
@@ -220,13 +512,18 @@ h2 { font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem; color: var(--pri
|
|
|
220
512
|
margin-bottom: 1.5rem;
|
|
221
513
|
}
|
|
222
514
|
|
|
223
|
-
.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
515
|
+
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 1.5rem; }
|
|
516
|
+
@media (max-width: 640px) { .two-col { grid-template-columns: 1fr; } }
|
|
517
|
+
|
|
518
|
+
.progress-section {
|
|
519
|
+
background: var(--surface);
|
|
520
|
+
border: 1px solid var(--border);
|
|
521
|
+
border-radius: var(--radius);
|
|
522
|
+
padding: 1.5rem;
|
|
523
|
+
margin-bottom: 1.5rem;
|
|
228
524
|
}
|
|
229
525
|
|
|
526
|
+
.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
|
|
230
527
|
.counter { color: var(--muted); font-size: 0.85rem; }
|
|
231
528
|
|
|
232
529
|
.progress-bar-wrap {
|
|
@@ -264,64 +561,198 @@ h2 { font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem; color: var(--pri
|
|
|
264
561
|
}
|
|
265
562
|
|
|
266
563
|
.phase-item.done { border-left-color: var(--success); }
|
|
267
|
-
.phase-item.in-progress { border-left-color: var(--
|
|
268
|
-
.phase-item.pending { border-left-color: var(--border); }
|
|
564
|
+
.phase-item.in-progress { border-left-color: var(--warning); }
|
|
269
565
|
|
|
270
|
-
.phase-num {
|
|
271
|
-
.phase-title { flex: 1;
|
|
566
|
+
.phase-num { font-size: 0.8rem; color: var(--muted); min-width: 28px; }
|
|
567
|
+
.phase-title { flex: 1; }
|
|
272
568
|
|
|
273
569
|
.phase-status {
|
|
274
570
|
font-size: 0.72rem;
|
|
275
|
-
font-weight: 600;
|
|
276
571
|
padding: 2px 8px;
|
|
277
572
|
border-radius: 20px;
|
|
278
|
-
|
|
573
|
+
font-weight: 600;
|
|
574
|
+
text-transform: uppercase;
|
|
575
|
+
background: var(--surface);
|
|
576
|
+
color: var(--muted);
|
|
279
577
|
}
|
|
280
|
-
.phase-status.done { background: #14532d; color: var(--success); }
|
|
281
|
-
.phase-status.in-progress { background: #1e1b4b; color: var(--primary-light); }
|
|
282
|
-
.phase-status.pending { background: var(--surface); color: var(--muted); }
|
|
283
578
|
|
|
284
|
-
.
|
|
579
|
+
.phase-status.done { background: rgba(34,197,94,0.15); color: var(--success); }
|
|
580
|
+
.phase-status.in-progress { background: rgba(245,158,11,0.15); color: var(--warning); }
|
|
581
|
+
|
|
582
|
+
.list { list-style: none; display: flex; flex-direction: column; gap: 0.4rem; }
|
|
583
|
+
.list li { padding: 0.4rem 0; border-bottom: 1px solid var(--border); font-size: 0.88rem; }
|
|
584
|
+
.list li:last-child { border-bottom: none; }
|
|
585
|
+
.list .empty { color: var(--muted); font-style: italic; }
|
|
586
|
+
|
|
587
|
+
/* Depth grid */
|
|
588
|
+
.depth-grid {
|
|
285
589
|
display: grid;
|
|
286
|
-
grid-template-columns:
|
|
287
|
-
gap:
|
|
288
|
-
margin-bottom: 1.5rem;
|
|
590
|
+
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
|
|
591
|
+
gap: 0.75rem;
|
|
289
592
|
}
|
|
290
593
|
|
|
291
|
-
|
|
594
|
+
.depth-item {
|
|
595
|
+
background: var(--surface2);
|
|
596
|
+
border-radius: 8px;
|
|
597
|
+
padding: 0.75rem;
|
|
598
|
+
display: flex;
|
|
599
|
+
flex-direction: column;
|
|
600
|
+
align-items: center;
|
|
601
|
+
gap: 4px;
|
|
602
|
+
}
|
|
292
603
|
|
|
293
|
-
.
|
|
294
|
-
|
|
604
|
+
.depth-value { font-size: 1.6rem; font-weight: 700; color: var(--primary-light); }
|
|
605
|
+
|
|
606
|
+
/* Docs grid */
|
|
607
|
+
.docs-grid {
|
|
608
|
+
display: grid;
|
|
609
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
610
|
+
gap: 0.75rem;
|
|
611
|
+
margin-bottom: 1rem;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.doc-category { margin-bottom: 1.5rem; }
|
|
615
|
+
.doc-cat-title { font-size: 0.85rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.75rem; }
|
|
616
|
+
.doc-cat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 0.75rem; }
|
|
617
|
+
|
|
618
|
+
.doc-card {
|
|
619
|
+
background: var(--surface2);
|
|
620
|
+
border: 1px solid var(--border);
|
|
621
|
+
border-radius: 8px;
|
|
622
|
+
padding: 0.75rem;
|
|
623
|
+
cursor: pointer;
|
|
624
|
+
transition: border-color 0.15s;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.doc-card:hover { border-color: var(--primary); }
|
|
628
|
+
.doc-card.missing { opacity: 0.5; cursor: default; }
|
|
629
|
+
.doc-card.missing:hover { border-color: var(--border); }
|
|
630
|
+
|
|
631
|
+
.doc-card-title { font-weight: 600; font-size: 0.9rem; margin-bottom: 0.25rem; }
|
|
632
|
+
.doc-card-path { font-size: 0.7rem; color: var(--muted); margin-bottom: 0.4rem; word-break: break-all; }
|
|
633
|
+
|
|
634
|
+
.doc-badge {
|
|
635
|
+
display: inline-block;
|
|
636
|
+
font-size: 0.68rem;
|
|
637
|
+
padding: 1px 6px;
|
|
638
|
+
border-radius: 10px;
|
|
639
|
+
font-weight: 600;
|
|
640
|
+
text-transform: uppercase;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.doc-badge.exists { background: rgba(34,197,94,0.15); color: var(--success); }
|
|
644
|
+
.doc-badge.missing { background: rgba(239,68,68,0.15); color: var(--error); }
|
|
645
|
+
|
|
646
|
+
/* Doc viewer */
|
|
647
|
+
.doc-viewer {
|
|
648
|
+
background: var(--surface2);
|
|
295
649
|
border: 1px solid var(--border);
|
|
296
650
|
border-radius: var(--radius);
|
|
297
|
-
padding:
|
|
651
|
+
padding: 1rem;
|
|
298
652
|
margin-bottom: 1.5rem;
|
|
299
653
|
}
|
|
300
654
|
|
|
301
|
-
.
|
|
302
|
-
|
|
655
|
+
.doc-viewer.hidden { display: none; }
|
|
656
|
+
|
|
657
|
+
.doc-viewer-header {
|
|
303
658
|
display: flex;
|
|
304
|
-
|
|
305
|
-
|
|
659
|
+
justify-content: space-between;
|
|
660
|
+
align-items: center;
|
|
661
|
+
margin-bottom: 0.75rem;
|
|
662
|
+
font-size: 0.85rem;
|
|
663
|
+
color: var(--muted);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.doc-viewer-content {
|
|
667
|
+
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
668
|
+
font-size: 0.8rem;
|
|
669
|
+
white-space: pre-wrap;
|
|
670
|
+
max-height: 400px;
|
|
671
|
+
overflow-y: auto;
|
|
672
|
+
color: var(--text);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.close-btn {
|
|
676
|
+
background: none;
|
|
677
|
+
border: none;
|
|
678
|
+
color: var(--muted);
|
|
679
|
+
cursor: pointer;
|
|
680
|
+
font-size: 1rem;
|
|
681
|
+
padding: 2px 6px;
|
|
682
|
+
border-radius: 4px;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.close-btn:hover { background: var(--surface); }
|
|
686
|
+
|
|
687
|
+
/* Status banners */
|
|
688
|
+
.status-banner {
|
|
689
|
+
padding: 0.75rem 1rem;
|
|
690
|
+
border-radius: 8px;
|
|
691
|
+
margin-bottom: 1rem;
|
|
692
|
+
font-weight: 500;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.status-banner.success { background: rgba(34,197,94,0.12); color: var(--success); border: 1px solid rgba(34,197,94,0.2); }
|
|
696
|
+
.status-banner.warn { background: rgba(245,158,11,0.12); color: var(--warning); border: 1px solid rgba(245,158,11,0.2); }
|
|
697
|
+
|
|
698
|
+
/* Defense checklist */
|
|
699
|
+
.checklist { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }
|
|
700
|
+
|
|
701
|
+
.check-item {
|
|
702
|
+
display: flex;
|
|
703
|
+
align-items: center;
|
|
704
|
+
gap: 0.75rem;
|
|
705
|
+
padding: 0.5rem 0.75rem;
|
|
706
|
+
border-radius: 8px;
|
|
707
|
+
font-size: 0.9rem;
|
|
306
708
|
}
|
|
307
709
|
|
|
308
|
-
.
|
|
309
|
-
|
|
710
|
+
.check-item.ok { background: rgba(34,197,94,0.08); }
|
|
711
|
+
.check-item.missing { background: rgba(239,68,68,0.08); }
|
|
712
|
+
|
|
713
|
+
.check-icon { font-size: 1rem; }
|
|
714
|
+
.check-item.ok .check-icon { color: var(--success); }
|
|
715
|
+
.check-item.missing .check-icon { color: var(--error); }
|
|
716
|
+
|
|
717
|
+
/* Command hints */
|
|
718
|
+
.cmd-hint {
|
|
719
|
+
display: flex;
|
|
720
|
+
align-items: center;
|
|
721
|
+
gap: 0.5rem;
|
|
722
|
+
flex-wrap: wrap;
|
|
723
|
+
padding: 0.75rem;
|
|
310
724
|
background: var(--surface2);
|
|
311
|
-
border-radius:
|
|
725
|
+
border-radius: 8px;
|
|
312
726
|
font-size: 0.85rem;
|
|
313
|
-
|
|
727
|
+
margin-top: 1rem;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.cmd-label { color: var(--muted); }
|
|
731
|
+
.cmd-hint code { background: var(--bg); padding: 2px 8px; border-radius: 4px; font-family: monospace; font-size: 0.82rem; }
|
|
732
|
+
|
|
733
|
+
/* Agents grid */
|
|
734
|
+
.agents-grid { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
735
|
+
|
|
736
|
+
.agent-family { }
|
|
737
|
+
.agent-family-title { font-size: 0.85rem; font-weight: 600; color: var(--primary-light); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.75rem; }
|
|
738
|
+
|
|
739
|
+
.agent-card {
|
|
740
|
+
display: inline-block;
|
|
741
|
+
background: var(--surface2);
|
|
742
|
+
border: 1px solid var(--border);
|
|
743
|
+
border-radius: 8px;
|
|
744
|
+
padding: 0.6rem 0.9rem;
|
|
745
|
+
margin: 0 0.4rem 0.4rem 0;
|
|
314
746
|
}
|
|
315
747
|
|
|
316
|
-
.
|
|
748
|
+
.agent-title { font-weight: 600; font-size: 0.88rem; }
|
|
749
|
+
.agent-summary { font-size: 0.78rem; color: var(--muted); }
|
|
317
750
|
|
|
318
751
|
.footer {
|
|
319
752
|
text-align: center;
|
|
753
|
+
padding: 2rem 0 1rem;
|
|
320
754
|
color: var(--muted);
|
|
321
|
-
font-size: 0.
|
|
322
|
-
padding-top: 1.5rem;
|
|
323
|
-
border-top: 1px solid var(--border);
|
|
324
|
-
margin-top: 1rem;
|
|
755
|
+
font-size: 0.82rem;
|
|
325
756
|
}
|
|
326
757
|
`;
|
|
327
758
|
}
|