claude-lock 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 cc-lock contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,354 @@
1
+ # cc-lock
2
+
3
+ Lock yourself out of the `claude` CLI. Think Cold Turkey / Screen Time, but for Claude Code.
4
+
5
+ > Claude Code is addictive. You start a quick session, then suddenly it's midnight and you cancelled dinner with friends because you just had to ship one more feature. cc-lock gives you a hard stop — set a limit before you open it, and let it hold the line when you won't.
6
+
7
+ ```
8
+ ___________
9
+ / _________ \
10
+ | | | |
11
+ | | | |
12
+ ____|_|_________|_|___
13
+ | |
14
+ | ██████╗ ██████╗ |
15
+ | ██╔═══╝ ██╔═══╝ |
16
+ | ██║ ██║ |
17
+ | ██║ ██║ |
18
+ | ██████╗ ██████╗ |
19
+ | ╚═════╝ ╚═════╝ |
20
+ | L O C K |
21
+ |______________________|
22
+ | O O O O |
23
+ |______________|
24
+ ```
25
+
26
+ ## How it works
27
+
28
+ cc-lock creates a "vault" that blocks the `claude` CLI for set durations or on recurring schedules. When a lock is active, it swaps the `claude` symlink with a shim script that blocks execution. When unlocked, the original symlink is restored — **zero overhead** during normal usage.
29
+
30
+ Unlocking requires completing escalating bypass challenges (typing strings backwards, solving math problems, waiting through cooldowns) to add friction against impulsive overrides.
31
+
32
+ ### Lock mechanism
33
+
34
+ ```
35
+ Lock engages → daemon replaces ~/.local/bin/claude with a shim script
36
+ Lock expires → daemon restores the original symlink
37
+ Daemon offline → original symlink stays, claude works normally
38
+ ```
39
+
40
+ ### Escalating bypass
41
+
42
+ Each unlock attempt during a lock period gets progressively harder:
43
+
44
+ | Attempt | Challenge |
45
+ |---------|-----------|
46
+ | 1 | Type a 30-char random string backwards |
47
+ | 2 | 60s cooldown, then type a 50-char string backwards |
48
+ | 3 | Solve 3 arithmetic problems |
49
+ | 4 | 120s cooldown, then write a 50-word justification |
50
+ | 5+ | 300s cooldown + 5 math problems + 80-char string backwards |
51
+
52
+ Successful bypass grants a **15-minute grace window**, then the lock re-engages.
53
+
54
+ ### Payment bypass
55
+
56
+ Instead of solving a challenge, you can pay real money — to yourself (savings jar), a charity, or a friend — to get the grace period. The psychological cost of spending $5 makes you genuinely reconsider whether you really need to open Claude right now.
57
+
58
+ **No payment verification server needed.** You configure any payment URL (Stripe link, Venmo, PayPal, Ko-fi, etc.) and cc-lock opens it in your browser, enforces a mandatory 30-second wait, then asks for confirmation.
59
+
60
+ ```bash
61
+ cc-lock config set paymentBypassEnabled true
62
+ cc-lock config set paymentBypassAmount 500 # $5.00 (cents)
63
+ cc-lock config set paymentBypassUrl "https://venmo.com/your-username"
64
+ ```
65
+
66
+ When you run `cc-lock unlock`, you'll see:
67
+
68
+ ```
69
+ Bypass Challenge
70
+ Attempt #1
71
+
72
+ How would you like to bypass?
73
+ A) Complete a challenge (free)
74
+ B) Pay $5.00 — opens browser for payment
75
+
76
+ Choice [A/B]:
77
+ ```
78
+
79
+ Choosing **B** opens the payment URL, waits 30 seconds, then asks you to confirm. On confirmation, grace is granted — same as a successful challenge.
80
+
81
+ **Optional Stripe verification:** if you provide a Stripe secret key, cc-lock verifies the payment intent ID before granting access:
82
+
83
+ ```bash
84
+ cc-lock config set paymentBypassStripeKey sk_live_xxx
85
+ ```
86
+
87
+ With Stripe configured, Option B asks for the `pi_...` Payment Intent ID from your receipt email instead of the 30-second wait.
88
+
89
+ ### Hard lock
90
+
91
+ Add `--hard` to disable all bypass options for the lock duration — no challenge, no grace period, no early exit:
92
+
93
+ ```bash
94
+ cc-lock lock --hard 4h
95
+ ```
96
+
97
+ When hard-locked, `cc-lock unlock` will refuse and the shim shows "Hard lock is active — bypass is not allowed." The only way out is waiting for the lock to expire.
98
+
99
+ ## Install
100
+
101
+ ### npm (recommended)
102
+
103
+ ```bash
104
+ npm install -g claude-lock
105
+ cc-lock install
106
+ ```
107
+
108
+ ### curl (macOS / Linux)
109
+
110
+ ```bash
111
+ curl -fsSL https://raw.githubusercontent.com/alonw0/cc-lock/main/install.sh | bash
112
+ ```
113
+
114
+ ### PowerShell (Windows)
115
+
116
+ ```powershell
117
+ iex (iwr -useb https://raw.githubusercontent.com/alonw0/cc-lock/main/install.ps1).Content
118
+ ```
119
+
120
+ ### Build from source
121
+
122
+ ```bash
123
+ git clone https://github.com/alonw0/cc-lock.git && cd cc-lock
124
+ bash install.sh
125
+ ```
126
+
127
+ `install.sh` will:
128
+ 1. Check Node.js 20+ and pnpm (installs pnpm if missing)
129
+ 2. Build all TypeScript packages
130
+ 3. Link `cc-lock` into `~/.local/bin/`
131
+ 4. Auto-detect your Claude Code installation and start the daemon (persisted via launchd)
132
+ 5. Build and install `CCLock.app` to `~/Applications/` if Swift is available
133
+
134
+ **Prerequisites:** Node.js 20+, `claude` CLI installed. Swift 5.9+ optional (for menu bar app).
135
+
136
+ **PATH:** If `~/.local/bin` isn't on your PATH, the script will tell you what to add to your shell profile.
137
+
138
+ ### macOS menu bar app
139
+
140
+ The menu bar app is built as a proper `.app` bundle with `LSUIElement` set (no Dock icon):
141
+
142
+ ```bash
143
+ # Build CCLock.app into macos/CCLock/dist/
144
+ pnpm run bundle:menubar
145
+
146
+ # Build and install to ~/Applications/
147
+ pnpm run bundle:menubar:install
148
+
149
+ # Create a distributable unsigned DMG
150
+ pnpm run bundle:menubar:dmg
151
+
152
+ # Codesign + notarize + staple for public distribution (requires Developer ID cert)
153
+ pnpm run bundle:menubar:sign
154
+ ```
155
+
156
+ To launch at login: **System Settings → General → Login Items → add CCLock**.
157
+
158
+ ### Windows system tray app
159
+
160
+ An Electron-based system tray app with feature parity to the macOS menu bar:
161
+ - Tray icon changes with lock state (green/red/yellow/gray padlock)
162
+ - Click the tray icon to open a popup with live status and countdown
163
+ - Quick-lock presets (30m / 1h / 2h / 4h), schedule toggles, usage stats
164
+ - "Start on login" checkbox (uses `app.setLoginItemSettings`)
165
+ - "Start Daemon" button when daemon is not running
166
+
167
+ ```bash
168
+ # Cross-compile for Windows from macOS (no Wine needed for NSIS/portable targets)
169
+ pnpm run package:windows-tray
170
+ # → windows/CCLock/release/CCLock Setup 1.0.0.exe (NSIS installer)
171
+ # → windows/CCLock/release/CCLock 1.0.0.exe (portable .exe)
172
+ ```
173
+
174
+ ## Usage
175
+
176
+ ```bash
177
+ # Lock claude for a duration
178
+ cc-lock lock 2h
179
+ cc-lock lock 30m
180
+ cc-lock lock 1d
181
+
182
+ # Hard lock — no bypass allowed until it expires
183
+ cc-lock lock --hard 2h
184
+
185
+ # Check status
186
+ cc-lock status
187
+
188
+ # Unlock (must complete bypass challenge)
189
+ cc-lock unlock
190
+
191
+ # Usage statistics
192
+ cc-lock stats
193
+ cc-lock stats --week
194
+ cc-lock stats --month
195
+
196
+ # Reset usage stats
197
+ cc-lock stats reset # reset today's usage only
198
+ cc-lock stats reset --all # reset all historical data
199
+
200
+ # Recurring schedules (5-minute system notification fires before each lock)
201
+ cc-lock schedule add # interactive
202
+ cc-lock schedule list
203
+ cc-lock schedule remove <id>
204
+
205
+ # Configuration
206
+ cc-lock config get
207
+ cc-lock config set graceMinutes 10
208
+ cc-lock config set chmodGuard true
209
+
210
+ # Interactive TUI dashboard
211
+ cc-lock tui
212
+
213
+ # Uninstall (blocked while locked)
214
+ cc-lock uninstall
215
+ ```
216
+
217
+ ### Configuration options
218
+
219
+ | Key | Type | Default | Description |
220
+ |-----|------|---------|-------------|
221
+ | `graceMinutes` | integer (1–120) | `5` | How long the grace period lasts after a successful bypass before the lock re-engages |
222
+ | `chmodGuard` | boolean | `false` | Removes write permission from the shim so it can't be trivially replaced |
223
+ | `weekendDays` | `sat-sun` \| `fri-sat` \| `0,6` | `sat-sun` | Which days count as "weekend" for weekend-type schedules |
224
+ | `challengeBypassEnabled` | boolean | `true` | Allow free challenge-based bypass. Set to `false` to require payment (or block bypass entirely if no payment method is configured) |
225
+ | `paymentBypassEnabled` | boolean | `false` | Enable pay-to-bypass mode as an alternative to challenges |
226
+ | `paymentBypassAmount` | integer (cents) | `500` | Amount to pay in cents ($5.00 = 500) |
227
+ | `paymentBypassUrl` | string | — | Payment URL to open (Stripe link, Venmo, PayPal, Ko-fi…) |
228
+ | `paymentBypassStripeKey` | string | — | Stripe secret key (`sk_...`) for payment intent verification |
229
+
230
+ Read-only fields (set by `cc-lock install`, not editable directly):
231
+
232
+ | Key | Description |
233
+ |-----|-------------|
234
+ | `installationType` | `standalone` or `npm` |
235
+ | `claudeBinaryPath` | Path to the real `claude` binary |
236
+ | `claudeShimPath` | Path being managed (replaced with shim when locked) |
237
+
238
+ ### What it looks like when locked
239
+
240
+ ```
241
+ $ claude
242
+
243
+ 🔒 Claude Code is locked by cc-lock
244
+
245
+ Lock expires at: 18:43:24
246
+ Bypass attempts this period: 0
247
+
248
+ To bypass, run: cc-lock unlock
249
+ ```
250
+
251
+ With `--hard`:
252
+
253
+ ```
254
+ $ claude
255
+
256
+ 🔒 Claude Code is locked by cc-lock
257
+
258
+ Lock expires at: 18:43:24
259
+ Hard lock is active — bypass is not allowed.
260
+ Wait for the lock to expire.
261
+ ```
262
+
263
+ ### TUI Dashboard
264
+
265
+ Launch with `cc-lock tui` for an interactive terminal dashboard with:
266
+ - Real-time lock status with countdown timer
267
+ - Quick-lock presets (30m / 1h / 2h / 4h)
268
+ - Usage bar charts by day/week/month
269
+ - Schedule viewer
270
+ - Settings overview
271
+
272
+ The padlock logo changes color with state: **green** = unlocked, **red** = locked, **yellow** = grace period.
273
+
274
+ ## Architecture
275
+
276
+ ```
277
+ ┌─────────────┐ ┌─────────────┐
278
+ │ cc-lock CLI │ │ cc-lock TUI │
279
+ │ (Commander) │ │ (Ink/React) │
280
+ └──────┬───────┘ └──────┬──────┘
281
+ │ │
282
+ └── Unix Domain Socket ──┐
283
+ /tmp/cc-lock.sock │
284
+ │ │
285
+ ┌──────────▼──────────┐
286
+ │ cc-lock daemon │
287
+ │ (Node.js) │
288
+ │ │
289
+ │ - Lock state machine│
290
+ │ - Schedule evaluator│
291
+ │ - Usage tracker │
292
+ │ - Version watcher │
293
+ │ - Shim manager │
294
+ └───┬───────────┬─────┘
295
+ │ │
296
+ ┌────▼───┐ ┌───▼──────────┐
297
+ │ SQLite │ │ Shim script │
298
+ │ (stats)│ │ (enforcement)│
299
+ └────────┘ └──────────────┘
300
+ ```
301
+
302
+ ### Packages
303
+
304
+ | Package | Description |
305
+ |---------|-------------|
306
+ | `@cc-lock/core` | Shared types, IPC protocol, constants, challenge generators |
307
+ | `@cc-lock/daemon` | Background service — socket server, lock state machine, shim manager, schedule evaluator, usage tracker, version watcher |
308
+ | `cc-lock` | Commander.js CLI with all commands |
309
+ | `@cc-lock/tui` | Ink/React interactive terminal dashboard |
310
+ | `@cc-lock/check-lock` | Minimal scripts invoked by the shim for lock checking and bypass |
311
+ | `@cc-lock/windows-tray` | Electron system tray app for Windows |
312
+
313
+ ## Supported installations
314
+
315
+ - **Standalone** (native binary): `~/.local/share/claude/versions/X.Y.Z`, symlinked from `~/.local/bin/claude`
316
+ - **npm global**: via `which claude` (Unix) or `where claude` (Windows)
317
+
318
+ | Platform | Daemon persistence | Shim format |
319
+ |----------|--------------------|-------------|
320
+ | macOS | launchd (`KeepAlive` + `RunAtLoad`) | bash script |
321
+ | Linux | detached process | bash script |
322
+ | Windows | Task Scheduler (`/sc onlogon`) | `.cmd` file |
323
+
324
+ ## Tech stack
325
+
326
+ | Component | Technology |
327
+ |-----------|-----------|
328
+ | Core/Daemon/CLI | TypeScript, Node.js 20+ |
329
+ | TUI | Ink (React for CLI) |
330
+ | macOS menu bar | Swift 5.9 + SwiftUI |
331
+ | Windows tray | Electron 33 |
332
+ | Database | better-sqlite3 |
333
+ | IPC | Unix domain sockets (macOS/Linux), named pipes (Windows) |
334
+ | Build | tsup (esbuild) + electron-builder |
335
+ | Tests | vitest |
336
+ | Monorepo | pnpm workspaces |
337
+ | File watching | chokidar |
338
+ | CLI framework | Commander.js |
339
+
340
+ ## Data
341
+
342
+ All data lives in `~/.cc-lock/`:
343
+
344
+ | File | Purpose |
345
+ |------|---------|
346
+ | `config.json` | Installation type, binary paths, settings |
347
+ | `state.json` | Current lock state (read by shim) |
348
+ | `stats.db` | SQLite database with session and daily usage stats |
349
+ | `daemon.pid` | Daemon process ID |
350
+ | `daemon.log` | Daemon stdout log |
351
+
352
+ ## License
353
+
354
+ MIT