@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.
- package/README.md +11 -14
- package/bizar-dash/CHANGELOG.md +1 -1
- package/bizar-dash/src/server/api.mjs +2 -2
- package/bizar-dash/src/server/artifacts-store.mjs +4 -4
- package/bizar-dash/src/server/memory-git.mjs +80 -0
- package/bizar-dash/src/server/memory-lightrag.mjs +767 -0
- package/bizar-dash/src/server/memory-store.mjs +47 -0
- package/bizar-dash/src/server/mod-security.mjs +2 -2
- package/bizar-dash/src/server/routes/memory.mjs +174 -15
- package/bizar-dash/src/server/server.mjs +1 -1
- package/bizar-dash/src/server/state.mjs +2 -2
- package/bizar-dash/src/web/views/Config.tsx +461 -1
- package/bizar-dash/tests/memory-cli.test.mjs +542 -0
- package/bizar-dash/tests/memory-config.test.mjs +422 -0
- package/bizar-dash/tests/memory-git.test.mjs +109 -1
- package/bizar-dash/tests/memory-lightrag.test.mjs +153 -0
- package/bizar-dash/tests/memory-protocol-drift.test.mjs +45 -0
- package/cli/banner.mjs +1 -1
- package/cli/bin.mjs +4 -4
- package/cli/bootstrap.mjs +1 -1
- package/cli/copy.mjs +22 -16
- package/cli/doctor.mjs +4 -4
- package/cli/doctor.test.mjs +2 -2
- package/cli/init.mjs +2 -2
- package/cli/install.mjs +21 -16
- package/cli/memory.mjs +710 -31
- package/cli/utils.mjs +6 -3
- package/config/AGENTS.md +7 -7
- package/config/agents/_shared/AGENT_BASELINE.md +59 -61
- package/config/opencode.json +13 -38
- package/config/skills/memory-protocol/SKILL.md +105 -0
- package/config/skills/obsidian/SKILL.md +58 -1
- package/install.sh +11 -1
- package/package.json +2 -2
- package/plugins/bizar/index.ts +7 -0
- package/plugins/bizar/src/commands.ts +42 -1
- package/plugins/bizar/src/tools/open-kb.ts +191 -0
- 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 ·
|
|
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
|
-
•
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
349
|
+
const spinner = ora({ text: 'Configuring Headroom for opencode...', color: 'magenta' }).start();
|
|
350
350
|
try {
|
|
351
|
-
execSync('
|
|
352
|
-
spinner.succeed(chalk.green('
|
|
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
|
|
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
|
|
359
|
+
const spinner = ora({ text: 'Installing Headroom (context compressor)...', color: 'magenta' }).start();
|
|
360
360
|
|
|
361
361
|
if (process.platform === 'win32') {
|
|
362
|
-
|
|
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
|
-
'
|
|
368
|
+
'pip install --user "headroom-ai[all]"',
|
|
372
369
|
{ stdio: 'pipe', timeout: 60000 },
|
|
373
370
|
);
|
|
374
|
-
spinner.text = 'Configuring
|
|
375
|
-
execSync('
|
|
376
|
-
spinner.succeed(chalk.green('
|
|
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
|
-
|
|
380
|
-
|
|
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
|
-
* (
|
|
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
|
|
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 = ['
|
|
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`);
|
package/cli/doctor.test.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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: '
|
|
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,
|
|
9
|
-
import { installAgents, installAgentsMd, installSkill, installOpencodeJson, installBizarFolder, installPluginBizar,
|
|
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
|
|
558
|
-
const
|
|
559
|
-
if (!
|
|
560
|
-
console.log('BizarHarness: installing
|
|
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
|
-
|
|
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
|
-
'
|
|
566
|
+
'pip install --user "headroom-ai[all]"',
|
|
569
567
|
{ stdio: 'pipe', timeout: 60000 },
|
|
570
568
|
);
|
|
571
|
-
execSync('
|
|
572
|
-
console.log('BizarHarness:
|
|
569
|
+
execSync('headroom wrap opencode', { stdio: 'pipe' });
|
|
570
|
+
console.log('BizarHarness: Headroom installed and configured.');
|
|
573
571
|
}
|
|
574
572
|
} catch {
|
|
575
|
-
|
|
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('
|
|
580
|
-
console.log('BizarHarness:
|
|
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
|
|
587
|
+
console.log('BizarHarness: could not configure Headroom. Run `headroom wrap opencode` manually.');
|
|
583
588
|
}
|
|
584
589
|
}
|
|
585
590
|
|