mirroir-mcp 0.17.0 → 0.19.0

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
@@ -7,7 +7,6 @@ This npm package downloads the pre-built macOS binary from [GitHub releases](htt
7
7
  ## Requirements
8
8
 
9
9
  - macOS 15+ with iPhone Mirroring
10
- - [Karabiner-Elements](https://karabiner-elements.pqrs.org/) installed and activated
11
10
  - iPhone connected via iPhone Mirroring
12
11
 
13
12
  ## Install
@@ -28,7 +27,7 @@ Then add to your MCP client config:
28
27
  }
29
28
  ```
30
29
 
31
- See the [full documentation](https://github.com/jfarcand/mirroir-mcp) for setup instructions including the Karabiner helper daemon.
30
+ See the [full documentation](https://github.com/jfarcand/mirroir-mcp) for details.
32
31
 
33
32
  ## License
34
33
 
package/bin/mirroir-mcp CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // ABOUTME: Thin wrapper that launches the native MCP server binary.
3
- // ABOUTME: Routes "setup" and "install" subcommands to their respective scripts.
3
+ // ABOUTME: Routes "install" subcommand to the interactive MCP client configuration script.
4
4
 
5
5
  const { execFileSync } = require("child_process");
6
6
  const fs = require("fs");
@@ -9,10 +9,9 @@ const path = require("path");
9
9
  const binDir = __dirname;
10
10
  const pkgDir = path.dirname(binDir);
11
11
  const binary = path.join(binDir, "mirroir-mcp-native");
12
- const setupScript = path.join(pkgDir, "setup.js");
13
12
  const installScript = path.join(pkgDir, "install-cmd.js");
14
13
 
15
- // Handle "install" subcommand — full interactive installer (Karabiner + helper + MCP client)
14
+ // Handle "install" subcommand — interactive MCP client configuration
16
15
  if (process.argv[2] === "install") {
17
16
  if (!fs.existsSync(installScript)) {
18
17
  console.error("Install script not found. Run: npm rebuild mirroir-mcp");
@@ -27,24 +26,7 @@ if (process.argv[2] === "install") {
27
26
  process.exit(0);
28
27
  }
29
28
 
30
- // Handle "setup" subcommand — interactive helper daemon installation
31
- if (process.argv[2] === "setup") {
32
- if (!fs.existsSync(setupScript)) {
33
- console.error("Setup script not found. Run: npm rebuild mirroir-mcp");
34
- process.exit(1);
35
- }
36
- try {
37
- execFileSync("node", [setupScript], { stdio: "inherit" });
38
- } catch (e) {
39
- console.error("Setup failed. See https://github.com/jfarcand/mirroir-mcp for manual install.");
40
- process.exit(1);
41
- }
42
- process.exit(0);
43
- }
44
-
45
- // Run the MCP server — starts regardless of helper daemon state.
46
- // If the helper isn't running, tools return helpful error messages
47
- // telling the user to run: npx mirroir-mcp setup
29
+ // Run the MCP server
48
30
  try {
49
31
  execFileSync(binary, process.argv.slice(2), { stdio: "inherit" });
50
32
  } catch (e) {
package/install-cmd.js CHANGED
@@ -1,100 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  // ABOUTME: Interactive one-command installer for mirroir-mcp.
3
- // ABOUTME: Handles standalone DriverKit install (or reuses Karabiner-Elements), helper daemon setup, and MCP client configuration.
3
+ // ABOUTME: Builds from source if in a checkout, then configures the MCP client.
4
4
 
5
- const { execSync, execFileSync, spawnSync } = require("child_process");
5
+ const { execSync } = require("child_process");
6
6
  const fs = require("fs");
7
7
  const path = require("path");
8
8
  const readline = require("readline");
9
9
 
10
- const HELPER_SOCK = "/var/run/mirroir-helper.sock";
11
- const KARABINER_APP = "/Applications/Karabiner-Elements.app";
12
- const DRIVERKIT_MANAGER = "/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager";
13
- const DRIVERKIT_VERSION = "6.10.0";
14
- const DRIVERKIT_PKG = `Karabiner-DriverKit-VirtualHIDDevice-${DRIVERKIT_VERSION}.pkg`;
15
- const DRIVERKIT_URL = `https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases/download/v${DRIVERKIT_VERSION}/${DRIVERKIT_PKG}`;
16
- const KARABINER_SOCK_DIR = "/Library/Application Support/org.pqrs/tmp/rootonly/vhidd_server";
17
- const SETUP_SCRIPT = path.join(__dirname, "setup.js");
18
10
  const BIN_DIR = path.join(__dirname, "bin");
19
11
  const REPO_ROOT = path.dirname(__dirname);
20
12
 
21
- // --- DriverKit ---
22
-
23
- function hasVhiddSocket() {
24
- try {
25
- const result = spawnSync("sudo", ["bash", "-c",
26
- `ls '${KARABINER_SOCK_DIR}'/*.sock`
27
- ], { timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
28
- return result.status === 0;
29
- } catch (checkErr) {
30
- return false;
31
- }
32
- }
33
-
34
- function ensureDriverKit() {
35
- if (hasVhiddSocket()) {
36
- const provider = fs.existsSync(KARABINER_APP) ? "Karabiner-Elements" : "standalone DriverKit";
37
- console.log(`[1/3] DriverKit virtual HID is running (${provider}).`);
38
- return;
39
- }
40
-
41
- if (fs.existsSync(KARABINER_APP)) {
42
- console.log("[1/3] Karabiner-Elements is installed but the DriverKit extension is not running.");
43
- console.log(" Approve the extension in System Settings:");
44
- console.log(" System Settings > General > Login Items & Extensions");
45
- console.log(" Enable all toggles under Karabiner-Elements");
46
- console.log("");
47
- console.log("Press Enter once you have approved the extension...");
48
- spawnSync("bash", ["-c", "read -r"], { stdio: "inherit" });
49
- return;
50
- }
51
-
52
- if (fs.existsSync(DRIVERKIT_MANAGER)) {
53
- console.log("[1/3] Standalone DriverKit is installed but the extension is not running.");
54
- console.log(" Activating...");
55
- try {
56
- execSync(`"${DRIVERKIT_MANAGER}" activate`, { stdio: "inherit" });
57
- } catch (activateErr) {
58
- // Activation may fail if already activated — continue
59
- }
60
- console.log(" Approve the extension in System Settings > General > Login Items & Extensions.");
61
- console.log("");
62
- console.log("Press Enter once you have approved the extension...");
63
- spawnSync("bash", ["-c", "read -r"], { stdio: "inherit" });
64
- return;
65
- }
66
-
67
- console.log("[1/3] Installing standalone Karabiner DriverKit package...");
68
-
69
- const tmpPkg = `/tmp/${DRIVERKIT_PKG}`;
70
- try {
71
- execSync(`curl -fSL -o "${tmpPkg}" "${DRIVERKIT_URL}"`, { stdio: "inherit" });
72
- execSync(`sudo installer -pkg "${tmpPkg}" -target /`, { stdio: "inherit" });
73
- execSync(`rm -f "${tmpPkg}"`, { stdio: "ignore" });
74
- } catch (installErr) {
75
- console.error("Failed to install DriverKit package.");
76
- console.error(`Download manually from: https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases`);
77
- process.exit(1);
78
- }
79
-
80
- console.log("");
81
- console.log("Activating DriverKit system extension...");
82
- try {
83
- execSync(`"${DRIVERKIT_MANAGER}" activate`, { stdio: "inherit" });
84
- } catch (activateErr) {
85
- // Continue — user will approve in System Settings
86
- }
87
-
88
- console.log("");
89
- console.log("Approve the system extension in System Settings:");
90
- console.log(" System Settings > General > Login Items & Extensions");
91
- console.log(" Enable the Karabiner-DriverKit-VirtualHIDDevice toggle");
92
- console.log("");
93
- console.log("Press Enter once you have approved the extension...");
94
-
95
- spawnSync("bash", ["-c", "read -r"], { stdio: "inherit" });
96
- }
97
-
98
13
  // --- Source Build ---
99
14
 
100
15
  function isSourceCheckout() {
@@ -106,56 +21,10 @@ function buildFromSource() {
106
21
  execSync("swift build -c release", { cwd: REPO_ROOT, stdio: "inherit" });
107
22
 
108
23
  const releaseBin = path.join(REPO_ROOT, ".build", "release");
109
- const plistSrc = path.join(REPO_ROOT, "Resources", "com.jfarcand.mirroir-helper.plist");
110
24
 
111
25
  fs.mkdirSync(BIN_DIR, { recursive: true });
112
- fs.copyFileSync(path.join(releaseBin, "mirroir-helper"), path.join(BIN_DIR, "mirroir-helper"));
113
- fs.chmodSync(path.join(BIN_DIR, "mirroir-helper"), 0o755);
114
26
  fs.copyFileSync(path.join(releaseBin, "mirroir-mcp"), path.join(BIN_DIR, "mirroir-mcp-native"));
115
27
  fs.chmodSync(path.join(BIN_DIR, "mirroir-mcp-native"), 0o755);
116
- fs.copyFileSync(plistSrc, path.join(BIN_DIR, "com.jfarcand.mirroir-helper.plist"));
117
- }
118
-
119
- // --- Helper Daemon ---
120
-
121
- function isHelperRunning() {
122
- if (!fs.existsSync(HELPER_SOCK)) return false;
123
- try {
124
- const result = spawnSync("bash", ["-c",
125
- `echo '{"action":"status"}' | nc -U ${HELPER_SOCK} 2>/dev/null`
126
- ], { timeout: 3000 });
127
- const output = result.stdout ? result.stdout.toString() : "";
128
- return output.includes('"ok"');
129
- } catch (socketErr) {
130
- return false;
131
- }
132
- }
133
-
134
- function ensureHelper() {
135
- if (isHelperRunning()) {
136
- console.log("[2/3] Helper daemon is running.");
137
- return;
138
- }
139
-
140
- console.log("[2/3] Helper daemon not running. Setting up...");
141
-
142
- // If helper binary is missing and we're in a source checkout, build first
143
- const helperBin = path.join(BIN_DIR, "mirroir-helper");
144
- if (!fs.existsSync(helperBin) && isSourceCheckout()) {
145
- buildFromSource();
146
- }
147
-
148
- if (!fs.existsSync(SETUP_SCRIPT)) {
149
- console.error("Setup script not found. Run: npm rebuild mirroir-mcp");
150
- process.exit(1);
151
- }
152
-
153
- try {
154
- execFileSync("node", [SETUP_SCRIPT], { stdio: "inherit" });
155
- } catch (setupErr) {
156
- console.error("Helper setup failed. See https://github.com/jfarcand/mirroir-mcp for manual install.");
157
- process.exit(1);
158
- }
159
28
  }
160
29
 
161
30
  // --- MCP Client Configuration ---
@@ -174,7 +43,7 @@ function ask(question) {
174
43
  }
175
44
 
176
45
  async function configureMcpClient() {
177
- console.log("[3/3] Configure MCP client");
46
+ console.log("[1/1] Configure MCP client");
178
47
  console.log("");
179
48
  console.log(" 1) Claude Code");
180
49
  console.log(" 2) Cursor");
@@ -377,8 +246,12 @@ async function main() {
377
246
  console.log("=== mirroir-mcp installer ===");
378
247
  console.log("");
379
248
 
380
- ensureDriverKit();
381
- ensureHelper();
249
+ // Build from source if in a development checkout
250
+ const nativeBin = path.join(BIN_DIR, "mirroir-mcp-native");
251
+ if (!fs.existsSync(nativeBin) && isSourceCheckout()) {
252
+ buildFromSource();
253
+ }
254
+
382
255
  await configureMcpClient();
383
256
 
384
257
  console.log("");
package/install.js CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // Downloads the pre-built mirroir-mcp and mirroir-helper binaries
3
- // plus the LaunchDaemon plist from GitHub releases.
2
+ // Downloads the pre-built mirroir-mcp binary from GitHub releases.
4
3
  // Only supports macOS (darwin) since iPhone Mirroring is a macOS feature.
5
4
 
6
5
  const https = require("https");
@@ -9,7 +8,7 @@ const fs = require("fs");
9
8
  const path = require("path");
10
9
  const { execSync } = require("child_process");
11
10
 
12
- const VERSION = "0.17.0";
11
+ const VERSION = "0.19.0";
13
12
  const REPO = "jfarcand/mirroir-mcp";
14
13
  const BINARY = "mirroir-mcp";
15
14
 
@@ -48,7 +47,7 @@ function main() {
48
47
 
49
48
  download(url, tmpFile, () => {
50
49
  verifyChecksum(tarball, tmpFile, () => {
51
- // Extract all files: mirroir-mcp, mirroir-helper, plist
50
+ // Extract mirroir-mcp binary
52
51
  execSync(`tar xzf "${tmpFile}" -C "${binDir}"`, { stdio: "inherit" });
53
52
 
54
53
  // Rename native binary to -native to avoid conflicting with the JS wrapper
@@ -62,12 +61,6 @@ function main() {
62
61
  fs.unlinkSync(jsWrapperBackup);
63
62
  }
64
63
 
65
- // Make helper executable
66
- const helperBin = path.join(binDir, "mirroir-helper");
67
- if (fs.existsSync(helperBin)) {
68
- fs.chmodSync(helperBin, 0o755);
69
- }
70
-
71
64
  fs.unlinkSync(tmpFile);
72
65
  console.log(`Installed binaries to ${binDir}`);
73
66
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirroir-mcp",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "MCP server that controls a real iPhone through macOS iPhone Mirroring. Screenshot, tap, swipe, type — from any MCP client.",
5
5
  "mcpName": "io.github.jfarcand/mirroir-mcp",
6
6
  "license": "Apache-2.0",
@@ -30,7 +30,6 @@
30
30
  "bin/",
31
31
  "install.js",
32
32
  "install-cmd.js",
33
- "setup.js",
34
33
  "prompts/",
35
34
  "agents/",
36
35
  "README.md"
@@ -1,18 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>Label</key>
6
- <string>com.jfarcand.mirroir-helper</string>
7
- <key>ProgramArguments</key>
8
- <array>
9
- <string>/usr/local/bin/mirroir-helper</string>
10
- </array>
11
- <key>RunAtLoad</key>
12
- <true/>
13
- <key>KeepAlive</key>
14
- <true/>
15
- <key>StandardErrorPath</key>
16
- <string>/var/log/mirroir-helper.log</string>
17
- </dict>
18
- </plist>
package/setup.js DELETED
@@ -1,237 +0,0 @@
1
- #!/usr/bin/env node
2
- // Sets up the mirroir-helper daemon as a macOS LaunchDaemon.
3
- // Requires sudo for copying the helper binary and plist to system directories.
4
-
5
- const { execSync, spawnSync } = require("child_process");
6
- const fs = require("fs");
7
- const path = require("path");
8
-
9
- const PLIST_NAME = "com.jfarcand.mirroir-helper";
10
- const HELPER_SOCK = "/var/run/mirroir-helper.sock";
11
- const HELPER_DEST = "/usr/local/bin/mirroir-helper";
12
- const PLIST_DEST = `/Library/LaunchDaemons/${PLIST_NAME}.plist`;
13
- const KARABINER_SOCK_DIR = "/Library/Application Support/org.pqrs/tmp/rootonly/vhidd_server";
14
- const DRIVERKIT_MANAGER = "/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager";
15
- const DRIVERKIT_VERSION = "6.10.0";
16
- const DRIVERKIT_URL = `https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases/download/v${DRIVERKIT_VERSION}/Karabiner-DriverKit-VirtualHIDDevice-${DRIVERKIT_VERSION}.pkg`;
17
-
18
- function main() {
19
- const binDir = path.join(__dirname, "bin");
20
- const helperSrc = path.join(binDir, "mirroir-helper");
21
- const plistSrc = path.join(binDir, `${PLIST_NAME}.plist`);
22
-
23
- if (!fs.existsSync(helperSrc)) {
24
- console.error("Helper binary not found. Run: npm rebuild mirroir-mcp");
25
- process.exit(1);
26
- }
27
-
28
- if (!fs.existsSync(plistSrc)) {
29
- console.error("LaunchDaemon plist not found. Run: npm rebuild mirroir-mcp");
30
- process.exit(1);
31
- }
32
-
33
- // Check if DriverKit virtual HID is available (works for both standalone and Karabiner-Elements)
34
- if (!hasVhiddSocket()) {
35
- if (fs.existsSync("/Applications/Karabiner-Elements.app")) {
36
- console.log("");
37
- console.log("Karabiner-Elements is installed but the DriverKit extension is not running.");
38
- console.log("Approve the extension in System Settings:");
39
- console.log(" System Settings > General > Login Items & Extensions");
40
- console.log(" Enable all toggles under Karabiner-Elements");
41
- console.log("");
42
- console.log("After that, re-run setup.");
43
- process.exit(1);
44
- } else if (fs.existsSync(DRIVERKIT_MANAGER)) {
45
- console.log("");
46
- console.log("Standalone DriverKit is installed but the extension is not running.");
47
- console.log("Activate it:");
48
- console.log(` ${DRIVERKIT_MANAGER} activate`);
49
- console.log("");
50
- console.log("Then approve in System Settings > General > Login Items & Extensions.");
51
- console.log("After that, re-run setup.");
52
- process.exit(1);
53
- } else {
54
- console.log("");
55
- console.log("A DriverKit virtual HID device is required for tap and swipe input.");
56
- console.log("");
57
- console.log("Install the standalone Karabiner DriverKit package:");
58
- console.log(` curl -fSL -o /tmp/driverkit.pkg "${DRIVERKIT_URL}"`);
59
- console.log(" sudo installer -pkg /tmp/driverkit.pkg -target /");
60
- console.log(` ${DRIVERKIT_MANAGER} activate`);
61
- console.log("");
62
- console.log("Then approve the extension in System Settings > General > Login Items & Extensions.");
63
- console.log("After that, re-run setup.");
64
- process.exit(1);
65
- }
66
- }
67
-
68
- console.log("=== Setting up mirroir-helper daemon ===");
69
- console.log("");
70
- console.log("This requires administrator privileges to install the helper daemon.");
71
- console.log("");
72
-
73
- // Stop existing daemon if running
74
- try {
75
- execSync(`sudo launchctl bootout system/${PLIST_NAME} 2>/dev/null`, { stdio: "inherit" });
76
- spawnSync("sleep", ["1"]);
77
- } catch (ignoreNotRunning) {
78
- // Daemon wasn't loaded, safe to continue
79
- }
80
-
81
- // Copy helper binary
82
- execSync(`sudo cp "${helperSrc}" "${HELPER_DEST}"`, { stdio: "inherit" });
83
- execSync(`sudo chmod 755 "${HELPER_DEST}"`, { stdio: "inherit" });
84
-
85
- // Copy and configure plist
86
- execSync(`sudo cp "${plistSrc}" "${PLIST_DEST}"`, { stdio: "inherit" });
87
- execSync(`sudo chown root:wheel "${PLIST_DEST}"`, { stdio: "inherit" });
88
- execSync(`sudo chmod 644 "${PLIST_DEST}"`, { stdio: "inherit" });
89
-
90
- // Start daemon
91
- execSync(`sudo launchctl bootstrap system "${PLIST_DEST}"`, { stdio: "inherit" });
92
-
93
- // Configure Karabiner ignore rule only when Karabiner-Elements is installed
94
- // (the ignore rule prevents the grabber from intercepting our virtual keyboard;
95
- // standalone DriverKit has no grabber)
96
- if (fs.existsSync("/Applications/Karabiner-Elements.app")) {
97
- configureKarabiner();
98
- } else {
99
- console.log("Using standalone DriverKit (no Karabiner grabber, ignore rule not needed).");
100
- }
101
-
102
- // Wait for helper to become ready
103
- console.log("");
104
- console.log("Waiting for helper daemon...");
105
- let ready = false;
106
- for (let i = 0; i < 15; i++) {
107
- spawnSync("sleep", ["2"]);
108
- if (checkHelper()) {
109
- ready = true;
110
- break;
111
- }
112
- }
113
-
114
- console.log("");
115
- if (ready) {
116
- console.log("=== Helper daemon is running ===");
117
- } else {
118
- console.log("Helper daemon started but may need more time to initialize.");
119
- console.log("Check: echo '{\"action\":\"status\"}' | nc -U " + HELPER_SOCK);
120
- }
121
-
122
- // Install prompts and agent profiles to global config dir
123
- installPromptsAndAgents();
124
- }
125
-
126
- function installPromptsAndAgents() {
127
- const globalConfigDir = path.join(process.env.HOME || "", ".mirroir-mcp");
128
- const promptsDir = path.join(globalConfigDir, "prompts");
129
- const agentsDir = path.join(globalConfigDir, "agents");
130
-
131
- fs.mkdirSync(promptsDir, { recursive: true });
132
- fs.mkdirSync(agentsDir, { recursive: true });
133
-
134
- // Source directories are in the npm package alongside setup.js
135
- const srcPromptsDir = path.join(__dirname, "prompts");
136
- const srcAgentsDir = path.join(__dirname, "agents");
137
-
138
- // Copy prompts (skip if user has customized)
139
- if (fs.existsSync(srcPromptsDir)) {
140
- for (const file of fs.readdirSync(srcPromptsDir)) {
141
- if (!file.endsWith(".md")) continue;
142
- const dest = path.join(promptsDir, file);
143
- if (!fs.existsSync(dest)) {
144
- fs.copyFileSync(path.join(srcPromptsDir, file), dest);
145
- console.log(` Installed: ${dest}`);
146
- }
147
- }
148
- }
149
-
150
- // Copy agent profiles (skip if user has customized)
151
- if (fs.existsSync(srcAgentsDir)) {
152
- for (const file of fs.readdirSync(srcAgentsDir)) {
153
- if (!file.endsWith(".yaml")) continue;
154
- const dest = path.join(agentsDir, file);
155
- if (!fs.existsSync(dest)) {
156
- fs.copyFileSync(path.join(srcAgentsDir, file), dest);
157
- console.log(` Installed: ${dest}`);
158
- }
159
- }
160
- }
161
- }
162
-
163
- function checkHelper() {
164
- if (!fs.existsSync(HELPER_SOCK)) return false;
165
- try {
166
- const result = spawnSync("bash", ["-c",
167
- `echo '{"action":"status"}' | nc -U ${HELPER_SOCK} 2>/dev/null`
168
- ], { timeout: 3000 });
169
- const output = result.stdout ? result.stdout.toString() : "";
170
- return output.includes('"ok"');
171
- } catch (socketError) {
172
- return false;
173
- }
174
- }
175
-
176
- function hasVhiddSocket() {
177
- try {
178
- // Socket dir is mode 700 — glob expansion needs sudo bash -c
179
- const result = spawnSync("sudo", ["bash", "-c",
180
- `ls '${KARABINER_SOCK_DIR}'/*.sock`
181
- ], { timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
182
- return result.status === 0;
183
- } catch (checkError) {
184
- return false;
185
- }
186
- }
187
-
188
- function configureKarabiner() {
189
- const configPath = path.join(
190
- process.env.HOME || "",
191
- ".config/karabiner/karabiner.json"
192
- );
193
-
194
- if (!fs.existsSync(configPath)) {
195
- // Create minimal config with ignore rule
196
- const configDir = path.dirname(configPath);
197
- fs.mkdirSync(configDir, { recursive: true });
198
- const config = {
199
- profiles: [{
200
- devices: [{
201
- identifiers: { is_keyboard: true, product_id: 592, vendor_id: 1452 },
202
- ignore: true
203
- }],
204
- name: "Default profile",
205
- selected: true,
206
- virtual_hid_keyboard: { keyboard_type_v2: "ansi" }
207
- }]
208
- };
209
- fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
210
- console.log("Created Karabiner config with device ignore rule.");
211
- return;
212
- }
213
-
214
- // Check if rule already exists
215
- const content = fs.readFileSync(configPath, "utf8");
216
- if (content.includes('"product_id": 592') || content.includes('"product_id":592')) {
217
- return;
218
- }
219
-
220
- // Add ignore rule to first profile
221
- try {
222
- const config = JSON.parse(content);
223
- const profile = config.profiles[0];
224
- if (!profile.devices) profile.devices = [];
225
- profile.devices.push({
226
- identifiers: { is_keyboard: true, product_id: 592, vendor_id: 1452 },
227
- ignore: true
228
- });
229
- fs.writeFileSync(configPath, JSON.stringify(config, null, 4));
230
- console.log("Added device ignore rule to Karabiner config.");
231
- } catch (parseError) {
232
- console.log("Warning: Could not update Karabiner config automatically.");
233
- console.log("Add this device ignore rule manually: product_id 592, vendor_id 1452");
234
- }
235
- }
236
-
237
- main();