claude-lock 0.1.0 → 0.2.1
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/README.md +15 -19
- package/dist/chunk-GSDKZKKT.js +36 -0
- package/dist/chunk-GSDKZKKT.js.map +1 -0
- package/dist/dist-56C5YEZV.js +1007 -0
- package/dist/dist-56C5YEZV.js.map +1 -0
- package/dist/index.js +77 -12
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -5,22 +5,14 @@ Lock yourself out of the `claude` CLI. Think Cold Turkey / Screen Time, but for
|
|
|
5
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
6
|
|
|
7
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
|
-
|______________|
|
|
8
|
+
╭──────╮
|
|
9
|
+
│ │
|
|
10
|
+
╔═══╧══════╧═══╗
|
|
11
|
+
║ ║
|
|
12
|
+
║ cc · lock ║
|
|
13
|
+
║ ║
|
|
14
|
+
║ ○ ○ ○ ○ ║
|
|
15
|
+
╚══════════════╝
|
|
24
16
|
```
|
|
25
17
|
|
|
26
18
|
## How it works
|
|
@@ -49,7 +41,7 @@ Each unlock attempt during a lock period gets progressively harder:
|
|
|
49
41
|
| 4 | 120s cooldown, then write a 50-word justification |
|
|
50
42
|
| 5+ | 300s cooldown + 5 math problems + 80-char string backwards |
|
|
51
43
|
|
|
52
|
-
Successful bypass grants a **
|
|
44
|
+
Successful bypass grants a **10-minute grace window** (configurable), then the lock re-engages.
|
|
53
45
|
|
|
54
46
|
### Payment bypass
|
|
55
47
|
|
|
@@ -101,7 +93,7 @@ When hard-locked, `cc-lock unlock` will refuse and the shim shows "Hard lock is
|
|
|
101
93
|
### npm (recommended)
|
|
102
94
|
|
|
103
95
|
```bash
|
|
104
|
-
npm install -g
|
|
96
|
+
npm install -g cc-lock
|
|
105
97
|
cc-lock install
|
|
106
98
|
```
|
|
107
99
|
|
|
@@ -218,7 +210,7 @@ cc-lock uninstall
|
|
|
218
210
|
|
|
219
211
|
| Key | Type | Default | Description |
|
|
220
212
|
|-----|------|---------|-------------|
|
|
221
|
-
| `graceMinutes` | integer (1–120) | `
|
|
213
|
+
| `graceMinutes` | integer (1–120) | `10` | How long the grace period lasts after a successful bypass before the lock re-engages |
|
|
222
214
|
| `chmodGuard` | boolean | `false` | Removes write permission from the shim so it can't be trivially replaced |
|
|
223
215
|
| `weekendDays` | `sat-sun` \| `fri-sat` \| `0,6` | `sat-sun` | Which days count as "weekend" for weekend-type schedules |
|
|
224
216
|
| `challengeBypassEnabled` | boolean | `true` | Allow free challenge-based bypass. Set to `false` to require payment (or block bypass entirely if no payment method is configured) |
|
|
@@ -242,6 +234,8 @@ $ claude
|
|
|
242
234
|
|
|
243
235
|
🔒 Claude Code is locked by cc-lock
|
|
244
236
|
|
|
237
|
+
The shim script has more self-control than you do.
|
|
238
|
+
|
|
245
239
|
Lock expires at: 18:43:24
|
|
246
240
|
Bypass attempts this period: 0
|
|
247
241
|
|
|
@@ -255,6 +249,8 @@ $ claude
|
|
|
255
249
|
|
|
256
250
|
🔒 Claude Code is locked by cc-lock
|
|
257
251
|
|
|
252
|
+
Your future self is sighing right now.
|
|
253
|
+
|
|
258
254
|
Lock expires at: 18:43:24
|
|
259
255
|
Hard lock is active — bypass is not allowed.
|
|
260
256
|
Wait for the lock to expire.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// ../core/dist/index.js
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var CC_LOCK_DIR = join(homedir(), ".cc-lock");
|
|
7
|
+
var STATE_FILE = join(CC_LOCK_DIR, "state.json");
|
|
8
|
+
var CONFIG_FILE = join(CC_LOCK_DIR, "config.json");
|
|
9
|
+
var DB_FILE = join(CC_LOCK_DIR, "stats.db");
|
|
10
|
+
var SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\cc-lock" : "/tmp/cc-lock.sock";
|
|
11
|
+
var PID_FILE = join(CC_LOCK_DIR, "daemon.pid");
|
|
12
|
+
var CLAUDE_STANDALONE_BIN = join(homedir(), ".local", "bin", "claude");
|
|
13
|
+
var CLAUDE_STANDALONE_VERSIONS_DIR = join(
|
|
14
|
+
homedir(),
|
|
15
|
+
".local",
|
|
16
|
+
"share",
|
|
17
|
+
"claude",
|
|
18
|
+
"versions"
|
|
19
|
+
);
|
|
20
|
+
var LAUNCHD_PLIST_PATH = join(
|
|
21
|
+
homedir(),
|
|
22
|
+
"Library",
|
|
23
|
+
"LaunchAgents",
|
|
24
|
+
"com.cc-lock.daemon.plist"
|
|
25
|
+
);
|
|
26
|
+
var LAUNCHD_LABEL = "com.cc-lock.daemon";
|
|
27
|
+
var TASK_SCHEDULER_NAME = "cc-lock-daemon";
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
CC_LOCK_DIR,
|
|
31
|
+
SOCKET_PATH,
|
|
32
|
+
LAUNCHD_PLIST_PATH,
|
|
33
|
+
LAUNCHD_LABEL,
|
|
34
|
+
TASK_SCHEDULER_NAME
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=chunk-GSDKZKKT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/constants.ts","../../core/src/challenges.ts"],"sourcesContent":["import { homedir } from \"os\";\nimport { join } from \"path\";\n\nexport const CC_LOCK_DIR = join(homedir(), \".cc-lock\");\nexport const STATE_FILE = join(CC_LOCK_DIR, \"state.json\");\nexport const CONFIG_FILE = join(CC_LOCK_DIR, \"config.json\");\nexport const DB_FILE = join(CC_LOCK_DIR, \"stats.db\");\nexport const SOCKET_PATH =\n process.platform === \"win32\" ? \"\\\\\\\\.\\\\pipe\\\\cc-lock\" : \"/tmp/cc-lock.sock\";\nexport const PID_FILE = join(CC_LOCK_DIR, \"daemon.pid\");\n\nexport const CLAUDE_STANDALONE_BIN = join(homedir(), \".local\", \"bin\", \"claude\");\nexport const CLAUDE_STANDALONE_VERSIONS_DIR = join(\n homedir(),\n \".local\",\n \"share\",\n \"claude\",\n \"versions\"\n);\n\nexport const LAUNCHD_PLIST_PATH = join(\n homedir(),\n \"Library\",\n \"LaunchAgents\",\n \"com.cc-lock.daemon.plist\"\n);\nexport const LAUNCHD_LABEL = \"com.cc-lock.daemon\";\nexport const TASK_SCHEDULER_NAME = \"cc-lock-daemon\";\n\nexport const DEFAULT_GRACE_MINUTES = 5;\nexport const BYPASS_COOLDOWNS = [0, 60, 0, 120, 300]; // seconds per attempt\nexport const PROCESS_POLL_INTERVAL_MS = 10_000;\nexport const VERSION_WATCH_DEBOUNCE_MS = 2_000;\n","import { randomBytes } from \"crypto\";\nimport type { Challenge } from \"./types.js\";\nimport { BYPASS_COOLDOWNS } from \"./constants.js\";\n\nfunction randomString(length: number): string {\n const chars =\n \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*\";\n const bytes = randomBytes(length);\n return Array.from(bytes)\n .map((b: number) => chars[b % chars.length])\n .join(\"\");\n}\n\nfunction randomMathProblem(): { prompt: string; answer: string } {\n const ops = [\n { sym: \"*\", fn: (a: number, b: number) => a * b },\n { sym: \"+\", fn: (a: number, b: number) => a + b },\n { sym: \"-\", fn: (a: number, b: number) => a - b },\n ];\n const op = ops[Math.floor(Math.random() * ops.length)]!;\n const a = Math.floor(Math.random() * 900) + 100;\n const b = Math.floor(Math.random() * 90) + 10;\n return {\n prompt: `${a} ${op.sym} ${b}`,\n answer: String(op.fn(a, b)),\n };\n}\n\nexport function generateChallenges(attemptNumber: number): Challenge[] {\n const cooldown =\n BYPASS_COOLDOWNS[Math.min(attemptNumber - 1, BYPASS_COOLDOWNS.length - 1)]!;\n\n if (attemptNumber === 1) {\n return [\n {\n type: \"typing\",\n prompt: randomString(30),\n cooldownSeconds: cooldown,\n },\n ];\n }\n\n if (attemptNumber === 2) {\n return [\n {\n type: \"typing\",\n prompt: randomString(50),\n cooldownSeconds: cooldown,\n },\n ];\n }\n\n if (attemptNumber === 3) {\n const problems = Array.from({ length: 3 }, () => {\n const { prompt, answer } = randomMathProblem();\n return { type: \"math\" as const, prompt, answer, cooldownSeconds: 0 };\n });\n return [{ type: \"cooldown\", prompt: \"\", cooldownSeconds: cooldown }, ...problems];\n }\n\n if (attemptNumber === 4) {\n return [\n {\n type: \"justification\",\n prompt:\n \"Write a 50+ word justification for why you need to use Claude right now:\",\n cooldownSeconds: cooldown,\n },\n ];\n }\n\n // 5+: everything\n const problems = Array.from({ length: 5 }, () => {\n const { prompt, answer } = randomMathProblem();\n return { type: \"math\" as const, prompt, answer, cooldownSeconds: 0 };\n });\n return [\n { type: \"cooldown\", prompt: \"\", cooldownSeconds: cooldown },\n ...problems,\n {\n type: \"typing\",\n prompt: randomString(80),\n cooldownSeconds: 0,\n },\n ];\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,IAAM,cAAc,KAAK,QAAQ,GAAG,UAAU;AAC9C,IAAM,aAAa,KAAK,aAAa,YAAY;AACjD,IAAM,cAAc,KAAK,aAAa,aAAa;AACnD,IAAM,UAAU,KAAK,aAAa,UAAU;AAC5C,IAAM,cACX,QAAQ,aAAa,UAAU,yBAAyB;AACnD,IAAM,WAAW,KAAK,aAAa,YAAY;AAE/C,IAAM,wBAAwB,KAAK,QAAQ,GAAG,UAAU,OAAO,QAAQ;AACvE,IAAM,iCAAiC;EAC5C,QAAQ;EACR;EACA;EACA;EACA;AACF;AAEO,IAAM,qBAAqB;EAChC,QAAQ;EACR;EACA;EACA;AACF;AACO,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;","names":[]}
|