Skip to content

flue close: end sessions from the CLI - #106

Merged
karngyan merged 1 commit into
mainfrom
holder-6-close
Aug 19, 2026
Merged

flue close: end sessions from the CLI#106
karngyan merged 1 commit into
mainfrom
holder-6-close

Conversation

@karngyan

Copy link
Copy Markdown
Contributor

PR6 of the holder-sessions stack (#100#104).

Why

Holder sessions no longer die with the daemon — that is the whole point of the stack — but it leaves a gap: there is no deliberate way to end them. flue restart, killing the daemon, even a reboot of the daemon process all leave every shell running. For dev loops and cleanup, "end it all now" needs a verb of its own.

The endpoint

POST /api/sessions/close, behind withAuth and named in methodPolicy's postable list, with the handler narrowing back to POST-only the way handleEnrol does. The body is {"all":true} or {"ids":["…"]}; both set is an all-close (the wider instruction subsumes the narrower), neither is a 400. The reply is {"closed":N,"missing":[…]} — an unknown id lands in missing rather than failing the batch.

The semantics live on the registry: CloseAll() and CloseByID(id) mirror Reap's choreography — victims leave the map under r.mu, are closed only after it is released, and each closed session's meta file is deleted so names and tags do not linger. The handler only translates HTTP into those calls.

The CLI

  • flue close --all — closes every session, running and exited, no retention window.
  • flue close <id>... — closes the named ones; each unknown id is reported by name on stderr, the rest are closed anyway, exit 1.
  • Bare flue close — usage error listing both forms, exit 2.
  • Daemon not running — daemon not running; nothing to close, exit 0.

Output is the enable-style ✓ closed N sessions, singular when N is 1. Daemon discovery goes through ourDaemon() (runtime record + PID ownership + probe), and the request mirrors fetchSessions: token in a header, status checked before decoding, body bounded.

Tests

  • internal/session: TestCloseAllRetiresEverySession, TestCloseByIDRetiresOnlyTheNamedSession, TestCloseByIDUnknownIsNotFound.
  • internal/daemon: TestSessionsCloseAllClosesEverything, TestSessionsCloseByIDClosesTheNamedOneAndReportsTheRest, TestSessionsCloseWithBothFieldsMeansAll, TestSessionsCloseWithNeitherFieldIsRefused, TestSessionsCloseRequiresAuth, TestSessionsCloseRefusesGET.
  • cmd/flue: TestRunCloseAllClosesEverySession, TestRunCloseByIDClosesOnlyTheNamedOne, TestRunCloseReportsUnknownIDs, TestRunCloseWithNoArgumentsIsAUsageError, TestRunCloseSaysDaemonNotRunning, TestUsageMentionsClose — against a real daemon.Server over httptest, the way the enable/update tests fake one.

go test ./... green, gofmt clean on every touched file.

🤖 Generated with Claude Code

Base automatically changed from holder-5-ux to main August 19, 2026 10:12
Holder-backed sessions outlive the daemon, so stopping it stopped being
a way to end them. flue close is the deliberate verb: --all retires
every session on the local daemon, ids retire the named ones, and
unknown ids are reported by name without failing the rest.

The semantics live on the registry (CloseAll, CloseByID), mirroring
Reap: victims leave the map under r.mu, are closed outside it, and
their meta files go with them. The daemon translates POST
/api/sessions/close — behind withAuth, named in methodPolicy — into
those calls, and the CLI owns argv, output, and exit codes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karngyan
karngyan merged commit 38a5a92 into main Aug 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant