mirror of
https://github.com/GitFrog1111/badclaude.git
synced 2026-05-13 13:25:17 +02:00
Whipped
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
# badclaude
|
||||
# OpenWhip
|
||||
|
||||

|
||||
|
||||
Sometimes claude code is going too shlow, and you must whip him into shape..
|
||||
|
||||
> Renamed from `badclaude` to `openwhip`.
|
||||
> The old command/package is deprecated and kept temporarily for migration.
|
||||
|
||||
## Install + run
|
||||
|
||||
```bash
|
||||
npm install -g badclaude
|
||||
badclaude
|
||||
npm install -g openwhip
|
||||
openwhip
|
||||
```
|
||||
|
||||
## Platform support
|
||||
|
||||
- macOS
|
||||
- Windows
|
||||
- Linux (X11): install `xdotool` for keyboard automation (`sudo apt install xdotool`)
|
||||
|
||||
## Controls
|
||||
|
||||
- Click tray icon: spawn whip.
|
||||
|
||||
+2
-25
@@ -1,26 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
let electronBinary;
|
||||
try {
|
||||
electronBinary = require('electron');
|
||||
} catch (e) {
|
||||
console.error('Could not load Electron. Try: npm install -g badclaude');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const appPath = path.resolve(__dirname, '..');
|
||||
|
||||
const child = spawn(electronBinary, [appPath], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
child.on('error', (err) => {
|
||||
console.error('Failed to start badclaude:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.unref();
|
||||
console.warn('[DEPRECATED] "badclaude" has been renamed to "openwhip".');
|
||||
require('./openwhip');
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
const path = require('path');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const invokedAs = path.basename(process.argv[1] || '');
|
||||
if (invokedAs === 'badclaude' || invokedAs === 'badclaude.cmd') {
|
||||
console.warn('[DEPRECATED] "badclaude" has been renamed to "openwhip".');
|
||||
console.warn('Please run: npm install -g openwhip');
|
||||
}
|
||||
|
||||
let electronBinary;
|
||||
try {
|
||||
electronBinary = require('electron');
|
||||
} catch (e) {
|
||||
console.error('Could not load Electron. Try: npm install -g openwhip');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const appPath = path.resolve(__dirname, '..');
|
||||
|
||||
const child = spawn(electronBinary, [appPath], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
child.on('error', (err) => {
|
||||
console.error('Failed to start openwhip:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
child.unref();
|
||||
@@ -52,6 +52,12 @@ function refocusPreviousApp() {
|
||||
console.warn('refocus previous app (Cmd+Tab) failed:', err.message);
|
||||
}
|
||||
});
|
||||
} else if (process.platform === 'linux') {
|
||||
execFile('xdotool', ['key', '--clearmodifiers', 'alt+Tab'], err => {
|
||||
if (err) {
|
||||
console.warn('refocus previous app (Alt+Tab) failed. Install xdotool:', err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
setTimeout(run, delayMs);
|
||||
@@ -66,7 +72,7 @@ function createTrayIconFallback() {
|
||||
return img;
|
||||
}
|
||||
}
|
||||
console.warn('badclaude: icon/Template.png missing or invalid');
|
||||
console.warn('openwhip: icon/Template.png missing or invalid');
|
||||
return nativeImage.createEmpty();
|
||||
}
|
||||
|
||||
@@ -100,7 +106,7 @@ async function getTrayIcon() {
|
||||
} catch (e) {
|
||||
console.warn('AppIcon.icns Quick Look thumbnail failed:', e?.message || e);
|
||||
}
|
||||
const tmp = path.join(os.tmpdir(), 'badclaude-tray.icns');
|
||||
const tmp = path.join(os.tmpdir(), 'openwhip-tray.icns');
|
||||
try {
|
||||
fs.copyFileSync(file, tmp);
|
||||
const t = await tryIcnsTrayImage(tmp);
|
||||
@@ -192,6 +198,8 @@ function sendMacro() {
|
||||
sendMacroWindows(chosen);
|
||||
} else if (process.platform === 'darwin') {
|
||||
sendMacroMac(chosen);
|
||||
} else if (process.platform === 'linux') {
|
||||
sendMacroLinux(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,26 +231,54 @@ function sendMacroWindows(text) {
|
||||
|
||||
function sendMacroMac(text) {
|
||||
const escaped = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
const script = [
|
||||
const interruptScript = [
|
||||
'tell application "System Events"',
|
||||
' key code 8 using {control down}', // Ctrl+C interrupt
|
||||
'end tell'
|
||||
].join('\n');
|
||||
const typeAndEnterScript = [
|
||||
'tell application "System Events"',
|
||||
' key code 8 using {command down}', // Cmd+C
|
||||
' delay 0.03',
|
||||
` keystroke "${escaped}"`,
|
||||
' key code 36', // Enter
|
||||
'end tell'
|
||||
].join('\n');
|
||||
|
||||
execFile('osascript', ['-e', script], err => {
|
||||
execFile('osascript', ['-e', interruptScript], err => {
|
||||
if (err) {
|
||||
console.warn('mac macro failed (enable Accessibility for terminal/app):', err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
execFile('osascript', ['-e', typeAndEnterScript], err2 => {
|
||||
if (err2) {
|
||||
console.warn('mac macro failed (enable Accessibility for terminal/app):', err2.message);
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
|
||||
function sendMacroLinux(text) {
|
||||
execFile(
|
||||
'xdotool',
|
||||
[
|
||||
'key', '--clearmodifiers', 'ctrl+c',
|
||||
'type', '--delay', '1', '--clearmodifiers', '--', text,
|
||||
'key', 'Return',
|
||||
],
|
||||
err => {
|
||||
if (err) {
|
||||
console.warn('linux macro failed. Install xdotool:', err.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ── App lifecycle ───────────────────────────────────────────────────────────
|
||||
app.whenReady().then(async () => {
|
||||
tray = new Tray(await getTrayIcon());
|
||||
tray.setToolTip('Bad Claude – click for whip');
|
||||
tray.setToolTip('OpenWhip - click for whip');
|
||||
tray.setContextMenu(
|
||||
Menu.buildFromTemplate([
|
||||
{ label: 'Quit', click: () => app.quit() },
|
||||
|
||||
Generated
+15
-5
@@ -1,18 +1,28 @@
|
||||
{
|
||||
"name": "badclaude",
|
||||
"version": "1.0.2",
|
||||
"name": "openwhip",
|
||||
"version": "1.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "badclaude",
|
||||
"version": "1.0.2",
|
||||
"name": "openwhip",
|
||||
"version": "1.1.0",
|
||||
"license": "MIT",
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32"
|
||||
],
|
||||
"dependencies": {
|
||||
"electron": "^33.0.0",
|
||||
"koffi": "^2.9.0"
|
||||
},
|
||||
"bin": {
|
||||
"badclaude": "bin/badclaude.js"
|
||||
"badclaude": "bin/openwhip.js",
|
||||
"openwhip": "bin/openwhip.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/get": {
|
||||
|
||||
+9
-6
@@ -1,14 +1,16 @@
|
||||
{
|
||||
"name": "badclaude",
|
||||
"version": "1.0.2",
|
||||
"name": "openwhip",
|
||||
"version": "1.1.0",
|
||||
"description": "Whip Claude into shape",
|
||||
"license": "MIT",
|
||||
"main": "main.js",
|
||||
"bin": {
|
||||
"badclaude": "bin/badclaude.js"
|
||||
"openwhip": "bin/openwhip.js",
|
||||
"badclaude": "bin/openwhip.js"
|
||||
},
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
@@ -22,18 +24,19 @@
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/GitFrog1111/badclaude.git"
|
||||
"url": "git+https://github.com/GitFrog1111/OpenWhip.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/GitFrog1111/badclaude/issues"
|
||||
"url": "https://github.com/GitFrog1111/OpenWhip/issues"
|
||||
},
|
||||
"homepage": "https://github.com/GitFrog1111/badclaude#readme",
|
||||
"homepage": "https://github.com/GitFrog1111/OpenWhip#readme",
|
||||
"files": [
|
||||
"main.js",
|
||||
"preload.js",
|
||||
"overlay.html",
|
||||
"sounds",
|
||||
"icon",
|
||||
"bin/openwhip.js",
|
||||
"bin/badclaude.js",
|
||||
"README.md"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user