rethocker 0.1.1 → 0.1.3
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/bin/rethocker-native +0 -0
- package/package.json +12 -3
- package/src/actions.ts +1 -2
- package/src/cli.ts +350 -0
- package/src/daemon.ts +2 -4
- package/src/index.test.ts +654 -30
- package/src/parse-key.test.ts +534 -0
- package/src/parse-key.ts +1 -1
- package/src/rethocker.ts +8 -2
- package/src/scripts/debug-keys.ts +0 -5
- package/src/scripts/log.ts +233 -0
- package/src/types.ts +0 -21
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 rethocker 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/bin/rethocker-native
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rethocker",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Intercept and remap global keys on macOS — with per-app
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
7
7
|
"module": "src/index.ts",
|
|
8
8
|
"types": "src/index.ts",
|
|
9
|
+
"license": "MIT",
|
|
9
10
|
"os": [
|
|
10
11
|
"darwin"
|
|
11
12
|
],
|
|
13
|
+
"bin": {
|
|
14
|
+
"rethocker": "src/cli.ts"
|
|
15
|
+
},
|
|
12
16
|
"files": [
|
|
13
17
|
"src/",
|
|
14
18
|
"bin/rethocker-native"
|
|
@@ -16,11 +20,16 @@
|
|
|
16
20
|
"scripts": {
|
|
17
21
|
"build:native": "cd swift && swift build -c release && cp .build/release/rethocker-native ../bin/rethocker-native && codesign --sign - ../bin/rethocker-native",
|
|
18
22
|
"build:native:universal": "cd swift && swift build -c release --arch arm64 --arch x86_64 && lipo -create .build/arm64-apple-macosx/release/rethocker-native .build/x86_64-apple-macosx/release/rethocker-native -output ../bin/rethocker-native && codesign --sign - ../bin/rethocker-native",
|
|
23
|
+
"build:cli:arm64": "bun build --compile --target=bun-darwin-arm64 src/cli.ts --outfile dist/rethocker-darwin-arm64",
|
|
24
|
+
"build:cli:x64": "bun build --compile --target=bun-darwin-x64 src/cli.ts --outfile dist/rethocker-darwin-x64",
|
|
25
|
+
"build:cli": "bun run build:cli:arm64 && bun run build:cli:x64",
|
|
26
|
+
"build": "bun run build:native:universal && bun run build:cli",
|
|
19
27
|
"typecheck": "tsc --noEmit",
|
|
20
28
|
"lint": "biome lint --error-on-warnings .",
|
|
21
29
|
"format": "biome format --write .",
|
|
22
30
|
"check": "biome check --error-on-warnings .",
|
|
23
|
-
"test": "bun test"
|
|
31
|
+
"test": "bun test",
|
|
32
|
+
"test:coverage": "bun test --coverage"
|
|
24
33
|
},
|
|
25
34
|
"devDependencies": {
|
|
26
35
|
"@biomejs/biome": "^2.4.9",
|
package/src/actions.ts
CHANGED
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
*
|
|
11
11
|
* const rk = rethocker([
|
|
12
12
|
* { key: "Ctrl+Left", execute: actions.window.halfLeft() },
|
|
13
|
-
* { key: "Ctrl+F", execute: actions.focusMode.toggle() },
|
|
14
13
|
* { key: "Ctrl+Shift+S", execute: actions.app.focus("Slack") },
|
|
15
14
|
* { key: "F8", execute: actions.media.playPause() },
|
|
16
15
|
* // Multiple actions at once:
|
|
17
|
-
* { key: "Ctrl+Alt+L", execute: [actions.
|
|
16
|
+
* { key: "Ctrl+Alt+L", execute: [actions.window.halfLeft(), actions.app.focus("Slack")] },
|
|
18
17
|
* ])
|
|
19
18
|
*/
|
|
20
19
|
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* rethocker CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* rethocker <command>
|
|
7
|
+
*
|
|
8
|
+
* Commands: install | uninstall | restart | status | log | help
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { runLog } from "./scripts/log.ts";
|
|
15
|
+
|
|
16
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const GITHUB = "https://github.com/benjamine/rethocker";
|
|
19
|
+
const AGENT_LABEL = "com.rethocker.default";
|
|
20
|
+
const AGENT_DOMAIN = `gui/${process.getuid?.() ?? 501}`;
|
|
21
|
+
|
|
22
|
+
const CONFIG_DIR = join(homedir(), ".config", "rethocker");
|
|
23
|
+
const CONFIG_FILE = join(CONFIG_DIR, "default.ts");
|
|
24
|
+
const PLIST_DIR = join(homedir(), "Library", "LaunchAgents");
|
|
25
|
+
const PLIST_FILE = join(PLIST_DIR, `${AGENT_LABEL}.plist`);
|
|
26
|
+
const LOG_FILE = join(homedir(), "Library", "Logs", "rethocker.log");
|
|
27
|
+
|
|
28
|
+
// ─── Templates ────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
const DEFAULT_CONFIG = `#!/usr/bin/env bun
|
|
31
|
+
/**
|
|
32
|
+
* rethocker config
|
|
33
|
+
*
|
|
34
|
+
* Edit this file to set up your keyboard rules.
|
|
35
|
+
* Changes are picked up automatically — rethocker restarts when you save.
|
|
36
|
+
* Docs & examples: ${GITHUB}
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { rethocker, actions, Key } from "rethocker";
|
|
40
|
+
|
|
41
|
+
const rk = rethocker([
|
|
42
|
+
// ── Add your rules here ───────────────────────────────────────────
|
|
43
|
+
//
|
|
44
|
+
// Remap Caps Lock → Escape:
|
|
45
|
+
// { key: Key.capsLock, remap: Key.escape },
|
|
46
|
+
//
|
|
47
|
+
// Run a shell command on a key combo:
|
|
48
|
+
// { key: "Cmd+Shift+S", execute: actions.app.focus("Slack") },
|
|
49
|
+
//
|
|
50
|
+
// Call a TypeScript function:
|
|
51
|
+
// { key: "F1", handler: (e) => console.log("F1 pressed", e) },
|
|
52
|
+
//
|
|
53
|
+
// Restrict a rule to a specific app:
|
|
54
|
+
// { key: "Ctrl+J", execute: "echo hello", app: "iTerm2" },
|
|
55
|
+
//
|
|
56
|
+
// ─────────────────────────────────────────────────────────────────
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
await rk.start();
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
function makePlist(
|
|
63
|
+
cliPath: string,
|
|
64
|
+
configFile: string,
|
|
65
|
+
logFile: string,
|
|
66
|
+
): string {
|
|
67
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
68
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
69
|
+
<plist version="1.0">
|
|
70
|
+
<dict>
|
|
71
|
+
<key>Label</key>
|
|
72
|
+
<string>${AGENT_LABEL}</string>
|
|
73
|
+
|
|
74
|
+
<key>ProgramArguments</key>
|
|
75
|
+
<array>
|
|
76
|
+
<string>${cliPath}</string>
|
|
77
|
+
<string>--run-config</string>
|
|
78
|
+
<string>${configFile}</string>
|
|
79
|
+
</array>
|
|
80
|
+
|
|
81
|
+
<key>RunAtLoad</key>
|
|
82
|
+
<true/>
|
|
83
|
+
|
|
84
|
+
<key>KeepAlive</key>
|
|
85
|
+
<true/>
|
|
86
|
+
|
|
87
|
+
<key>ThrottleInterval</key>
|
|
88
|
+
<integer>5</integer>
|
|
89
|
+
|
|
90
|
+
<key>WatchPaths</key>
|
|
91
|
+
<array>
|
|
92
|
+
<string>${configFile}</string>
|
|
93
|
+
</array>
|
|
94
|
+
|
|
95
|
+
<key>StandardOutPath</key>
|
|
96
|
+
<string>${logFile}</string>
|
|
97
|
+
|
|
98
|
+
<key>StandardErrorPath</key>
|
|
99
|
+
<string>${logFile}</string>
|
|
100
|
+
</dict>
|
|
101
|
+
</plist>
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
function tildeify(p: string): string {
|
|
108
|
+
const home = homedir();
|
|
109
|
+
return p.startsWith(home) ? `~${p.slice(home.length)}` : p;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function run(cmd: string[]): { ok: boolean; stdout: string; stderr: string } {
|
|
113
|
+
const result = Bun.spawnSync(cmd, { stdout: "pipe", stderr: "pipe" });
|
|
114
|
+
return {
|
|
115
|
+
ok: result.exitCode === 0,
|
|
116
|
+
stdout: new TextDecoder().decode(result.stdout).trim(),
|
|
117
|
+
stderr: new TextDecoder().decode(result.stderr).trim(),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function findBun(): string {
|
|
122
|
+
const fromPath = run(["which", "bun"]).stdout;
|
|
123
|
+
if (fromPath) return fromPath;
|
|
124
|
+
const fallback = join(homedir(), ".bun", "bin", "bun");
|
|
125
|
+
if (existsSync(fallback)) return fallback;
|
|
126
|
+
console.error("Could not find bun. Please install it from https://bun.sh");
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function bootstrapAgent(): void {
|
|
131
|
+
// bootout first (no-op if not loaded)
|
|
132
|
+
run(["launchctl", "bootout", AGENT_DOMAIN, PLIST_FILE]);
|
|
133
|
+
const result = run(["launchctl", "bootstrap", AGENT_DOMAIN, PLIST_FILE]);
|
|
134
|
+
if (!result.ok) {
|
|
135
|
+
console.error(`Failed to load agent: ${result.stderr}`);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function bootoutAgent(): void {
|
|
141
|
+
run(["launchctl", "bootout", AGENT_DOMAIN, PLIST_FILE]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─── --run-config (internal, used by LaunchAgent) ─────────────────────────────
|
|
145
|
+
// Spawns the user's config via bun, pipes stderr to the log file, and sends
|
|
146
|
+
// a macOS notification if it crashes.
|
|
147
|
+
|
|
148
|
+
async function cmdRunConfig(configFile: string) {
|
|
149
|
+
const bunBin = findBun();
|
|
150
|
+
const stderrChunks: string[] = [];
|
|
151
|
+
|
|
152
|
+
const child = Bun.spawn([bunBin, configFile], {
|
|
153
|
+
stdin: "inherit",
|
|
154
|
+
stdout: "inherit",
|
|
155
|
+
stderr: "pipe",
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Stream stderr through (lands in log file via LaunchAgent) and buffer it
|
|
159
|
+
(async () => {
|
|
160
|
+
const reader = child.stderr.getReader();
|
|
161
|
+
const dec = new TextDecoder();
|
|
162
|
+
while (true) {
|
|
163
|
+
const { done, value } = await reader.read();
|
|
164
|
+
if (done) break;
|
|
165
|
+
const chunk = dec.decode(value);
|
|
166
|
+
process.stderr.write(chunk);
|
|
167
|
+
stderrChunks.push(chunk);
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
|
|
171
|
+
const code = await child.exited;
|
|
172
|
+
|
|
173
|
+
if (code !== 0) {
|
|
174
|
+
const detail =
|
|
175
|
+
stderrChunks.join("").trim().slice(-200).replace(/"/g, "'") ||
|
|
176
|
+
`See ${tildeify(LOG_FILE)} for details.`;
|
|
177
|
+
const script = `display notification "${detail}" with title "rethocker" subtitle "Config error — fix and save to reload"`;
|
|
178
|
+
Bun.spawnSync(["osascript", "-e", script]);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
process.exit(code ?? 1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ─── Help ─────────────────────────────────────────────────────────────────────
|
|
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
|
+
Examples:
|
|
200
|
+
rethocker install
|
|
201
|
+
rethocker log
|
|
202
|
+
rethocker status
|
|
203
|
+
|
|
204
|
+
Docs: ${GITHUB}
|
|
205
|
+
`.trim();
|
|
206
|
+
|
|
207
|
+
// ─── Command dispatch ─────────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
const [, , subcommand, ...rest] = process.argv;
|
|
210
|
+
|
|
211
|
+
switch (subcommand) {
|
|
212
|
+
case "log":
|
|
213
|
+
await runLog();
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case "--run-config":
|
|
217
|
+
if (!rest[0]) {
|
|
218
|
+
console.error("Usage: rethocker --run-config <configFile>");
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
await cmdRunConfig(rest[0]);
|
|
222
|
+
break;
|
|
223
|
+
|
|
224
|
+
case "install":
|
|
225
|
+
cmdInstall();
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
case "uninstall":
|
|
229
|
+
cmdUninstall();
|
|
230
|
+
break;
|
|
231
|
+
|
|
232
|
+
case "restart":
|
|
233
|
+
cmdRestart();
|
|
234
|
+
break;
|
|
235
|
+
|
|
236
|
+
case "status":
|
|
237
|
+
cmdStatus();
|
|
238
|
+
break;
|
|
239
|
+
|
|
240
|
+
case "help":
|
|
241
|
+
case "--help":
|
|
242
|
+
case "-h":
|
|
243
|
+
console.log(HELP);
|
|
244
|
+
break;
|
|
245
|
+
|
|
246
|
+
default:
|
|
247
|
+
if (subcommand) console.error(`Unknown command: "${subcommand}"\n`);
|
|
248
|
+
console.log(HELP);
|
|
249
|
+
process.exit(subcommand ? 1 : 0);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ─── install ──────────────────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
function cmdInstall() {
|
|
255
|
+
// Scaffold config dir
|
|
256
|
+
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
257
|
+
if (!existsSync(PLIST_DIR)) mkdirSync(PLIST_DIR, { recursive: true });
|
|
258
|
+
|
|
259
|
+
// Scaffold default.ts (skip if exists — user may have edited it)
|
|
260
|
+
if (existsSync(CONFIG_FILE)) {
|
|
261
|
+
console.log(
|
|
262
|
+
`Config already exists — leaving it untouched:\n ${tildeify(CONFIG_FILE)}`,
|
|
263
|
+
);
|
|
264
|
+
} else {
|
|
265
|
+
writeFileSync(CONFIG_FILE, DEFAULT_CONFIG, { mode: 0o755 });
|
|
266
|
+
console.log(`Created config:\n ${tildeify(CONFIG_FILE)}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Write plist — LaunchAgent calls `rethocker --run-config <configFile>`
|
|
270
|
+
// process.execPath is the rethocker binary itself (resolved at runtime)
|
|
271
|
+
writeFileSync(PLIST_FILE, makePlist(process.execPath, CONFIG_FILE, LOG_FILE));
|
|
272
|
+
console.log(`Created LaunchAgent:\n ${tildeify(PLIST_FILE)}`);
|
|
273
|
+
|
|
274
|
+
// Load agent
|
|
275
|
+
bootstrapAgent();
|
|
276
|
+
console.log("Background agent loaded and running.");
|
|
277
|
+
|
|
278
|
+
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "your editor";
|
|
279
|
+
console.log(`
|
|
280
|
+
Open your config to start setting up rules:
|
|
281
|
+
${editor} ${tildeify(CONFIG_FILE)}
|
|
282
|
+
|
|
283
|
+
rethocker runs in the background and reloads automatically when you save.
|
|
284
|
+
Logs: ${tildeify(LOG_FILE)}
|
|
285
|
+
Docs: ${GITHUB}
|
|
286
|
+
`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ─── uninstall ────────────────────────────────────────────────────────────────
|
|
290
|
+
|
|
291
|
+
function cmdUninstall() {
|
|
292
|
+
if (!existsSync(PLIST_FILE)) {
|
|
293
|
+
console.log("No LaunchAgent found — nothing to uninstall.");
|
|
294
|
+
process.exit(0);
|
|
295
|
+
}
|
|
296
|
+
bootoutAgent();
|
|
297
|
+
console.log("Background agent stopped.");
|
|
298
|
+
const { unlinkSync } = require("node:fs") as typeof import("node:fs");
|
|
299
|
+
unlinkSync(PLIST_FILE);
|
|
300
|
+
console.log(`Removed: ${tildeify(PLIST_FILE)}`);
|
|
301
|
+
console.log(`\nYour config is untouched at: ${tildeify(CONFIG_FILE)}`);
|
|
302
|
+
console.log('Run "rethocker install" to set it up again.');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ─── restart ──────────────────────────────────────────────────────────────────
|
|
306
|
+
|
|
307
|
+
function cmdRestart() {
|
|
308
|
+
if (!existsSync(PLIST_FILE)) {
|
|
309
|
+
console.error('Agent not installed. Run "rethocker install" first.');
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
const result = run([
|
|
313
|
+
"launchctl",
|
|
314
|
+
"kickstart",
|
|
315
|
+
"-k",
|
|
316
|
+
`${AGENT_DOMAIN}/${AGENT_LABEL}`,
|
|
317
|
+
]);
|
|
318
|
+
if (result.ok) {
|
|
319
|
+
console.log("rethocker restarted.");
|
|
320
|
+
} else {
|
|
321
|
+
bootstrapAgent();
|
|
322
|
+
console.log("rethocker started.");
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ─── status ───────────────────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
function cmdStatus() {
|
|
329
|
+
if (!existsSync(PLIST_FILE)) {
|
|
330
|
+
console.log("Status: not installed");
|
|
331
|
+
console.log('Run "rethocker install" to set up the background agent.');
|
|
332
|
+
process.exit(0);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const result = run(["launchctl", "print", `${AGENT_DOMAIN}/${AGENT_LABEL}`]);
|
|
336
|
+
if (!result.ok) {
|
|
337
|
+
console.log("Status: installed but not running");
|
|
338
|
+
console.log('Run "rethocker restart" to start it.');
|
|
339
|
+
process.exit(0);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const pidMatch = result.stdout.match(/pid\s*=\s*(\d+)/);
|
|
343
|
+
const pid = pidMatch?.[1] ?? null;
|
|
344
|
+
const stateMatch = result.stdout.match(/state\s*=\s*(\w+)/);
|
|
345
|
+
const state = stateMatch?.[1] ?? "running";
|
|
346
|
+
|
|
347
|
+
console.log(`Status: ${state}${pid ? ` (pid ${pid})` : ""}`);
|
|
348
|
+
console.log(`Config: ${tildeify(CONFIG_FILE)}`);
|
|
349
|
+
console.log(`Logs: ${tildeify(LOG_FILE)}`);
|
|
350
|
+
}
|
package/src/daemon.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { EventEmitter } from "node:events";
|
|
14
|
-
import type {
|
|
14
|
+
import type { KeyEvent, RethockerEvents } from "./types.ts";
|
|
15
15
|
|
|
16
16
|
// ─── Typed EventEmitter (internal, never exported) ────────────────────────────
|
|
17
17
|
|
|
@@ -117,9 +117,7 @@ export function createDaemon(binaryPath: string): Daemon {
|
|
|
117
117
|
msg.eventID as string | undefined,
|
|
118
118
|
);
|
|
119
119
|
break;
|
|
120
|
-
|
|
121
|
-
emitter.emit("devices", msg.devices as DeviceInfo[]);
|
|
122
|
-
break;
|
|
120
|
+
|
|
123
121
|
case "error":
|
|
124
122
|
if (msg.code === "accessibility_denied") {
|
|
125
123
|
emitter.emit("accessibilityDenied");
|