diff --git a/cli/install.sh b/cli/install.sh index 4ef8a373..4b5a8ab0 100755 --- a/cli/install.sh +++ b/cli/install.sh @@ -139,7 +139,10 @@ clone_cli() { git sparse-checkout set cli 2>/dev/null mv cli "${dest}/cli" cd "${dest}" - rm -rf "${dest}/repo" + # Safety check: only delete if path contains 'repo' and is within dest directory + if [[ "${dest}/repo" == "${dest}/"* ]] && [[ -d "${dest}/repo" ]]; then + rm -rf "${dest}/repo" + fi else log_step "Downloading CLI source..." mkdir -p "${dest}/cli/src" diff --git a/cli/src/__tests__/list-display.test.ts b/cli/src/__tests__/list-display.test.ts index 9c875a61..cfbdf1de 100644 --- a/cli/src/__tests__/list-display.test.ts +++ b/cli/src/__tests__/list-display.test.ts @@ -322,7 +322,10 @@ describe("cmdList output", () => { consoleMocks.error.mockRestore(); processExitMock.mockRestore(); process.env = originalEnv; - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { rmSync(testDir, { recursive: true, force: true }); } catch (err: any) { + // Expected: ENOENT if directory doesn't exist. + if (err.code !== "ENOENT") console.error("Unexpected error removing test directory:", err); + } }); it("should show empty state when no history exists", async () => { diff --git a/cli/src/__tests__/list-filter-suggestions.test.ts b/cli/src/__tests__/list-filter-suggestions.test.ts index 51181ee2..a20c6b22 100644 --- a/cli/src/__tests__/list-filter-suggestions.test.ts +++ b/cli/src/__tests__/list-filter-suggestions.test.ts @@ -230,7 +230,10 @@ describe("cmdList - filter suggestions", () => { global.fetch = originalFetch; restoreMocks(consoleMocks.log, consoleMocks.error); delete process.env.SPAWN_HOME; - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { rmSync(testDir, { recursive: true, force: true }); } catch (err: any) { + // Expected: ENOENT if directory doesn't exist. + if (err.code !== "ENOENT") console.error("Unexpected error removing test directory:", err); + } }); // ── Typo correction for agent filter ──────────────────────────────── diff --git a/cli/src/__tests__/list-prompt-display.test.ts b/cli/src/__tests__/list-prompt-display.test.ts index e6053120..d5f303dd 100644 --- a/cli/src/__tests__/list-prompt-display.test.ts +++ b/cli/src/__tests__/list-prompt-display.test.ts @@ -296,7 +296,10 @@ describe("cmdList prompt display", () => { consoleMocks.log.mockRestore(); consoleMocks.error.mockRestore(); process.env = originalEnv; - try { rmSync(testDir, { recursive: true, force: true }); } catch {} + try { rmSync(testDir, { recursive: true, force: true }); } catch (err: any) { + // Expected: ENOENT if directory doesn't exist. + if (err.code !== "ENOENT") console.error("Unexpected error removing test directory:", err); + } }); describe("prompt preview in record rows", () => { diff --git a/cli/src/__tests__/shared-common-input-validation.test.ts b/cli/src/__tests__/shared-common-input-validation.test.ts index 04056ab3..0b5c9a27 100644 --- a/cli/src/__tests__/shared-common-input-validation.test.ts +++ b/cli/src/__tests__/shared-common-input-validation.test.ts @@ -44,7 +44,10 @@ function runBash( stderr = execSync(`cat /tmp/spawn-test-stderr$$ 2>/dev/null; rm -f /tmp/spawn-test-stderr$$`, { encoding: "utf-8", }); - } catch {} + } catch (err: any) { + // Expected: cat fails if file doesn't exist. Log unexpected command failures. + if (err.status !== 1) console.error("Unexpected error in stderr cleanup:", err); + } return { exitCode: 0, stdout: stdout.trim(), stderr: stderr.trim() }; } catch (err: any) { let stderr = (err.stderr || "").trim(); @@ -53,7 +56,10 @@ function runBash( encoding: "utf-8", }); if (captured.trim()) stderr = captured.trim(); - } catch {} + } catch (captureErr: any) { + // Expected: cat fails if file doesn't exist. + if (captureErr.status !== 1) console.error("Unexpected error capturing stderr:", captureErr); + } return { exitCode: err.status ?? 1, stdout: (err.stdout || "").trim(), @@ -82,16 +88,26 @@ function runBashCapture( let stderr = ""; try { stderr = execSync(`cat "${stderrFile}" 2>/dev/null`, { encoding: "utf-8" }); - } catch {} - try { execSync(`rm -f "${stderrFile}"`); } catch {} + } catch (err: any) { + // Expected: cat fails if file doesn't exist. + if (err.status !== 1) console.error("Unexpected error reading stderr file:", err); + } + try { execSync(`rm -f "${stderrFile}"`); } catch (err: any) { + console.error("Unexpected error removing stderr file:", err); + } return { exitCode: 0, stdout: stdout.trim(), stderr: stderr.trim() }; } catch (err: any) { let stderr = (err.stderr || "").trim(); try { const captured = execSync(`cat "${stderrFile}" 2>/dev/null`, { encoding: "utf-8" }); if (captured.trim()) stderr = captured.trim(); - } catch {} - try { execSync(`rm -f "${stderrFile}"`); } catch {} + } catch (captureErr: any) { + // Expected: cat fails if file doesn't exist. + if (captureErr.status !== 1) console.error("Unexpected error capturing stderr:", captureErr); + } + try { execSync(`rm -f "${stderrFile}"`); } catch (rmErr: any) { + console.error("Unexpected error removing stderr file:", rmErr); + } return { exitCode: err.status ?? 1, stdout: (err.stdout || "").trim(), diff --git a/cli/src/__tests__/shared-common-oauth-security.test.ts b/cli/src/__tests__/shared-common-oauth-security.test.ts index 68e012f0..99fa904c 100644 --- a/cli/src/__tests__/shared-common-oauth-security.test.ts +++ b/cli/src/__tests__/shared-common-oauth-security.test.ts @@ -82,7 +82,10 @@ function runBashHeredoc( } finally { try { rmSync(tmpFile); - } catch {} + } catch (err: any) { + // Expected: ENOENT if file was already deleted. + if (err.code !== "ENOENT") console.error("Unexpected error removing temp file:", err); + } } } diff --git a/cli/src/__tests__/shared-common-token-provider.test.ts b/cli/src/__tests__/shared-common-token-provider.test.ts index 5a0bb067..85746ee0 100644 --- a/cli/src/__tests__/shared-common-token-provider.test.ts +++ b/cli/src/__tests__/shared-common-token-provider.test.ts @@ -62,13 +62,22 @@ function runBash(script: string): { exitCode: number; stdout: string; stderr: st } ); let stderr = ""; - try { stderr = readFileSync(stderrFile, "utf-8"); } catch {} - try { rmSync(stderrFile, { force: true }); } catch {} + try { stderr = readFileSync(stderrFile, "utf-8"); } catch (err: any) { + // Expected: ENOENT if stderr file wasn't created. Log unexpected errors. + if (err.code !== "ENOENT") console.error("Unexpected error reading stderr:", err); + } + try { rmSync(stderrFile, { force: true }); } catch (err: any) { + if (err.code !== "ENOENT") console.error("Unexpected error removing stderr file:", err); + } return { exitCode: 0, stdout: stdout.trim(), stderr: stderr.trim() }; } catch (err: any) { let stderr = (err.stderr || "").trim(); - try { stderr = readFileSync(stderrFile, "utf-8").trim() || stderr; } catch {} - try { rmSync(stderrFile, { force: true }); } catch {} + try { stderr = readFileSync(stderrFile, "utf-8").trim() || stderr; } catch (readErr: any) { + if (readErr.code !== "ENOENT") console.error("Unexpected error reading stderr:", readErr); + } + try { rmSync(stderrFile, { force: true }); } catch (rmErr: any) { + if (rmErr.code !== "ENOENT") console.error("Unexpected error removing stderr file:", rmErr); + } return { exitCode: err.status ?? 1, stdout: (err.stdout || "").trim(), diff --git a/shared/common.sh b/shared/common.sh index 50e818d2..f44729af 100644 --- a/shared/common.sh +++ b/shared/common.sh @@ -719,8 +719,11 @@ wait_for_oauth_code() { while [[ ! -f "${code_file}" ]] && [[ ${elapsed} -lt ${timeout} ]]; do sleep "${POLL_INTERVAL}" # Use python3 for float addition since bash arithmetic only handles integers - # If POLL_INTERVAL is 0.5, bash $(( )) would fail. Fallback keeps timeout working. - elapsed=$(python3 -c "print(int(${elapsed} + ${POLL_INTERVAL}))" 2>/dev/null || echo "$((elapsed + 1))") + # If POLL_INTERVAL is 0.5, bash $(( )) would fail. Fallback to integer increment. + if ! elapsed=$(python3 -c "print(int(${elapsed} + ${POLL_INTERVAL}))" 2>/dev/null); then + # Python failed (not installed or syntax error) - fallback to integer increment + elapsed=$((elapsed + 1)) + fi done [[ -f "${code_file}" ]]