@polderlabs/bizar 4.2.4 → 4.4.0
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/src/server/api.mjs +2 -0
- package/bizar-dash/src/server/opencode-sdk.mjs +72 -0
- package/bizar-dash/src/server/routes/background.mjs +92 -0
- package/bizar-dash/src/server/routes/chat.mjs +300 -123
- package/bizar-dash/src/server/routes/opencode-session-detail.mjs +452 -0
- package/bizar-dash/src/server/routes/tasks.mjs +59 -1
- package/bizar-dash/src/server/serve-info.mjs +124 -1
- package/bizar-dash/src/server/task-delegator.mjs +154 -8
- package/bizar-dash/src/server/tasks-store.mjs +50 -2
- package/bizar-dash/src/web/components/background/AttachButton.tsx +96 -0
- package/bizar-dash/src/web/components/background/TmuxAttachCard.tsx +122 -0
- package/bizar-dash/src/web/components/chat/AgentNode.tsx +127 -0
- package/bizar-dash/src/web/components/chat/AgentTree.tsx +80 -0
- package/bizar-dash/src/web/components/chat/ChatComposer.tsx +76 -0
- package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +144 -0
- package/bizar-dash/src/web/components/chat/ChatRail.tsx +387 -0
- package/bizar-dash/src/web/components/chat/ChatThread.tsx +28 -7
- package/bizar-dash/src/web/components/chat/JumpToLatest.tsx +58 -0
- package/bizar-dash/src/web/components/chat/MessageBlock.tsx +260 -0
- package/bizar-dash/src/web/components/chat/SessionList.tsx +15 -5
- package/bizar-dash/src/web/components/chat/SessionRowMenu.tsx +206 -0
- package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +33 -5
- package/bizar-dash/src/web/components/chat/_legacy.ts +30 -0
- package/bizar-dash/src/web/components/chat/index.ts +11 -0
- package/bizar-dash/src/web/components/chat/useChat.ts +426 -62
- package/bizar-dash/src/web/components/tasks/BacklogPanel.css +109 -0
- package/bizar-dash/src/web/components/tasks/BacklogPanel.tsx +209 -0
- package/bizar-dash/src/web/lib/types.ts +1 -0
- package/bizar-dash/src/web/mobile/views/MobileChat.tsx +7 -5
- package/bizar-dash/src/web/styles/chat.css +1536 -133
- package/bizar-dash/src/web/views/BackgroundAgents.tsx +3 -0
- package/bizar-dash/src/web/views/Chat.tsx +147 -55
- package/bizar-dash/src/web/views/Tasks.tsx +23 -1
- package/bizar-dash/tests/opencode-sessions-detail.test.mjs +273 -0
- package/cli/bg.mjs +94 -71
- package/cli/bin.mjs +19 -7
- package/cli/service-controller.mjs +587 -0
- package/cli/service-controller.test.mjs +92 -0
- package/cli/service.mjs +162 -14
- package/config/agents/baldr.md +2 -0
- package/config/agents/browser-harness.md +2 -0
- package/config/agents/forseti.md +2 -0
- package/config/agents/frigg.md +2 -0
- package/config/agents/heimdall.md +2 -0
- package/config/agents/hermod.md +2 -0
- package/config/agents/mimir.md +2 -0
- package/config/agents/odin.md +2 -0
- package/config/agents/quick.md +2 -0
- package/config/agents/semble-search.md +2 -0
- package/config/agents/thor.md +2 -0
- package/config/agents/tyr.md +2 -0
- package/config/agents/vidarr.md +2 -0
- package/config/agents/vor.md +2 -0
- package/config/opencode.json.template +1 -0
- package/install.sh +448 -787
- package/package.json +2 -2
- package/packages/sdk/package.json +20 -0
- package/packages/sdk/src/client.ts +5 -0
- package/packages/sdk/src/errors.ts +11 -2
- package/packages/sdk/src/index.ts +19 -0
- package/packages/sdk/src/opencode-events.ts +134 -0
- package/packages/sdk/src/opencode-types.ts +66 -0
- package/packages/sdk/src/opencode.ts +335 -0
package/cli/bg.mjs
CHANGED
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
* kill <id> Kill a running agent
|
|
16
16
|
* logs <id> Tail the agent's log file
|
|
17
17
|
*
|
|
18
|
-
* The "view" subcommand is the headline feature: it
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* anything?" — you can
|
|
18
|
+
* The "view" subcommand (v3.22) is the headline feature: it creates a
|
|
19
|
+
* tmux control session (`bizar-bg-view`) with one pane per running
|
|
20
|
+
* agent (each pane attached to the agent's own tmux session, tiled).
|
|
21
|
+
* This is the antidote to "is the agent doing anything?" — you can
|
|
22
|
+
* SEE them all working in parallel.
|
|
22
23
|
*/
|
|
23
24
|
import { execFileSync, spawn, spawnSync } from 'node:child_process';
|
|
24
25
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
@@ -245,59 +246,112 @@ async function runKill(instanceId) {
|
|
|
245
246
|
// --- view ----------------------------------------------------------------
|
|
246
247
|
|
|
247
248
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
249
|
+
* View subcommand (v3.22):
|
|
250
|
+
* - Detects tmux. If missing, prints per-instance `bizar bg logs <id>`
|
|
251
|
+
* fallback instructions and exits 0.
|
|
252
|
+
* - Creates a fresh tmux control session `bizar-bg-view` with one pane
|
|
253
|
+
* per running instance, each pane running `tmux attach -t <session>`.
|
|
254
|
+
* - Caps at 16 panes (beyond that, tmux tiled layout degrades).
|
|
255
|
+
* - Zero running instances → prints "no running agents" and exits 0.
|
|
251
256
|
*/
|
|
252
|
-
|
|
257
|
+
|
|
258
|
+
async function runView() {
|
|
253
259
|
const all = readAllBgInstances();
|
|
254
|
-
const
|
|
260
|
+
const tmuxSessions = listBgrTmuxSessions();
|
|
255
261
|
const running = all.filter(
|
|
262
|
+
(e) => e.data.status === 'running' || e.data.status === 'pending',
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// Zero running agents — not an error.
|
|
266
|
+
if (running.length === 0) {
|
|
267
|
+
console.log(chalk.dim('\n No running background agents.\n'));
|
|
268
|
+
return 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Tmux presence check. If missing, print fallback instructions and exit 0
|
|
272
|
+
// (not an error — the operator can still use per-instance logs).
|
|
273
|
+
if (!which('tmux')) {
|
|
274
|
+
console.log(chalk.yellow('\n ⚠ tmux is not installed on this host.\n'));
|
|
275
|
+
console.log(chalk.dim(' You can inspect individual agents via:\n'));
|
|
276
|
+
for (const r of running) {
|
|
277
|
+
console.log(chalk.cyan(` bizar bg logs ${r.data.instanceId}`));
|
|
278
|
+
}
|
|
279
|
+
console.log();
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Filter to instances that actually have a live tmux session.
|
|
284
|
+
const active = running.filter(
|
|
256
285
|
(e) =>
|
|
257
|
-
(e.data.status === 'running' || e.data.status === 'pending') &&
|
|
258
286
|
e.data.sessionId &&
|
|
259
|
-
|
|
287
|
+
tmuxSessions.includes(tmuxSessionForSessionId(e.data.sessionId)),
|
|
260
288
|
);
|
|
261
289
|
|
|
262
|
-
if (
|
|
263
|
-
|
|
290
|
+
if (active.length === 0) {
|
|
291
|
+
console.log(chalk.dim('\n No agents with active tmux sessions found.\n'));
|
|
292
|
+
console.log(chalk.dim(' State files exist but no tmux sessions are running.\n'));
|
|
293
|
+
console.log(chalk.dim(' Run `bizar bg list` to inspect state.\n'));
|
|
294
|
+
return 0;
|
|
264
295
|
}
|
|
265
296
|
|
|
266
|
-
//
|
|
297
|
+
// Cap at 16 panes — beyond that, tiled layout is unusable.
|
|
298
|
+
const capped = active.slice(0, 16);
|
|
299
|
+
const overflow = active.length - capped.length;
|
|
300
|
+
|
|
301
|
+
// Kill any stale bizar-bg-view session, then create a fresh one.
|
|
267
302
|
try {
|
|
268
|
-
execFileSync('tmux', ['kill-session', '-t', '
|
|
303
|
+
execFileSync('tmux', ['kill-session', '-t', 'bizar-bg-view'], { stdio: 'pipe' });
|
|
269
304
|
} catch {
|
|
270
|
-
|
|
305
|
+
/* didn't exist */
|
|
271
306
|
}
|
|
272
307
|
execFileSync('tmux', [
|
|
273
|
-
'new-session', '-d', '-s', '
|
|
308
|
+
'new-session', '-d', '-s', 'bizar-bg-view',
|
|
274
309
|
'-x', '220', '-y', '50',
|
|
275
310
|
], { stdio: 'pipe' });
|
|
276
311
|
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const r = running[i];
|
|
289
|
-
const tmuxName = tmuxSessionForSessionId(r.data.sessionId);
|
|
290
|
-
const logPath = r.data.logPath || join(homedir(), '.cache', 'bizar', 'logs', `${r.data.sessionId}.log`);
|
|
291
|
-
const header = `echo "═══ ${r.data.agent} │ ${r.data.instanceId} │ ${tmuxName} ═══"; tail -n 200 -F "${logPath}"`;
|
|
292
|
-
// Use send-keys so the echo+tail are sent in sequence, then Enter
|
|
293
|
-
// to run them. Target the pane by index in the bgr_view session.
|
|
312
|
+
// Pane 0 → first instance
|
|
313
|
+
const firstSession = tmuxSessionForSessionId(capped[0].data.sessionId);
|
|
314
|
+
execFileSync('tmux', [
|
|
315
|
+
'send-keys', '-t', 'bizar-bg-view:0.0',
|
|
316
|
+
`tmux attach -t ${firstSession}`, 'Enter',
|
|
317
|
+
], { stdio: 'pipe' });
|
|
318
|
+
|
|
319
|
+
// Split for remaining instances (2..N)
|
|
320
|
+
for (let i = 1; i < capped.length; i++) {
|
|
321
|
+
execFileSync('tmux', ['split-window', '-v', '-t', 'bizar-bg-view'], { stdio: 'pipe' });
|
|
322
|
+
const sessionName = tmuxSessionForSessionId(capped[i].data.sessionId);
|
|
294
323
|
execFileSync('tmux', [
|
|
295
|
-
'send-keys', '-t', `
|
|
296
|
-
|
|
324
|
+
'send-keys', '-t', `bizar-bg-view:0.${i}`,
|
|
325
|
+
`tmux attach -t ${sessionName}`, 'Enter',
|
|
297
326
|
], { stdio: 'pipe' });
|
|
298
327
|
}
|
|
299
328
|
|
|
300
|
-
|
|
329
|
+
// Tiled layout for a clean grid.
|
|
330
|
+
execFileSync('tmux', ['select-layout', '-t', 'bizar-bg-view', 'tiled'], { stdio: 'pipe' });
|
|
331
|
+
|
|
332
|
+
console.log(chalk.green(`\n ✓ Built tmux view session with ${capped.length} pane(s)\n`));
|
|
333
|
+
|
|
334
|
+
if (overflow > 0) {
|
|
335
|
+
console.log(chalk.yellow(` ⚠ ${overflow} more agent(s) not shown (16-pane cap):\n`));
|
|
336
|
+
for (const r of active.slice(16)) {
|
|
337
|
+
const sn = tmuxSessionForSessionId(r.data.sessionId);
|
|
338
|
+
console.log(chalk.dim(` bizar bg logs ${r.data.instanceId} — tmux attach -t ${sn}`));
|
|
339
|
+
}
|
|
340
|
+
console.log();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Open an OS terminal window attached to the control session.
|
|
344
|
+
const open = openTerminalAttached('bizar-bg-view');
|
|
345
|
+
if (open.ok) {
|
|
346
|
+
console.log(chalk.green(` ✓ Opened ${open.terminal} attached to "bizar-bg-view"\n`));
|
|
347
|
+
console.log(chalk.dim(' Tip: `tmux attach -t bizar-bg-view` from any terminal.\n'));
|
|
348
|
+
} else {
|
|
349
|
+
console.log(chalk.yellow(` ⚠ Could not open terminal: ${open.error}\n`));
|
|
350
|
+
console.log(chalk.dim(' Run in a terminal you can see:\n'));
|
|
351
|
+
console.log(chalk.cyan(` tmux attach -t bizar-bg-view\n`));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return 0;
|
|
301
355
|
}
|
|
302
356
|
|
|
303
357
|
/**
|
|
@@ -362,39 +416,7 @@ function openTerminalAttached(tmuxSession) {
|
|
|
362
416
|
return { ok: false, error: `unsupported platform: ${platform}` };
|
|
363
417
|
}
|
|
364
418
|
|
|
365
|
-
async function runView() {
|
|
366
|
-
if (!which('tmux')) {
|
|
367
|
-
console.log(chalk.red('\n ✗ tmux is not installed. Install it and retry.'));
|
|
368
|
-
console.log(chalk.dim(' macOS: brew install tmux'));
|
|
369
|
-
console.log(chalk.dim(' Linux: apt-get install tmux (or your distro equivalent)'));
|
|
370
|
-
console.log(chalk.dim(' Windows: choco install tmux\n'));
|
|
371
|
-
return 1;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const build = buildTmuxControlSession();
|
|
375
|
-
if (!build.ok) {
|
|
376
|
-
if (build.reason === 'no-running-agents') {
|
|
377
|
-
console.log(chalk.dim('\n No running background agents to view.\n'));
|
|
378
|
-
console.log(chalk.dim(' Spawn one with `bizar_spawn_background` (Odin) or via the dashboard,\n'));
|
|
379
|
-
console.log(chalk.dim(' then re-run this command.\n'));
|
|
380
|
-
return 1;
|
|
381
|
-
}
|
|
382
|
-
console.log(chalk.red(`\n ✗ Failed to build control session: ${build.error || build.reason}\n`));
|
|
383
|
-
return 1;
|
|
384
|
-
}
|
|
385
419
|
|
|
386
|
-
console.log(chalk.green(`\n ✓ Built tmux control session with ${build.count} pane(s)\n`));
|
|
387
|
-
const open = openTerminalAttached(build.session);
|
|
388
|
-
if (open.ok) {
|
|
389
|
-
console.log(chalk.green(` ✓ Opened ${open.terminal} attached to tmux session "${build.session}"\n`));
|
|
390
|
-
console.log(chalk.dim(` Tip: \`tmux attach -t ${build.session}\` from any terminal.\n`));
|
|
391
|
-
} else {
|
|
392
|
-
console.log(chalk.yellow(` ⚠ Could not open a terminal window: ${open.error}\n`));
|
|
393
|
-
console.log(chalk.dim(' Run one of the following in a terminal you can see:\n'));
|
|
394
|
-
console.log(chalk.cyan(` tmux attach -t ${build.session}\n`));
|
|
395
|
-
}
|
|
396
|
-
return 0;
|
|
397
|
-
}
|
|
398
420
|
|
|
399
421
|
// --- Help ----------------------------------------------------------------
|
|
400
422
|
|
|
@@ -416,8 +438,9 @@ function showHelp() {
|
|
|
416
438
|
and a log file (default ~/.cache/bizar/logs/<sessionId>.log).
|
|
417
439
|
|
|
418
440
|
The \`view\` subcommand is the headline feature: it creates a new
|
|
419
|
-
tmux session (\`
|
|
420
|
-
|
|
441
|
+
tmux session (\`bizar-bg-view\`) with one pane per running agent,
|
|
442
|
+
each pane attached to the agent's own tmux session (tiled layout),
|
|
443
|
+
then opens a new OS terminal window attached to it. You can see all
|
|
421
444
|
your agents working in parallel at a glance.
|
|
422
445
|
`);
|
|
423
446
|
}
|
package/cli/bin.mjs
CHANGED
|
@@ -291,17 +291,27 @@ function showServiceHelp() {
|
|
|
291
291
|
bizar service — Manage the background service daemon
|
|
292
292
|
|
|
293
293
|
Usage:
|
|
294
|
-
bizar service start
|
|
295
|
-
bizar service stop
|
|
296
|
-
bizar service status
|
|
297
|
-
bizar service logs
|
|
298
|
-
bizar service follow
|
|
294
|
+
bizar service start Start the service in background
|
|
295
|
+
bizar service stop Stop the running service
|
|
296
|
+
bizar service status Show whether the service is running
|
|
297
|
+
bizar service logs Tail the service log
|
|
298
|
+
bizar service follow Follow the service log until Ctrl-C
|
|
299
|
+
bizar service install Register with systemd / launchd / scheduled task
|
|
300
|
+
bizar service install --force Re-install even when the unit matches
|
|
301
|
+
bizar service uninstall Remove the OS-level autostart
|
|
302
|
+
bizar service uninstall --force Force-uninstall even when nothing is registered
|
|
299
303
|
|
|
300
304
|
Description:
|
|
301
305
|
The service watches per-project schedules (cron / interval / once)
|
|
302
306
|
and runs them at the right time. It logs to
|
|
303
307
|
${bizarConfigDir}/service.log and writes its PID to
|
|
304
308
|
${bizarConfigDir}/service.pid.
|
|
309
|
+
|
|
310
|
+
install registers the daemon under the OS init system — systemd user
|
|
311
|
+
unit on Linux, launchd LaunchAgent on macOS, scheduled task
|
|
312
|
+
("BizarDashboardService", ONSTART, HIGHEST) on Windows. After
|
|
313
|
+
install, a normal user does not need to run \`bizar service start\`
|
|
314
|
+
for the dashboard background process — the OS does it at login.
|
|
305
315
|
`);
|
|
306
316
|
}
|
|
307
317
|
|
|
@@ -613,9 +623,11 @@ async function runTestGate() {
|
|
|
613
623
|
}
|
|
614
624
|
|
|
615
625
|
/**
|
|
616
|
-
* Service commands — start / stop / status / logs.
|
|
626
|
+
* Service commands — start / stop / status / logs / install / uninstall.
|
|
617
627
|
*
|
|
618
|
-
* Implementation lives in cli/service.mjs
|
|
628
|
+
* Implementation lives in cli/service.mjs. The install / uninstall
|
|
629
|
+
* branches delegate to cli/service-controller.mjs for OS-level
|
|
630
|
+
* registration (systemd / launchd / schtasks).
|
|
619
631
|
*/
|
|
620
632
|
async function runServiceCommand(sub) {
|
|
621
633
|
const { runService } = await import('./service.mjs');
|