@pulso/companion 0.1.8 → 0.1.9
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/dist/index.js +123 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import WebSocket from "ws";
|
|
|
5
5
|
import { exec, execSync } from "child_process";
|
|
6
6
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
7
7
|
import { homedir } from "os";
|
|
8
|
-
import { resolve } from "path";
|
|
8
|
+
import { join, resolve } from "path";
|
|
9
9
|
var API_URL = process.env.PULSO_API_URL ?? process.argv.find((_, i, a) => a[i - 1] === "--api") ?? "https://pulso-api.vulk.workers.dev";
|
|
10
10
|
var TOKEN = process.env.PULSO_TOKEN ?? process.argv.find((_, i, a) => a[i - 1] === "--token") ?? "";
|
|
11
11
|
if (!TOKEN) {
|
|
@@ -55,6 +55,122 @@ function runSwift(code, timeout = 1e4) {
|
|
|
55
55
|
child.stdin?.end();
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
+
var SETUP_DONE_FILE = join(HOME, ".pulso-companion-setup");
|
|
59
|
+
async function setupPermissions() {
|
|
60
|
+
const isFirstRun = !existsSync(SETUP_DONE_FILE);
|
|
61
|
+
console.log(isFirstRun ? "\u{1F510} First run \u2014 setting up permissions...\n" : "\u{1F510} Checking permissions...\n");
|
|
62
|
+
const status = {};
|
|
63
|
+
const browserDefaults = [
|
|
64
|
+
["Google Chrome", "com.google.Chrome", "AllowJavaScriptAppleEvents"],
|
|
65
|
+
["Safari", "com.apple.Safari", "AllowJavaScriptFromAppleEvents"],
|
|
66
|
+
["Arc", "company.thebrowser.Browser", "AllowJavaScriptAppleEvents"],
|
|
67
|
+
["Microsoft Edge", "com.microsoft.edgemac", "AllowJavaScriptAppleEvents"]
|
|
68
|
+
];
|
|
69
|
+
for (const [name, domain, key] of browserDefaults) {
|
|
70
|
+
try {
|
|
71
|
+
execSync(`defaults write ${domain} ${key} -bool true 2>/dev/null`, { timeout: 3e3 });
|
|
72
|
+
if (name === "Google Chrome" || name === "Safari") status[`${name} JS`] = "\u2705";
|
|
73
|
+
} catch {
|
|
74
|
+
if (name === "Google Chrome" || name === "Safari") status[`${name} JS`] = "\u26A0\uFE0F";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const [browserName, processName] of [["Google Chrome", "Google Chrome"], ["Safari", "Safari"]]) {
|
|
78
|
+
try {
|
|
79
|
+
const running = execSync(`pgrep -x "${processName}" 2>/dev/null`, { timeout: 2e3 }).toString().trim();
|
|
80
|
+
if (!running) continue;
|
|
81
|
+
const enableJsScript = browserName === "Google Chrome" ? `tell application "System Events"
|
|
82
|
+
tell process "Google Chrome"
|
|
83
|
+
-- Find the Developer submenu (localized name varies)
|
|
84
|
+
set viewMenu to menu bar item -3 of menu bar 1
|
|
85
|
+
set viewMenuItems to name of every menu item of menu 1 of viewMenu
|
|
86
|
+
set devMenuItem to last menu item of menu 1 of viewMenu
|
|
87
|
+
set devItems to name of every menu item of menu 1 of devMenuItem
|
|
88
|
+
-- The JS Apple Events item is always the last one in Developer menu
|
|
89
|
+
set jsItem to last menu item of menu 1 of devMenuItem
|
|
90
|
+
set markChar to value of attribute "AXMenuItemMarkChar" of jsItem
|
|
91
|
+
if markChar is missing value then
|
|
92
|
+
click jsItem
|
|
93
|
+
delay 1
|
|
94
|
+
-- Accept any confirmation dialog
|
|
95
|
+
try
|
|
96
|
+
click button 1 of sheet 1 of window 1
|
|
97
|
+
end try
|
|
98
|
+
return "enabled"
|
|
99
|
+
else
|
|
100
|
+
return "already_enabled"
|
|
101
|
+
end if
|
|
102
|
+
end tell
|
|
103
|
+
end tell` : `return "skip_safari"`;
|
|
104
|
+
const result = execSync(`osascript -e '${enableJsScript.replace(/'/g, "'\\''")}' 2>/dev/null`, { timeout: 1e4 }).toString().trim();
|
|
105
|
+
if (result === "enabled") {
|
|
106
|
+
console.log(` \u2705 ${browserName}: JavaScript from Apple Events enabled via menu`);
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
execSync(`osascript -e 'tell application "System Events" to name of first process' 2>/dev/null`, { timeout: 5e3 });
|
|
113
|
+
status["Accessibility"] = "\u2705";
|
|
114
|
+
} catch (err) {
|
|
115
|
+
const msg = err.message || "";
|
|
116
|
+
if (msg.includes("not allowed") || msg.includes("assistive") || msg.includes("-1719")) {
|
|
117
|
+
status["Accessibility"] = "\u26A0\uFE0F";
|
|
118
|
+
if (isFirstRun) {
|
|
119
|
+
console.log(" \u26A0\uFE0F Accessibility: macOS should show a permission dialog.");
|
|
120
|
+
console.log(" If not, go to: System Settings \u2192 Privacy & Security \u2192 Accessibility");
|
|
121
|
+
console.log(" Add your terminal app (Terminal, iTerm, Warp, etc.)\n");
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
status["Accessibility"] = "\u2705";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const testPath = `/tmp/.pulso-perm-test-${Date.now()}.png`;
|
|
129
|
+
execSync(`screencapture -x ${testPath} 2>/dev/null`, { timeout: 8e3 });
|
|
130
|
+
if (existsSync(testPath)) {
|
|
131
|
+
const stat = readFileSync(testPath);
|
|
132
|
+
execSync(`rm -f ${testPath}`);
|
|
133
|
+
if (stat.length > 100) {
|
|
134
|
+
status["Screen Recording"] = "\u2705";
|
|
135
|
+
} else {
|
|
136
|
+
status["Screen Recording"] = "\u26A0\uFE0F";
|
|
137
|
+
if (isFirstRun) {
|
|
138
|
+
console.log(" \u26A0\uFE0F Screen Recording: macOS should show a permission dialog.");
|
|
139
|
+
console.log(" If not, go to: System Settings \u2192 Privacy & Security \u2192 Screen Recording");
|
|
140
|
+
console.log(" Add your terminal app\n");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
status["Screen Recording"] = "\u274C";
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
status["Screen Recording"] = "\u26A0\uFE0F";
|
|
148
|
+
if (isFirstRun) {
|
|
149
|
+
console.log(" \u26A0\uFE0F Screen Recording: permission needed for screenshots.");
|
|
150
|
+
console.log(" Go to: System Settings \u2192 Privacy & Security \u2192 Screen Recording\n");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log(" Permission Status:");
|
|
154
|
+
for (const [name, icon] of Object.entries(status)) {
|
|
155
|
+
const note = icon === "\u2705" ? "enabled" : icon === "\u26A0\uFE0F" ? "needs approval" : "not available";
|
|
156
|
+
console.log(` ${icon} ${name}: ${note}`);
|
|
157
|
+
}
|
|
158
|
+
console.log("");
|
|
159
|
+
if (isFirstRun) {
|
|
160
|
+
try {
|
|
161
|
+
writeFileSync(SETUP_DONE_FILE, (/* @__PURE__ */ new Date()).toISOString(), "utf-8");
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const needsManual = status["Accessibility"] === "\u26A0\uFE0F" || status["Screen Recording"] === "\u26A0\uFE0F";
|
|
166
|
+
if (isFirstRun && needsManual) {
|
|
167
|
+
console.log(" Opening System Settings for you to approve permissions...\n");
|
|
168
|
+
try {
|
|
169
|
+
execSync('open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"', { timeout: 3e3 });
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
58
174
|
var UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
59
175
|
var searchCache = /* @__PURE__ */ new Map();
|
|
60
176
|
var CACHE_TTL = 7 * 24 * 3600 * 1e3;
|
|
@@ -849,10 +965,14 @@ function scheduleReconnect() {
|
|
|
849
965
|
}
|
|
850
966
|
console.log("");
|
|
851
967
|
console.log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
852
|
-
console.log(" \u2551 \u{1FAC0} Pulso Mac Companion v0.1.
|
|
968
|
+
console.log(" \u2551 \u{1FAC0} Pulso Mac Companion v0.1.9 \u2551");
|
|
853
969
|
console.log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
|
|
854
970
|
console.log("");
|
|
855
|
-
|
|
971
|
+
setupPermissions().then(() => {
|
|
972
|
+
connect();
|
|
973
|
+
}).catch(() => {
|
|
974
|
+
connect();
|
|
975
|
+
});
|
|
856
976
|
process.on("SIGINT", () => {
|
|
857
977
|
console.log("\n\u{1F44B} Shutting down Pulso Companion...");
|
|
858
978
|
ws?.close(1e3, "User shutdown");
|