Skip to content

Commit d2a66f3

Browse files
avivsinaiclaude
andauthored
fix: resolve CLI update/uninstall TTY detection and re-exec issues (#34)
* fix: implement hardened re-exec after update finalization Fixes #33 After running 'promptcode update' on Unix/macOS, the first '--version' command now correctly shows the new version instead of the old one. Changes: - Add early-update.ts with production-ready finalization logic - Use spawnSync instead of execSync for safer execution - Add exclusive locking to prevent race conditions - Implement atomic operations with rollback capability - Properly propagate exit codes and signals - Handle symlinks, permissions, and platform differences - Clean up old backup files automatically The implementation follows industry best practices and handles all identified edge cases including shell escaping, signal handling, concurrent invocations, and permission preservation. * feat: add debug logging to backup cleanup for better diagnostics - Added debug logging when DEBUG=promptcode is set - Tracks cleanup success/failure counts - Helps diagnose issues with backup file deletion - Confirmed cleanup is working correctly (was blocked by stale locks) * fix: implement all critical fixes from GPT-5 review Implements all must-fix items identified in expert review: Critical Fixes: - Lock lifetime: Released immediately after swap (was held for entire child duration) - Stale lock detection: Added metadata and process checking - Backup cleanup: Fixed dead code path, cleanup happens after child success - Signal propagation: Re-raise actual signals instead of exit codes - Preflight check: Test staged binary before swap Additional Improvements: - Security: Verify staged is regular file, check managed installations - Error handling: Specific messages for ENOSPC, EACCES, EPERM - Platform support: Remove macOS quarantine, handle missing hard links - Debug logging: Comprehensive logging with DEBUG=promptcode All tests passing, production ready. * fix: address all blockers and improvements from colleague review Blockers fixed: 1. Moved permissions/quarantine removal BEFORE preflight check - Prevents false rejections of legitimate staged binaries - Ensures quarantined files are cleaned before testing 2. Fixed EPERM handling in stale lock detection - Only treat ESRCH (no such process) as stale - EPERM (permission denied) means process exists -> not stale - Prevents incorrectly removing valid locks on multi-user systems Improvements: - Clear PROMPTCODE_REEXEC_DEPTH env var after finalization - Fix permission comparison mask (use 0o7777 on both sides) - Improve version string formatting (avoid double 'v' prefix) - Add environment isolation to preflight check - Be conservative on unknown errors in stale lock detection All tests passing. Ready for production. * removed redudandant temp file * feat: add comprehensive E2E tests for installation and update features - Add E2E tests for self-update flow with mock GitHub API server - Add E2E tests for installer scripts (both Unix and Windows) - Add E2E tests for early update finalizer with concurrency testing - Add centralized asset naming module to prevent platform inconsistencies - Fix production bug: Git Bash detection now properly exits with error - Add test helper utilities for isolated CLI execution - Ensure all tests pass (152 tests, 0 failures) Key improvements: - Self-update tests verify checksum validation and staged file handling - Installer tests verify Git Bash rejection and architecture detection - Concurrent finalization tests verify exclusive locking mechanism - All E2E tests use realistic scenarios without PROMPTCODE_TEST=1 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * fix: add PROMPTCODE_ALLOW_INSECURE env var for PowerShell installer test The installer test was failing because our recent security changes require both -Insecure flag AND PROMPTCODE_ALLOW_INSECURE=1 in CI environments. This ensures the Windows installer test passes. * 0.6.14 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>
1 parent 3d68de0 commit d2a66f3

26 files changed

+1617
-126
lines changed

.claude/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
{}
1+
{
2+
"permissions": {
3+
"allow": [
4+
"bun"
5+
]
6+
}
7+
}

.claude/settings.local.json

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,50 @@
296296
"Bash(PROMPTCODE_TEST=1 CI=true bun test --bail=1)",
297297
"Bash(XDG_CONFIG_HOME=/tmp/test-xdg-config XDG_CACHE_HOME=/tmp/test-xdg-cache node -e:*)",
298298
"Bash(PROMPTCODE_TEST=1 ./dist/promptcode preset create test-mixed --from-files \"src/**/*.ts\" \"src/utils\" \"package.json\" \"README.md\" --path /tmp/test-promptcode)",
299-
"Bash(PROMPTCODE_TEST=1 ./dist/promptcode preset create test-real-mixed --from-files \"src/**/*.ts\" \"src/utils\" \"test\" \"package.json\")"
299+
"Bash(PROMPTCODE_TEST=1 ./dist/promptcode preset create test-real-mixed --from-files \"src/**/*.ts\" \"src/utils\" \"test\" \"package.json\")",
300+
"Bash(/tmp/test-promptcode:*)",
301+
"Bash(PROMPTCODE_SKIP_FINALIZE=1 PROMPTCODE_TEST=1 bun test test/cli-parsing.test.ts)",
302+
"Bash(\"packages/cli/src/index.ts\" )",
303+
"Bash(\"packages/cli/src/commands/update.ts\" )",
304+
"Bash(\"packages/cli/final-review-prompt.md\" )",
305+
"Bash(\"packages/cli/test-results.md\" )",
306+
"Bash(\"test/**/*.test.ts\" )",
307+
"Bash(\"test/**/*.ts\" )",
308+
"Bash(\"src/early-update.ts\" )",
309+
"Bash(\"src/commands/update.ts\" )",
310+
"Bash(\"src/commands/uninstall.ts\" )",
311+
"Bash(\"src/utils/update-checker.ts\" )",
312+
"Bash(\"scripts/install.sh\" )",
313+
"Bash(\"scripts/install.ps1\" )",
314+
"Bash(\"package.json\" )",
315+
"Bash(\"bun.lockb\" )",
316+
"Bash(\".github/workflows/build-cli.yml\" )",
317+
"Bash(\".github/workflows/promote-cli.yml\")",
318+
"Bash(\"packages/cli/test/**/*.test.ts\" )",
319+
"Bash(\"packages/cli/test/**/*.ts\" )",
320+
"Bash(\"packages/cli/src/commands/update.ts\" )",
321+
"Bash(\"packages/cli/src/commands/uninstall.ts\" )",
322+
"Bash(\"packages/cli/src/utils/update-checker.ts\" )",
323+
"Bash(\"packages/cli/src/utils/paths.ts\" )",
324+
"Bash(\"packages/cli/scripts/install.sh\" )",
325+
"Bash(\"packages/cli/scripts/install.ps1\" )",
326+
"Bash(\"packages/cli/package.json\" )",
327+
"Bash(\".github/workflows/build-cli.yml\")",
328+
"Bash(\"packages/cli/src/commands/update.ts\" )",
329+
"Bash(\"packages/cli/src/commands/uninstall.ts\" )",
330+
"Bash(\"packages/cli/src/utils/update-checker.ts\" )",
331+
"Bash(\"packages/cli/src/utils/paths.ts\" )",
332+
"Bash(\"packages/cli/scripts/install.sh\" )",
333+
"Bash(\"packages/cli/scripts/install.ps1\" )",
334+
"Bash(\"packages/cli/test/e2e/self-update.test.ts\" )",
335+
"Bash(\"packages/cli/test/e2e/installer.test.ts\" )",
336+
"Bash(\"packages/cli/package.json\" )",
337+
"Bash(\"packages/cli/test/e2e/self-update.test.ts\" )",
338+
"Bash(\"packages/cli/test/e2e/installer.test.ts\" )",
339+
"Bash(\"packages/cli/test/e2e/early-finalizer.test.ts\" )",
340+
"Bash(\"packages/cli/src/commands/update.ts\" )",
341+
"Bash(\"packages/cli/src/utils/environment.ts\" )",
342+
"Bash(\"packages/cli/package.json\")"
300343
],
301344
"deny": [],
302345
"defaultMode": "acceptEdits",

.github/workflows/test-installer.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ jobs:
122122
}
123123
124124
# Run installer (with -Insecure for CI testing, since checksum might fail)
125+
# Need to set PROMPTCODE_ALLOW_INSECURE=1 for CI as per recent security changes
126+
$env:PROMPTCODE_ALLOW_INSECURE = "1"
125127
try {
126128
& packages/cli/scripts/install.ps1 -Insecure
127129
} catch {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# cli-testing-review preset
2+
# Generated: 2025-08-31T14:24:22.759Z
3+
# Source: mixed (2 patterns preserved, 9 files → 8 patterns)
4+
# Patterns preserved as provided: 2
5+
# Optimization: balanced
6+
# Optimized: 8 files → 8 patterns (saved 0)
7+
# Applied rules:
8+
# - dir-extension: packages/cli/scripts *.ps1
9+
10+
packages/cli/test/**/*.test.ts
11+
packages/cli/test/**/*.ts
12+
packages/cli/scripts/*.ps1
13+
packages/cli/package.json
14+
packages/cli/scripts/install.sh
15+
packages/cli/src/commands/uninstall.ts
16+
packages/cli/src/commands/update.ts
17+
packages/cli/src/early-update.ts
18+
packages/cli/src/utils/paths.ts
19+
packages/cli/src/utils/update-checker.ts
20+
!**/node_modules/**
21+
!**/dist/**
22+
!**/build/**
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# e2e-test-fixes preset
2+
# Generated: 2025-08-31T19:29:24.389Z
3+
4+
!**/node_modules/**
5+
!**/dist/**
6+
!**/build/**
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# final-update-review preset
2+
# Generated: 2025-08-31T12:04:22.287Z
3+
4+
!**/node_modules/**
5+
!**/dist/**
6+
!**/build/**
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# installation-feature-complete preset
2+
# Generated: 2025-08-31T12:07:47.966Z
3+
# Source: mixed (2 patterns preserved, 16 files → 15 patterns)
4+
# Patterns preserved as provided: 2
5+
# Optimization: balanced
6+
# Optimized: 15 files → 15 patterns (saved 0)
7+
# Applied rules:
8+
# - dir-extension: packages/cli/scripts *.ps1
9+
10+
packages/cli/test/**/*.test.ts
11+
packages/cli/test/**/*.ts
12+
packages/cli/scripts/*.ps1
13+
.github/workflows/promote-cli.yml
14+
packages/cli/README.md
15+
packages/cli/package.json
16+
packages/cli/scripts/install.sh
17+
packages/cli/src/commands/cc.ts
18+
packages/cli/src/commands/cursor.ts
19+
packages/cli/src/commands/uninstall.ts
20+
packages/cli/src/commands/update.ts
21+
packages/cli/src/index.ts
22+
packages/cli/src/utils/claude-integration.ts
23+
packages/cli/src/utils/cursor-integration.ts
24+
packages/cli/src/utils/environment.ts
25+
packages/cli/src/utils/paths.ts
26+
packages/cli/src/utils/update-checker.ts
27+
!**/node_modules/**
28+
!**/dist/**
29+
!**/build/**
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# production-readiness-review preset
2+
# Generated: 2025-08-31T18:06:43.170Z
3+
# Source: files optimized (13 → 11 patterns)
4+
# Optimization: balanced
5+
# Optimized: 12 files → 11 patterns (saved 1)
6+
# Applied rules:
7+
# - full-directory: packages/cli/test/e2e
8+
# - full-directory: packages/cli/test/helpers
9+
# - dir-extension: packages/cli/scripts *.ps1
10+
11+
packages/cli/test/e2e/**
12+
packages/cli/test/helpers/**
13+
packages/cli/scripts/*.ps1
14+
.github/workflows/promote-cli.yml
15+
packages/cli/package.json
16+
packages/cli/scripts/install.sh
17+
packages/cli/src/commands/uninstall.ts
18+
packages/cli/src/commands/update.ts
19+
packages/cli/src/early-update.ts
20+
packages/cli/src/utils/paths.ts
21+
packages/cli/src/utils/update-checker.ts
22+
!**/node_modules/**
23+
!**/dist/**
24+
!**/build/**
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# testing-strategy-review preset
2+
# Generated: 2025-08-31T14:23:58.228Z
3+
# Source: mixed (2 patterns preserved, 11 files → 2 patterns)
4+
# Patterns preserved as provided: 2
5+
# Optimization: balanced
6+
# Optimized: 2 files → 2 patterns (saved 0)
7+
8+
test/**/*.test.ts
9+
test/**/*.ts
10+
.github/workflows/promote-cli.yml
11+
package.json
12+
!**/node_modules/**
13+
!**/dist/**
14+
!**/build/**
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# update-finalization-review preset
2+
# Generated: 2025-08-31T06:46:15.588Z
3+
4+
!**/node_modules/**
5+
!**/dist/**
6+
!**/build/**
7+
8+
packages/cli/src/early-update.ts
9+
packages/cli/src/index.ts

0 commit comments

Comments
 (0)