@polderlabs/bizar 4.2.2 → 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
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * tests/memory-install-bootstrap.test.mjs
3
+ *
4
+ * Regression test for v4.2.2: the `bizar` CLI bootstrap path crashed with
5
+ * `ERR_AMBIGUOUS_MODULE_SYNTAX` on a fresh install because `promptAndInstallOptional`
6
+ * in `cli/install.mjs` referenced `__dirname` (a CommonJS global) without defining
7
+ * the ESM polyfill. This was only triggered by the bootstrap path, which the
8
+ * existing test suite never exercised.
9
+ *
10
+ * Test: spawn the CLI in a fresh temp project, with BIZAR_SKIP_INSTALL unset.
11
+ * The bootstrap should run and exit cleanly (rc 0 or rc 1 for missing auth, but
12
+ * NOT crash with ERR_AMBIGUOUS_MODULE_SYNTAX).
13
+ *
14
+ * Fix: move the `__dirname` polyfill to module scope in cli/install.mjs.
15
+ */
16
+
17
+ import { describe, it, beforeEach, afterEach } from 'node:test';
18
+ import assert from 'node:assert/strict';
19
+ import { tmpdir } from 'node:os';
20
+ import { join, dirname } from 'node:path';
21
+ import { mkdirSync, rmSync } from 'node:fs';
22
+ import { execFileSync } from 'node:child_process';
23
+ import { fileURLToPath } from 'node:url';
24
+
25
+ const __filename = fileURLToPath(import.meta.url);
26
+ const CLI_BIN = join(dirname(__filename), '..', '..', 'cli', 'bin.mjs');
27
+
28
+ const uid = () => `${Date.now()}-${Math.random().toString(36).slice(2)}`;
29
+
30
+ /**
31
+ * Spawn `bizar <subcmd>` in the given cwd, with the given env vars.
32
+ * Returns { code, stdout, stderr }.
33
+ *
34
+ * The bootstrap path is checked by NOT setting BIZAR_SKIP_INSTALL.
35
+ */
36
+ function runBizarWithoutSkip(args, cwd, extraEnv = {}) {
37
+ try {
38
+ const stdout = execFileSync('node', [CLI_BIN, ...args], {
39
+ cwd,
40
+ encoding: 'utf8',
41
+ stdio: 'pipe',
42
+ timeout: 30_000,
43
+ env: { ...process.env, ...extraEnv }, // no BIZAR_SKIP_INSTALL
44
+ });
45
+ return { code: 0, stdout, stderr: '' };
46
+ } catch (err) {
47
+ return {
48
+ code: err.status ?? 1,
49
+ stdout: err.stdout ? err.stdout.toString() : '',
50
+ stderr: err.stderr ? err.stderr.toString() : (err.message ?? ''),
51
+ };
52
+ }
53
+ }
54
+
55
+ describe('bizar CLI bootstrap (v4.2.3 regression)', () => {
56
+ let projectRoot;
57
+ let homeDir;
58
+
59
+ beforeEach(() => {
60
+ projectRoot = join(tmpdir(), `bizar-bootstrap-${uid()}`);
61
+ homeDir = join(tmpdir(), `bizar-bootstrap-home-${uid()}`);
62
+ mkdirSync(projectRoot, { recursive: true });
63
+ mkdirSync(homeDir, { recursive: true });
64
+ });
65
+
66
+ afterEach(() => {
67
+ try { rmSync(projectRoot, { recursive: true, force: true }); } catch { /* ignore */ }
68
+ try { rmSync(homeDir, { recursive: true, force: true }); } catch { /* ignore */ }
69
+ });
70
+
71
+ it('bizar --version does not crash with ERR_AMBIGUOUS_MODULE_SYNTAX', () => {
72
+ const r = runBizarWithoutSkip(['--version'], projectRoot, { HOME: homeDir });
73
+ // Whatever exit code, the key thing is the bootstrap doesn't crash
74
+ assert.ok(
75
+ !r.stderr.includes('ERR_AMBIGUOUS_MODULE_SYNTAX'),
76
+ `bootstrap crashed with ERR_AMBIGUOUS_MODULE_SYNTAX. stderr=${r.stderr}`,
77
+ );
78
+ assert.ok(
79
+ !r.stderr.includes('Cannot determine intended module format'),
80
+ `bootstrap module-format error. stderr=${r.stderr}`,
81
+ );
82
+ });
83
+
84
+ it('bizar memory status does not crash with ERR_AMBIGUOUS_MODULE_SYNTAX', () => {
85
+ const r = runBizarWithoutSkip(['memory', 'status'], projectRoot, { HOME: homeDir });
86
+ assert.ok(
87
+ !r.stderr.includes('ERR_AMBIGUOUS_MODULE_SYNTAX'),
88
+ `bootstrap crashed with ERR_AMBIGUOUS_MODULE_SYNTAX. stderr=${r.stderr}`,
89
+ );
90
+ assert.ok(
91
+ !r.stderr.includes('Cannot determine intended module format'),
92
+ `bootstrap module-format error. stderr=${r.stderr}`,
93
+ );
94
+ });
95
+
96
+ it('bizar memory doctor does not crash with ERR_AMBIGUOUS_MODULE_SYNTAX', () => {
97
+ const r = runBizarWithoutSkip(['memory', 'doctor'], projectRoot, { HOME: homeDir });
98
+ assert.ok(
99
+ !r.stderr.includes('ERR_AMBIGUOUS_MODULE_SYNTAX'),
100
+ `bootstrap crashed with ERR_AMBIGUOUS_MODULE_SYNTAX. stderr=${r.stderr}`,
101
+ );
102
+ });
103
+
104
+ it('install.mjs source defines __dirname at module scope (regression guard)', () => {
105
+ // Read the source of cli/install.mjs and check that __dirname is
106
+ // defined at module scope (not only inside runInstaller).
107
+ const installSrc = execFileSync('node', ['-e', `
108
+ const fs = require('fs');
109
+ const src = fs.readFileSync(${JSON.stringify(join(dirname(CLI_BIN), 'install.mjs'))}, 'utf8');
110
+ // Find first __dirname definition (should be at module scope, not inside a function)
111
+ const lines = src.split('\\n');
112
+ let firstDefine = -1;
113
+ for (let i = 0; i < lines.length; i++) {
114
+ if (lines[i].includes('__dirname = dirname(fileURLToPath')) {
115
+ firstDefine = i;
116
+ break;
117
+ }
118
+ }
119
+ // The first definition must be BEFORE any function definition that uses __dirname
120
+ // Simple heuristic: it must be within the first 20 lines
121
+ process.stdout.write(JSON.stringify({ firstDefine, totalLines: lines.length }));
122
+ `], { encoding: 'utf8' });
123
+ const { firstDefine, totalLines } = JSON.parse(installSrc);
124
+ assert.ok(
125
+ firstDefine >= 0 && firstDefine < 20,
126
+ `__dirname polyfill should be at module scope (first 20 lines). Found at line ${firstDefine + 1} of ${totalLines}.`,
127
+ );
128
+ });
129
+ });
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 {
package/cli/install.mjs CHANGED
@@ -1,7 +1,17 @@
1
1
  import chalk from 'chalk';
2
2
  import boxen from 'boxen';
3
3
  import { existsSync, lstatSync, rmSync } from 'node:fs';
4
- import { join } from 'node:path';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ // ── ESM `__dirname` polyfill ────────────────────────────────────────────────
8
+ // `__dirname` is a CommonJS global. ESM modules don't have it. We define it
9
+ // at module scope so all functions in this file can use it without each
10
+ // having to recreate the polyfill. (v4.2.3 — previously only `runInstaller`
11
+ // had it, which caused `promptAndInstallOptional` to crash with
12
+ // `ERR_AMBIGUOUS_MODULE_SYNTAX` when the bootstrap path fired on a fresh
13
+ // install.)
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
15
 
6
16
  import { showBanner, showPantheon, sectionHeading } from './banner.mjs';
7
17
  import { promptComponents, promptInstallMode, promptAgents, promptSkillPacks, promptApiKeys, promptConfirmInstall, promptRestartOpenCode } from './prompts.mjs';
@@ -232,11 +242,10 @@ export async function installPluginFromGlobal(opts = {}) {
232
242
  */
233
243
  export async function runInstaller() {
234
244
  const { existsSync } = await import('node:fs');
235
- const { join, dirname } = await import('node:path');
236
- const { fileURLToPath } = await import('node:url');
245
+ const { join } = await import('node:path');
237
246
  const { spawnSync } = await import('node:child_process');
238
247
 
239
- const __dirname = dirname(fileURLToPath(import.meta.url));
248
+ // __dirname is defined at module scope (see top of file)
240
249
  // cli/install.mjs → ../install.sh
241
250
  const installSh = join(__dirname, '..', 'install.sh');
242
251
 
@@ -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.2",
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
  },