@polderlabs/bizar 3.9.1 → 3.10.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/README.md +47 -1
- package/cli/bin.mjs +175 -68
- package/cli/copy.mjs +13 -6
- package/cli/graph.mjs +54 -12
- package/cli/init.mjs +16 -6
- package/cli/install.mjs +58 -15
- package/cli/update.mjs +41 -21
- package/config/AGENTS.md +1 -1
- package/config/commands/bizar.md +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -143,7 +143,9 @@ npx bizar
|
|
|
143
143
|
|
|
144
144
|
The interactive installer walks you through component selection, agent choice, install mode, API key setup, and auto-restarts opencode.
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
> **Windows users:** the `npm install -g @polderlabs/bizar` command above is the recommended path on Windows. The installer uses `irm | iex` for uv, `py -m pip` for the pip fallback, `taskkill` for forced kills, and JS `setTimeout` instead of `sleep` — so it works on both Windows PowerShell and POSIX shells. See the [Windows](#-windows) section below for prerequisites, known limitations, and the optional graph feature install.
|
|
147
|
+
|
|
148
|
+
### Source — git clone (Linux/macOS contributors)
|
|
147
149
|
|
|
148
150
|
```bash
|
|
149
151
|
git clone git@github.com:DrB0rk/BizarHarness.git
|
|
@@ -154,6 +156,50 @@ chmod +x install.sh
|
|
|
154
156
|
|
|
155
157
|
Copies agent definitions and config to `~/.config/opencode/`, merges `opencode.json`, and prints next steps. Use this if you want to hack on BizarHarness itself.
|
|
156
158
|
|
|
159
|
+
> This `install.sh` script is bash-only and does **not** run on Windows natively. Windows contributors should use the npm path above instead.
|
|
160
|
+
|
|
161
|
+
### Windows
|
|
162
|
+
|
|
163
|
+
The `bizar` CLI is cross-platform — the npm install runs a Node.js installer that handles `curl | sh` redirects, signal handling, and temp paths on Windows PowerShell automatically.
|
|
164
|
+
|
|
165
|
+
**Prerequisites**
|
|
166
|
+
|
|
167
|
+
- [Node.js 18+](https://nodejs.org/) on `PATH`
|
|
168
|
+
- [Python 3.10+](https://www.python.org/downloads/windows/) (only required for the optional `bizar graph` knowledge-graph feature)
|
|
169
|
+
- [Git for Windows](https://git-scm.com/download/win) — only needed if you want to run the bash `install.sh` from a Git Bash shell
|
|
170
|
+
|
|
171
|
+
**Install**
|
|
172
|
+
|
|
173
|
+
```powershell
|
|
174
|
+
npm install -g @polderlabs/bizar
|
|
175
|
+
bizar
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Optional: graph feature (knowledge graph + per-project .bizar/)**
|
|
179
|
+
|
|
180
|
+
The `bizar graph build` subcommand uses [graphify](https://github.com/bretbhomas/graphify). Install uv and graphify from PowerShell:
|
|
181
|
+
|
|
182
|
+
```powershell
|
|
183
|
+
# Install uv (Python package manager) — Windows-native PowerShell installer
|
|
184
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
185
|
+
|
|
186
|
+
# Install graphify
|
|
187
|
+
uv tool install graphifyy
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Then build the project graph from any repo:
|
|
191
|
+
|
|
192
|
+
```powershell
|
|
193
|
+
bizar graph build
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Known Windows limitations**
|
|
197
|
+
|
|
198
|
+
- The `blessed` TUI library may render with quirks inside Windows Terminal; if you see garbled output in the TUI, use the browser UI via `bizar dash start --bg` and open http://localhost:4321 instead.
|
|
199
|
+
- Some shell scripts under `config/skills/embedded-esp-idf/` are bash-only and require Git Bash (or WSL).
|
|
200
|
+
- The bash `install.sh` does not run on Windows cmd/PowerShell; use the `npm install -g` path above.
|
|
201
|
+
- RTK (Rust Token Killer) ships a bash-only installer. On Windows, install it manually via [Cargo](https://github.com/rtk-ai/rtk#installation) or a [prebuilt binary](https://github.com/rtk-ai/rtk/releases), then run `rtk init -g --opencode`.
|
|
202
|
+
|
|
157
203
|
### Prerequisites
|
|
158
204
|
|
|
159
205
|
- [opencode CLI](https://opencode.ai) installed and on `$PATH`
|
package/cli/bin.mjs
CHANGED
|
@@ -2,20 +2,17 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* cli/bin.mjs
|
|
4
4
|
*
|
|
5
|
-
* v3.
|
|
5
|
+
* v3.10.0 — `bizar` runtime CLI.
|
|
6
6
|
*
|
|
7
7
|
* Architecture:
|
|
8
8
|
* - `bizar` is the core runtime + installer + audit/init/export/update/plan
|
|
9
|
-
* + service commands.
|
|
10
|
-
* - The dashboard lives in
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* + service + dash commands.
|
|
10
|
+
* - The dashboard lives in `@polderlabs/bizar-dash` as a library.
|
|
11
|
+
* Commands live under `bizar dash <subcommand>` (new canonical form).
|
|
12
|
+
* `bizar dashboard` is a deprecated alias (still works, prints warning).
|
|
13
13
|
*
|
|
14
|
-
* Subcommands
|
|
15
|
-
* install, audit, init, export, plan, update, test-gate, service
|
|
16
|
-
*
|
|
17
|
-
* Flags (unchanged):
|
|
18
|
-
* --web / --no-web / --web-only / --bg / --detach
|
|
14
|
+
* Subcommands:
|
|
15
|
+
* install, audit, init, export, plan, update, test-gate, service, dash
|
|
19
16
|
*/
|
|
20
17
|
import { existsSync } from 'node:fs';
|
|
21
18
|
import { readFileSync } from 'node:fs';
|
|
@@ -77,36 +74,34 @@ function showHelp() {
|
|
|
77
74
|
Bizar — Norse Pantheon Agent System for opencode
|
|
78
75
|
|
|
79
76
|
Usage:
|
|
80
|
-
bizar
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
bizar
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
bizar
|
|
96
|
-
bizar
|
|
97
|
-
bizar
|
|
98
|
-
bizar
|
|
77
|
+
bizar <command> [options]
|
|
78
|
+
|
|
79
|
+
Commands:
|
|
80
|
+
install Run the interactive installer
|
|
81
|
+
audit Run security audit on agent configuration
|
|
82
|
+
init Initialize .bizar/ in current project
|
|
83
|
+
export [target] Export agents/rules to another harness
|
|
84
|
+
plan <subcommand> Manage visual plans
|
|
85
|
+
graph Per-project knowledge graph (powered by graphify)
|
|
86
|
+
test-gate Detect & run the project's test suite
|
|
87
|
+
update Update opencode, bizar, and/or bizar-plugin
|
|
88
|
+
service Manage the background service daemon
|
|
89
|
+
dash <subcommand> Manage the dashboard (start/stop/status/tui)
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
bizar install
|
|
93
|
+
bizar audit
|
|
94
|
+
bizar dash start
|
|
95
|
+
bizar dash start --bg
|
|
96
|
+
bizar dash stop
|
|
97
|
+
bizar dash status
|
|
98
|
+
|
|
99
|
+
Run \`bizar <command> --help\` for per-command help.
|
|
99
100
|
|
|
100
101
|
Install:
|
|
101
102
|
npm install -g @polderlabs/bizar Install globally
|
|
102
|
-
npm install -g @polderlabs/bizar-dash Optional
|
|
103
|
+
npm install -g @polderlabs/bizar-dash Optional dashboard package
|
|
103
104
|
npm install -g @polderlabs/bizar-plugin Bizar opencode plugin
|
|
104
|
-
|
|
105
|
-
Notes:
|
|
106
|
-
The TUI is the default command — press 1-8 for tabs, q to quit.
|
|
107
|
-
\`bizar --bg\` launches the dashboard detached; \`bizar dashboard stop\`
|
|
108
|
-
terminates it. The web dashboard lives in the \`@polderlabs/bizar-dash\`
|
|
109
|
-
package — if it's not installed, you'll be prompted to install it.
|
|
110
105
|
`);
|
|
111
106
|
}
|
|
112
107
|
|
|
@@ -181,7 +176,7 @@ function showInstallHelp() {
|
|
|
181
176
|
|
|
182
177
|
function showUpdateHelp() {
|
|
183
178
|
console.log(`
|
|
184
|
-
bizar update — Update opencode, bizar,
|
|
179
|
+
bizar update — Update opencode, bizar, and/or bizar-plugin
|
|
185
180
|
|
|
186
181
|
Usage:
|
|
187
182
|
bizar update Interactive prompt for components
|
|
@@ -207,7 +202,7 @@ function showUpdateHelp() {
|
|
|
207
202
|
• Sends SIGTERM, waits up to 5s, escalates to SIGKILL if needed.
|
|
208
203
|
• Re-runs the install script so the deployed plugin source matches
|
|
209
204
|
the just-upgraded npm version (avoids the version-skew trap).
|
|
210
|
-
• If the dashboard was running and bizar
|
|
205
|
+
• If the dashboard was running and bizar or dash was updated,
|
|
211
206
|
spawns a fresh detached dashboard process with the new code
|
|
212
207
|
(skipped with --no-restart).
|
|
213
208
|
|
|
@@ -244,19 +239,35 @@ function showServiceHelp() {
|
|
|
244
239
|
`);
|
|
245
240
|
}
|
|
246
241
|
|
|
247
|
-
function
|
|
242
|
+
function showDashHelp() {
|
|
248
243
|
console.log(`
|
|
249
|
-
bizar
|
|
244
|
+
bizar dash — Manage the Bizar dashboard
|
|
250
245
|
|
|
251
246
|
Usage:
|
|
252
|
-
bizar
|
|
253
|
-
bizar dashboard start Same
|
|
254
|
-
bizar dashboard stop Kill the running dashboard
|
|
255
|
-
bizar dashboard status Show port + URL
|
|
247
|
+
bizar dash <subcommand> [options]
|
|
256
248
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
249
|
+
Subcommands:
|
|
250
|
+
start [--bg] [--port N] Start the dashboard (default port 4321)
|
|
251
|
+
stop Stop the running dashboard
|
|
252
|
+
status Show dashboard port and URL
|
|
253
|
+
tui [--no-web] Launch the TUI
|
|
254
|
+
|
|
255
|
+
Options:
|
|
256
|
+
--bg Detach and run in background (for start)
|
|
257
|
+
--port N Override the default port
|
|
258
|
+
--no-web Skip launching the web UI (for tui)
|
|
259
|
+
|
|
260
|
+
Examples:
|
|
261
|
+
bizar dash start
|
|
262
|
+
bizar dash start --bg
|
|
263
|
+
bizar dash stop
|
|
264
|
+
bizar dash status
|
|
265
|
+
bizar dash tui
|
|
266
|
+
bizar dash tui --no-web
|
|
267
|
+
|
|
268
|
+
Note:
|
|
269
|
+
\`bizar dashboard\` is a deprecated alias for \`bizar dash\` and still
|
|
270
|
+
works, but new code should use \`bizar dash\`.
|
|
260
271
|
`);
|
|
261
272
|
}
|
|
262
273
|
|
|
@@ -420,35 +431,131 @@ async function main() {
|
|
|
420
431
|
} else if (args[0] === 'service') {
|
|
421
432
|
if (isHelpRequest) showServiceHelp();
|
|
422
433
|
else await runServiceCommand(args[1]);
|
|
423
|
-
} else if (args[0] === '
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
434
|
+
} else if (args[0] === 'dash' || args[0] === 'dashboard') {
|
|
435
|
+
// `bizar dashboard` is a deprecated alias for `bizar dash`
|
|
436
|
+
if (args[0] === 'dashboard') {
|
|
437
|
+
console.warn(chalk.yellow(' ⚠ `bizar dashboard` is deprecated, use `bizar dash` instead.'));
|
|
438
|
+
}
|
|
439
|
+
const dashArgs = args.slice(1); // everything after 'dash' or 'dashboard'
|
|
440
|
+
if (dashArgs.length === 0 || isHelpRequest) {
|
|
441
|
+
showDashHelp();
|
|
442
|
+
} else {
|
|
443
|
+
await runDash(dashArgs);
|
|
444
|
+
}
|
|
431
445
|
} else if (isHelpRequest) {
|
|
432
446
|
showHelp();
|
|
433
447
|
} else {
|
|
434
|
-
//
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
448
|
+
// No args — show help (breaking: previously launched TUI)
|
|
449
|
+
showHelp();
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ── Dashboard subcommand ───────────────────────────────────────────────────────
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Parse dash-specific options from an array of args.
|
|
458
|
+
* Returns { opts, remaining } where opts have --bg / --port stripped.
|
|
459
|
+
*/
|
|
460
|
+
function parseDashOpts(dashArgs) {
|
|
461
|
+
const opts = { bg: false, port: null, noWeb: false };
|
|
462
|
+
const remaining = [];
|
|
463
|
+
for (let i = 0; i < dashArgs.length; i++) {
|
|
464
|
+
const a = dashArgs[i];
|
|
465
|
+
if (a === '--bg') {
|
|
466
|
+
opts.bg = true;
|
|
467
|
+
} else if (a === '--no-web') {
|
|
468
|
+
opts.noWeb = true;
|
|
469
|
+
} else if (a === '--port' && i + 1 < dashArgs.length) {
|
|
470
|
+
opts.port = Number(dashArgs[i + 1]);
|
|
471
|
+
i++;
|
|
442
472
|
} else {
|
|
443
|
-
|
|
444
|
-
console.log(chalk.cyan(' npm install -g @polderlabs/bizar-dash'));
|
|
445
|
-
console.log('');
|
|
446
|
-
console.log('Or run the installer to set up everything:');
|
|
447
|
-
console.log(chalk.cyan(' npx -y @polderlabs/bizar install'));
|
|
473
|
+
remaining.push(a);
|
|
448
474
|
}
|
|
449
475
|
}
|
|
476
|
+
return { opts, remaining };
|
|
450
477
|
}
|
|
451
478
|
|
|
479
|
+
/**
|
|
480
|
+
* Try to load the dashboard CLI module.
|
|
481
|
+
* Try 1: import via the package exports map (@polderlabs/bizar-dash/dash-cli)
|
|
482
|
+
* Try 2: file path probing for older installs or dev trees
|
|
483
|
+
*/
|
|
484
|
+
async function loadDashCli() {
|
|
485
|
+
// Try 1: import via exports map (requires Tyr's package.json changes)
|
|
486
|
+
try {
|
|
487
|
+
const mod = await import('@polderlabs/bizar-dash/dash-cli');
|
|
488
|
+
return mod;
|
|
489
|
+
} catch (_e) {
|
|
490
|
+
// fall through to file probing
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Try 2: file path probing
|
|
494
|
+
const { join } = await import('node:path');
|
|
495
|
+
const { homedir } = await import('node:os');
|
|
496
|
+
const candidates = [
|
|
497
|
+
// npm global install
|
|
498
|
+
join(homedir(), '.npm-global', 'lib', 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
|
|
499
|
+
// nvm
|
|
500
|
+
join(homedir(), '.nvm', 'versions', 'node'),
|
|
501
|
+
// relative to current process
|
|
502
|
+
join(process.execPath, '..', '..', 'lib', 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
|
|
503
|
+
// local node_modules
|
|
504
|
+
join(process.cwd(), 'node_modules', '@polderlabs', 'bizar-dash', 'src', 'cli.mjs'),
|
|
505
|
+
];
|
|
506
|
+
|
|
507
|
+
const { pathToFileURL } = await import('node:url');
|
|
508
|
+
for (const p of candidates) {
|
|
509
|
+
try {
|
|
510
|
+
const url = pathToFileURL(p).href;
|
|
511
|
+
const mod = await import(url);
|
|
512
|
+
return mod;
|
|
513
|
+
} catch (_e) {
|
|
514
|
+
// try next
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Dispatch a dashboard subcommand by loading the dashboard module and
|
|
522
|
+
* calling the appropriate exported function.
|
|
523
|
+
*/
|
|
524
|
+
async function runDash(dashArgs) {
|
|
525
|
+
const { opts, remaining } = parseDashOpts(dashArgs);
|
|
526
|
+
const sub = remaining[0];
|
|
527
|
+
const subOpts = { ...opts, subArgs: remaining.slice(1) };
|
|
528
|
+
|
|
529
|
+
const dashModule = await loadDashCli();
|
|
530
|
+
if (!dashModule) {
|
|
531
|
+
console.error(chalk.red(' ✗ Dashboard not installed.'));
|
|
532
|
+
console.error(chalk.dim(' Run: npm install -g @polderlabs/bizar-dash'));
|
|
533
|
+
console.error(chalk.dim(' Or: npx -y @polderlabs/bizar install'));
|
|
534
|
+
process.exit(1);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
switch (sub) {
|
|
538
|
+
case 'start':
|
|
539
|
+
await dashModule.start(subOpts);
|
|
540
|
+
break;
|
|
541
|
+
case 'stop':
|
|
542
|
+
await dashModule.stop(subOpts);
|
|
543
|
+
break;
|
|
544
|
+
case 'status':
|
|
545
|
+
await dashModule.status(subOpts);
|
|
546
|
+
break;
|
|
547
|
+
case 'tui':
|
|
548
|
+
await dashModule.tui(subOpts);
|
|
549
|
+
break;
|
|
550
|
+
default:
|
|
551
|
+
console.error(chalk.red(` ✗ Unknown subcommand: ${sub}`));
|
|
552
|
+
showDashHelp();
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
558
|
+
|
|
452
559
|
await main().catch((err) => {
|
|
453
560
|
console.error(chalk.red(`bizar: ${err && err.message ? err.message : String(err)}`));
|
|
454
561
|
process.exit(1);
|
package/cli/copy.mjs
CHANGED
|
@@ -356,6 +356,9 @@ export async function installRtk() {
|
|
|
356
356
|
const spinner = ora({ text: 'Installing RTK (Rust Token Killer)...', color: 'magenta' }).start();
|
|
357
357
|
|
|
358
358
|
if (process.platform === 'win32') {
|
|
359
|
+
// RTK ships a bash-only installer; no PowerShell equivalent. On
|
|
360
|
+
// Windows the user must install RTK manually (e.g. via Cargo or
|
|
361
|
+
// prebuilt binary) and re-run `rtk init -g --opencode`.
|
|
359
362
|
spinner.fail(chalk.red('Automatic RTK install not supported on Windows. Install manually from https://github.com/rtk-ai/rtk'));
|
|
360
363
|
return false;
|
|
361
364
|
}
|
|
@@ -392,13 +395,17 @@ export async function installSemble() {
|
|
|
392
395
|
spinner.text = 'Installing uv (Python package manager)...';
|
|
393
396
|
try {
|
|
394
397
|
if (process.platform === 'win32') {
|
|
395
|
-
|
|
396
|
-
|
|
398
|
+
// Windows: use the official PowerShell installer
|
|
399
|
+
execSync(
|
|
400
|
+
'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"',
|
|
401
|
+
{ stdio: 'pipe', timeout: 60000 },
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
execSync(
|
|
405
|
+
'curl -LsSf https://astral.sh/uv/install.sh | sh',
|
|
406
|
+
{ stdio: 'pipe', timeout: 60000 },
|
|
407
|
+
);
|
|
397
408
|
}
|
|
398
|
-
execSync(
|
|
399
|
-
'curl -LsSf https://astral.sh/uv/install.sh | sh',
|
|
400
|
-
{ stdio: 'pipe', timeout: 60000 },
|
|
401
|
-
);
|
|
402
409
|
spinner.text = 'Setting up Semble...';
|
|
403
410
|
} catch {
|
|
404
411
|
spinner.fail(chalk.red('uv install failed. Install manually from https://docs.astral.sh/uv'));
|
package/cli/graph.mjs
CHANGED
|
@@ -20,13 +20,18 @@ export const GRAPHIFY_OUT_ENV = 'GRAPHIFY_OUT';
|
|
|
20
20
|
/**
|
|
21
21
|
* Find a Python 3 interpreter on PATH.
|
|
22
22
|
* Returns the absolute path string, or null if none found.
|
|
23
|
+
*
|
|
24
|
+
* On Windows the `py` launcher is the most reliable option; on Unix
|
|
25
|
+
* we prefer python3 then python.
|
|
23
26
|
*/
|
|
24
27
|
export function findPython() {
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
const candidates = process.platform === 'win32'
|
|
29
|
+
? ['py', 'python', 'python3']
|
|
30
|
+
: ['python3', 'python'];
|
|
31
|
+
for (const name of candidates) {
|
|
27
32
|
try {
|
|
28
33
|
const result = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });
|
|
29
|
-
if (result.status === 0 && result.stdout.includes('Python
|
|
34
|
+
if (result.status === 0 && result.stdout.includes('Python')) {
|
|
30
35
|
return name;
|
|
31
36
|
}
|
|
32
37
|
} catch {
|
|
@@ -37,10 +42,33 @@ export function findPython() {
|
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
|
-
* Check whether graphify is available
|
|
45
|
+
* Check whether graphify is available.
|
|
46
|
+
*
|
|
47
|
+
* Strategy:
|
|
48
|
+
* 1. Probe PATH for the `graphify` binary (uv tool install puts a shim at
|
|
49
|
+
* ~/.local/bin/graphify — invisible to the isolated python -m lookup).
|
|
50
|
+
* 2. Fall back to `python -m graphify --version` for pip/pipx installs.
|
|
51
|
+
*
|
|
41
52
|
* Returns true if available, false otherwise.
|
|
42
53
|
*/
|
|
43
54
|
function checkGraphify(python) {
|
|
55
|
+
// Try 1: check for the graphify binary on PATH (uv tool install shim).
|
|
56
|
+
// On Windows the Python launcher `py` is not on PATH by default, but the
|
|
57
|
+
// graphify shim is placed next to pip/pipx so a plain `where` works.
|
|
58
|
+
const whichCmd = process.platform === 'win32' ? 'where' : 'which';
|
|
59
|
+
try {
|
|
60
|
+
const whichResult = spawnSync(whichCmd, ['graphify'], {
|
|
61
|
+
encoding: 'utf8',
|
|
62
|
+
timeout: 5000,
|
|
63
|
+
});
|
|
64
|
+
if (whichResult.status === 0 && (whichResult.stdout || '').trim().length > 0) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
// fall through to python -m check
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Try 2: check via python -m (catches pip/pipx installs into system python)
|
|
44
72
|
try {
|
|
45
73
|
const result = spawnSync(python, ['-m', 'graphify', '--version'], {
|
|
46
74
|
encoding: 'utf8',
|
|
@@ -219,19 +247,33 @@ async function cmdInstall() {
|
|
|
219
247
|
return 1;
|
|
220
248
|
}
|
|
221
249
|
|
|
222
|
-
|
|
250
|
+
// Prefer uv (handles PEP 668 isolated installs cleanly); fall back to pip.
|
|
251
|
+
const { detectUv } = await import('./utils.mjs');
|
|
252
|
+
const hasUv = await detectUv();
|
|
223
253
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
254
|
+
if (hasUv) {
|
|
255
|
+
console.log(chalk.dim(' Installing graphify via uv...\n'));
|
|
256
|
+
const result = spawnSync('uv', ['tool', 'install', 'graphifyy'], { stdio: 'inherit' });
|
|
257
|
+
if (result.status !== 0) {
|
|
258
|
+
console.log(chalk.red(' ✗ uv tool install graphifyy failed.\n'));
|
|
259
|
+
return 1;
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
console.log(chalk.dim(' Installing graphify via pip...\n'));
|
|
263
|
+
// On Windows `pip` may not be on PATH; use `py -m pip` as the fallback.
|
|
264
|
+
const pipCmd = process.platform === 'win32'
|
|
265
|
+
? [python, '-m', 'pip']
|
|
266
|
+
: ['pip'];
|
|
267
|
+
const result = spawnSync(pipCmd[0], pipCmd.slice(1).concat(['install', 'graphifyy']), { stdio: 'inherit' });
|
|
268
|
+
if (result.status !== 0) {
|
|
269
|
+
console.log(chalk.red(' ✗ pip install graphifyy failed.\n'));
|
|
270
|
+
return 1;
|
|
271
|
+
}
|
|
230
272
|
}
|
|
231
273
|
|
|
232
274
|
// graphify install --platform opencode --project
|
|
233
275
|
console.log(chalk.dim('\n $ graphify install --platform opencode --project'));
|
|
234
|
-
result = spawnSync('graphify', ['install', '--platform', 'opencode', '--project'], {
|
|
276
|
+
const result = spawnSync('graphify', ['install', '--platform', 'opencode', '--project'], {
|
|
235
277
|
stdio: 'inherit',
|
|
236
278
|
});
|
|
237
279
|
if (result.status !== 0) {
|
package/cli/init.mjs
CHANGED
|
@@ -154,12 +154,22 @@ ${stack.runner ? `- Dev: \`${stack.runner}\`` : ''}
|
|
|
154
154
|
// Soft step: never fails init. If graphify is missing or build errors,
|
|
155
155
|
// the user can retry manually with `bizar graph build`.
|
|
156
156
|
console.log(chalk.bold('\n--- Graph ---\n'));
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
|
|
157
|
+
|
|
158
|
+
// Check for the graphify binary on PATH first (uv tool install shim).
|
|
159
|
+
// Falls back to python -m for pip/pipx installs.
|
|
160
|
+
const whichCmd = process.platform === 'win32' ? 'where' : 'which';
|
|
161
|
+
const whichCheck = spawnSync(whichCmd, ['graphify'], { encoding: 'utf8', timeout: 5000 });
|
|
162
|
+
let graphifyAvailable = whichCheck.status === 0 && (whichCheck.stdout || '').trim().length > 0;
|
|
163
|
+
|
|
164
|
+
if (!graphifyAvailable) {
|
|
165
|
+
const python = process.platform === 'win32' ? 'py' : 'python3';
|
|
166
|
+
const detectGraphify = spawnSync(python, ['-c', 'import graphify; print(graphify.__version__)'], {
|
|
167
|
+
cwd,
|
|
168
|
+
encoding: 'utf8',
|
|
169
|
+
timeout: 5000,
|
|
170
|
+
});
|
|
171
|
+
graphifyAvailable = detectGraphify.status === 0 && (detectGraphify.stdout || '').trim().length > 0;
|
|
172
|
+
}
|
|
163
173
|
|
|
164
174
|
if (!graphifyAvailable) {
|
|
165
175
|
console.log(chalk.yellow(' graphify not detected — skipping project graph build.'));
|
package/cli/install.mjs
CHANGED
|
@@ -395,8 +395,12 @@ async function promptGraphifyInstall() {
|
|
|
395
395
|
console.log();
|
|
396
396
|
sectionHeading('Knowledge Graph (graphify)');
|
|
397
397
|
|
|
398
|
-
// 1. Detect graphify already installed
|
|
399
|
-
|
|
398
|
+
// 1. Detect graphify already installed. Windows users typically have
|
|
399
|
+
// `py` on PATH (the Python launcher) rather than `python3`, so probe
|
|
400
|
+
// the right binary per platform. A failed probe just means we will
|
|
401
|
+
// prompt to install below.
|
|
402
|
+
const pythonBin = process.platform === 'win32' ? 'py' : 'python3';
|
|
403
|
+
const detect = spawnSync(pythonBin, ['-c', 'import graphify; print(graphify.__version__)'], {
|
|
400
404
|
cwd: process.cwd(),
|
|
401
405
|
encoding: 'utf8',
|
|
402
406
|
timeout: 5000,
|
|
@@ -408,6 +412,26 @@ async function promptGraphifyInstall() {
|
|
|
408
412
|
return;
|
|
409
413
|
}
|
|
410
414
|
|
|
415
|
+
// Install graphify via pip as a fallback when uv is unavailable or the
|
|
416
|
+
// user declined the uv-based install. On Windows, `pip` is often not
|
|
417
|
+
// on PATH, so we invoke it as a `py -m pip` module instead. Returns
|
|
418
|
+
// the spawn result so the caller can log success/failure.
|
|
419
|
+
const installGraphifyWithPip = () => {
|
|
420
|
+
if (process.platform === 'win32') {
|
|
421
|
+
return spawnSync('py', ['-m', 'pip', 'install', 'graphifyy'], {
|
|
422
|
+
stdio: 'inherit',
|
|
423
|
+
timeout: 120000,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
return spawnSync('pip', ['install', 'graphifyy'], {
|
|
427
|
+
stdio: 'inherit',
|
|
428
|
+
timeout: 120000,
|
|
429
|
+
});
|
|
430
|
+
};
|
|
431
|
+
const pipManualHint = process.platform === 'win32'
|
|
432
|
+
? 'py -m pip install graphifyy'
|
|
433
|
+
: 'pip install graphifyy';
|
|
434
|
+
|
|
411
435
|
// 2. Non-interactive: print hint and exit
|
|
412
436
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
413
437
|
console.log(chalk.dim(' graphify not detected. Install later with:'));
|
|
@@ -469,7 +493,12 @@ async function promptGraphifyInstall() {
|
|
|
469
493
|
|
|
470
494
|
console.log(' Installing uv...');
|
|
471
495
|
try {
|
|
472
|
-
|
|
496
|
+
if (process.platform === 'win32') {
|
|
497
|
+
// Windows: use the official PowerShell installer
|
|
498
|
+
execSync('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"', { stdio: 'inherit', timeout: 60000 });
|
|
499
|
+
} else {
|
|
500
|
+
execSync('curl -LsSf https://astral.sh/uv/install.sh | sh', { stdio: 'inherit', timeout: 60000 });
|
|
501
|
+
}
|
|
473
502
|
} catch (err) {
|
|
474
503
|
console.log(chalk.red(` uv install failed: ${err.message}`));
|
|
475
504
|
console.log(chalk.dim(' Install manually from https://docs.astral.sh/uv'));
|
|
@@ -480,12 +509,12 @@ async function promptGraphifyInstall() {
|
|
|
480
509
|
rl2.close();
|
|
481
510
|
if (pipAnswer === '' || pipAnswer.startsWith('y')) {
|
|
482
511
|
console.log(' Installing graphify via pip...');
|
|
483
|
-
const result =
|
|
512
|
+
const result = installGraphifyWithPip();
|
|
484
513
|
if (result.status === 0) {
|
|
485
514
|
console.log(chalk.green(' graphify installed. Run `bizar graph build` to populate .bizar/graph/.'));
|
|
486
515
|
} else {
|
|
487
516
|
console.log(chalk.red(` pip install failed (exit ${result.status}).`));
|
|
488
|
-
console.log(chalk.dim(
|
|
517
|
+
console.log(chalk.dim(` Install manually: ${pipManualHint}`));
|
|
489
518
|
}
|
|
490
519
|
} else {
|
|
491
520
|
console.log(chalk.dim(' Skipped.'));
|
|
@@ -513,12 +542,12 @@ async function promptGraphifyInstall() {
|
|
|
513
542
|
rl2.close();
|
|
514
543
|
if (pipAnswer === '' || pipAnswer.startsWith('y')) {
|
|
515
544
|
console.log(' Installing graphify via pip...');
|
|
516
|
-
const result =
|
|
545
|
+
const result = installGraphifyWithPip();
|
|
517
546
|
if (result.status === 0) {
|
|
518
547
|
console.log(chalk.green(' graphify installed. Run `bizar graph build` to populate .bizar/graph/.'));
|
|
519
548
|
} else {
|
|
520
549
|
console.log(chalk.red(` pip install failed (exit ${result.status}).`));
|
|
521
|
-
console.log(chalk.dim(
|
|
550
|
+
console.log(chalk.dim(` Install manually: ${pipManualHint}`));
|
|
522
551
|
}
|
|
523
552
|
} else {
|
|
524
553
|
console.log(chalk.dim(' Skipped.'));
|
|
@@ -578,12 +607,18 @@ export async function runPostInstall() {
|
|
|
578
607
|
if (!rtkPresent) {
|
|
579
608
|
console.log('BizarHarness: installing RTK (token optimizer)...');
|
|
580
609
|
try {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
610
|
+
if (process.platform === 'win32') {
|
|
611
|
+
// RTK ships a bash-only installer; on Windows the user installs it
|
|
612
|
+
// manually (e.g. `cargo install --git https://github.com/rtk-ai/rtk`).
|
|
613
|
+
console.log('BizarHarness: RTK bash installer does not run on Windows. Install manually from https://github.com/rtk-ai/rtk');
|
|
614
|
+
} else {
|
|
615
|
+
execSync(
|
|
616
|
+
'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh',
|
|
617
|
+
{ stdio: 'pipe', timeout: 60000 },
|
|
618
|
+
);
|
|
619
|
+
execSync('rtk init -g --opencode', { stdio: 'pipe' });
|
|
620
|
+
console.log('BizarHarness: RTK installed and configured.');
|
|
621
|
+
}
|
|
587
622
|
} catch {
|
|
588
623
|
console.log('BizarHarness: RTK install failed. Install manually from https://github.com/rtk-ai/rtk');
|
|
589
624
|
}
|
|
@@ -601,13 +636,21 @@ export async function runPostInstall() {
|
|
|
601
636
|
if (!semblePresent) {
|
|
602
637
|
console.log('BizarHarness: installing Semble (code search)...');
|
|
603
638
|
try {
|
|
604
|
-
|
|
605
|
-
|
|
639
|
+
const hasUv = await detectUv();
|
|
640
|
+
if (!hasUv) {
|
|
641
|
+
if (process.platform === 'win32') {
|
|
642
|
+
// Windows: use the official PowerShell installer
|
|
643
|
+
execSync(
|
|
644
|
+
'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"',
|
|
645
|
+
{ stdio: 'pipe', timeout: 60000 },
|
|
646
|
+
);
|
|
647
|
+
} else {
|
|
606
648
|
execSync(
|
|
607
649
|
'curl -LsSf https://astral.sh/uv/install.sh | sh',
|
|
608
650
|
{ stdio: 'pipe', timeout: 60000 },
|
|
609
651
|
);
|
|
610
652
|
}
|
|
653
|
+
}
|
|
611
654
|
execSync('uv tool install "semble[mcp]"', { stdio: 'pipe', timeout: 60000 });
|
|
612
655
|
console.log('BizarHarness: Semble installed.');
|
|
613
656
|
} catch {
|
package/cli/update.mjs
CHANGED
|
@@ -121,23 +121,30 @@ export function readLivePid(pidFile) {
|
|
|
121
121
|
* We treat any successful signal delivery as success; if SIGKILL is
|
|
122
122
|
* sent, the original process is certainly dead (uncatchable).
|
|
123
123
|
*
|
|
124
|
+
* Cross-platform note: Node.js 14+ maps `process.kill(pid)` without an
|
|
125
|
+
* explicit signal to the platform-appropriate default (`SIGTERM` on
|
|
126
|
+
* POSIX, `TerminateProcess` on Windows). We drop the signal argument so
|
|
127
|
+
* the same code works on both platforms. For the forced-kill phase on
|
|
128
|
+
* Windows we use `taskkill /F /PID <pid>` because `SIGKILL` is not
|
|
129
|
+
* delivered the same way there.
|
|
130
|
+
*
|
|
124
131
|
* Exported for testability.
|
|
125
132
|
*/
|
|
126
|
-
export function killAndWait(pid, { timeoutMs = 5000, label = 'process' } = {}) {
|
|
133
|
+
export async function killAndWait(pid, { timeoutMs = 5000, label = 'process' } = {}) {
|
|
127
134
|
if (!pid) return true;
|
|
128
135
|
|
|
129
|
-
// Phase 1: graceful SIGTERM
|
|
136
|
+
// Phase 1: graceful SIGTERM (or platform default on Windows)
|
|
130
137
|
let sigtermOk = false;
|
|
131
138
|
try {
|
|
132
|
-
process.kill(pid
|
|
139
|
+
process.kill(pid);
|
|
133
140
|
sigtermOk = true;
|
|
134
141
|
} catch (err) {
|
|
135
142
|
if (err.code === 'ESRCH') return true; // already dead
|
|
136
|
-
console.log(chalk.yellow(` ! could not
|
|
143
|
+
console.log(chalk.yellow(` ! could not signal ${label} (pid ${pid}): ${err.message}`));
|
|
137
144
|
return false;
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
// Best-effort poll for graceful exit. Note: a
|
|
147
|
+
// Best-effort poll for graceful exit. Note: a signal-handling process
|
|
141
148
|
// (Express dashboard, Node sleeper) usually exits within ~100ms. We
|
|
142
149
|
// poll for up to `timeoutMs`; if anything responds to kill -0 it may be
|
|
143
150
|
// a recycled PID, so we don't treat that as "still our process".
|
|
@@ -149,7 +156,7 @@ export function killAndWait(pid, { timeoutMs = 5000, label = 'process' } = {}) {
|
|
|
149
156
|
} catch (err) {
|
|
150
157
|
if (err.code === 'ESRCH') { sawExit = true; break; }
|
|
151
158
|
}
|
|
152
|
-
|
|
159
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
153
160
|
}
|
|
154
161
|
|
|
155
162
|
if (sawExit) {
|
|
@@ -157,20 +164,26 @@ export function killAndWait(pid, { timeoutMs = 5000, label = 'process' } = {}) {
|
|
|
157
164
|
return true;
|
|
158
165
|
}
|
|
159
166
|
|
|
160
|
-
// Phase 2: escalate to
|
|
161
|
-
// recycled or process truly stuck), SIGKILL is uncatchable and
|
|
162
|
-
// original process — if it was still our PID — is now dead.
|
|
167
|
+
// Phase 2: escalate to forced kill. Even if `kill -0` still succeeds
|
|
168
|
+
// (PID recycled or process truly stuck), SIGKILL is uncatchable and
|
|
169
|
+
// the original process — if it was still our PID — is now dead.
|
|
170
|
+
// On Windows, use `taskkill /F` because POSIX SIGKILL semantics don't
|
|
171
|
+
// exist there.
|
|
163
172
|
try {
|
|
164
|
-
process.
|
|
173
|
+
if (process.platform === 'win32') {
|
|
174
|
+
spawnSync('taskkill', ['/F', '/T', '/PID', String(pid)], { stdio: 'ignore' });
|
|
175
|
+
} else {
|
|
176
|
+
process.kill(pid, 'SIGKILL');
|
|
177
|
+
}
|
|
165
178
|
if (sigtermOk) {
|
|
166
|
-
console.log(chalk.yellow(` ! ${label} (pid ${pid}) did not exit gracefully; sent
|
|
179
|
+
console.log(chalk.yellow(` ! ${label} (pid ${pid}) did not exit gracefully; sent forced kill`));
|
|
167
180
|
}
|
|
168
181
|
// Brief settle for the kernel.
|
|
169
|
-
|
|
182
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
170
183
|
return true;
|
|
171
184
|
} catch (err) {
|
|
172
185
|
if (err.code === 'ESRCH') return true;
|
|
173
|
-
console.log(chalk.red(` ✗ could not
|
|
186
|
+
console.log(chalk.red(` ✗ could not force-kill ${label} (pid ${pid}): ${err.message}`));
|
|
174
187
|
return false;
|
|
175
188
|
}
|
|
176
189
|
}
|
|
@@ -272,9 +285,16 @@ function rerunInstallScript() {
|
|
|
272
285
|
return { ok: false, message: 'setup rerun failed' };
|
|
273
286
|
}
|
|
274
287
|
const installSh = join(pkgRoot, 'install.sh');
|
|
275
|
-
if (
|
|
288
|
+
if (!existsSync(installSh)) {
|
|
276
289
|
return { ok: false, message: 'could not locate a compatible setup script to re-run' };
|
|
277
290
|
}
|
|
291
|
+
if (process.platform === 'win32') {
|
|
292
|
+
// On Windows, the bash install path doesn't apply. The plugin is
|
|
293
|
+
// already installed globally via the npm install
|
|
294
|
+
// (see cli/install.mjs:installPluginFromGlobal).
|
|
295
|
+
console.log(chalk.dim(' Skipping install.sh (Windows uses npm-based plugin install)'));
|
|
296
|
+
return { ok: true, message: 'install.sh skipped on Windows' };
|
|
297
|
+
}
|
|
278
298
|
console.log(chalk.dim(`\n Re-running install script at ${installSh}...`));
|
|
279
299
|
const r = spawnSync('bash', [installSh], { stdio: 'inherit' });
|
|
280
300
|
if (r.status !== 0) {
|
|
@@ -349,17 +369,17 @@ async function confirmKill(instances, { assumeYes } = {}) {
|
|
|
349
369
|
}
|
|
350
370
|
}
|
|
351
371
|
|
|
352
|
-
function killInstances(instances) {
|
|
372
|
+
async function killInstances(instances) {
|
|
353
373
|
const out = [];
|
|
354
374
|
if (instances.service) {
|
|
355
|
-
const ok = killAndWait(instances.service.pid, { label: 'bizar service' });
|
|
375
|
+
const ok = await killAndWait(instances.service.pid, { label: 'bizar service' });
|
|
356
376
|
out.push({ name: 'service', ok });
|
|
357
377
|
if (ok) {
|
|
358
378
|
try { rmSync(SERVICE_PID_FILE, { force: true }); } catch { /* ignore */ }
|
|
359
379
|
}
|
|
360
380
|
}
|
|
361
381
|
if (instances.dashboard) {
|
|
362
|
-
const ok = killAndWait(instances.dashboard.pid, { label: 'bizar-dash' });
|
|
382
|
+
const ok = await killAndWait(instances.dashboard.pid, { label: 'bizar-dash' });
|
|
363
383
|
out.push({ name: 'dashboard', ok });
|
|
364
384
|
if (ok) {
|
|
365
385
|
try { rmSync(DASHBOARD_PID_FILE, { force: true }); } catch { /* ignore */ }
|
|
@@ -428,7 +448,7 @@ async function promptForUpdates(forceAll) {
|
|
|
428
448
|
choices: [
|
|
429
449
|
{ name: 'opencode (the opencode CLI itself)', value: 'opencode', checked: true },
|
|
430
450
|
{ name: `bizar (${PKG_MAIN})`, value: 'bizar', checked: true },
|
|
431
|
-
{ name: `bizar
|
|
451
|
+
{ name: `bizar dash (${PKG_DASH}) — web dashboard`, value: 'dash', checked: true },
|
|
432
452
|
{ name: `plugin (${PKG_PLUGIN})`, value: 'plugin', checked: true },
|
|
433
453
|
],
|
|
434
454
|
},
|
|
@@ -460,14 +480,14 @@ export async function runUpdate(subargs = []) {
|
|
|
460
480
|
process.exit(1);
|
|
461
481
|
}
|
|
462
482
|
console.log(chalk.cyan('\n Stopping running instances...'));
|
|
463
|
-
const kills = killInstances(instances);
|
|
483
|
+
const kills = await killInstances(instances);
|
|
464
484
|
for (const k of kills) {
|
|
465
485
|
const marker = k.ok ? chalk.green('✓') : chalk.red('✗');
|
|
466
486
|
console.log(` ${marker} ${k.name} stopped`);
|
|
467
487
|
}
|
|
468
488
|
// Give the kernel a moment to release any open file handles on the
|
|
469
489
|
// npm-global directory before npm tries to replace files.
|
|
470
|
-
|
|
490
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
471
491
|
} else {
|
|
472
492
|
console.log(chalk.dim(' No running Bizar instances detected.'));
|
|
473
493
|
}
|
|
@@ -565,7 +585,7 @@ export async function runUpdate(subargs = []) {
|
|
|
565
585
|
console.log(chalk.green(` ✓ ${res.message}`));
|
|
566
586
|
} else {
|
|
567
587
|
console.log(chalk.yellow(` ⚠ ${res.message}`));
|
|
568
|
-
console.log(chalk.dim(' Start it manually with `bizar
|
|
588
|
+
console.log(chalk.dim(' Start it manually with `bizar dash start --bg`.'));
|
|
569
589
|
}
|
|
570
590
|
}
|
|
571
591
|
|
package/config/AGENTS.md
CHANGED
|
@@ -334,7 +334,7 @@ This section is the single source of truth for every Bizar agent's behavior. It
|
|
|
334
334
|
> | `bash_tool` | `bash` |
|
|
335
335
|
> | `web_search` | `websearch` (opencode built-in) |
|
|
336
336
|
> | `web_fetch` | `webfetch` (opencode built-in) |
|
|
337
|
-
> | `present_files` | not applicable — Bizar delivers files via the dashboard (
|
|
337
|
+
> | `present_files` | not applicable — Bizar delivers files via the dashboard (`@polderlabs/bizar-dash/src/server/routes/artifacts.mjs`) or by writing to the workspace |
|
|
338
338
|
> | `image_search` / `places_*` / `weather_fetch` / `recipe_display_v0` / `fetch_sports_data` / `message_compose_v1` / `recommend_claude_apps` | not available in Bizar — do not assume these exist |
|
|
339
339
|
> | `search_mcp_registry` / `suggest_connectors` | use the `skills` CLI (`skills add <owner/repo> -s <name>`) to discover and install skills instead |
|
|
340
340
|
> | `ask_user_input_v0` | Bizar has a `question` tool — same shape, single high-value question |
|
package/config/commands/bizar.md
CHANGED
|
@@ -13,6 +13,6 @@ If the user invoked `/bizar` with arguments, treat them as a request and route a
|
|
|
13
13
|
- "dashboard" or "open dashboard" → `/bizar` (no args, will launch the dashboard)
|
|
14
14
|
- Otherwise: ask one clarifying question
|
|
15
15
|
|
|
16
|
-
If the user invoked `/bizar` with no arguments, the dashboard is launching in the background. Visit `http://localhost:<port>/` to access it. The plugin's `chat.message` hook spawns `bizar
|
|
16
|
+
If the user invoked `/bizar` with no arguments, the dashboard is launching in the background. Visit `http://localhost:<port>/` to access it. The plugin's `chat.message` hook spawns `bizar dash start` as a detached child process and surfaces the live URL in its response.
|
|
17
17
|
|
|
18
|
-
Common ports: 4321 is preferred; if it's taken, the launcher walks upward and picks the next free port. The PID and port are recorded under `~/.config/bizar/dashboard.{pid,port}` so `bizar
|
|
18
|
+
Common ports: 4321 is preferred; if it's taken, the launcher walks upward and picks the next free port. The PID and port are recorded under `~/.config/bizar/dashboard.{pid,port}` so `bizar dash stop` and `bizar dash status` can find the running instance.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polderlabs/bizar",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Norse-pantheon multi-agent system for opencode — 13 agents across 4 cost tiers with cost-aware routing, plans, and a configurable agent harness.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|