@pushpalsdev/cli 1.0.95 → 1.0.96

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": "@pushpalsdev/cli",
3
- "version": "1.0.95",
3
+ "version": "1.0.96",
4
4
  "description": "PushPals terminal CLI for LocalBuddy -> RemoteBuddy orchestration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -369,21 +369,41 @@ def _normalize_choice(
369
369
  return default
370
370
 
371
371
 
372
- def _is_git_repo(repo: str) -> bool:
373
- try:
374
- proc = subprocess.run(
375
- ["git", "rev-parse", "--is-inside-work-tree"],
376
- cwd=repo,
377
- capture_output=True,
378
- text=True,
379
- timeout=10,
380
- check=False,
381
- )
382
- if proc.returncode != 0:
372
+ def _is_git_repo(repo: str, timeout_seconds: float = 5.0, poll_seconds: float = 0.1) -> bool:
373
+ deadline = time.monotonic() + max(0.0, timeout_seconds)
374
+ last_detail = ""
375
+ attempts = 0
376
+
377
+ while True:
378
+ attempts += 1
379
+ try:
380
+ proc = subprocess.run(
381
+ ["git", "rev-parse", "--is-inside-work-tree"],
382
+ cwd=repo,
383
+ capture_output=True,
384
+ text=True,
385
+ timeout=10,
386
+ check=False,
387
+ )
388
+ if proc.returncode == 0 and (proc.stdout or "").strip().lower() == "true":
389
+ return True
390
+ last_detail = "\n".join(
391
+ part.strip()
392
+ for part in [proc.stderr or "", proc.stdout or ""]
393
+ if part and part.strip()
394
+ )
395
+ except Exception as exc:
396
+ last_detail = str(exc)
397
+
398
+ if time.monotonic() >= deadline:
399
+ if last_detail:
400
+ log.warning(
401
+ "Git repository preflight failed "
402
+ f"after {attempts} attempt(s) for {repo}: {to_single_line(last_detail, 240)}"
403
+ )
383
404
  return False
384
- return (proc.stdout or "").strip().lower() == "true"
385
- except Exception:
386
- return False
405
+
406
+ time.sleep(max(0.01, poll_seconds))
387
407
 
388
408
 
389
409
  def _codex_project_config_roots(repo: str, env: Dict[str, str]) -> List[Path]:
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "crypto";
2
- import { existsSync, mkdirSync } from "fs";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
3
  import { homedir, tmpdir } from "os";
4
4
  import { basename, resolve } from "path";
5
5
 
@@ -33,6 +33,18 @@ function ensureDirs(paths: string[]): void {
33
33
  }
34
34
  }
35
35
 
36
+ function ensureSandboxGitConfig(homeDir: string): void {
37
+ const gitConfigPath = resolve(homeDir, ".gitconfig");
38
+ try {
39
+ const existing = existsSync(gitConfigPath) ? readFileSync(gitConfigPath, "utf8") : "";
40
+ if (/(^|\n)\s*directory\s*=\s*\*/.test(existing)) return;
41
+ const prefix = existing.trim() ? `${existing.replace(/\s+$/, "")}\n\n` : "";
42
+ writeFileSync(gitConfigPath, `${prefix}[safe]\n\tdirectory = *\n`, "utf8");
43
+ } catch {
44
+ // Best effort: git will surface any remaining safe.directory blocker.
45
+ }
46
+ }
47
+
36
48
  function resolveOriginalHome(env: Record<string, string>): string {
37
49
  return env.HOME || env.USERPROFILE || homedir();
38
50
  }
@@ -56,6 +68,7 @@ export function buildWorkerSandboxWritableEnv(
56
68
  const expoDir = resolve(baseDir, "expo");
57
69
  const defaultExpoPort = defaultExpoPortForRepo(repo);
58
70
  ensureDirs([homeDir, cacheDir, expoDir, resolve(cacheDir, "npm")]);
71
+ ensureSandboxGitConfig(homeDir);
59
72
 
60
73
  return {
61
74
  ...env,