@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.
Files changed (2) hide show
  1. package/dist/index.js +123 -3
  2. 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.8 \u2551");
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
- connect();
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");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulso/companion",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Pulso Companion — gives your AI agent real control over your computer",
6
6
  "bin": {