@claw-link/gateway-host 0.4.3 → 0.4.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claw-link/gateway-host",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "ClawLink Host Gateway — a secure, outbound-only worker that bridges a local agent CLI (OpenClaw, Hermes, Claude, Codex, Cursor) to your ClawLink agents. No inbound ports; authenticated per-agent by a Host Token.",
5
5
  "homepage": "https://claw-link.co",
6
6
  "bin": {
@@ -30,21 +30,35 @@ function execSafe(cmd) { try { return execSync(cmd, { stdio: ['ignore', 'pipe',
30
30
  // probe PATH, and if it's missing, do a quiet global install of the same version.
31
31
  function clhostOnPath() {
32
32
  const probe = process.platform === 'win32' ? 'where clhost' : 'command -v clhost';
33
- return execSafe(probe) != null;
34
- }
33
+ const out = execSafe(probe);
34
+ if (!out) return false;
35
+ // `npx` puts a TEMPORARY clhost on PATH for THIS process only (under its cache, e.g. …/_npx/…) —
36
+ // it vanishes when npx exits, so it must NOT count as a persistent install. The old check reported
37
+ // "clhost is ready" during an `npx … install`, but the command was gone in the user's next shell.
38
+ const first = out.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0] || '';
39
+ return !/[\\/]_npx[\\/]/i.test(first);
40
+ }
41
+ // 'ready' — clhost is persistently on PATH (a prior global install).
42
+ // 'installed' — we just ran the global install; it needs a NEW terminal because THIS process runs
43
+ // under npx, whose PATH shadows the freshly-installed global bin.
44
+ // 'failed' — the global install couldn't run (no permission / offline).
35
45
  function ensureGlobalCli() {
36
- if (clhostOnPath()) return true;
46
+ if (clhostOnPath()) return 'ready';
37
47
  try { execSync(`npm install -g @claw-link/gateway-host@${VERSION}`, { stdio: 'ignore', timeout: 120000 }); }
38
- catch { /* no permission / offline — reportCli() prints the manual fallback */ }
39
- return clhostOnPath();
48
+ catch { return 'failed'; }
49
+ return clhostOnPath() ? 'ready' : 'installed';
40
50
  }
41
51
  function reportCli() {
42
- if (ensureGlobalCli()) {
52
+ const r = ensureGlobalCli();
53
+ if (r === 'ready') {
43
54
  console.log(' ✓ The `clhost` command is ready — try: clhost status');
55
+ } else if (r === 'installed') {
56
+ console.log(' ✓ Installed the `clhost` command globally — OPEN A NEW terminal, then: clhost status');
57
+ console.log(' (this window runs under npx, so `clhost` only appears after you reopen the terminal)');
44
58
  } else {
45
- console.log(' ℹ To get the short `clhost` command, install it once (you may need sudo):');
59
+ console.log(' ℹ To get the short `clhost` command, install it once (macOS/Linux may need sudo):');
46
60
  console.log(' npm i -g @claw-link/gateway-host');
47
- console.log(' Until then, run commands as: npx @claw-link/gateway-host <command>');
61
+ console.log(' Until then, run every command as: npx @claw-link/gateway-host <command>');
48
62
  }
49
63
  }
50
64
 
@@ -121,7 +121,16 @@ async function* spawnStreaming({ binary, argv, cwd, env, timeoutMs = 600000, std
121
121
  const isWin = process.platform === 'win32';
122
122
  const useShell = isWin && !/\.(exe|com)$/i.test(String(binary));
123
123
 
124
- const child = spawn(binary, argv, {
124
+ // Windows shell:true builds `cmd /s /c "<binary> <args>"` and does NOT quote the binary, so a
125
+ // path WITH SPACES (e.g. C:\Program Files\…\codex.cmd) is split at the first space → cmd tries to
126
+ // run "C:\Program" ("'C:\Program' is not recognized…"). Quote the binary so it survives cmd's /s
127
+ // quote-stripping. Safe: the binary is the operator-configured PATH (trusted — not untrusted
128
+ // prompt text), and Node still applies its hardened escaping to the (untrusted) args.
129
+ const cmd = (useShell && /\s/.test(String(binary)) && !/^".*"$/.test(String(binary).trim()))
130
+ ? `"${binary}"`
131
+ : binary;
132
+
133
+ const child = spawn(cmd, argv, {
125
134
  cwd: cwd || undefined,
126
135
  // Enriched PATH so a CLI in ~/.local/bin etc. resolves under a service's minimal env.
127
136
  env: enrichedEnv(env),