@polderlabs/bizar 5.6.0-beta.12 → 5.6.0-beta.14

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/cli/provision.mjs CHANGED
@@ -259,11 +259,40 @@ export function writeInstallMarker({ version, repoPath, serviceUnit }) {
259
259
  */
260
260
  export function detectState({ cwd = process.cwd() } = {}) {
261
261
  // ── npm-global package location ─────────────────────────────────────
262
+ // Try multiple strategies because `npm root -g` doesn't always
263
+ // respect NPM_CONFIG_PREFIX (notably when npm is installed by the
264
+ // system package manager on Debian/Ubuntu).
262
265
  let globalRoot = null;
266
+ const npmRootCandidates = [];
267
+
268
+ // 1. Honour the user's explicit env override first.
269
+ if (process.env.NPM_CONFIG_PREFIX) {
270
+ npmRootCandidates.push(join(process.env.NPM_CONFIG_PREFIX, 'lib', 'node_modules'));
271
+ }
272
+ // 2. Honour NPM_CONFIG_GLOBAL_PREFIX (set by `npm -g`).
273
+ if (process.env.NPM_CONFIG_GLOBAL_PREFIX) {
274
+ npmRootCandidates.push(join(process.env.NPM_CONFIG_GLOBAL_PREFIX, 'lib', 'node_modules'));
275
+ }
276
+ // 3. The classic `npm root -g` query (works on most distros).
263
277
  try {
264
- globalRoot = execSync('npm root -g', { stdio: ['ignore', 'pipe', 'ignore'] })
278
+ const r = execSync('npm root -g', { stdio: ['ignore', 'pipe', 'ignore'] })
265
279
  .toString().trim();
280
+ if (r) npmRootCandidates.push(r);
266
281
  } catch { /* ignore */ }
282
+ // 4. Common distro defaults.
283
+ npmRootCandidates.push('/usr/local/lib/node_modules');
284
+ npmRootCandidates.push('/usr/lib/node_modules');
285
+
286
+ // Pick the first candidate that actually has @polderlabs/bizar.
287
+ for (const candidate of npmRootCandidates) {
288
+ if (existsSync(join(candidate, '@polderlabs', 'bizar'))) {
289
+ globalRoot = candidate;
290
+ break;
291
+ }
292
+ }
293
+ // Fall back to the first candidate (even if it doesn't have the
294
+ // package) so downstream code can produce a clean error message.
295
+ if (!globalRoot) globalRoot = npmRootCandidates[0] ?? null;
267
296
 
268
297
  const pkgRoot = globalRoot ? join(globalRoot, '@polderlabs', 'bizar') : null;
269
298
  const pkgVersion = globalRoot ? currentVersion(PKG_MAIN) : null;
@@ -515,7 +544,11 @@ export async function ensureNpmPackage(pkg, { mode, dryRun, force }) {
515
544
  // processes are reading files inside the npm-global install dir. We
516
545
  // can't replace those files atomically while they're open. The caller
517
546
  // is expected to have already killed them via ensureInstancesKilled().
518
- const r = spawnSync('npm', ['install', '-g', `${pkg}@latest`], { stdio: 'inherit', timeout: 600000 });
547
+ const npmArgs = ['install', '-g', `${pkg}@latest`];
548
+ if (process.env.NPM_CONFIG_PREFIX) {
549
+ npmArgs.push('--prefix', process.env.NPM_CONFIG_PREFIX);
550
+ }
551
+ const r = spawnSync('npm', npmArgs, { stdio: 'inherit', timeout: 600000 });
519
552
  if (r.status === null && r.error?.code === 'ETIMEDOUT') {
520
553
  return { ok: false, message: `${pkg} install timed out after 10 minutes`, installed: current };
521
554
  }
@@ -543,7 +576,11 @@ export async function updateClineCli({ dryRun, force }) {
543
576
  return { ok: true, message: 'cline updated via `cline upgrade`' };
544
577
  }
545
578
  console.log(chalk.dim(' cline upgrade not available; falling back to npm'));
546
- const r2 = spawnSync('npm', ['install', '-g', 'cline@latest'], { stdio: 'inherit', timeout: 600000 });
579
+ const npm2Args = ['install', '-g', 'cline@latest'];
580
+ if (process.env.NPM_CONFIG_PREFIX) {
581
+ npm2Args.push('--prefix', process.env.NPM_CONFIG_PREFIX);
582
+ }
583
+ const r2 = spawnSync('npm', npm2Args, { stdio: 'inherit', timeout: 600000 });
547
584
  if (r2.status === null && r2.error?.code === 'ETIMEDOUT') {
548
585
  return { ok: false, message: 'cline install timed out after 10 minutes' };
549
586
  }
@@ -583,6 +620,40 @@ export async function copyPluginToCline({ dryRun, force }) {
583
620
  };
584
621
  }
585
622
 
623
+ // v5.6.0-beta.14: require a package.json with a `cline` field before
624
+ // copying. Per https://docs.cline.bot/customization/plugins — without
625
+ // the `cline.plugins` manifest, Cline falls back to recursive
626
+ // auto-discovery and tries to load every .ts file in the plugin tree
627
+ // (including `src/tools/*.ts`, `tests/*.test.ts`) as a plugin module,
628
+ // which produces ~100 `Invalid plugin module` errors at startup.
629
+ // Refuse to copy a plugin that isn't actually a Cline plugin.
630
+ const pkgJsonPath = join(src, 'package.json');
631
+ if (!existsSync(pkgJsonPath)) {
632
+ return {
633
+ ok: false,
634
+ message:
635
+ `plugin source missing package.json at ${pkgJsonPath} — ` +
636
+ `rebuild @polderlabs/bizar (the plugin must ship a cline field)`,
637
+ };
638
+ }
639
+ try {
640
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
641
+ if (!pkg.cline?.plugins?.length) {
642
+ return {
643
+ ok: false,
644
+ message:
645
+ `plugin package.json at ${pkgJsonPath} is missing the ` +
646
+ 'cline.plugins manifest required by Cline — see ' +
647
+ 'https://docs.cline.bot/customization/plugins',
648
+ };
649
+ }
650
+ } catch (err) {
651
+ return {
652
+ ok: false,
653
+ message: `plugin package.json at ${pkgJsonPath} is invalid JSON: ${err.message}`,
654
+ };
655
+ }
656
+
586
657
  if (state.plugin.symlink && !force) {
587
658
  return {
588
659
  ok: true,
@@ -626,7 +697,19 @@ export async function copyPluginToCline({ dryRun, force }) {
626
697
  // Filter against RELATIVE path segments, not absolute substrings. This
627
698
  // is the v5.6.0-beta.12 fix: the old filter excluded the src dir itself
628
699
  // because npm-global paths contain `node_modules`.
629
- const skipDirs = new Set(['node_modules', 'dist', '.DS_Store']);
700
+ //
701
+ // v5.6.0-beta.14: also skip `tests/` and `scripts/` (test fixtures &
702
+ // helper scripts aren't part of the runtime plugin) and `coverage/`
703
+ // (jest artifacts). The runtime only needs `index.ts`, `src/`,
704
+ // `package.json`, and the static docs.
705
+ const skipDirs = new Set([
706
+ 'node_modules',
707
+ 'dist',
708
+ 'tests',
709
+ 'scripts',
710
+ 'coverage',
711
+ '.DS_Store',
712
+ ]);
630
713
  await cp(src, dest, {
631
714
  recursive: true,
632
715
  filter: (p) => {
@@ -683,9 +766,9 @@ function pluginContentMatches(src, dest) {
683
766
  if (!sEntries) return false;
684
767
  // src should not have files missing from dest
685
768
  for (const e of sEntries) {
686
- if (skipDirs.has(e)) continue;
687
- const sFull = join(s, e);
688
- const dFull = join(d, e);
769
+ if (skipDirs.has(e.name)) continue;
770
+ const sFull = join(s, e.name);
771
+ const dFull = join(d, e.name);
689
772
  try {
690
773
  const sSt = statSync(sFull);
691
774
  if (sSt.isDirectory()) {
@@ -780,7 +863,14 @@ export async function patchClineJson({ dryRun, force }) {
780
863
  }
781
864
 
782
865
  if (!hasEntry) {
783
- plugins.push(['./plugins/bizar/index.ts', {
866
+ // v5.6.0-beta.14: point at the plugin DIRECTORY (not a file inside
867
+ // it). Cline reads `package.json#cline.plugins` from there and loads
868
+ // the entry point declared in the manifest. Pointing at `index.ts`
869
+ // directly used to work, but with the new auto-discovery rules (see
870
+ // https://docs.cline.bot/customization/plugins) it can cause every
871
+ // .ts file under the plugin tree to be loaded as a separate plugin
872
+ // module — producing ~100 `Invalid plugin module` errors at startup.
873
+ plugins.push(['./plugins/bizar', {
784
874
  loopThresholdWarn: 5,
785
875
  loopThresholdEscalate: 8,
786
876
  loopThresholdBlock: 12,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar",
3
- "version": "5.6.0-beta.12",
3
+ "version": "5.6.0-beta.14",
4
4
  "description": "Norse-pantheon multi-agent system for cline — 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, cline plugin, and typed SDK.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polderlabs/bizar-sdk",
3
- "version": "0.2.0-beta.12",
3
+ "version": "0.2.0-beta.14",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@polderlabs/bizar-plugin",
3
+ "version": "5.6.0-beta.14",
4
+ "description": "Bizar Norse-pantheon multi-agent plugin for Cline — 14 agents across 4 cost tiers with cost-aware routing and plans.",
5
+ "type": "module",
6
+ "main": "./index.ts",
7
+ "cline": {
8
+ "plugins": [
9
+ {
10
+ "paths": ["./index.ts"],
11
+ "capabilities": ["tools", "hooks"]
12
+ }
13
+ ]
14
+ },
15
+ "peerDependencies": {
16
+ "@cline/sdk": "*",
17
+ "@cline/core": "*",
18
+ "@cline/shared": "*"
19
+ },
20
+ "peerDependenciesMeta": {
21
+ "@cline/sdk": { "optional": true },
22
+ "@cline/core": { "optional": true },
23
+ "@cline/shared": { "optional": true }
24
+ }
25
+ }