wisp-router 2.0.0 → 2.0.1

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.
@@ -2,4 +2,4 @@
2
2
  // ---------- claude-wisp.js — npm thin shell: same binary, claude-wisp dispatch token ---------- //
3
3
 
4
4
  // One compiled binary serves both bins — `wisp claude-wisp …` reaches the launcher (#67).
5
- require('./wisp.js').run(['claude-wisp']);
5
+ void require('./wisp.js').run(['claude-wisp']);
package/bin/wisp.js CHANGED
@@ -3,44 +3,95 @@
3
3
 
4
4
  /*
5
5
  * Depends on:
6
- * - child_process (node stdlib): spawnSync with inherited stdio the binary owns the terminal.
6
+ * - child_process / fs / path / os / https (node stdlib): resolve, download, and run the
7
+ * bun-compiled `wisp` binary with inherited stdio — the binary owns the terminal.
7
8
  *
8
- * Data shapes: none. The real program is the bun-compiled `wisp` binary shipped by the
9
- * per-platform optionalDependency (esbuild/biome pattern); this shim only resolves and runs it.
9
+ * Data shapes: none. The real program ships two ways (esbuild pattern): a per-platform
10
+ * optionalDependency when npm serves it, else a one-time download of the same binary from the
11
+ * GitHub release into ~/.wisp/bin (npm's spam filter has taken the platform packages down before
12
+ * — the fallback keeps installs working regardless).
10
13
  */
11
14
 
12
15
  const { spawnSync } = require('child_process');
16
+ const fs = require('fs');
17
+ const os = require('os');
18
+ const path = require('path');
13
19
 
14
- // platform-arch the optionalDependency that carries its compiled binary.
20
+ const VERSION = require('../package.json').version;
21
+ const RELEASE_BASE = `https://github.com/EstarinAzx/Wisp-Router/releases/download/v${VERSION}`;
22
+
23
+ // platform-arch → optionalDependency name + GitHub release asset name.
15
24
  // ponytail: musl (Alpine) matches linux-x64 but the glibc-linked binary fails at dlopen —
16
25
  // add a musl probe with a plain error if it ever bites.
17
- const PLATFORM_PACKAGES = {
18
- 'win32-x64': '@tsd47216/wisp-router-win32-x64',
19
- 'darwin-arm64': '@tsd47216/wisp-router-darwin-arm64',
20
- 'darwin-x64': '@tsd47216/wisp-router-darwin-x64',
21
- 'linux-x64': '@tsd47216/wisp-router-linux-x64',
26
+ const PLATFORMS = {
27
+ 'win32-x64': { pkg: '@tsd47216/wisp-router-win32-x64', asset: `wisp-v${VERSION}-win32-x64.exe` },
28
+ 'darwin-arm64': { pkg: '@tsd47216/wisp-router-darwin-arm64', asset: `wisp-v${VERSION}-darwin-arm64` },
29
+ 'darwin-x64': { pkg: '@tsd47216/wisp-router-darwin-x64', asset: `wisp-v${VERSION}-darwin-x64` },
30
+ 'linux-x64': { pkg: '@tsd47216/wisp-router-linux-x64', asset: `wisp-v${VERSION}-linux-x64` },
31
+ };
32
+
33
+ const BIN_NAME = process.platform === 'win32' ? 'wisp.exe' : 'wisp';
34
+
35
+ // ----------------------------- Release-asset download (fallback) ----------------------------- //
36
+
37
+ // GET following redirects (GitHub release assets 302 to storage) onto a temp file, then rename —
38
+ // a killed download never leaves a half-written "binary" behind.
39
+ const download = (url, dest, redirects = 0) =>
40
+ new Promise((resolve, reject) => {
41
+ if (redirects > 5) return reject(new Error('too many redirects'));
42
+ require('https').get(url, (res) => {
43
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
44
+ res.resume();
45
+ return resolve(download(res.headers.location, dest, redirects + 1));
46
+ }
47
+ if (res.statusCode !== 200) {
48
+ res.resume();
49
+ return reject(new Error(`download failed: HTTP ${res.statusCode} for ${url}`));
50
+ }
51
+ const tmp = `${dest}.tmp-${process.pid}`;
52
+ const out = fs.createWriteStream(tmp);
53
+ res.pipe(out);
54
+ out.on('finish', () => out.close(() => { fs.renameSync(tmp, dest); resolve(); }));
55
+ out.on('error', (err) => { fs.rmSync(tmp, { force: true }); reject(err); });
56
+ }).on('error', reject);
57
+ });
58
+
59
+ const fetchBinary = async (platform) => {
60
+ const dir = path.join(os.homedir(), '.wisp', 'bin', `v${VERSION}`);
61
+ const file = path.join(dir, BIN_NAME);
62
+ if (!fs.existsSync(file)) {
63
+ console.error(`wisp-router: downloading ${platform.asset} from the GitHub release (one-time)…`);
64
+ fs.mkdirSync(dir, { recursive: true });
65
+ await download(`${RELEASE_BASE}/${platform.asset}`, file);
66
+ if (process.platform !== 'win32') fs.chmodSync(file, 0o755);
67
+ }
68
+ return file;
22
69
  };
23
70
 
24
- const resolveBinary = () => {
71
+ // ----------------------------- Resolve + run ----------------------------- //
72
+
73
+ const resolveBinary = async () => {
25
74
  const key = `${process.platform}-${process.arch}`;
26
- const pkg = PLATFORM_PACKAGES[key];
27
- if (!pkg) {
28
- console.error(`wisp-router: unsupported platform ${key} (supported: ${Object.keys(PLATFORM_PACKAGES).join(', ')})`);
75
+ const platform = PLATFORMS[key];
76
+ if (!platform) {
77
+ console.error(`wisp-router: unsupported platform ${key} (supported: ${Object.keys(PLATFORMS).join(', ')})`);
29
78
  process.exit(1);
30
79
  }
31
- try {
32
- return require.resolve(`${pkg}/bin/${process.platform === 'win32' ? 'wisp.exe' : 'wisp'}`);
33
- } catch {
34
- console.error(`wisp-router: platform package ${pkg} is missing — reinstall without --no-optional/--omit=optional.`);
80
+ // The optionalDependency wins when npm delivered it; otherwise the release download.
81
+ try { return require.resolve(`${platform.pkg}/bin/${BIN_NAME}`); } catch {}
82
+ try { return await fetchBinary(platform); } catch (err) {
83
+ console.error(`wisp-router: could not get the platform binary: ${err.message}`);
84
+ console.error(`Grab it manually: ${RELEASE_BASE}/${platform.asset}`);
35
85
  process.exit(1);
36
86
  }
37
87
  };
38
88
 
39
89
  // Run the binary with extra leading args (the claude-wisp shim passes its dispatch token here).
40
- const run = (extraArgs) => {
90
+ const run = async (extraArgs) => {
91
+ const binary = await resolveBinary();
41
92
  // Ctrl+C belongs to the child (TUI / claude handle their own); default would kill this shim first.
42
93
  process.on('SIGINT', () => {});
43
- const result = spawnSync(resolveBinary(), [...extraArgs, ...process.argv.slice(2)], { stdio: 'inherit' });
94
+ const result = spawnSync(binary, [...extraArgs, ...process.argv.slice(2)], { stdio: 'inherit' });
44
95
  if (result.error) {
45
96
  console.error(`wisp-router: failed to start the platform binary: ${result.error.message}`);
46
97
  process.exit(1);
@@ -49,4 +100,4 @@ const run = (extraArgs) => {
49
100
  };
50
101
 
51
102
  module.exports = { run };
52
- if (require.main === module) run([]);
103
+ if (require.main === module) void run([]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wisp-router",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Wisp — BYOK model router: terminal UI, local Bridge (OpenAI + Anthropic doors), and the claude-wisp launcher for Claude Code",
5
5
  "bin": {
6
6
  "wisp": "bin/wisp.js",
@@ -17,9 +17,9 @@
17
17
  "node": ">=16"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@tsd47216/wisp-router-win32-x64": "2.0.0",
21
- "@tsd47216/wisp-router-darwin-arm64": "2.0.0",
22
- "@tsd47216/wisp-router-darwin-x64": "2.0.0",
23
- "@tsd47216/wisp-router-linux-x64": "2.0.0"
20
+ "@tsd47216/wisp-router-win32-x64": "2.0.1",
21
+ "@tsd47216/wisp-router-darwin-arm64": "2.0.1",
22
+ "@tsd47216/wisp-router-darwin-x64": "2.0.1",
23
+ "@tsd47216/wisp-router-linux-x64": "2.0.1"
24
24
  }
25
25
  }