krz/keycask

Password manager: Swift core library, CLI for macOS/Linux/Windows, iOS/macOS app. cli password-manager swift

Commit 304b782efc

304b782efcd676edc0b9535d0f8a4d97917e9409

parent: 4261024032

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-17 16:39 UTC

Write the clipboard before spawning the daemon

Layout: unified · split

Sources/keycask/Clipboard.swift +1 −1
@@ -76,6 +76,7 @@ enum Clipboard {
76 static func copyWithTimeout(_ secret: String, seconds: Int = timeoutSeconds) throws { 76 static func copyWithTimeout(_ secret: String, seconds: Int = timeoutSeconds) throws {
77 _ = try requireTool() 77 _ = try requireTool()
78 let handoff = Handoff(secret: secret, previous: try read()) 78 let handoff = Handoff(secret: secret, previous: try read())
79 try write(secret)
79 let process = Process() 80 let process = Process()
80 process.executableURL = Bundle.main.executableURL 81 process.executableURL = Bundle.main.executableURL
81 process.arguments = ["clipboard-daemon", String(seconds)] 82 process.arguments = ["clipboard-daemon", String(seconds)]
@@ -100,7 +101,6 @@ enum Clipboard {
100 } catch { 101 } catch {
101 throw KeycaskError.failure("bad handoff") 102 throw KeycaskError.failure("bad handoff")
102 } 103 }
103 try write(handoff.secret)
104 Thread.sleep(forTimeInterval: TimeInterval(seconds)) 104 Thread.sleep(forTimeInterval: TimeInterval(seconds))
105 let current = try? read() 105 let current = try? read()
106 guard shouldRestore(secret: handoff.secret, current: current) else { return } 106 guard shouldRestore(secret: handoff.secret, current: current) else { return }
docs/superpowers/specs/2026-09-17-keycask-design.md +4 −3
@@ -225,9 +225,10 @@ and a Windows body where they differ.
225 read on Windows. No tool found is exit 1 with a message naming the 225 read on Windows. No tool found is exit 1 with a message naming the
226 tools. `clip` spawns `keycask clipboard-daemon` detached with stdout 226 tools. `clip` spawns `keycask clipboard-daemon` detached with stdout
227 and stderr to null, writes `{"secret": ..., "previous": ...}` to its 227 and stderr to null, writes `{"secret": ..., "previous": ...}` to its
228 stdin, and exits without waiting. The daemon sets the clipboard, 228 stdin, and exits without waiting. `clip` writes the clipboard itself,
229 sleeps 45 seconds, reads the clipboard, and if it still equals the 229 then spawns the daemon. The daemon sleeps 45 seconds, reads the
230 secret restores `previous` or clears when `previous` is empty. 230 clipboard, and if it still equals the secret restores `previous` or
231 clears when `previous` is empty.
231 232
232## Errors 233## Errors
233 234