@beastmode-develeap/beastmode 0.1.275 → 0.1.277
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/dist/web/board.html +87 -48
- package/dist/web/build-commit.txt +1 -1
- package/dist/web/build-stamp.txt +1 -1
- package/package.json +1 -1
package/dist/web/board.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
</script>
|
|
17
17
|
<!--BOARD_DATA-->
|
|
18
|
-
<script>window.__BUILD_STAMP__ = "20260516-
|
|
18
|
+
<script>window.__BUILD_STAMP__ = "20260516-140206-eb6aa87";</script>
|
|
19
19
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
20
20
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
21
21
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -1259,6 +1259,11 @@ input[type="range"]::-webkit-slider-thumb {
|
|
|
1259
1259
|
.card-status-age.status-age-info { color: var(--accent); background: var(--accent-subtle); }
|
|
1260
1260
|
.card-status-age.status-age-warn { color: #fb923c; background: rgba(249, 115, 22, 0.15); }
|
|
1261
1261
|
.card-status-age.status-age-stale { color: #f87171; background: rgba(239, 68, 68, 0.15); }
|
|
1262
|
+
.card-badge-wrap {
|
|
1263
|
+
/* Flex child wrapper: blockified by parent flex, but sized to content.
|
|
1264
|
+
The inner .card-badge is NOT a direct flex item, so it keeps display:inline-block. */
|
|
1265
|
+
line-height: 0;
|
|
1266
|
+
}
|
|
1262
1267
|
.card-badge {
|
|
1263
1268
|
display: inline-block;
|
|
1264
1269
|
padding: 2px 8px;
|
|
@@ -6319,7 +6324,7 @@ function PipelineView({
|
|
|
6319
6324
|
${(() => {
|
|
6320
6325
|
const cost = costsByItem && costsByItem[String(item.id)];
|
|
6321
6326
|
const label = cost ? formatCost(cost.total_cost_usd) : null;
|
|
6322
|
-
return label ? html`<span class="card-badge badge-cost" title=${'Total cost: ' + label}>${label}</span>` : null;
|
|
6327
|
+
return label ? html`<span class="card-badge-wrap"><span class="card-badge badge-cost" title=${'Total cost: ' + label}>${label}</span></span>` : null;
|
|
6323
6328
|
})()}
|
|
6324
6329
|
${(() => {
|
|
6325
6330
|
const env = item.extra && item.extra.current_env;
|
|
@@ -6736,8 +6741,7 @@ function BoardPage({ selectedProject }) {
|
|
|
6736
6741
|
// append ?board=<proj> here. Errors are swallowed: if the cost
|
|
6737
6742
|
// batch endpoint is unreachable, cards render without badges.
|
|
6738
6743
|
const fetchCosts = useCallback(() => {
|
|
6739
|
-
const
|
|
6740
|
-
const boardParam = (proj && proj !== 'all') ? '?board=' + encodeURIComponent(proj) : '';
|
|
6744
|
+
const boardParam = (selectedProject && selectedProject !== 'all') ? '?board=' + encodeURIComponent(selectedProject) : '';
|
|
6741
6745
|
fetch('/api/costs/by-items' + boardParam)
|
|
6742
6746
|
.then(r => r.ok ? r.json() : {})
|
|
6743
6747
|
.then(data => setCostsByItem(data || {}))
|
|
@@ -7531,7 +7535,7 @@ function BoardPage({ selectedProject }) {
|
|
|
7531
7535
|
${(() => {
|
|
7532
7536
|
const cost = costsByItem && costsByItem[String(item.id)];
|
|
7533
7537
|
const label = cost ? formatCost(cost.total_cost_usd) : null;
|
|
7534
|
-
return label ? html`<span class="card-badge badge-cost" title=${'Total cost: ' + label}>${label}</span>` : null;
|
|
7538
|
+
return label ? html`<span class="card-badge-wrap"><span class="card-badge badge-cost" title=${'Total cost: ' + label}>${label}</span></span>` : null;
|
|
7535
7539
|
})()}
|
|
7536
7540
|
${(() => {
|
|
7537
7541
|
const env = item.extra && item.extra.current_env;
|
|
@@ -8568,7 +8572,21 @@ function ProjectsPage({ selectedProject, onProjectChange }) {
|
|
|
8568
8572
|
setGuideErrors(prev => ({ ...prev, [name]: null }));
|
|
8569
8573
|
return resp;
|
|
8570
8574
|
} catch (e) {
|
|
8571
|
-
|
|
8575
|
+
// 404 means no guide exists yet — treat as empty sentinel so the
|
|
8576
|
+
// render shows the status-based fallback instead of a raw error.
|
|
8577
|
+
const noGuide = e.message && (
|
|
8578
|
+
e.message.includes('No codebase guide') ||
|
|
8579
|
+
e.message.includes('Guide file not found') ||
|
|
8580
|
+
e.message === 'HTTP 404'
|
|
8581
|
+
);
|
|
8582
|
+
if (noGuide) {
|
|
8583
|
+
setGuideContent(prev => ({
|
|
8584
|
+
...prev,
|
|
8585
|
+
[name]: { ...(prev[name] || {}), [level]: '' },
|
|
8586
|
+
}));
|
|
8587
|
+
} else {
|
|
8588
|
+
setGuideErrors(prev => ({ ...prev, [name]: e.message }));
|
|
8589
|
+
}
|
|
8572
8590
|
return null;
|
|
8573
8591
|
}
|
|
8574
8592
|
}, []);
|
|
@@ -8579,12 +8597,14 @@ function ProjectsPage({ selectedProject, onProjectChange }) {
|
|
|
8579
8597
|
return;
|
|
8580
8598
|
}
|
|
8581
8599
|
setExpandedProject(name);
|
|
8582
|
-
//
|
|
8583
|
-
|
|
8584
|
-
|
|
8600
|
+
// Optimistically fetch L1 guide on expand regardless of analysis status.
|
|
8601
|
+
// Guide files exist even when a re-analysis is in progress (previous run's
|
|
8602
|
+
// output persists). fetchGuide silently treats 404 as empty so this is
|
|
8603
|
+
// safe to call unconditionally — it never shows a raw HTTP error.
|
|
8604
|
+
if (!(guideContent[name] && guideContent[name].l1)) {
|
|
8585
8605
|
await fetchGuide(name, 'l1');
|
|
8586
8606
|
}
|
|
8587
|
-
}, [expandedProject,
|
|
8607
|
+
}, [expandedProject, guideContent, fetchGuide]);
|
|
8588
8608
|
|
|
8589
8609
|
const stopPolling = useCallback((name) => {
|
|
8590
8610
|
if (pollTimersRef.current[name]) {
|
|
@@ -8831,7 +8851,7 @@ function ProjectsPage({ selectedProject, onProjectChange }) {
|
|
|
8831
8851
|
data-testid="codebase-summary-panel">
|
|
8832
8852
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
|
|
8833
8853
|
<strong style="font-size:13px;">Codebase summary</strong>
|
|
8834
|
-
${
|
|
8854
|
+
${guide.l1 ? html`
|
|
8835
8855
|
<button class="btn btn-sm btn-secondary"
|
|
8836
8856
|
onClick=${() => toggleFullGuide(proj.name)}
|
|
8837
8857
|
data-testid="project-show-full-guide">
|
|
@@ -8840,44 +8860,45 @@ function ProjectsPage({ selectedProject, onProjectChange }) {
|
|
|
8840
8860
|
` : null}
|
|
8841
8861
|
</div>
|
|
8842
8862
|
${guideErr ? html`<div class="error-msg" style="margin-bottom:8px;">${guideErr}</div>` : null}
|
|
8843
|
-
${
|
|
8844
|
-
? (guide
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
: pillState === 'failed'
|
|
8868
|
-
? html`<div>
|
|
8869
|
-
<div class="error-msg" style="margin-bottom:8px;">${st.error || 'Analysis failed'}</div>
|
|
8870
|
-
<button class="btn btn-sm btn-primary"
|
|
8871
|
-
onClick=${() => reanalyze(proj.name)}
|
|
8872
|
-
data-testid="project-retry-btn">Retry</button>
|
|
8863
|
+
${guide.l1 === undefined
|
|
8864
|
+
? html`<div style="color:var(--text-secondary);font-size:12px;">Loading guide\u2026</div>`
|
|
8865
|
+
: guide.l1
|
|
8866
|
+
? html`
|
|
8867
|
+
${isBusy ? html`<div style="font-size:11px;color:var(--text-secondary);margin-bottom:6px;">Re-analysis in progress\u2026</div>` : null}
|
|
8868
|
+
<pre style="white-space:pre-wrap;font-family:inherit;font-size:13px;line-height:1.5;
|
|
8869
|
+
background:var(--bg-subtle);padding:10px;border-radius:6px;margin:0;"
|
|
8870
|
+
data-testid="codebase-guide-l1">${guide.l1}</pre>
|
|
8871
|
+
${showFullGuide[proj.name]
|
|
8872
|
+
? (guide.l2 === undefined
|
|
8873
|
+
? html`<div style="margin-top:8px;color:var(--text-secondary);font-size:12px;">Loading full guide\u2026</div>`
|
|
8874
|
+
: html`
|
|
8875
|
+
<pre style="white-space:pre-wrap;font-family:inherit;font-size:12px;line-height:1.5;
|
|
8876
|
+
background:var(--bg-subtle);padding:10px;border-radius:6px;margin-top:8px;"
|
|
8877
|
+
data-testid="codebase-guide-l2">${guide.l2}</pre>
|
|
8878
|
+
`)
|
|
8879
|
+
: null}
|
|
8880
|
+
`
|
|
8881
|
+
: pillState === 'running'
|
|
8882
|
+
? html`<div style="display:flex;align-items:center;gap:8px;color:var(--text-secondary);">
|
|
8883
|
+
<span class="spinner" style="display:inline-block;width:12px;height:12px;border:2px solid var(--border);
|
|
8884
|
+
border-top-color:var(--accent);border-radius:50%;
|
|
8885
|
+
animation:spin 0.8s linear infinite;"></span>
|
|
8886
|
+
Analyzing codebase\u2026
|
|
8873
8887
|
</div>`
|
|
8874
|
-
:
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8888
|
+
: pillState === 'failed'
|
|
8889
|
+
? html`<div>
|
|
8890
|
+
<div class="error-msg" style="margin-bottom:8px;">${st.error || 'Analysis failed'}</div>
|
|
8891
|
+
<button class="btn btn-sm btn-primary"
|
|
8892
|
+
onClick=${() => reanalyze(proj.name)}
|
|
8893
|
+
data-testid="project-retry-btn">Retry</button>
|
|
8894
|
+
</div>`
|
|
8895
|
+
: html`<div style="color:var(--text-secondary);">
|
|
8896
|
+
Not analyzed yet \u2014
|
|
8897
|
+
<button class="btn btn-sm btn-primary"
|
|
8898
|
+
style="margin-left:6px;"
|
|
8899
|
+
onClick=${() => reanalyze(proj.name)}
|
|
8900
|
+
data-testid="project-run-analysis-btn">Run analysis</button>
|
|
8901
|
+
</div>`}
|
|
8881
8902
|
</div>
|
|
8882
8903
|
` : null}
|
|
8883
8904
|
<${EnvironmentPanel} projectName=${proj.name} />
|
|
@@ -11723,6 +11744,24 @@ function App() {
|
|
|
11723
11744
|
setSelectedProjectRaw(value);
|
|
11724
11745
|
}, []);
|
|
11725
11746
|
|
|
11747
|
+
// Auto-select the first registered project when localStorage has no prior
|
|
11748
|
+
// choice. Without this, items and costs both route to the default board
|
|
11749
|
+
// (board.db) which doesn't match project board data — no badges render in
|
|
11750
|
+
// a fresh Playwright or incognito session. Multi-project factories default
|
|
11751
|
+
// to the first registered project; users can override via the sidebar.
|
|
11752
|
+
useEffect(() => {
|
|
11753
|
+
if (localStorage.getItem('beastmode-selected-project')) return;
|
|
11754
|
+
fetch('/api/projects')
|
|
11755
|
+
.then(r => r.ok ? r.json() : null)
|
|
11756
|
+
.then(data => {
|
|
11757
|
+
const projects = data && data.projects;
|
|
11758
|
+
if (Array.isArray(projects) && projects.length > 0) {
|
|
11759
|
+
setSelectedProject(projects[0].name);
|
|
11760
|
+
}
|
|
11761
|
+
})
|
|
11762
|
+
.catch(() => {});
|
|
11763
|
+
}, []);
|
|
11764
|
+
|
|
11726
11765
|
// If ?view=pipeline or ?view=board is in the URL but no hash route is
|
|
11727
11766
|
// set, the router would default to Dashboard. Redirect to #/board so
|
|
11728
11767
|
// the board page renders (and BoardPage can read the ?view= param).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
eb6aa87c2a0979bee58379926ffeb4c8bb6ffa12
|
package/dist/web/build-stamp.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
20260516-
|
|
1
|
+
20260516-140206-eb6aa87
|