Repository navigation
Conversation
Insomnia --session start <seconds> | extend <seconds> | end | status lets a script or an agent start, extend and end the session the menu bar counts down, with the same battery and heat rules. The command line changes nothing itself: it links one request into session-command in the support directory, the app's watcher claims it, runs it like the matching menu action and answers in session-command.reply.<id>. A request nothing claims within 2 s is taken back, and one older than 5 s is dropped, so a request left behind never starts a session later.
A start queued behind another, an end whose restore failed, and an end that arrived while a start was in flight could all answer done. The manager's tryStart and tryExtend now say whether this call took effect, an end maps every EndOutcome other than restored to a reason, and an end or extend with no session yet waits for queued work first. The watcher starts after the launch reconcile, a request a killed command line left no longer blocks the next one, a command line waits on and takes back only its own file (by inode), old answers are removed, and an app still starting is told apart from an older build.
…nd every time Greptile on #99: an end that found no session answered done without ending, which left a dirty journal or an unadopted session.json behind, and the take-back of a shared request path could still drop another caller's request when three command lines raced. An end now always runs end(reason: .user), which also abandons a start in flight. Each command line writes its own session-command.<id>.request, so publishing, the app's claim and a take-back are each one rename of that caller's own file, and the app serves the requests it finds oldest first.
…st runs first `end` then `start` each run in their own task. While the end waited on the lifecycle queue or the recovery lock, the early `session != nil` check in `run(.start)` still saw the old session and refused the start as already running; the end then ran and left no session. The check is gone, so the start queues behind the end and `performStart` decides under the lock. The check after `tryStart` still gives the refusal message. The new test holds an extend at the backstop arm, queues `end` and then `start`, and checks that the start makes a new session.
`tryStart` refuses a start while an end is pending, but only when the request arrives. An end already in the queue can leave itself to its retry (`scheduleEndRetry` in `performEnd`), and a start queued behind it went on to start a session that the retry stopped 30 s later. `performStart` now checks `pendingEnd` as well, with the same refusal. Removing the early check in `run(.start)` made this reachable from `end` then `start`; a start sent with no session running could already reach it. The new test fails the end's arm, lets the start's succeed, and checks the start is refused and nothing runs.
Lands #99 at e738536, by 0xRafie. Conflict with #137 and the maintainer's time change fix, resolved here: each added an app-lifetime object to InsomniaApp, the display sleep and time change observers and #99's session command watcher. All three are kept. The observers start first; the watcher starts after the launch reconcile, as in #99. Co-Authored-By: Claude Opus 5.5 <[email protected]>
tryExtend reported success whenever it saved the session. At the 30 day cap the new end equals the old one, and after a lower maxDuration in config.json it is earlier, so `Insomnia --session extend` printed a success for an extension that never happened. It now reports success only when the end moved later, and the command line prints its "not extended" reason otherwise. The menu's extend ignores the result, so it behaves as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Brings in 54f3c7e, which keeps the pills open when a pill is clicked on macOS 27. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Brings in 732de03: one refocus watch per press, and the pills return focus to the app the user was in. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Brings in 85576e5, a test seam for the focus-loss test. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…uccess 0ec2765 counted any later end as an extension, on the belief that at the 30 day cap the new end equals the old one. It doesn't: the cap is now + maxDuration, so each extend at the cap moves the end out by the time since the last one. In a macOS 27 VM, a second `extend 2147483647` right after the first moved the end about 0.1 s and exited 0. The test used a frozen clock, so it never saw this. An extend now counts only when the end moves out by at least a second, the smallest request the command line takes. A new test advances the clock 0.1 s at the cap (not extended), then 60 s (extended, by the minute the cap moved), and fails with the old comparison. Another pins a one second extend below the cap as a success. Co-Authored-By: Claude Opus 5.5 <[email protected]>
VM run on macOS 27.0.1 at 7f6654a: the session command line worksEvery case below passes at the head, Setup. macOS 27.0.1 (26A434) with Xcode 27.0, in a Tart VM on the maintainer's Mac mini. The commit was installed from a clean checkout with
The bug at Evidence: t146-7f6654a.log (the head), t146-37f87d5.log (before the fix), the images and the README, the script. Limits
🤖 Generated with Claude Code |




Scripts and coding agents can start, extend and end the menu bar app's session with
Insomnia --session start <seconds> | extend <seconds> | end | status. The session they start is the same one the menu bar counts down, and the command line never runs pmset itself.This lands #99 by @0xRafie at e738536. The commit is merged here unchanged, so GitHub marks #99 merged when this one merges and its author keeps the credit. It sits on #145 (menu controls), because both add an object to the app's launch code. Review and merge #145 first; this pull request's base then moves to main.
To @0xRafie: please don't push to your branch now. A new commit on it isn't in this pull request, so #99 would stay open instead of showing as merged.
Conflicts resolved
Maintainer fixes
tryExtendreturned true whenever it saved the session. At the 30 day cap, or after a lowermaxDurationin config.json,Insomnia --session extend 3600printed success for an extension that never happened. It now reports success only when the end moved later, and the command prints its "not extended" reason otherwise. The menu's extend ignores the result and behaves as before.extend 2147483647right after the first moved the end about 0.1 s and exited 0. 0ec2765's test used a frozen clock, so it missed this. An extend now counts only when the end moves out by at least a second, the smallest request the command takes. A new test advances the clock 0.1 s at the cap (not extended), then 60 s (extended), and fails with the old comparison. Another keeps a one second extend below the cap a success.Not changed: after a hand-lowered
maxDuration, an extend still moves the end in to the new cap, from the menu or the command line. That is main's existing rule ("never past now + maxDuration"); only the command's answer changes.Tests
Full suite at 7f6654a on macOS 26.2 (Xcode 26.4.1): 1,281 tests, 0 failures. Hosted CI on macOS 26 and 27 passes at 7f6654a. UIStatusTests, UIStartupTests and KeychainStoreTests are skipped on the maintainer's Mac; hosted CI runs them.
Codex review
Clean at 0ec2765, at 37f87d5 and at 7f6654a (gpt-6.1-sol, xhigh, read-only): the whole of #99 combined with #145, the merge resolution and both extend fixes. A read-only audit of #99 alone at e738536 found only the extend result, fixed in 0ec2765. None of these reviews caught the moving cap; the VM run did. #145's pill fixes, merged in at 37f87d5, were reviewed on #145 (clean at 85576e5).
Evidence
🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; no blocking issue was found.Summary
Adds
Insomnia --session start,extend,end, andstatusfor scripts driving the running menu bar app.No actionable issues were found in the changes since the previous review or the full-PR rule check. Tests were inspected, not run.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR CLI["Insomnia --session"] --> Action{"Command"} Action -->|status| Session["Read session.json"] Action -->|start, extend, end| Request["Write request file"] Request --> Watcher["Running app claims request"] Watcher --> Manager["SessionManager runs action"] Manager --> Reply["Write reply file"] Reply --> CLIReviews (5) · Last reviewed commit: "Session command: an extend that only cre..." · Reviewed by Greptile