feat(wrapper): launch claude via caffeinate to prevent idle sleep - #125
Merged
Merged
Conversation
The system could idle-sleep partway through a long CCCLI session. The wrapper now execs claude through `caffeinate -i`, which holds a PreventUserIdleSystemSleep assertion for the life of the utility it launches and releases it on exit. caffeinate execs the utility in place, so claude keeps the same PID, TTY, signal disposition, and exit status it had before. Nothing needs to forward signals or propagate exit codes. CAFF_BIN is hardcoded to /usr/bin/caffeinate rather than resolved with `command -v`: caffeinate inherits GH_TOKEN and OP_SERVICE_ACCOUNT_TOKEN, so a same-named binary earlier in PATH would receive both and would bypass the ownership/permission validation applied to the claude binary. SIP guarantees the path. Also fixes a pre-existing bug in test 4.3, which has never actually run. It copied the wrapper to TEST_TMP, but the wrapper resolves WRAPPER_LIB as "<own dir>/../lib" -- so the copy could not source lib/logging.sh and exited 1 before reaching exec, landing in a branch that reports a skip and passes. The copy now lives beside the real wrapper and is removed by a RETURN trap. Both of its assertions pass for the first time. Adds test 4.5 to cover the new behavior: caffeinate is hardcoded, is not PATH-resolved, and every exec branch goes through `caffeinate -i`. Both assertions were verified to fail against the corresponding regressions. Closes #121
|
The PR wraps the No blocking issues found. The hardcoded VERDICT: PASS |
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
Launches
claudethroughcaffeinate -iso the system does not idle-sleep partway through a long CCCLI session.caffeinateholds aPreventUserIdleSystemSleepassertion for the life of the utility it launches and releases it on exit — verified no leak across 11 sequential invocations.Why hardcode
/usr/bin/caffeinatecaffeinateruns withGH_TOKENandOP_SERVICE_ACCOUNT_TOKENin its environment. Resolving it withcommand -vmeans a same-named binary earlier in$PATHreceives both, and bypasses the ownership/permission validation this repo applies to theclaudebinary. SIP guarantees the/usr/binpath and prevents it being replaced.Behavior notes
caffeinateexecs the utility in place rather than supervising it. Verified directly: the child reports the same PID ascaffeinate, a trapped SIGTERM reaches it, exit code 7 propagates unchanged, and the TTY survives under a pty. Nothing downstream needs to forward signals or propagate exit codes.-iholds the assertion on battery as well as AC;-sis AC-only.Test 4.3 had never run
Found while updating the test for the new exec line. The stale sed pattern was the smaller problem: test 4.3 copied the wrapper to
TEST_TMP, but the wrapper resolvesWRAPPER_LIBas<own dir>/../lib, so the copy could not sourcelib/logging.sh. It exited 1 before reachingexecand landed in a branch that prints a skip and returns 0 — passing without asserting anything, since it was written.The copy now lives beside the real wrapper and is removed by a
RETURNtrap. Both of its assertions ("Mock claude was executed", "Git identity passed through") pass for the first time.bin/.test-integration-wrapper.*is gitignored so an interrupted run cannot leave an untracked file inbin/.Because it now runs for real, it sources
credentials.sh, which may hit the Keychain when the tokens are not already exported. Both lookups aretimeout-bounded and degrade to no-ops, so the suite still passes offline in ~2.5s.New coverage
Test 4.5 asserts the path is hardcoded, is not PATH-resolved, and that every
execbranch goes throughcaffeinate -i. Both assertions were validated against known-bad inputs: reverting tocommand -vfails two of them, and dropping caffeinate from one branch fails the branch-count check.Verification
shellcheck -S infoclean acrosslib/,bin/,tests/— nodisabledirectives addedtests/test-gh-token-permissions.sh(performs live mutations; untouched by this change)https://claude.ai/code/session_019n5uxsRsrT4PDiYAxHUYyu