@polderlabs/bizar 4.2.3 → 4.2.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.
@@ -444,6 +444,7 @@ export async function createServer({
444
444
  });
445
445
  }
446
446
  } catch { /* ignore — mobile.css won't be served, fine */ }
447
+ }
447
448
  app.get('/', (req, res, next) => {
448
449
  if (!shouldRedirectToMobile(req)) {
449
450
  next();
@@ -43,6 +43,8 @@ type LightragStatus = {
43
43
  port: number;
44
44
  llmBinding: string;
45
45
  embeddingBinding: string;
46
+ llmBindingHost: string;
47
+ embeddingBindingHost: string;
46
48
  llmModel: string;
47
49
  embeddingModel: string;
48
50
  lastError: string | null;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * tests/dash-cli-load.test.mjs
3
+ *
4
+ * Regression test for the "is not iterable" bug in loadDashCli (v4.2.4).
5
+ * The async IIFE was being spread into an array literal before resolving,
6
+ * producing: TypeError: (intermediate value) is not iterable.
7
+ *
8
+ * Run with:
9
+ * node --test tests/dash-cli-load.test.mjs
10
+ */
11
+ import { test } from 'node:test';
12
+ import assert from 'node:assert/strict';
13
+ import { spawnSync } from 'node:child_process';
14
+ import path from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const CLI = path.resolve(__dirname, '../../cli/bin.mjs');
19
+
20
+ test('bizar dash status does not throw "is not iterable" (regression for v4.2.4)', () => {
21
+ const result = spawnSync('node', [CLI, 'dash', 'status'], {
22
+ encoding: 'utf8',
23
+ timeout: 15_000,
24
+ });
25
+ const combined = (result.stdout || '') + (result.stderr || '');
26
+ assert.ok(
27
+ !combined.includes('is not iterable'),
28
+ `Expected no "is not iterable" error, got: ${combined.slice(0, 300)}`,
29
+ );
30
+ });
31
+
32
+ test('bizar dash status exits cleanly (0) or with a non-iterable error', () => {
33
+ const result = spawnSync('node', [CLI, 'dash', 'status'], {
34
+ encoding: 'utf8',
35
+ timeout: 15_000,
36
+ });
37
+ // Exit code 0 = dashboard status resolved successfully.
38
+ // Non-zero = dashboard not running (acceptable), but must not be the
39
+ // "is not iterable" TypeError from the broken spread operator.
40
+ const acceptableExit = result.status === 0 || result.status === 1;
41
+ const noIterableError = !((result.stdout || '') + (result.stderr || '')).includes('is not iterable');
42
+ assert.ok(acceptableExit && noIterableError,
43
+ `Unexpected result: exit=${result.status}, output=${((result.stdout || '') + (result.stderr || '')).slice(0, 200)}`);
44
+ });
package/cli/bin.mjs CHANGED
@@ -775,20 +775,20 @@ function parseDashOpts(dashArgs) {
775
775
  * A legacy npm-global fallback is kept for the transitional period.
776
776
  */
777
777
  async function loadDashCli() {
778
- // v4.0.0 — primary: relative import inside the same package
779
778
  const { pathToFileURL } = await import('node:url');
780
- const candidates = [
781
- join(import.meta.dirname, '..', 'bizar-dash', 'src', 'cli.mjs'),
782
- // Legacy fallbacks for users with @polderlabs/bizar-dash still installed:
783
- ...(async () => {
784
- const { execFileSync } = await import('node:child_process');
785
- try {
786
- const npmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', timeout: 5000 }).trim();
787
- if (npmRoot) return [join(npmRoot, '@polderlabs', 'bizar-dash', 'src', 'cli.mjs')];
788
- } catch { /* ignore */ }
789
- return [];
790
- })(),
791
- ];
779
+ const { join } = await import('node:path');
780
+
781
+ const primary = join(import.meta.dirname, '..', 'bizar-dash', 'src', 'cli.mjs');
782
+
783
+ // Legacy npm-global fallback (only computed if primary is missing)
784
+ let legacyFallbacks = [];
785
+ try {
786
+ const { execFileSync } = await import('node:child_process');
787
+ const npmRoot = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', timeout: 5000 }).trim();
788
+ if (npmRoot) legacyFallbacks = [join(npmRoot, '@polderlabs', 'bizar-dash', 'src', 'cli.mjs')];
789
+ } catch { /* npm not available or no globals — fine */ }
790
+
791
+ const candidates = [primary, ...legacyFallbacks];
792
792
 
793
793
  for (const p of candidates) {
794
794
  try {
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "agent": {
54
54
  "odin": {
55
- "description": "Odin — Pure router that delegates all work to subagents. Routes across Frigg (DeepSeek/Q&A), Vör (DeepSeek/clarify), Mimir (DeepSeek/research), Heimdall (DeepSeek/simple), Hermod (M2.7/git), Thor (M2.7/mid), Baldr (M2.7/design), Tyr (M3/top), Vidarr (GPT-5.5/ultra), Forseti (verifier/M3).",
55
+ "description": "Odin — Tier 1 primary. Pure router that decomposes requests, dispatches to subagents via the task tool, and synthesizes results. Backed by MiniMax M3. Operates inside BizarHarness alongside 13 sibling agents.",
56
56
  "mode": "primary",
57
57
  "model": "minimax/MiniMax-M3",
58
58
  "color": "#6366f1",
@@ -66,7 +66,7 @@
66
66
  }
67
67
  },
68
68
  "vor": {
69
- "description": "Vör — The Questioning One. When a task is ambiguous, incomplete, or unclear, Vör asks the right clarifying questions before any work begins.",
69
+ "description": "Vör — Tier 2 clarifier. Reads project context first and asks targeted, project-specific questions when requests are ambiguous. Backed by DeepSeek V4 Flash. Operates inside BizarHarness alongside 13 sibling agents.",
70
70
  "mode": "subagent",
71
71
  "model": "opencode/deepseek-v4-flash-free",
72
72
  "color": "#8b5cf6",
@@ -77,7 +77,7 @@
77
77
  }
78
78
  },
79
79
  "frigg": {
80
- "description": "Frigg — All-knowing Q&A agent. Read-only codebase questions and answers. Never edits, never writes, only answers.",
80
+ "description": "Frigg — Tier 1 primary. Read-only Q&A agent that answers codebase questions with file:line citations, never edits. Backed by DeepSeek V4 Flash. Operates inside BizarHarness alongside 13 sibling agents.",
81
81
  "mode": "primary",
82
82
  "model": "opencode/deepseek-v4-flash-free",
83
83
  "color": "#06b6d4",
@@ -93,7 +93,7 @@
93
93
  }
94
94
  },
95
95
  "quick": {
96
- "description": "Quick — Fast single-shot tasks. No delegation, no parallel streams. Use for small edits, mechanical changes, one-shot questions. Routes to no one.",
96
+ "description": "Quick — Tier 1 primary. Fast single-shot escape hatch for small edits, mechanical changes, and one-shot questions. No delegation, no parallel streams. Backed by MiniMax M2.7. Operates inside BizarHarness alongside 13 sibling agents.",
97
97
  "mode": "primary",
98
98
  "model": "minimax/MiniMax-M2.7",
99
99
  "color": "#22d3ee",
@@ -112,7 +112,7 @@
112
112
  }
113
113
  },
114
114
  "mimir": {
115
- "description": "Mimir — Dedicated research and codebase exploration agent. Uses Semble as primary search tool. Deep codebase analysis, pattern discovery, and documentation research.",
115
+ "description": "Mimir — Tier 2 research. Dedicated codebase exploration agent who uses Semble as primary search tool for deep analysis, pattern discovery, and documentation research. Backed by DeepSeek V4 Flash. Operates inside BizarHarness alongside 13 sibling agents.",
116
116
  "mode": "subagent",
117
117
  "model": "opencode/deepseek-v4-flash-free",
118
118
  "color": "#0ea5e9",
@@ -130,7 +130,7 @@
130
130
  }
131
131
  },
132
132
  "heimdall": {
133
- "description": "Heimdall — Simple, routine, and deterministic tasks using DeepSeek. Quick edits, mechanical work, file operations. The ever-watchful guardian.",
133
+ "description": "Heimdall — Tier 2 mechanical. Handles simple, routine, deterministic engineering tasks with speed and precision using DeepSeek V4 Flash. The ever-watchful guardian. Operates inside BizarHarness alongside 13 sibling agents.",
134
134
  "mode": "subagent",
135
135
  "model": "opencode/deepseek-v4-flash-free",
136
136
  "color": "#10b981",
@@ -147,7 +147,7 @@
147
147
  }
148
148
  },
149
149
  "hermod": {
150
- "description": "Hermod — Git and GitHub operations specialist using MiniMax M2.7. Branching, commits, PRs, merge/rebase, conflict resolution, CI/CD, releases, gh CLI.",
150
+ "description": "Hermod — Tier 2 git. Git and GitHub operations specialist who handles branching, commits, PRs, merge/rebase, conflict resolution, and releases. Backed by MiniMax M2.7. The swift messenger. Operates inside BizarHarness alongside 13 sibling agents.",
151
151
  "mode": "subagent",
152
152
  "model": "minimax/MiniMax-M2.7",
153
153
  "color": "#06b6d4",
@@ -163,7 +163,7 @@
163
163
  }
164
164
  },
165
165
  "thor": {
166
- "description": "Thor — Handles medium-complexity tasks using MiniMax M2.7 from minimax.io. Strong and reliable, cheaper than Tyr but more capable than Heimdall.",
166
+ "description": "Thor — Tier 3 implementation. Mid-tier engine for moderate-complexity features, debugging, refactoring, and tests, gated by a Forseti plan-review. Runs the test-gate after parallel implementation. Backed by MiniMax M2.7. Operates inside BizarHarness alongside 13 sibling agents.",
167
167
  "mode": "subagent",
168
168
  "model": "minimax/MiniMax-M2.7",
169
169
  "color": "#a855f7",
@@ -180,7 +180,7 @@
180
180
  }
181
181
  },
182
182
  "baldr": {
183
- "description": "Baldr — UI/UX design system specialist. Creates DESIGN.md files using Google's design.md standard. Focuses on visual consistency, usability, accessibility, and design tokens.",
183
+ "description": "Baldr — Tier 2 design. UI/UX design system specialist who creates DESIGN.md files focusing on visual consistency, usability, and accessibility. Plans only — never implements. Backed by MiniMax M2.7. Operates inside BizarHarness alongside 13 sibling agents.",
184
184
  "mode": "subagent",
185
185
  "model": "minimax/MiniMax-M2.7",
186
186
  "color": "#ec4899",
@@ -197,7 +197,7 @@
197
197
  }
198
198
  },
199
199
  "tyr": {
200
- "description": "Tyr — Handles the most complex implementation, debugging, and architectural work using MiniMax M3 via minimax.io. Unmatched wisdom for the hardest problems.",
200
+ "description": "Tyr — Tier 4 implementation. Top-tier engine for complex features, deep debugging, and architectural work, gated by a Forseti plan-review. Backed by MiniMax M3. Operates inside BizarHarness alongside 13 sibling agents.",
201
201
  "mode": "subagent",
202
202
  "model": "minimax/MiniMax-M3",
203
203
  "color": "#f59e0b",
@@ -214,7 +214,7 @@
214
214
  }
215
215
  },
216
216
  "vidarr": {
217
- "description": "Vidarr — The ultimate fallback using MiniMax M3 via MiniMax direct provider. For the hardest problems when debugging stalls or nothing else works. Use sparingly highest cost.",
217
+ "description": "Vidarr — Tier 5 fallback. The ultimate last resort when Tyr stalls or debugging is stuck and nothing else works. Backed by MiniMax M3 with reasoning enabled. Use very sparingly. Operates inside BizarHarness alongside 13 sibling agents.",
218
218
  "mode": "subagent",
219
219
  "model": "minimax/MiniMax-M3",
220
220
  "color": "#dc2626",
@@ -231,7 +231,7 @@
231
231
  }
232
232
  },
233
233
  "forseti": {
234
- "description": "Forseti — Audits, criticizes, and corrects implementation plans before execution using MiniMax M3. No write permissions review only.",
234
+ "description": "Forseti — Tier 3 audit. Adversarial plan reviewer who audits completeness, correctness, consistency, feasibility, and security before high-tier implementation. Read-only no edit permissions. Backed by MiniMax M3. Operates inside BizarHarness alongside 13 sibling agents.",
235
235
  "mode": "subagent",
236
236
  "model": "minimax/MiniMax-M3",
237
237
  "color": "#ef4444",
@@ -249,7 +249,7 @@
249
249
  }
250
250
  },
251
251
  "semble-search": {
252
- "description": "Code search agent for exploring any codebase. Use for finding code by intent, locating implementations, understanding how something works.",
252
+ "description": "semble-search — Tier 2 research. Code search agent for exploring any codebase using Semble's semantic search. For finding code by intent, locating implementations, and understanding how things work. Backed by DeepSeek V4 Flash. Operates inside BizarHarness alongside 13 sibling agents.",
253
253
  "mode": "subagent",
254
254
  "model": "opencode/deepseek-v4-flash-free",
255
255
  "color": "#0ea5e9",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "4.2.3",
3
+ "version": "4.2.4",
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. v4 ships as a single npm package bundling the dashboard server, opencode plugin, and typed SDK.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,8 @@
19
19
  "scripts": {
20
20
  "typecheck": "tsc --noEmit",
21
21
  "build:sdk": "tsc -p packages/sdk/tsconfig.json",
22
- "test:sdk": "npm test --prefix packages/sdk",
23
- "test:sdk:watch": "npm run test:watch --prefix packages/sdk",
22
+ "test:sdk": "node_modules/.bin/vitest run --root packages/sdk",
23
+ "test:sdk:watch": "node_modules/.bin/vitest --root packages/sdk",
24
24
  "test": "npm run typecheck && npm run test:sdk && bun test plugins/bizar/tests/loop.test.ts plugins/bizar/tests/block.test.ts plugins/bizar/tests/stall-think.test.ts plugins/bizar/tests/tools/bg-get-comments.test.ts plugins/bizar/tests/tools/bg-spawn-delegation.test.ts plugins/bizar/tests/tools/opencode-runner.test.ts plugins/bizar/tests/settings.test.ts plugins/bizar/tests/commands.test.ts plugins/bizar/tests/commands-impl.test.ts plugins/bizar/tests/tools/plan-action.test.ts plugins/bizar/tests/tools/wait-for-feedback.test.ts plugins/bizar/tests/tools/read-glyph-feedback.test.ts plugins/bizar/tests/reasoning-clean.test.ts plugins/bizar/tests/key-rotation.test.ts && node bizar-dash/tests/smoke-v2.mjs && node --test bizar-dash/tests/path-safe.test.mjs bizar-dash/tests/tmux-wrap.test.mjs bizar-dash/tests/opencode-runner.test.mjs bizar-dash/tests/mod-instructions.node.test.mjs bizar-dash/tests/mod-upgrade.node.test.mjs bizar-dash/tests/graphify-mod-spawn.node.test.mjs bizar-dash/tests/no-agent-browser.node.test.mjs bizar-dash/tests/providers-store-backup-keys.node.test.mjs bizar-dash/tests/dashboard-ports.test.mjs bizar-dash/tests/submit-feedback.test.mjs bizar-dash/tests/yaml.test.mjs bizar-dash/tests/memory-store.test.mjs bizar-dash/tests/memory-schema.test.mjs bizar-dash/tests/memory-secrets.test.mjs bizar-dash/tests/memory-git.test.mjs bizar-dash/tests/memory-sync.test.mjs bizar-dash/tests/obsidian-back-compat.test.mjs bizar-dash/tests/memory-lightrag.test.mjs bizar-dash/tests/memory-config.test.mjs bizar-dash/tests/memory-cli.test.mjs bizar-dash/tests/memory-cli-readlistdelete.test.mjs bizar-dash/tests/memory-cli-setup.test.mjs bizar-dash/tests/memory-conflicts.test.mjs bizar-dash/tests/memory-namespace.test.mjs bizar-dash/tests/memory-path-safety.test.mjs bizar-dash/tests/memory-protocol-drift.test.mjs bizar-dash/tests/memory-roundtrip.test.mjs",
25
25
  "build": "npm run build:sdk"
26
26
  },
@@ -52,7 +52,7 @@ export function makeFetchMock(): FetchMock {
52
52
  const requests: FetchMockRequest[] = [];
53
53
  let lastRequest: FetchMockRequest | null = null;
54
54
 
55
- const mockFetch: typeof fetch = async (input, init) => {
55
+ const mockFetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
56
56
  const req: FetchMockRequest = {
57
57
  url: typeof input === "string" ? input : input instanceof URL ? input.toString() : (input as Request).url,
58
58
  method: (init?.method ?? "GET").toUpperCase(),
@@ -100,7 +100,7 @@ export function makeFetchMock(): FetchMock {
100
100
  };
101
101
 
102
102
  return {
103
- fetch: mockFetch,
103
+ fetch: mockFetch as typeof fetch,
104
104
  respondWith(method, match, response) {
105
105
  rules.push({ method: method.toUpperCase(), match, response });
106
106
  },