rethocker 0.2.0 → 0.2.2

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 CHANGED
@@ -1,8 +1,27 @@
1
- # rethocker
2
-
3
- Global key interception and remapping for macOS. Intercept any key or combo system-wide, remap keys, fire shell commands, react to key sequences, and scope rules to specific apps — all from TypeScript.
4
-
5
- Requires **macOS 13+** and **Accessibility permission** (prompted automatically on first run).
1
+ <p align="center">
2
+ <img src="src/assets/logo.png" width="280px" align="center" alt="rethocker logo" />
3
+ <h1 align="center">rethocker</h1>
4
+ <p align="center">
5
+ System-wide key interception and remapping for macOS, in TypeScript.
6
+ </p>
7
+ </p>
8
+
9
+ <!--- badges -->
10
+ <p align="center">
11
+ <a href="https://github.com/benjamine/rethocker/actions?query=branch%3Amain"><img src="https://github.com/benjamine/rethocker/actions/workflows/publish.yml/badge.svg?branch=main" alt="rethocker CI status" /></a>
12
+ <a href="https://twitter.com/beneidel" rel="nofollow"><img src="https://img.shields.io/badge/created%20by-@beneidel-BACABA.svg" alt="Created by Benjamin Eidelman"></a>
13
+ <a href="https://opensource.org/licenses/MIT" rel="nofollow"><img src="https://img.shields.io/github/license/benjamine/rethocker" alt="License"></a>
14
+ <a href="https://www.npmjs.com/package/rethocker" rel="nofollow"><img src="https://img.shields.io/npm/dw/rethocker.svg" alt="npm"></a>
15
+ <a href="https://github.com/benjamine/rethocker" rel="nofollow"><img src="https://img.shields.io/github/stars/benjamine/rethocker" alt="stars"></a>
16
+ </p>
17
+
18
+ ---
19
+
20
+ - Requires **macOS 13+** and **Accessibility permission** (prompted automatically on first run).
21
+ - Built with a native daemon for low-latency key interception, and a TypeScript API for maximum flexibility and AI agent friendliness.
22
+ - Intercept any key or key chord, with per-app scoping and advanced conditions.
23
+ - Remap to other keys, execute shell commands, or call TypeScript handlers with full access to the API.
24
+ - Bundled with convenient actions for common macOS tasks like window management, media control, etc..
6
25
 
7
26
  ## Install
8
27
 
@@ -14,7 +33,7 @@ brew install rethocker
14
33
  rethocker install
15
34
  ```
16
35
 
17
- `rethocker install` scaffolds `~/.config/rethocker/default.ts` and registers a LaunchAgent that starts on login and auto-reloads whenever you save the file.
36
+ `rethocker install` scaffolds `~/.config/rethocker/default.ts` (where you write your own rules) and registers a LaunchAgent that starts on login and auto-reloads whenever you save the file.
18
37
 
19
38
  ```bash
20
39
  rethocker log # live key monitor — see what rethocker captures
@@ -34,6 +53,8 @@ bun add rethocker
34
53
  ## Usage
35
54
 
36
55
  ```ts
56
+ #!/usr/bin/env bun
57
+
37
58
  import { actions, Key, rethocker } from "rethocker"
38
59
 
39
60
  const rk = rethocker([
@@ -253,6 +274,8 @@ actions.window.thirdCenter()
253
274
  actions.window.thirdRight()
254
275
  actions.window.quarterTopLeft()
255
276
  actions.window.maximize()
277
+
278
+ // NOTE: you can use this to compose any custom layouts
256
279
  actions.window.halfLeft("Figma") // move specific app
257
280
 
258
281
  // App management
@@ -272,8 +295,6 @@ actions.media.volumeDown(10)
272
295
  // System
273
296
  actions.system.sleep()
274
297
  actions.system.lockScreen()
275
- actions.system.missionControl()
276
- actions.system.emptyTrash()
277
298
 
278
299
  // Run a Shortcut from the macOS Shortcuts app
279
300
  actions.shortcut("My Shortcut Name")
@@ -365,48 +386,3 @@ await rk.stop()
365
386
  // (by default rethocker keeps the event loop alive)
366
387
  rk.unref()
367
388
  ```
368
-
369
- ## API reference
370
-
371
- ### `rethocker(rules?, options?)` → `RethockerHandle`
372
-
373
- | Option | Type | Description |
374
- |---|---|---|
375
- | `binaryPath` | `string?` | Override the native binary path |
376
-
377
- ### `RethockerHandle`
378
-
379
- | Method | Returns | Description |
380
- |---|---|---|
381
- | `add(rule \| rule[])` | `void` | Add one or more rules |
382
- | `remove(id)` | `void` | Remove a rule permanently |
383
- | `enable(id?)` | `void` | Enable a rule by ID, or all rules if no ID |
384
- | `disable(id?)` | `void` | Disable a rule by ID, or all rules if no ID |
385
- | `on(event, listener)` | `() => void` | Subscribe to an event; returns an unsubscribe function |
386
- | `execute(command)` | `Promise<void>` | Run a shell command immediately (accepts `string \| string[]`) |
387
- | `start()` | `Promise<void>` | Await daemon readiness (optional) |
388
- | `stop()` | `Promise<void>` | Stop the daemon |
389
- | `unref()` | `void` | Allow the process to exit while the daemon runs |
390
- | `ready` | `boolean` | Whether the daemon is ready |
391
-
392
- ### Events
393
-
394
- | Event | Arguments | Description |
395
- |---|---|---|
396
- | `"ready"` | — | Daemon ready |
397
- | `"key"` | `KeyEvent` | Every key event (stream auto-activates on subscribe) |
398
- | `"accessibilityDenied"` | — | Accessibility permission not granted |
399
- | `"error"` | `code, message` | Native daemon error |
400
- | `"exit"` | `code` | Native process exited unexpectedly |
401
-
402
- ### `KeyEvent`
403
-
404
- | Field | Type | Description |
405
- |---|---|---|
406
- | `type` | `"keydown" \| "keyup" \| "flags"` | Event type |
407
- | `keyCode` | `number` | macOS virtual key code |
408
- | `modifiers` | `Modifier[]` | Active modifiers |
409
- | `app` | `string?` | Frontmost app display name |
410
- | `appBundleID` | `string?` | Frontmost app bundle ID |
411
- | `suppressed` | `boolean` | Whether the key was consumed |
412
- | `ruleID` | `string?` | ID of the matched rule |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rethocker",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Intercept and remap global keys on macOS — with per-app and key-sequence support",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
Binary file
package/src/cli.ts CHANGED
@@ -183,26 +183,44 @@ async function cmdRunConfig(configFile: string) {
183
183
 
184
184
  // ─── Help ─────────────────────────────────────────────────────────────────────
185
185
 
186
- const HELP = `
187
- Usage: rethocker <command>
188
-
189
- Commands:
190
- install Scaffold a config file and set up a background agent that
191
- starts on login and auto-reloads when the config is saved
192
- uninstall Stop the background agent and remove it (keeps your config)
193
- restart Restart the background agent
194
- status Show whether the background agent is running
195
- log Live key monitor shows keypresses in rethocker rule syntax
196
- so you can copy-paste them directly into your config
197
- help Print this help message
198
-
199
- Install via Homebrew:
200
- brew tap benjamine/tap
201
- brew install rethocker
202
- rethocker install
186
+ function buildHelp() {
187
+ const lines = [
188
+ "Usage: rethocker <command>",
189
+ "",
190
+ "Commands:",
191
+ " install Scaffold a config file and set up a background agent that",
192
+ " starts on login and auto-reloads when the config is saved",
193
+ " uninstall Stop the background agent and remove it (keeps your config)",
194
+ " restart Restart the background agent",
195
+ " status Show whether the background agent is running",
196
+ " log Live key monitor shows keypresses in rethocker rule syntax",
197
+ " so you can copy-paste them directly into your config",
198
+ " help Print this help message",
199
+ "",
200
+ ];
201
+
202
+ if (existsSync(PLIST_FILE)) {
203
+ const result = run([
204
+ "launchctl",
205
+ "print",
206
+ `${AGENT_DOMAIN}/${AGENT_LABEL}`,
207
+ ]);
208
+ const running = result.ok;
209
+ lines.push(
210
+ `Config: ${tildeify(CONFIG_FILE)} (your rethocker rules are here)`,
211
+ );
212
+ lines.push(`Status: ${running ? "running" : "not running"}`);
213
+ if (!running)
214
+ lines.push('Run "rethocker restart" to start the background agent.');
215
+ } else {
216
+ lines.push(
217
+ `Config: ${tildeify(CONFIG_FILE)} (not found — run "rethocker install")`,
218
+ );
219
+ }
203
220
 
204
- Docs: ${GITHUB}
205
- `.trim();
221
+ lines.push("", `Docs: ${GITHUB}`);
222
+ return lines.join("\n");
223
+ }
206
224
 
207
225
  // ─── Command dispatch ─────────────────────────────────────────────────────────
208
226
 
@@ -240,12 +258,12 @@ switch (subcommand) {
240
258
  case "help":
241
259
  case "--help":
242
260
  case "-h":
243
- console.log(HELP);
261
+ console.log(buildHelp());
244
262
  break;
245
263
 
246
264
  default:
247
265
  if (subcommand) console.error(`Unknown command: "${subcommand}"\n`);
248
- console.log(HELP);
266
+ console.log(buildHelp());
249
267
  process.exit(subcommand ? 1 : 0);
250
268
  }
251
269