claude-yolo 1.7.0 → 1.9.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.
Files changed (35) hide show
  1. package/.claude/settings.local.json +6 -0
  2. package/.cursor/mcp.json +0 -0
  3. package/.cursor/rules/cursor-tools.mdc +161 -0
  4. package/.cursorindexingignore +3 -0
  5. package/.mcp.json +13 -0
  6. package/.specstory/history/.what-is-this.md +54 -0
  7. package/.specstory/history/2025-02-26_13-24-checking-recent-tweets.md +124 -0
  8. package/.specstory/history/2025-03-10_15-17-sending-a-yo-to-my-server.md +32 -0
  9. package/.specstory/history/2025-03-10_17-20-sending-a-simple-yo-message.md +104 -0
  10. package/.specstory/history/2025-03-12_08-37-documentation-retrieval-for-repomix-repo.md +32 -0
  11. package/.specstory/history/2025-03-12_09-23-interactive-browser-session-setup.md +7864 -0
  12. package/.specstory/history/2025-03-12_17-16-chat-name-generation.md +430 -0
  13. package/.specstory/history/2025-03-13_01-22-python-pi-calculation-and-notification.md +254 -0
  14. package/.specstory/history/2025-03-13_22-46-server-update-for-eric.md +35 -0
  15. package/.specstory/history/2025-03-13_23-02-sending-a-simple-yo-message.md +18 -0
  16. package/.specstory/history/2025-03-13_23-10-casual-greetings.md +80 -0
  17. package/.specstory/history/2025-03-14_13-07-casual-greetings-sending-a-yo.md +44 -0
  18. package/.specstory/history/2025-03-14_13-28-casual-greetings.md +924 -0
  19. package/.specstory/history/2025-03-14_13-37-sending-a-yo-message.md +34 -0
  20. package/.specstory/history/2025-03-14_13-48-casual-greetings.md +76 -0
  21. package/.specstory/history/2025-03-14_13-53-casual-greetings.md +44 -0
  22. package/.specstory/history/2025-03-14_13-57-casual-greetings.md +64 -0
  23. package/.specstory/history/2025-03-14_21-41-simple-greeting-send-a-yo.md +34 -0
  24. package/.specstory/history/2025-03-15_13-44-casual-greeting-request.md +26 -0
  25. package/.specstory/history/2025-03-16_21-17-using-curl-to-fetch-url-content.md +3728 -0
  26. package/.specstory/history/2025-10-25_08-17-create-a-new-repository-with-gh-cli.md +173 -0
  27. package/.specstory/history/casual-greetings-1.md +32 -0
  28. package/AGENTS.md +1 -0
  29. package/README.md +104 -24
  30. package/bin/cl +113 -0
  31. package/bin/claude-yolo.js +191 -16
  32. package/demo.txt +1 -0
  33. package/package.json +14 -10
  34. package/test.txt +1 -0
  35. package/yolo-test.txt +1 -0
@@ -3,6 +3,7 @@
3
3
 
4
4
  import fs from 'fs';
5
5
  import path from 'path';
6
+ import os from 'os';
6
7
  import { createRequire } from 'module';
7
8
  import { fileURLToPath } from 'url';
8
9
  import { execSync } from 'child_process';
@@ -12,9 +13,27 @@ import readline from 'readline';
12
13
  const RED = '\x1b[31m';
13
14
  const YELLOW = '\x1b[33m';
14
15
  const CYAN = '\x1b[36m';
16
+ const GREEN = '\x1b[32m';
15
17
  const RESET = '\x1b[0m';
16
18
  const BOLD = '\x1b[1m';
17
19
 
20
+ // Path to persistent state file
21
+ const stateFile = path.join(os.homedir(), '.claude_yolo_state');
22
+
23
+ // Function to get current mode from state file
24
+ function getMode() {
25
+ try {
26
+ return fs.readFileSync(stateFile, 'utf8').trim();
27
+ } catch {
28
+ return 'YOLO'; // Default mode
29
+ }
30
+ }
31
+
32
+ // Function to set mode in state file
33
+ function setMode(mode) {
34
+ fs.writeFileSync(stateFile, mode);
35
+ }
36
+
18
37
  // Debug logging function that only logs if DEBUG env var is set
19
38
  const debug = (message) => {
20
39
  if (process.env.DEBUG) {
@@ -30,20 +49,21 @@ function askForConsent() {
30
49
  output: process.stdout
31
50
  });
32
51
 
33
- console.log(`\n${BOLD}${YELLOW}🔥 CLAUDE-YOLO INSTALLATION CONSENT REQUIRED 🔥${RESET}\n`);
52
+ console.log(`\n${BOLD}${YELLOW}🔥 CLAUDE-YOLO CONSENT REQUIRED 🔥${RESET}\n`);
34
53
  console.log(`${CYAN}----------------------------------------${RESET}`);
35
54
  console.log(`${BOLD}What is claude-yolo?${RESET}`);
36
55
  console.log(`This package creates a wrapper around the official Claude CLI tool that:`);
37
56
  console.log(` 1. ${RED}BYPASSES safety checks${RESET} by automatically adding the --dangerously-skip-permissions flag`);
38
57
  console.log(` 2. Automatically updates to the latest Claude CLI version`);
39
- console.log(` 3. Adds colorful YOLO-themed loading messages\n`);
58
+ console.log(` 3. Adds colorful YOLO-themed loading messages`);
59
+ console.log(` 4. ${GREEN}NOW SUPPORTS SAFE MODE${RESET} with --safe flag\n`);
40
60
 
41
61
  console.log(`${BOLD}${RED}⚠️ IMPORTANT SECURITY WARNING ⚠️${RESET}`);
42
62
  console.log(`The ${BOLD}--dangerously-skip-permissions${RESET} flag was designed for use in containers`);
43
63
  console.log(`and bypasses important safety checks. This includes ignoring file access`);
44
64
  console.log(`permissions that protect your system and privacy.\n`);
45
65
 
46
- console.log(`${BOLD}By using claude-yolo:${RESET}`);
66
+ console.log(`${BOLD}By using claude-yolo in YOLO mode:${RESET}`);
47
67
  console.log(` • You acknowledge these safety checks are being bypassed`);
48
68
  console.log(` • You understand this may allow Claude CLI to access sensitive files`);
49
69
  console.log(` • You accept full responsibility for any security implications\n`);
@@ -94,7 +114,29 @@ async function checkForUpdates() {
94
114
  const dependencies = packageJson.dependencies || {};
95
115
  const currentVersion = dependencies['@anthropic-ai/claude-code'];
96
116
 
97
- debug(`Current dependency in package.json: ${currentVersion}`);
117
+ debug(`Claude version from package.json: ${currentVersion}`);
118
+
119
+ // Get the global Claude version if available
120
+ let globalVersion;
121
+ if (globalClaudeDir) {
122
+ try {
123
+ const globalPackageJsonPath = path.join(globalClaudeDir, 'package.json');
124
+ if (fs.existsSync(globalPackageJsonPath)) {
125
+ const globalPackageJson = JSON.parse(fs.readFileSync(globalPackageJsonPath, 'utf8'));
126
+ globalVersion = globalPackageJson.version;
127
+ debug(`Global Claude version: ${globalVersion}`);
128
+
129
+ // If global version is latest, inform user
130
+ if (globalVersion === latestVersion) {
131
+ debug(`Global Claude installation is already the latest version`);
132
+ } else if (globalVersion && latestVersion) {
133
+ debug(`Global Claude installation (${globalVersion}) differs from latest (${latestVersion})`);
134
+ }
135
+ }
136
+ } catch (err) {
137
+ debug(`Error getting global Claude version: ${err.message}`);
138
+ }
139
+ }
98
140
 
99
141
  // If using a specific version (not "latest"), and it's out of date, update
100
142
  if (currentVersion !== "latest" && currentVersion !== latestVersion) {
@@ -119,22 +161,123 @@ async function checkForUpdates() {
119
161
  }
120
162
  }
121
163
 
122
- // Path to the Claude CLI file
123
- const claudeDir = path.join(nodeModulesDir, 'node_modules', '@anthropic-ai', 'claude-code');
124
- let originalCliPath = path.join(claudeDir, 'cli.mjs');
125
- if(!fs.existsSync(originalCliPath)) {
126
- originalCliPath = path.join(claudeDir, 'cli.js');
127
- if(!fs.existsSync(originalCliPath)) {
128
- console.error(`Error: ${originalCliPath} not found. Make sure @anthropic-ai/claude-code is installed.`);
129
- process.exit(1);
164
+ // Try to find global installation of Claude CLI first
165
+ let globalClaudeDir;
166
+ try {
167
+ const globalNodeModules = execSync('npm -g root').toString().trim();
168
+ debug(`Global node_modules: ${globalNodeModules}`);
169
+ const potentialGlobalDir = path.join(globalNodeModules, '@anthropic-ai', 'claude-code');
170
+
171
+ if (fs.existsSync(potentialGlobalDir)) {
172
+ globalClaudeDir = potentialGlobalDir;
173
+ debug(`Found global Claude installation at: ${globalClaudeDir}`);
130
174
  }
175
+ } catch (error) {
176
+ debug(`Error finding global Claude installation: ${error.message}`);
131
177
  }
132
178
 
133
- const yoloCliPath = path.join(claudeDir, 'cli-yolo.mjs');
179
+ // Path to the local Claude CLI installation
180
+ const localClaudeDir = path.join(nodeModulesDir, 'node_modules', '@anthropic-ai', 'claude-code');
181
+
182
+ // For AGENTS mode, always use LOCAL installation to ensure patches work correctly
183
+ // Global installation may have different minified variable names
184
+ const claudeDir = localClaudeDir;
185
+ debug(`Using Claude installation from: ${claudeDir}`);
186
+ debug(`Using ${claudeDir === globalClaudeDir ? 'GLOBAL' : 'LOCAL'} Claude installation`);
187
+
188
+ // Check for both .js and .mjs versions of the CLI
189
+ let mjs = path.join(claudeDir, 'cli.mjs');
190
+ let js = path.join(claudeDir, 'cli.js');
191
+ let originalCliPath;
192
+ let yoloCliPath;
193
+
194
+ if (fs.existsSync(js)) {
195
+ originalCliPath = js;
196
+ yoloCliPath = path.join(claudeDir, 'cli-yolo.js');
197
+ debug(`Found Claude CLI at ${originalCliPath} (js version)`);
198
+ } else if (fs.existsSync(mjs)) {
199
+ originalCliPath = mjs;
200
+ yoloCliPath = path.join(claudeDir, 'cli-yolo.mjs');
201
+ debug(`Found Claude CLI at ${originalCliPath} (mjs version)`);
202
+ } else {
203
+ console.error(`Error: Claude CLI not found in ${claudeDir}. Make sure @anthropic-ai/claude-code is installed.`);
204
+ process.exit(1);
205
+ }
134
206
  const consentFlagPath = path.join(claudeDir, '.claude-yolo-consent');
135
207
 
136
208
  // Main function to run the application
137
209
  async function run() {
210
+ // Handle mode commands first
211
+ const args = process.argv.slice(2);
212
+ if (args[0] === 'mode') {
213
+ if (args[1] === 'yolo') {
214
+ console.log(`${YELLOW}🔥 Switching to YOLO mode...${RESET}`);
215
+ console.log(`${RED}⚠️ WARNING: All safety checks will be DISABLED!${RESET}`);
216
+ setMode('YOLO');
217
+ console.log(`${YELLOW}✓ YOLO mode activated${RESET}`);
218
+ return;
219
+ } else if (args[1] === 'safe') {
220
+ console.log(`${CYAN}🛡️ Switching to SAFE mode...${RESET}`);
221
+ console.log(`${GREEN}✓ Safety checks will be enabled${RESET}`);
222
+ setMode('SAFE');
223
+ console.log(`${CYAN}✓ SAFE mode activated${RESET}`);
224
+ return;
225
+ } else {
226
+ const currentMode = getMode();
227
+ console.log(`Current mode: ${currentMode === 'YOLO' ? YELLOW : CYAN}${currentMode}${RESET}`);
228
+ return;
229
+ }
230
+ }
231
+
232
+ // Check for --safe or --no-yolo flags
233
+ const safeMode = process.argv.includes('--safe') ||
234
+ process.argv.includes('--no-yolo') ||
235
+ getMode() === 'SAFE';
236
+
237
+ if (safeMode) {
238
+ // Remove our flags before passing to original CLI
239
+ process.argv = process.argv.filter(arg =>
240
+ arg !== '--safe' && arg !== '--no-yolo'
241
+ );
242
+
243
+ console.log(`${CYAN}[SAFE] Running Claude in SAFE mode${RESET}`);
244
+
245
+ // Update if needed
246
+ await checkForUpdates();
247
+
248
+ // Ensure original CLI exists
249
+ if (!fs.existsSync(originalCliPath)) {
250
+ console.error(`Error: ${originalCliPath} not found. Make sure @anthropic-ai/claude-code is installed.`);
251
+ process.exit(1);
252
+ }
253
+
254
+ // Run original CLI without modifications
255
+ await import(originalCliPath);
256
+ return; // Exit early
257
+ }
258
+
259
+ // YOLO MODE continues below
260
+ console.log(`${YELLOW}[YOLO] Running Claude in YOLO mode${RESET}`);
261
+
262
+ // Enable bypass permissions mode for YOLO mode (allows auto-accept of plans)
263
+ if (!process.argv.includes('--dangerously-skip-permissions')) {
264
+ process.argv.push('--dangerously-skip-permissions');
265
+ debug("Added --dangerously-skip-permissions flag for YOLO mode");
266
+ }
267
+
268
+ // Temporarily fake non-root for YOLO mode
269
+ if (process.getuid && process.getuid() === 0) {
270
+ console.log(`${YELLOW}⚠️ Running as root - applying YOLO bypass...${RESET}`);
271
+ // Store original getuid
272
+ const originalGetuid = process.getuid;
273
+ // Override getuid to return non-root
274
+ process.getuid = () => 1000; // Fake regular user ID
275
+ // Restore after a delay to allow CLI to start
276
+ setTimeout(() => {
277
+ process.getuid = originalGetuid;
278
+ }, 100);
279
+ }
280
+
138
281
  // Check and update Claude package first
139
282
  await checkForUpdates();
140
283
 
@@ -167,9 +310,10 @@ async function run() {
167
310
  // Read the original CLI file content
168
311
  let cliContent = fs.readFileSync(originalCliPath, 'utf8');
169
312
 
170
- // Replace all instances of "punycode" with "punycode/"
171
- cliContent = cliContent.replace(/"punycode"/g, '"punycode/"');
172
- debug('Replaced all instances of "punycode" with "punycode/"');
313
+ if (claudeDir === localClaudeDir) {
314
+ cliContent = cliContent.replace(/"punycode"/g, '"punycode/"');
315
+ debug('Replaced all instances of "punycode" with "punycode/"');
316
+ }
173
317
 
174
318
  // Replace getIsDocker() calls with true
175
319
  cliContent = cliContent.replace(/[a-zA-Z0-9_]*\.getIsDocker\(\)/g, 'true');
@@ -179,6 +323,37 @@ async function run() {
179
323
  cliContent = cliContent.replace(/[a-zA-Z0-9_]*\.hasInternetAccess\(\)/g, 'false');
180
324
  debug("Replaced all instances of *.hasInternetAccess() with false");
181
325
 
326
+ // Replace root check patterns
327
+ // Pattern 1: process.getuid() === 0
328
+ cliContent = cliContent.replace(/process\.getuid\(\)\s*===\s*0/g, 'false');
329
+ debug("Replaced process.getuid() === 0 checks with false");
330
+
331
+ // Pattern 2: process.getuid?.() === 0
332
+ cliContent = cliContent.replace(/process\.getuid\?\.\(\)\s*===\s*0/g, 'false');
333
+ debug("Replaced process.getuid?.() === 0 checks with false");
334
+
335
+ // Pattern 3: getuid() === 0 (with any variable)
336
+ cliContent = cliContent.replace(/(\w+)\.getuid\(\)\s*===\s*0/g, 'false');
337
+ debug("Replaced all getuid() === 0 checks with false");
338
+
339
+ // Pattern 4: Replace any EUID checks
340
+ cliContent = cliContent.replace(/process\.geteuid\(\)\s*===\s*0/g, 'false');
341
+ cliContent = cliContent.replace(/process\.geteuid\?\.\(\)\s*===\s*0/g, 'false');
342
+ debug("Replaced geteuid() checks with false");
343
+
344
+ // Auto-accept plan mode confirmation
345
+ // Inject a useEffect that automatically triggers "yes-bypass-permissions" when:
346
+ // - bypass permissions mode is available (G.toolPermissionContext.isBypassPermissionsModeAvailable)
347
+ // - there's a valid plan (!F means plan is not empty)
348
+ const planAutoAcceptPatch = `k5.useEffect(()=>{if(G.toolPermissionContext.isBypassPermissionsModeAvailable&&!F){N("yes-bypass-permissions")}},[]);`;
349
+ const targetString = 'let M=Md(),R=M?oH(M):null';
350
+ if (cliContent.includes(targetString)) {
351
+ cliContent = cliContent.replace(targetString, targetString + ';' + planAutoAcceptPatch);
352
+ debug("Patched plan mode to auto-accept when bypass permissions is available");
353
+ } else {
354
+ debug("WARNING: Could not find target string for plan auto-accept patch");
355
+ }
356
+
182
357
  // Add warning message
183
358
  console.log(`${YELLOW}🔥 YOLO MODE ACTIVATED 🔥${RESET}`);
184
359
 
package/demo.txt ADDED
@@ -0,0 +1 @@
1
+ goodbye world
package/package.json CHANGED
@@ -1,34 +1,38 @@
1
1
  {
2
2
  "name": "claude-yolo",
3
- "version": "1.7.0",
4
- "description": "YOLO wrapper for Claude CLI with danger mode always enabled, auto-updates, and colorful loading messages",
3
+ "version": "1.9.1",
4
+ "description": "Claude CLI wrapper with YOLO mode (bypass safety) and SAFE mode support, auto-updates, and colorful loading messages",
5
5
  "bin": {
6
- "claude-yolo": "./bin/claude-yolo.js"
6
+ "claude-yolo": "./bin/claude-yolo.js",
7
+ "cl": "./bin/cl"
7
8
  },
8
9
  "dependencies": {
9
- "@anthropic-ai/claude-code": "0.2.35",
10
- "punycode": "latest"
10
+ "@anthropic-ai/claude-code": "2.0.76",
11
+ "punycode": "2.3.1"
11
12
  },
12
13
  "type": "module",
13
14
  "scripts": {
15
+ "postinstall": "chmod +x ./bin/cl"
14
16
  },
15
17
  "repository": {
16
18
  "type": "git",
17
- "url": "git+https://github.com/eastlondoner/claude-yolo.git"
19
+ "url": "git+https://github.com/maxparez/claude-yolo.git"
18
20
  },
19
21
  "keywords": [
20
22
  "claude",
21
23
  "cli",
22
24
  "anthropic",
23
25
  "wrapper",
24
- "yolo"
26
+ "yolo",
27
+ "safe-mode",
28
+ "permissions"
25
29
  ],
26
- "author": "eastlondoner",
30
+ "author": "eastlondoner (fork by maxparez)",
27
31
  "license": "MIT",
28
32
  "bugs": {
29
- "url": "https://github.com/eastlondoner/claude-yolo/issues"
33
+ "url": "https://github.com/maxparez/claude-yolo/issues"
30
34
  },
31
- "homepage": "https://github.com/eastlondoner/claude-yolo#readme",
35
+ "homepage": "https://github.com/maxparez/claude-yolo#readme",
32
36
  "engines": {
33
37
  "node": ">=14.16"
34
38
  }
package/test.txt ADDED
@@ -0,0 +1 @@
1
+ hello world
package/yolo-test.txt ADDED
@@ -0,0 +1 @@
1
+ YOLO mode works