@polderlabs/bizar 4.0.0 → 4.2.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.
Files changed (38) hide show
  1. package/README.md +11 -14
  2. package/bizar-dash/CHANGELOG.md +1 -1
  3. package/bizar-dash/src/server/api.mjs +2 -2
  4. package/bizar-dash/src/server/artifacts-store.mjs +4 -4
  5. package/bizar-dash/src/server/memory-git.mjs +80 -0
  6. package/bizar-dash/src/server/memory-lightrag.mjs +767 -0
  7. package/bizar-dash/src/server/memory-store.mjs +47 -0
  8. package/bizar-dash/src/server/mod-security.mjs +2 -2
  9. package/bizar-dash/src/server/routes/memory.mjs +174 -15
  10. package/bizar-dash/src/server/server.mjs +1 -1
  11. package/bizar-dash/src/server/state.mjs +2 -2
  12. package/bizar-dash/src/web/views/Config.tsx +461 -1
  13. package/bizar-dash/tests/memory-cli.test.mjs +542 -0
  14. package/bizar-dash/tests/memory-config.test.mjs +422 -0
  15. package/bizar-dash/tests/memory-git.test.mjs +109 -1
  16. package/bizar-dash/tests/memory-lightrag.test.mjs +153 -0
  17. package/bizar-dash/tests/memory-protocol-drift.test.mjs +45 -0
  18. package/cli/banner.mjs +1 -1
  19. package/cli/bin.mjs +4 -4
  20. package/cli/bootstrap.mjs +1 -1
  21. package/cli/copy.mjs +22 -16
  22. package/cli/doctor.mjs +4 -4
  23. package/cli/doctor.test.mjs +2 -2
  24. package/cli/init.mjs +2 -2
  25. package/cli/install.mjs +21 -16
  26. package/cli/memory.mjs +710 -31
  27. package/cli/utils.mjs +6 -3
  28. package/config/AGENTS.md +7 -7
  29. package/config/agents/_shared/AGENT_BASELINE.md +59 -61
  30. package/config/opencode.json +13 -38
  31. package/config/skills/memory-protocol/SKILL.md +105 -0
  32. package/config/skills/obsidian/SKILL.md +58 -1
  33. package/install.sh +11 -1
  34. package/package.json +2 -2
  35. package/plugins/bizar/index.ts +7 -0
  36. package/plugins/bizar/src/commands.ts +42 -1
  37. package/plugins/bizar/src/tools/open-kb.ts +191 -0
  38. package/plugins/bizar/tests/commands.test.ts +36 -0
@@ -0,0 +1,45 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFileSync } from 'node:fs';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { dirname, resolve } from 'node:path';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const REPO_ROOT = resolve(__dirname, '..', '..');
9
+
10
+ function read(rel) {
11
+ return readFileSync(resolve(REPO_ROOT, rel), 'utf8');
12
+ }
13
+
14
+ test('memory-protocol SKILL.md has MANDATORY framing at the top', () => {
15
+ const skill = read('config/skills/memory-protocol/SKILL.md');
16
+ // The "MANDATORY" badge must appear in the first 10 lines
17
+ const head = skill.split('\n').slice(0, 10).join('\n');
18
+ assert.match(head, /MANDATORY/, 'memory-protocol/SKILL.md must mark the protocol as MANDATORY in the first 10 lines');
19
+ });
20
+
21
+ test('AGENT_BASELINE.md section 5 has MANDATORY marker', () => {
22
+ const baseline = read('config/agents/_shared/AGENT_BASELINE.md');
23
+ // Find section 5 header and the next 20 lines
24
+ const section5Idx = baseline.indexOf('## 5.');
25
+ assert.ok(section5Idx >= 0, 'AGENT_BASELINE.md must have a section 5');
26
+ const section5Head = baseline.slice(section5Idx, section5Idx + 600);
27
+ assert.match(section5Head, /MANDATORY/, 'AGENT_BASELINE.md section 5 must mark memory check as MANDATORY');
28
+ });
29
+
30
+ test('AGENT_BASELINE.md section 13 has mandatory language', () => {
31
+ const baseline = read('config/agents/_shared/AGENT_BASELINE.md');
32
+ const section13Idx = baseline.indexOf('## 13.');
33
+ assert.ok(section13Idx >= 0, 'AGENT_BASELINE.md must have a section 13');
34
+ const section13Head = baseline.slice(section13Idx, section13Idx + 3000);
35
+ // Either the ⚠️ ENFORCED marker we just added, or the existing "mandatory, not optional" line
36
+ const hasMandatory = /MANDATORY/.test(section13Head) || /mandatory, not optional/i.test(section13Head);
37
+ assert.ok(hasMandatory, 'AGENT_BASELINE.md section 13 must contain MANDATORY framing or the existing "mandatory, not optional" language');
38
+ });
39
+
40
+ test('AGENT_BASELINE.md session-start bootstrap commands are present', () => {
41
+ const baseline = read('config/agents/_shared/AGENT_BASELINE.md');
42
+ // The actual commands agents must run
43
+ assert.match(baseline, /bizar memory search/, 'AGENT_BASELINE.md must reference `bizar memory search`');
44
+ assert.match(baseline, /bizar memory status/, 'AGENT_BASELINE.md must reference `bizar memory status`');
45
+ });
package/cli/banner.mjs CHANGED
@@ -25,7 +25,7 @@ export function showBanner() {
25
25
  console.log(chalk.hex('#6366f1').bold(RUNE_HELM));
26
26
  console.log(chalk.hex('#a855f7')(' Norse Pantheon Agent System for opencode'));
27
27
  console.log();
28
- console.log(chalk.dim(' 13 agents · 4 cost tiers · Obsidian vault long-term memory · RTK · Semble · Skills CLI · Mods'));
28
+ console.log(chalk.dim(' 13 agents · 4 cost tiers · Obsidian vault long-term memory · Headroom · Semble · Skills CLI · Mods'));
29
29
  console.log();
30
30
  }
31
31
 
package/cli/bin.mjs CHANGED
@@ -272,7 +272,7 @@ function showDoctorHelp() {
272
272
  • plugin path resolves
273
273
  • @polderlabs/bizar-plugin is installed globally
274
274
  • core agent files are installed (odin, quick, thor, tyr)
275
- rtk / semble / skills on PATH (lenient — at least one)
275
+ headroom / semble / skills on PATH (lenient — at least one)
276
276
  • dashboard reachable (skipped if no port file)
277
277
  • provider.minimax block + MiniMax model flags are sane
278
278
 
@@ -491,8 +491,8 @@ function showDashHelp() {
491
491
  function showMemoryHelp() {
492
492
  console.log(`
493
493
  memory <subcommand> Manage project memory (local-only or Git-shared Obsidian vault)
494
- Subcommands: init, status, link, unlink, pull, commit, push,
495
- sync, reindex, conflicts, doctor
494
+ Subcommands: init, setup, status, link, unlink, write, pull, commit,
495
+ push, sync, reindex, conflicts, doctor
496
496
  `);
497
497
  }
498
498
 
@@ -643,7 +643,7 @@ async function main() {
643
643
  if (isHelpRequest) showInitHelp();
644
644
  else await runInit(process.cwd());
645
645
  } else if (args[0] === 'memory') {
646
- if (isHelpRequest) showMemoryHelp();
646
+ if (isHelpRequest && !args[1]) showMemoryHelp();
647
647
  else {
648
648
  const { runMemory } = await import('./memory.mjs');
649
649
  await runMemory(args[1], args.slice(2));
package/cli/bootstrap.mjs CHANGED
@@ -49,7 +49,7 @@ export function checkSetupStatus() {
49
49
  */
50
50
  function printSetupBanner() {
51
51
  // Use console.log directly to avoid chalk formatting issues in non-TTY
52
- console.log('\n ⚡ First-time setup — Bizar needs to install agents, plugin, RTK, Semble, Skills CLI...\n');
52
+ console.log('\n ⚡ First-time setup — Bizar needs to install agents, plugin, Headroom, Semble, Skills CLI...\n');
53
53
  }
54
54
 
55
55
  /**
package/cli/copy.mjs CHANGED
@@ -341,43 +341,49 @@ export async function installPluginBizar(projectRoot) {
341
341
  }
342
342
  }
343
343
 
344
- export async function installRtk() {
344
+ export async function installHeadroom() {
345
345
  const { execSync } = await import('node:child_process');
346
346
 
347
347
  const already = await detectRtk();
348
348
  if (already) {
349
- const spinner = ora({ text: 'Configuring RTK for opencode...', color: 'magenta' }).start();
349
+ const spinner = ora({ text: 'Configuring Headroom for opencode...', color: 'magenta' }).start();
350
350
  try {
351
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
352
- spinner.succeed(chalk.green('RTK configured for opencode'));
351
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
352
+ spinner.succeed(chalk.green('Headroom configured for opencode'));
353
353
  } catch {
354
- spinner.warn(chalk.yellow('Could not auto-configure RTK — run `rtk init -g --opencode` manually'));
354
+ spinner.warn(chalk.yellow('Could not auto-configure Headroom — run `headroom wrap opencode` manually'));
355
355
  }
356
356
  return true;
357
357
  }
358
358
 
359
- const spinner = ora({ text: 'Installing RTK (Rust Token Killer)...', color: 'magenta' }).start();
359
+ const spinner = ora({ text: 'Installing Headroom (context compressor)...', color: 'magenta' }).start();
360
360
 
361
361
  if (process.platform === 'win32') {
362
- // RTK ships a bash-only installer; no PowerShell equivalent. On
363
- // Windows the user must install RTK manually (e.g. via Cargo or
364
- // prebuilt binary) and re-run `rtk init -g --opencode`.
365
- spinner.fail(chalk.red('Automatic RTK install not supported on Windows. Install manually from https://github.com/rtk-ai/rtk'));
362
+ spinner.fail(chalk.red('Automatic Headroom install not supported on Windows. Install manually: pip install "headroom-ai[all]"'));
366
363
  return false;
367
364
  }
368
365
 
369
366
  try {
370
367
  execSync(
371
- 'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh',
368
+ 'pip install --user "headroom-ai[all]"',
372
369
  { stdio: 'pipe', timeout: 60000 },
373
370
  );
374
- spinner.text = 'Configuring RTK for opencode...';
375
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
376
- spinner.succeed(chalk.green('RTK installed and configured for opencode'));
371
+ spinner.text = 'Configuring Headroom for opencode...';
372
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
373
+ spinner.succeed(chalk.green('Headroom installed and configured for opencode'));
377
374
  return true;
378
375
  } catch {
379
- spinner.fail(chalk.red('RTK install failed. Install manually from https://github.com/rtk-ai/rtk'));
380
- return false;
376
+ // Fall back to npm
377
+ try {
378
+ execSync('npm install -g headroom-ai', { stdio: 'pipe', timeout: 60000 });
379
+ spinner.text = 'Configuring Headroom for opencode...';
380
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
381
+ spinner.succeed(chalk.green('Headroom installed (npm) and configured for opencode'));
382
+ return true;
383
+ } catch {
384
+ spinner.fail(chalk.red('Headroom install failed. Install manually: pip install "headroom-ai[all]" or npm install -g headroom-ai'));
385
+ return false;
386
+ }
381
387
  }
382
388
  }
383
389
 
package/cli/doctor.mjs CHANGED
@@ -9,8 +9,8 @@
9
9
  * result without re-printing the per-check output.
10
10
  *
11
11
  * The checks are intentionally tolerant: missing optional tools
12
- * (rtk/semble/skills) don't fail the run, and the dashboard check is
13
- * skipped silently if no port file exists. The goal is "is your
12
+ * (headroom/semble/skills) don't fail the run, and the dashboard check
13
+ * is skipped silently if no port file exists. The goal is "is your
14
14
  * install healthy?" not "is every conceivable thing present?".
15
15
  *
16
16
  * Usage:
@@ -187,13 +187,13 @@ async function checkAgentFilesInstalled() {
187
187
  }
188
188
 
189
189
  /**
190
- * Lenient: passes if at least one of rtk/semble/skills is on PATH.
190
+ * Lenient: passes if at least one of headroom/semble/skills is on PATH.
191
191
  * These are informational — none of them are strictly required for
192
192
  * `bizar doctor` to do its job, and missing them shouldn't fail the
193
193
  * overall health report.
194
194
  */
195
195
  async function checkToolsAvailable() {
196
- const tools = ['rtk', 'semble', 'skills'];
196
+ const tools = ['headroom', 'semble', 'skills'];
197
197
  const found = tools.filter(which);
198
198
  if (found.length === 0) {
199
199
  throw new Error(`none of ${tools.join('/')} on PATH`);
@@ -8,7 +8,7 @@
8
8
  * tmpdir, and craft the opencode.json + agents/ directory to drive
9
9
  * specific pass/fail outcomes. For checks that depend on global
10
10
  * npm-installed packages or external CLIs (e.g. opencode --version,
11
- * npm root -g, which rtk), we accept that they may pass or fail
11
+ * npm root -g, which headroom), we accept that they may pass or fail
12
12
  * depending on the test environment and just verify the framework
13
13
  * returns the right shape.
14
14
  */
@@ -116,7 +116,7 @@ describe('runDoctor() shape', () => {
116
116
 
117
117
  test('silent mode suppresses ALL output when nothing fails', async () => {
118
118
  // Build a fully healthy environment. We can't make opencode reachable
119
- // or rtk installed without modifying PATH, so we settle for: no failures
119
+ // or headroom installed without modifying PATH, so we settle for: no failures
120
120
  // means no output at all. Since we know some checks will fail in a
121
121
  // bare tmpdir, this test is structured to assert the negative case
122
122
  // differently: we verify silent+no-fail produces 0 lines.
package/cli/init.mjs CHANGED
@@ -260,10 +260,10 @@ ${stack.runner ? `- Dev: \`${stack.runner}\`` : ''}
260
260
  name: 'memoryMode',
261
261
  message: 'Memory backend',
262
262
  choices: [
263
- { name: 'local-only (vault stays in this project at .obsidian/)', value: 'local-only' },
264
263
  { name: 'managed (shared user-level repo at ~/.local/share/bizar/memory/bizar-memory/)', value: 'managed' },
264
+ { name: 'local-only (vault stays in this project at .obsidian/)', value: 'local-only' },
265
265
  ],
266
- default: 'local-only',
266
+ default: 'managed',
267
267
  }])).memoryMode;
268
268
  const memoryMode = initialMode === 'managed' ? 'managed' : 'local-only';
269
269
 
package/cli/install.mjs CHANGED
@@ -5,8 +5,8 @@ import { join } from 'node:path';
5
5
 
6
6
  import { showBanner, showPantheon, sectionHeading } from './banner.mjs';
7
7
  import { promptComponents, promptInstallMode, promptAgents, promptSkillPacks, promptApiKeys, promptConfirmInstall, promptRestartOpenCode } from './prompts.mjs';
8
- import { detectOpenCode, detectRtk, detectSemble, detectSkillsCli, detectUv, buildSummary, opencodeAgentsDir, opencodeConfigDir, repoPath } from './utils.mjs';
9
- import { installAgents, installAgentsMd, installSkill, installOpencodeJson, installBizarFolder, installPluginBizar, installRtk, installSemble, installSkillsCli, installCuratedSkills, installRules, installHooks, installCommands, installCommandsBizar, mergeToolsIntoUserConfig } from './copy.mjs';
8
+ import { detectOpenCode, detectHeadroom, detectSemble, detectSkillsCli, detectUv, buildSummary, opencodeAgentsDir, opencodeConfigDir, repoPath } from './utils.mjs';
9
+ import { installAgents, installAgentsMd, installSkill, installOpencodeJson, installBizarFolder, installPluginBizar, installHeadroom, installSemble, installSkillsCli, installCuratedSkills, installRules, installHooks, installCommands, installCommandsBizar, mergeToolsIntoUserConfig } from './copy.mjs';
10
10
 
11
11
  const AGENT_FILES = [
12
12
  'odin.md', 'vor.md', 'frigg.md', 'quick.md',
@@ -554,32 +554,37 @@ export async function runPostInstall() {
554
554
  }
555
555
  console.log('BizarHarness: agents installed.');
556
556
 
557
- // Install RTK
558
- const rtkPresent = await detectRtk();
559
- if (!rtkPresent) {
560
- console.log('BizarHarness: installing RTK (token optimizer)...');
557
+ // Install Headroom
558
+ const headroomPresent = await detectHeadroom();
559
+ if (!headroomPresent) {
560
+ console.log('BizarHarness: installing Headroom (context compressor)...');
561
561
  try {
562
562
  if (process.platform === 'win32') {
563
- // RTK ships a bash-only installer; on Windows the user installs it
564
- // manually (e.g. `cargo install --git https://github.com/rtk-ai/rtk`).
565
- console.log('BizarHarness: RTK bash installer does not run on Windows. Install manually from https://github.com/rtk-ai/rtk');
563
+ console.log('BizarHarness: Automatic Headroom install not supported on Windows. Install manually: pip install "headroom-ai[all]"');
566
564
  } else {
567
565
  execSync(
568
- 'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh',
566
+ 'pip install --user "headroom-ai[all]"',
569
567
  { stdio: 'pipe', timeout: 60000 },
570
568
  );
571
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
572
- console.log('BizarHarness: RTK installed and configured.');
569
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
570
+ console.log('BizarHarness: Headroom installed and configured.');
573
571
  }
574
572
  } catch {
575
- console.log('BizarHarness: RTK install failed. Install manually from https://github.com/rtk-ai/rtk');
573
+ // Fall back to npm
574
+ try {
575
+ execSync('npm install -g headroom-ai', { stdio: 'pipe', timeout: 60000 });
576
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
577
+ console.log('BizarHarness: Headroom installed (npm) and configured.');
578
+ } catch {
579
+ console.log('BizarHarness: Headroom install failed. Install manually: pip install "headroom-ai[all]" or npm install -g headroom-ai');
580
+ }
576
581
  }
577
582
  } else {
578
583
  try {
579
- execSync('rtk init -g --opencode', { stdio: 'pipe' });
580
- console.log('BizarHarness: RTK configured for opencode.');
584
+ execSync('headroom wrap opencode', { stdio: 'pipe' });
585
+ console.log('BizarHarness: Headroom configured for opencode.');
581
586
  } catch {
582
- console.log('BizarHarness: could not configure RTK. Run `rtk init -g --opencode` manually.');
587
+ console.log('BizarHarness: could not configure Headroom. Run `headroom wrap opencode` manually.');
583
588
  }
584
589
  }
585
590