claudeboard 2.15.3 → 2.15.4

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.
@@ -10,6 +10,9 @@ import { createConnection } from "net";
10
10
  import { spawn as _spawn, execSync } from "child_process";
11
11
 
12
12
  const require = createRequire(import.meta.url);
13
+ // On Windows, npm-installed binaries have a .cmd wrapper — use it for spawn()
14
+ const isWin = process.platform === "win32";
15
+ const NPX = isWin ? "npx.cmd" : "npx";
13
16
  const MAX_FIX_ATTEMPTS = 5;
14
17
  const BUILD_HASH_FILE = ".claudeboard-build-hash.txt";
15
18
  const BUILD_TIMEOUT_MS = 10 * 60 * 1000; // 10 min max for expo run:ios
@@ -244,7 +247,7 @@ export async function ensureDevBuild(projectPath) {
244
247
  }, BUILD_TIMEOUT_MS);
245
248
 
246
249
  try {
247
- const proc = _spawn("npx", ["expo", "run:ios", "--simulator"], {
250
+ const proc = _spawn(NPX, ["expo", "run:ios", "--simulator"], {
248
251
  cwd: projectPath,
249
252
  env: { ...process.env, CI: "1", EXPO_NO_INTERACTIVE: "1" },
250
253
  stdio: "pipe",
@@ -386,7 +389,7 @@ async function tryStartExpo(projectPath, port) {
386
389
  ? ["expo", "start", "--ios", "--port", String(port)]
387
390
  : ["expo", "start", "--web", "--port", String(port)];
388
391
 
389
- proc = _spawn("npx", expoArgs, {
392
+ proc = _spawn(NPX, expoArgs, {
390
393
  cwd: projectPath,
391
394
  env: (() => { const e = { ...process.env, CI: "1", EXPO_NO_INTERACTIVE: "1", EXPO_NO_DOTENV: "0" }; delete e.ANTHROPIC_API_KEY; return e; })(),
392
395
  stdio: "pipe",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeboard",
3
- "version": "2.15.3",
3
+ "version": "2.15.4",
4
4
  "description": "AI engineering team — from PRD to working mobile app, autonomously",
5
5
  "type": "module",
6
6
  "bin": {
package/tools/terminal.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { exec, spawn } from "child_process";
2
2
  import { promisify } from "util";
3
+ import { createConnection } from "net";
3
4
 
4
5
  const execAsync = promisify(exec);
6
+ const isWin = process.platform === "win32";
5
7
 
6
8
  /**
7
9
  * Run a shell command in a given directory, return { stdout, stderr, exitCode }
@@ -12,6 +14,7 @@ export async function runCommand(cmd, cwd, timeoutMs = 60000) {
12
14
  cwd,
13
15
  timeout: timeoutMs,
14
16
  env: { ...process.env, CI: "true", FORCE_COLOR: "0" },
17
+ shell: isWin ? "cmd.exe" : "/bin/sh",
15
18
  });
16
19
  return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode: 0 };
17
20
  } catch (err) {
@@ -43,15 +46,17 @@ export function startProcess(cmd, args, cwd, onLog) {
43
46
  }
44
47
 
45
48
  /**
46
- * Check if a port is in use
49
+ * Check if a port is in use — uses a TCP connection probe (cross-platform, no curl needed)
47
50
  */
48
51
  export async function waitForPort(port, timeoutMs = 30000) {
49
52
  const start = Date.now();
50
53
  while (Date.now() - start < timeoutMs) {
51
- try {
52
- const result = await execAsync(`curl -s -o /dev/null -w "%{http_code}" http://localhost:${port}`);
53
- if (result.stdout !== "000") return true;
54
- } catch {}
54
+ const open = await new Promise((resolve) => {
55
+ const sock = createConnection({ port, host: "127.0.0.1" });
56
+ sock.once("connect", () => { sock.destroy(); resolve(true); });
57
+ sock.once("error", () => { sock.destroy(); resolve(false); });
58
+ });
59
+ if (open) return true;
55
60
  await new Promise((r) => setTimeout(r, 1000));
56
61
  }
57
62
  return false;