synabun 2026.4.20-beta.4 → 2026.4.20-beta.6

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.
@@ -13,7 +13,6 @@
13
13
  "postinstall": "node scripts/rebuild-pty.js"
14
14
  },
15
15
  "dependencies": {
16
- "@anthropic-ai/claude-code": "^2.1.71",
17
16
  "@huggingface/transformers": "^3.0.0",
18
17
  "@openai/codex-sdk": "^0.121.0",
19
18
  "adm-zip": "^0.5.16",
@@ -9818,6 +9818,57 @@ function buildUpdateCommand(toolKey, installSource) {
9818
9818
  return `npm install -g ${npmPkg}@latest`;
9819
9819
  }
9820
9820
 
9821
+ // Resolve SynaBun's own install roots so we can reject any tool binary that
9822
+ // lives inside our bundled node_modules — bulletproof guard for the recurring
9823
+ // phantom-version bug (e.g. stale @anthropic-ai/claude-code left over from
9824
+ // prior SynaBun installs that shipped it as a dependency, which `npm install`
9825
+ // does not auto-prune when removed from package.json).
9826
+ const SYNABUN_ROOTS = (() => {
9827
+ const roots = new Set();
9828
+ try { roots.add(realpathSync(__dirname).replace(/\\/g, '/').toLowerCase()); } catch {}
9829
+ try { roots.add(realpathSync(resolve(__dirname, '..')).replace(/\\/g, '/').toLowerCase()); } catch {}
9830
+ return [...roots];
9831
+ })();
9832
+
9833
+ function isInsideSynabun(binPath) {
9834
+ if (!binPath) return false;
9835
+ try {
9836
+ const resolved = realpathSync(binPath).replace(/\\/g, '/').toLowerCase();
9837
+ return SYNABUN_ROOTS.some(root => resolved.startsWith(root + '/'));
9838
+ } catch {
9839
+ const norm = binPath.replace(/\\/g, '/').toLowerCase();
9840
+ return SYNABUN_ROOTS.some(root => norm.startsWith(root + '/'));
9841
+ }
9842
+ }
9843
+
9844
+ // Aggressively delete any stale bundled CLI tool packages left over in our
9845
+ // own node_modules. Idempotent — runs on every startup. Belt-and-suspenders
9846
+ // against `npm install` not auto-pruning packages removed from package.json.
9847
+ function pruneBundledCliTools() {
9848
+ const stalePkgs = ['@anthropic-ai/claude-code', '@openai/codex', 'opencode-ai', '@google/gemini-cli'];
9849
+ const moduleRoots = [
9850
+ join(__dirname, 'node_modules'),
9851
+ join(__dirname, '..', 'node_modules'),
9852
+ ];
9853
+ for (const root of moduleRoots) {
9854
+ for (const pkg of stalePkgs) {
9855
+ const target = join(root, pkg);
9856
+ try {
9857
+ if (existsSync(target)) {
9858
+ rmSync(target, { recursive: true, force: true });
9859
+ console.log(` Pruned stale bundled CLI: ${target}`);
9860
+ }
9861
+ } catch { /* permission or in-use — ignore */ }
9862
+ // Also remove .bin shims that point at the deleted package
9863
+ const binBase = pkg.split('/').pop().replace(/-cli$|-ai$/, '');
9864
+ for (const ext of ['', '.cmd', '.ps1', '.exe']) {
9865
+ const shim = join(root, '.bin', binBase + ext);
9866
+ try { if (existsSync(shim)) rmSync(shim, { force: true }); } catch {}
9867
+ }
9868
+ }
9869
+ }
9870
+ }
9871
+
9821
9872
  async function checkToolVersions() {
9822
9873
  // Strip node_modules/.bin entries so the version check reflects the user's
9823
9874
  // global install rather than any copy bundled with SynaBun itself.
@@ -9831,11 +9882,20 @@ async function checkToolVersions() {
9831
9882
  const results = {};
9832
9883
 
9833
9884
  for (const tool of TOOL_DEFS) {
9885
+ // Resolve binary path FIRST. If it lives inside SynaBun's own install
9886
+ // dir (stale bundled copy), treat the tool as not installed — do NOT
9887
+ // run --version against it, since that would report the bundled
9888
+ // version and trigger a false-positive update badge.
9889
+ const probedBinPath = resolveBinPath(tool.cmd, cleanEnv);
9890
+ const isStaleBundle = isInsideSynabun(probedBinPath);
9891
+
9834
9892
  let installed = null;
9835
- try {
9836
- const raw = execSync(`${tool.cmd} ${tool.versionArg}`, execOpts).trim();
9837
- installed = parseVersion(raw);
9838
- } catch { /* not installed or errored */ }
9893
+ if (!isStaleBundle) {
9894
+ try {
9895
+ const raw = execSync(`${tool.cmd} ${tool.versionArg}`, execOpts).trim();
9896
+ installed = parseVersion(raw);
9897
+ } catch { /* not installed or errored */ }
9898
+ }
9839
9899
 
9840
9900
  let latest = null;
9841
9901
  try {
@@ -9852,7 +9912,7 @@ async function checkToolVersions() {
9852
9912
  }
9853
9913
  } catch { /* network error */ }
9854
9914
 
9855
- const binPath = installed ? resolveBinPath(tool.cmd, cleanEnv) : null;
9915
+ const binPath = installed ? probedBinPath : null;
9856
9916
  const installSource = detectInstallSource(binPath);
9857
9917
  const updateCommand = installed ? buildUpdateCommand(tool.key, installSource) : null;
9858
9918
 
@@ -21082,6 +21142,12 @@ const httpServer = app.listen(PORT, async () => {
21082
21142
  // Check for npm updates
21083
21143
  try { await checkNpmUpdate(); } catch {}
21084
21144
 
21145
+ // Aggressively prune any stale bundled CLI tools left in our node_modules
21146
+ // before the version check runs — defends against `npm install` not auto-
21147
+ // pruning packages that were removed from package.json (recurring source of
21148
+ // phantom-version badges, e.g. v2.1.89 from a stale @anthropic-ai/claude-code).
21149
+ try { pruneBundledCliTools(); } catch {}
21150
+
21085
21151
  // Check for CLI tool updates
21086
21152
  try { await checkToolVersions(); } catch {}
21087
21153
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synabun",
3
- "version": "2026.4.20-beta.4",
3
+ "version": "2026.4.20-beta.6",
4
4
  "description": "Persistent vector memory for AI assistants",
5
5
  "license": "Apache-2.0",
6
6
  "author": "The SynaBun Authors",
@@ -59,8 +59,5 @@
59
59
  },
60
60
  "engines": {
61
61
  "node": ">=22.0.0"
62
- },
63
- "dependencies": {
64
- "@anthropic-ai/claude-code": "^2.1.91"
65
62
  }
66
63
  }