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 +21 -0
- package/README.md +354 -0
- package/dist/index.js +909 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
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
|