@polderlabs/bizar 7.0.2 → 7.0.4
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/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js.map +1 -1
- package/bizar-dash/dist/assets/Toast-ATSAmbdi.js.map +1 -1
- package/bizar-dash/dist/assets/main-CJAtrosO.css +1 -0
- package/bizar-dash/dist/assets/main-DKKj9dsq.js +430 -0
- package/bizar-dash/dist/assets/main-DKKj9dsq.js.map +1 -0
- package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js.map +1 -1
- package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js.map +1 -1
- package/bizar-dash/dist/index.html +2 -2
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/bizar-dash/src/web/components/SettingsNav.tsx +9 -4
- package/bizar-dash/src/web/components/Topbar.tsx +45 -0
- package/bizar-dash/src/web/styles/main.css +87 -89
- package/bizar-dash/src/web/styles/memory.css +30 -35
- package/bizar-dash/src/web/styles/settings.css +6 -26
- package/bizar-dash/src/web/ui/data/data.css +6 -1
- package/bizar-dash/src/web/ui/index.ts +1 -0
- package/bizar-dash/src/web/views/Memory.tsx +94 -62
- package/bizar-dash/src/web/views/Overview.tsx +2 -23
- package/bizar-dash/tests/settings-layout.test.tsx +2 -2
- package/bizar-dash/tests/settings-nav.test.tsx +6 -6
- package/cli/provision-claude.mjs +108 -5
- package/package.json +1 -1
- package/packages/sdk/.harness/agents.json +17 -0
- package/packages/sdk/.harness/topology.json +4 -0
- package/bizar-dash/dist/assets/main-306CZfn6.js +0 -430
- package/bizar-dash/dist/assets/main-306CZfn6.js.map +0 -1
- package/bizar-dash/dist/assets/main-G3bNDpY3.css +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
// src/web/views/Memory.tsx —
|
|
1
|
+
// src/web/views/Memory.tsx — v7.0.4 dedicated Memory tab.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
3
|
+
// Two-column layout: source rail on the left (10 sources), main panel on
|
|
4
|
+
// the right (one sub-panel at a time). v7.0.4 swaps the legacy
|
|
5
|
+
// `.view view-memory memory-tab` + `.memory-tab-body` + `.memory-source-rail`
|
|
6
|
+
// shell for the design-system primitives (Box / ViewHeader / Grid /
|
|
7
|
+
// cx-classed nav buttons) so the Memory tab matches the rest of the
|
|
8
|
+
// dashboard theme. Sub-panels keep their own shell until a follow-up
|
|
9
|
+
// sprint per-component migrates them.
|
|
9
10
|
|
|
10
11
|
import React, { useCallback, useState } from 'react';
|
|
11
12
|
import {
|
|
@@ -21,9 +22,9 @@ import {
|
|
|
21
22
|
Search as SearchIcon,
|
|
22
23
|
Sliders,
|
|
23
24
|
} from 'lucide-react';
|
|
24
|
-
import {
|
|
25
|
+
import { Box, Grid, IconButton, Inline, Stack, ViewHeader } from '../ui';
|
|
26
|
+
import { cx } from '../ui/utils/cx';
|
|
25
27
|
import { useToast } from '../components/Toast';
|
|
26
|
-
import { cn } from '../lib/utils';
|
|
27
28
|
import { MemoryOverview } from './memory/MemoryOverview';
|
|
28
29
|
import { LightragPanel } from './memory/LightragPanel';
|
|
29
30
|
import { ObsidianPanel } from './memory/ObsidianPanel';
|
|
@@ -35,7 +36,17 @@ import { FromScreenshotPanel } from './memory/FromScreenshotPanel';
|
|
|
35
36
|
import { VaultFromClipboardPanel } from './memory/VaultFromClipboardPanel';
|
|
36
37
|
import { VoiceNotesPanel } from '../components/VoiceNotesPanel';
|
|
37
38
|
|
|
38
|
-
type SubPanel =
|
|
39
|
+
type SubPanel =
|
|
40
|
+
| 'overview'
|
|
41
|
+
| 'lightrag'
|
|
42
|
+
| 'obsidian'
|
|
43
|
+
| 'git'
|
|
44
|
+
| 'semantic'
|
|
45
|
+
| 'config'
|
|
46
|
+
| 'graph'
|
|
47
|
+
| 'webclip'
|
|
48
|
+
| 'screenshot'
|
|
49
|
+
| 'voice';
|
|
39
50
|
|
|
40
51
|
type Props = {
|
|
41
52
|
snapshot: unknown;
|
|
@@ -79,7 +90,13 @@ function MemoryInner(_props: Props) {
|
|
|
79
90
|
const renderPanel = () => {
|
|
80
91
|
switch (active) {
|
|
81
92
|
case 'overview':
|
|
82
|
-
return
|
|
93
|
+
return (
|
|
94
|
+
<MemoryOverview
|
|
95
|
+
refreshKey={refreshKey}
|
|
96
|
+
onRefresh={refresh}
|
|
97
|
+
setActiveSubPanel={(id) => setActive(id as SubPanel)}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
83
100
|
case 'lightrag':
|
|
84
101
|
return <LightragPanel refreshKey={refreshKey} />;
|
|
85
102
|
case 'obsidian':
|
|
@@ -99,63 +116,78 @@ function MemoryInner(_props: Props) {
|
|
|
99
116
|
case 'voice':
|
|
100
117
|
return <VoiceNotesPanel refreshKey={refreshKey} />;
|
|
101
118
|
default:
|
|
102
|
-
return
|
|
119
|
+
return null;
|
|
103
120
|
}
|
|
104
121
|
};
|
|
105
122
|
|
|
106
123
|
return (
|
|
107
|
-
<div className="view view-memory
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
</div>
|
|
129
|
-
</header>
|
|
124
|
+
<Box as="div" className="view view-memory" bg="0" p={7}>
|
|
125
|
+
<Stack gap={5}>
|
|
126
|
+
<ViewHeader
|
|
127
|
+
title={
|
|
128
|
+
<Inline gap={2} align="center">
|
|
129
|
+
<Brain size={18} />
|
|
130
|
+
<span>Memory</span>
|
|
131
|
+
</Inline>
|
|
132
|
+
}
|
|
133
|
+
subtitle="LightRAG, Obsidian vault, git sync, semantic search, web clips, and screenshot OCR — all in one place."
|
|
134
|
+
actions={
|
|
135
|
+
<IconButton
|
|
136
|
+
variant="ghost"
|
|
137
|
+
size="md"
|
|
138
|
+
onClick={onRefreshAll}
|
|
139
|
+
aria-label="Refresh memory"
|
|
140
|
+
title="Refresh"
|
|
141
|
+
icon={<RefreshCw size={14} />}
|
|
142
|
+
/>
|
|
143
|
+
}
|
|
144
|
+
/>
|
|
130
145
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
<Grid
|
|
147
|
+
cols={2}
|
|
148
|
+
gap={4}
|
|
149
|
+
style={{
|
|
150
|
+
gridTemplateColumns: '240px 1fr',
|
|
151
|
+
alignItems: 'start',
|
|
152
|
+
minHeight: 0,
|
|
153
|
+
}}
|
|
154
|
+
data-testid="memory-grid"
|
|
155
|
+
>
|
|
156
|
+
{/* Source rail — Stack doesn't accept `as="nav"`, so wrap
|
|
157
|
+
in <nav> directly and let Stack render its rows. */}
|
|
158
|
+
<nav aria-label="Memory sources" data-testid="memory-source-rail">
|
|
159
|
+
<Stack direction="column" gap={1}>
|
|
160
|
+
{SOURCES.map((s) => {
|
|
161
|
+
const Icon = s.icon;
|
|
162
|
+
const isActive = active === s.id;
|
|
163
|
+
return (
|
|
164
|
+
<button
|
|
165
|
+
key={s.id}
|
|
166
|
+
type="button"
|
|
167
|
+
role="tab"
|
|
168
|
+
aria-selected={isActive}
|
|
169
|
+
className={cx(
|
|
170
|
+
'memory-source-button',
|
|
171
|
+
isActive && 'memory-source-button-active',
|
|
172
|
+
)}
|
|
173
|
+
onClick={() => setActive(s.id)}
|
|
174
|
+
>
|
|
175
|
+
<Icon size={16} aria-hidden />
|
|
176
|
+
<span>{s.label}</span>
|
|
177
|
+
</button>
|
|
178
|
+
);
|
|
179
|
+
})}
|
|
180
|
+
</Stack>
|
|
181
|
+
</nav>
|
|
152
182
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
183
|
+
{/* Main panel */}
|
|
184
|
+
<Box as="div" key={active} data-testid="memory-main-panel">
|
|
185
|
+
{renderPanel()}
|
|
186
|
+
</Box>
|
|
187
|
+
</Grid>
|
|
188
|
+
</Stack>
|
|
189
|
+
</Box>
|
|
159
190
|
);
|
|
160
191
|
}
|
|
192
|
+
|
|
161
193
|
export const Memory = React.memo(MemoryInner);
|
|
@@ -52,8 +52,6 @@ import {
|
|
|
52
52
|
EyeOff,
|
|
53
53
|
Eye,
|
|
54
54
|
X,
|
|
55
|
-
Sun,
|
|
56
|
-
Moon,
|
|
57
55
|
} from 'lucide-react';
|
|
58
56
|
|
|
59
57
|
import {
|
|
@@ -134,20 +132,8 @@ function OverviewInner({
|
|
|
134
132
|
// hide without losing the row from the underlying store. v3.15.0.
|
|
135
133
|
const [hiddenKeys, setHiddenKeys] = useState<Set<string>>(new Set());
|
|
136
134
|
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// handles the actual colour swap.
|
|
140
|
-
const [isDark, setIsDark] = useState<boolean>(() => {
|
|
141
|
-
if (typeof document === 'undefined') return true;
|
|
142
|
-
const attr = document.documentElement.getAttribute('data-theme');
|
|
143
|
-
return attr !== 'light';
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
if (typeof document === 'undefined') return;
|
|
148
|
-
if (isDark) document.documentElement.removeAttribute('data-theme');
|
|
149
|
-
else document.documentElement.setAttribute('data-theme', 'light');
|
|
150
|
-
}, [isDark]);
|
|
135
|
+
// v7.0.4 — theme toggle is now hoisted to Topbar (see
|
|
136
|
+
// components/Topbar.tsx); no per-view state needed here.
|
|
151
137
|
|
|
152
138
|
// Load hidden set once on mount — v3.15.0.
|
|
153
139
|
useEffect(() => {
|
|
@@ -536,13 +522,6 @@ function OverviewInner({
|
|
|
536
522
|
>
|
|
537
523
|
Refresh
|
|
538
524
|
</UiButton>
|
|
539
|
-
<IconButton
|
|
540
|
-
variant="ghost"
|
|
541
|
-
size="md"
|
|
542
|
-
onClick={() => setIsDark((v) => !v)}
|
|
543
|
-
aria-label={isDark ? 'Switch to light theme' : 'Switch to dark theme'}
|
|
544
|
-
icon={isDark ? <Sun size={14} /> : <Moon size={14} />}
|
|
545
|
-
/>
|
|
546
525
|
</Inline>
|
|
547
526
|
</Inline>
|
|
548
527
|
|
|
@@ -59,8 +59,8 @@ describe('Sidebar — settingsMode', () => {
|
|
|
59
59
|
// Should show the back button
|
|
60
60
|
expect(screen.getByRole('button', { name: /exit settings/i })).toBeInTheDocument();
|
|
61
61
|
// Should show section groups (use selector to avoid duplicate text matches)
|
|
62
|
-
expect(screen.getByText('General', { selector: '.
|
|
63
|
-
expect(screen.getByText('Core', { selector: '.
|
|
62
|
+
expect(screen.getByText('General', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
63
|
+
expect(screen.getByText('Core', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
it('shows Back button that calls onExitSettings', async () => {
|
|
@@ -41,7 +41,7 @@ describe('SettingsNav', () => {
|
|
|
41
41
|
expect(onExitSettings).toHaveBeenCalledTimes(1);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
it('renders section groups with
|
|
44
|
+
it('renders section groups with shared sidebar-section-label class', () => {
|
|
45
45
|
render(
|
|
46
46
|
<SettingsNav
|
|
47
47
|
activeSection={null}
|
|
@@ -49,11 +49,11 @@ describe('SettingsNav', () => {
|
|
|
49
49
|
onExitSettings={onExitSettings}
|
|
50
50
|
/>,
|
|
51
51
|
);
|
|
52
|
-
expect(screen.getByText('General', { selector: '.
|
|
53
|
-
expect(screen.getByText('Core', { selector: '.
|
|
54
|
-
expect(screen.getByText('Agents', { selector: '.
|
|
55
|
-
expect(screen.getByText('Experience', { selector: '.
|
|
56
|
-
expect(screen.getByText('Data', { selector: '.
|
|
52
|
+
expect(screen.getByText('General', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
53
|
+
expect(screen.getByText('Core', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
54
|
+
expect(screen.getByText('Agents', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
55
|
+
expect(screen.getByText('Experience', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
56
|
+
expect(screen.getByText('Data', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
57
57
|
});
|
|
58
58
|
|
|
59
59
|
it('renders section items within each group', () => {
|
package/cli/provision-claude.mjs
CHANGED
|
@@ -167,17 +167,37 @@ export async function buildSdk({ dryRun = false } = {}) {
|
|
|
167
167
|
// PATH — especially when invoked from a globally npm-installed package
|
|
168
168
|
// whose lifecycle scripts run with a minimal env. Without the absolute
|
|
169
169
|
// path, `bun run build:sdk` shells out to `tsc`, finds no shim on PATH,
|
|
170
|
-
// and fails with `tsc: command not found`.
|
|
171
|
-
//
|
|
170
|
+
// and fails with `tsc: command not found`.
|
|
171
|
+
//
|
|
172
|
+
// Bun's bin dir contains only `bun` and `bunx` — NOT `tsc`. So even
|
|
173
|
+
// when bun runs `build:sdk` (which executes the `tsc` line from
|
|
174
|
+
// package.json), the child shell still needs `tsc` on PATH. The npm
|
|
175
|
+
// global bin dir (where `npm install -g typescript` lands the shim) is
|
|
176
|
+
// the typical source — resolve it via `npm root -g`'s parent and
|
|
177
|
+
// prepend both bun's bin and the npm global bin to the child PATH.
|
|
172
178
|
const bunFromHome = join(process.env.HOME || '', '.bun', 'bin', 'bun');
|
|
173
179
|
let cmd, args, childEnv;
|
|
174
180
|
if (existsSync(bunFromHome)) {
|
|
175
181
|
cmd = bunFromHome;
|
|
176
182
|
args = ['run', 'build:sdk'];
|
|
177
|
-
// Make bun's bin dir visible to the child so its tsc shim resolves.
|
|
178
|
-
const bunBin = dirname(bunFromHome);
|
|
179
183
|
const pathDelim = process.platform === 'win32' ? ';' : ':';
|
|
180
|
-
|
|
184
|
+
const bunBin = dirname(bunFromHome);
|
|
185
|
+
let npmGlobalBin = '';
|
|
186
|
+
try {
|
|
187
|
+
const npmRootG = execSync('npm root -g', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
188
|
+
// npm root -g returns .../lib/node_modules — parent is .../lib, and
|
|
189
|
+
// the bin dir lives at .../bin. So walk up one and over.
|
|
190
|
+
npmGlobalBin = join(dirname(npmRootG), '..', 'bin');
|
|
191
|
+
} catch {
|
|
192
|
+
// npm not on PATH — fall back to the standard location.
|
|
193
|
+
npmGlobalBin = process.platform === 'win32'
|
|
194
|
+
? join(process.env.APPDATA || '', 'npm')
|
|
195
|
+
: join(process.env.HOME || '', '.local', 'bin');
|
|
196
|
+
}
|
|
197
|
+
const pathParts = [bunBin];
|
|
198
|
+
if (npmGlobalBin && existsSync(npmGlobalBin)) pathParts.push(npmGlobalBin);
|
|
199
|
+
pathParts.push(process.env.PATH || '');
|
|
200
|
+
childEnv = { ...process.env, PATH: pathParts.join(pathDelim) };
|
|
181
201
|
} else if (haveCmd('bun')) {
|
|
182
202
|
cmd = 'bun';
|
|
183
203
|
args = ['run', 'build:sdk'];
|
|
@@ -203,6 +223,81 @@ export async function buildSdk({ dryRun = false } = {}) {
|
|
|
203
223
|
}
|
|
204
224
|
}
|
|
205
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Build the dashboard SPA (Vite production bundle) so the Node server
|
|
228
|
+
* in `bizar-dash/src/server/server.mjs` can serve the React UI from
|
|
229
|
+
* `bizar-dash/dist/index.html` + `dist/assets/*`. Without this step,
|
|
230
|
+
* npm installs that don't ship a pre-built `dist/` (the published
|
|
231
|
+
* tarball excludes it because it is `.gitignore`'d) leave the
|
|
232
|
+
* dashboard serving 404s for every asset, and the page renders blank
|
|
233
|
+
* with errors like `can't access property 'useState', et is undefined`.
|
|
234
|
+
*
|
|
235
|
+
* v7.0.3 — `install.sh` + `bizar update` previously skipped the
|
|
236
|
+
* dashboard build entirely. Symptom: a fresh `bizar install` /
|
|
237
|
+
* `bizar update` overwrote the package's pre-existing `dist/` (if
|
|
238
|
+
* any) and the dashboard's first request returned a 404 for the
|
|
239
|
+
* bundle, followed by the React error above in the browser console.
|
|
240
|
+
*
|
|
241
|
+
* Same bun / npx resolution strategy as `buildSdk()`. The vite config
|
|
242
|
+
* reads the same `tsconfig.json` for type info, but the heavy lifting
|
|
243
|
+
* is `vite build` itself which uses esbuild internally, so no tsc
|
|
244
|
+
* dependency here.
|
|
245
|
+
*
|
|
246
|
+
* Idempotent: skips when `bizar-dash/dist/index.html` already exists.
|
|
247
|
+
* Non-fatal: returns `{ ok: false, message }` rather than throwing —
|
|
248
|
+
* the rest of the provision flow should still complete.
|
|
249
|
+
*/
|
|
250
|
+
export async function buildDash({ dryRun = false } = {}) {
|
|
251
|
+
const dashDir = join(REPO_ROOT, 'bizar-dash');
|
|
252
|
+
const distIndex = join(dashDir, 'dist', 'index.html');
|
|
253
|
+
|
|
254
|
+
if (!existsSync(join(dashDir, 'src', 'web', 'index.html'))) {
|
|
255
|
+
return { ok: true, skipped: true, message: `Dashboard src not found at ${join(dashDir, 'src', 'web', 'index.html')} — skipping build` };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (existsSync(distIndex)) {
|
|
259
|
+
return { ok: true, skipped: true, message: `Dashboard dist already present — skipping build (delete ${join(dashDir, 'dist')} to force)` };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (dryRun) {
|
|
263
|
+
return { ok: true, skipped: false, message: `would build dashboard at ${dashDir}` };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const bunFromHome = join(process.env.HOME || '', '.bun', 'bin', 'bun');
|
|
267
|
+
let cmd, args, childEnv;
|
|
268
|
+
if (existsSync(bunFromHome)) {
|
|
269
|
+
cmd = bunFromHome;
|
|
270
|
+
args = ['run', 'build:dash'];
|
|
271
|
+
const pathDelim = process.platform === 'win32' ? ';' : ':';
|
|
272
|
+
const bunBin = dirname(bunFromHome);
|
|
273
|
+
const pathParts = [bunBin, process.env.PATH || ''];
|
|
274
|
+
childEnv = { ...process.env, PATH: pathParts.join(pathDelim) };
|
|
275
|
+
} else if (haveCmd('bun')) {
|
|
276
|
+
cmd = 'bun';
|
|
277
|
+
args = ['run', 'build:dash'];
|
|
278
|
+
childEnv = process.env;
|
|
279
|
+
} else {
|
|
280
|
+
cmd = 'npx';
|
|
281
|
+
args = ['--yes', 'vite', 'build'];
|
|
282
|
+
childEnv = process.env;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
logInfo(`building dashboard with \`${cmd} ${args.join(' ')}\` (REPO_ROOT=${REPO_ROOT})`);
|
|
287
|
+
// `vite build` writes to the configured outDir (../../dist from
|
|
288
|
+
// src/web/). On a non-bun shell the cwd must be REPO_ROOT because
|
|
289
|
+
// the configured `root` is relative. Bun handles this either way.
|
|
290
|
+
execFileSync(cmd, args, { cwd: REPO_ROOT, stdio: 'pipe', timeout: 240_000, env: childEnv });
|
|
291
|
+
if (existsSync(distIndex)) {
|
|
292
|
+
return { ok: true, skipped: false, message: 'Dashboard built (dist/index.html present)' };
|
|
293
|
+
}
|
|
294
|
+
return { ok: false, message: `build completed but ${distIndex} still missing — check vite.config.ts outDir` };
|
|
295
|
+
} catch (err) {
|
|
296
|
+
const stderr = err.stderr ? err.stderr.toString().split('\n').slice(0, 5).join(' | ') : '(no stderr)';
|
|
297
|
+
return { ok: false, message: `Dashboard build failed: ${stderr}` };
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
206
301
|
function readTextSafe(file, fallback = '') {
|
|
207
302
|
try {
|
|
208
303
|
if (!existsSync(file)) return fallback;
|
|
@@ -892,6 +987,14 @@ export async function runProvision(opts = {}) {
|
|
|
892
987
|
// full story.
|
|
893
988
|
await runStep('Building SDK', () => buildSdk({ dryRun }));
|
|
894
989
|
|
|
990
|
+
// ── 4c. Build the dashboard SPA so dist/index.html exists. ───────────
|
|
991
|
+
// The Node server in `bizar-dash/src/server/server.mjs` serves the
|
|
992
|
+
// React UI from `bizar-dash/dist/`. The published npm tarball excludes
|
|
993
|
+
// `dist/` because it is `.gitignore`'d, so a fresh install must
|
|
994
|
+
// rebuild it. Skips when already present (idempotent). See
|
|
995
|
+
// `buildDash()` JSDoc for the v7.0.3 reason this step exists.
|
|
996
|
+
await runStep('Building dashboard', () => buildDash({ dryRun }));
|
|
997
|
+
|
|
895
998
|
// ── 9. settings.json (MCP + hooks + permissions + env) ──────────────
|
|
896
999
|
section('Writing settings.json');
|
|
897
1000
|
const settingsStep = writeClaudeSettings({ dryRun, force });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polderlabs/bizar",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.4",
|
|
4
4
|
"description": "Norse-pantheon multi-agent system for Claude Code — 14 agents across 4 cost tiers with cost-aware routing, plans, and a configurable agent harness. Ships as a single npm package with the dashboard server, Claude Code MCP server, and typed SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"agents": [
|
|
4
|
+
{
|
|
5
|
+
"agentId": "agent-ed692060-767f-4f8d-951f-6be038e63725",
|
|
6
|
+
"type": "coder",
|
|
7
|
+
"name": "ada",
|
|
8
|
+
"status": "terminated",
|
|
9
|
+
"taskCount": 0,
|
|
10
|
+
"createdAt": "2026-07-12T14:48:32.781Z",
|
|
11
|
+
"lastHeartbeatAt": "2026-07-12T14:48:32.781Z",
|
|
12
|
+
"terminatedAt": "2026-07-12T14:48:32.781Z",
|
|
13
|
+
"terminationReason": "smoke",
|
|
14
|
+
"gracefulTermination": true
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|