fix(lock,update): an interrupted write exits 130, releases the lock, names the backup (PHARN-10) - #204
Merged
Conversation
…names the backup (PHARN-10) While a clack spinner is up, @clack/core turns Ctrl-C into process.exit(0), which runs no `finally`. Reproduced: `update --force` interrupted during its records write printed "Canceled", exited 0, left .pharn.lock behind, and never named the .pharn-backup/<ts>/ it had already created — with originals already overwritten. - withProjectLock registers an `exit` listener while the lock is held: it releases the lock synchronously and turns an exit code of 0 into 130 with one stderr line saying the run was interrupted while writing. - update prints the backup pointer the moment the backup is created (as `add` does and docs/commands/update.md promises), not only at the end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…re the 97% gate CI's coverage gate failed at 96.79% statements: the exit listener only ran in a child process (invisible to coverage), on top of uncovered hook-wiring error branches. Adds in-process listener tests (0 -> 130, non-zero untouched) and two hook-wiring error-branch tests: 97.10%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
While a spinner is on screen, the prompt library (
@clack/core) handles Ctrl-C by callingprocess.exit(0), andfinallyblocks do not run onprocess.exit.Reproduced with
update --yes --forcein a terminal, pressing Ctrl-C while the records file was being written:.pharn.lockwas left behind;.pharn-backup/<ts>/had been created but was never named;pharn/CONSTITUTION.mdhad already been overwritten.The fix:
src/lib/project-lock.ts: whilewithProjectLockholds the lock, it registers a processexithandler and removes it again when the locked work finishes. If the process exits in that window, the handler releases the lock immediately. If the exit code is 0, it changes it to 130 and prints one line to stderr: "pharn was interrupted while writing to this project — it may be partially updated. Re-runpharn <command>." The code comment states the assumption this relies on: no prompt inside a locked section exits 0 on a normal cancel. Today the confirm prompts run before the lock is taken, and theaddpicker exits after it is released.src/commands/update.ts: prints where the backup went as soon as.pharn-backup/<ts>/is created, asaddalready does and asdocs/commands/update.mdalready promises. It is printed once on a successful run. An aborted run still repeats it on stderr, alongside the "stopped part-way" warning.Built with
/pharn-dev-ship; stage artifacts are in.dev/features/interrupt-exit-code/. Results:no-regressionsPASSType of change
feat— new stack option, wizard step, or command capabilityfix— bug fixdocs— docs-only changechore/refactor— tooling or internal restructure, no behavior changeArea(s) touched
lib/project-lock | commands/update
Checklist
.js-extension import convention.process.exit(0)while holding the lock exits 130, prints the line, and leaves no.pharn.lock(fails on the old code);updateprints the backup location when the backup is created (fails on the old code) and exactly once on success.docs/commands/update.mdalready describes the corrected behavior.Quality gates
npm run checkpasses locally (1349/1349; non-root user, node 22).npm run build/npm run test:coverage(left to CI).🤖 Generated with Claude Code
https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
Generated by Claude Code