015 — tp unlock restarts the clock; tp unlock query prints the time left (#38)
Status: shipped (v0.10.0)
Why
tp unlock caches a Bitwarden session key for 24 hours from the moment
the master password is typed, and a second run inside that window is a
no-op that reports the time left. That no-op is the wrong default for
the way the command is used: it is typed on purpose, usually before a
stretch of work that needs the vault, and the person expects a fresh
24 hours, not "already cached, 2h left" followed by an expiry
mid-session. The --refresh flag exists but has to be remembered.
Agents and scripts also need the session state without prose: today it
is one line of tp check ("ok, 7h12m left") or the error of the first
command that needs a token.
What changes
tp unlockalways prompts for the master password (viabw, which reads it; tp never sees it) and caches the new key, so the 24 hours run from the lasttp unlock. The--refreshflag goes: it is the behaviour now.tp unlock queryprints the time left as a Go duration rounded to the minute (7h12m) and nothing else on stdout, exit 0. With no cached session, an expired one, or a key the vault no longer accepts, it prints the reason on stderr and exits 1. Expiry has the side effectSessionalready has: the cached key is deleted and the vault locked.tp check's secrets line and thetp unlocksuccess message are unchanged;README.mdandtp -adescribe the new behaviour.
Acceptance
| Cached session | Command | Prompts | stdout | exit |
|---|---|---|---|---|
| none | tp unlock |
yes | cached message | 0 |
| valid, 2h left | tp unlock |
yes | cached message; 24h left afterwards | 0 |
| valid, vault locked elsewhere | tp unlock |
yes | cached message | 0 |
bw unlock fails or returns no key |
tp unlock |
yes | error on stderr; cache untouched | 1 |
| valid, 7h12m left, vault accepts the key | tp unlock query |
no | 7h12m |
0 |
| none | tp unlock query |
no | nothing; "no cached Bitwarden session — run: tp unlock" on stderr | 1 |
| older than 24h | tp unlock query |
no | nothing; "expired" on stderr; file removed, vault locked | 1 |
| within 24h, vault rejects the key | tp unlock query |
no | nothing; "not accepted by the vault" on stderr | 1 |
| any | tp unlock --refresh |
— | flag unknown | 2 |
Out of scope
- Extending a session without the master password (touching the cache file): see Decisions.
- A machine-readable form beyond the duration (JSON, seconds): the
duration is what
tp checkprints and what a person reads. - Changing the 24h TTL or making it configurable.
Decisions
None recorded as an ADR. The fork was whether "restarts the clock"
means re-authenticating (prompt, new key) or merely touching the cache
file's mtime when the vault still accepts the key. Touching would make
the 24h limit meaningless — a daily tp unlock would keep one session
alive for ever without a password — so the clock restarts only with a
new key. query verifies the key with the vault, one bw call, rather
than trusting the file: a 0 exit means the next token fetch will work.
Done when
- tests express the acceptance table and pass
- spec updated (
README.md) - roadmap ticked and stamped; changelog entry
- issue closed with a link to the release (v0.10.0)