openowl 0.3.5 → 0.3.7

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
@@ -18,10 +18,19 @@ npx openowl
18
18
 
19
19
  1. Sign up at [openowl.dev/quick-setup](https://openowl.dev/quick-setup)
20
20
  2. Save your API key:
21
+
22
+ **macOS / Linux:**
21
23
  ```bash
22
24
  mkdir -p ~/.openowl
23
25
  echo "owl-xxxx-xxxx-xxxx" > ~/.openowl/api.key
24
26
  ```
27
+
28
+ **Windows (PowerShell):**
29
+ ```powershell
30
+ New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.openowl"
31
+ "owl-xxxx-xxxx-xxxx" | Out-File "$env:USERPROFILE\.openowl\api.key" -Encoding utf8
32
+ ```
33
+
25
34
  3. Register with Claude Code:
26
35
  ```bash
27
36
  claude mcp add owl --transport stdio -s user -- owl
@@ -31,10 +40,16 @@ npx openowl
31
40
 
32
41
  OpenOwl gives AI assistants the ability to see your screen and interact with desktop applications — clicking, typing, scrolling, reading text, and more.
33
42
 
43
+ ## Supported platforms
44
+
45
+ - macOS (Apple Silicon and Intel)
46
+ - Windows 10/11 (x64)
47
+
34
48
  ## Requirements
35
49
 
36
- - macOS (Apple Silicon or Intel)
37
- - Grant Accessibility and Screen Recording permissions when prompted
50
+ **macOS:** Grant Accessibility and Screen Recording permissions when prompted.
51
+
52
+ **Windows:** Run as Administrator for full desktop control. Python 3.10+ is installed automatically in a local venv on first run.
38
53
 
39
54
  ## Links
40
55
 
package/bin/owl.cmd ADDED
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ node "%~dp0\owl" %*
package/install.js CHANGED
@@ -7,8 +7,9 @@ const path = require("path");
7
7
  const https = require("https");
8
8
  const http = require("http");
9
9
  const { execSync } = require("child_process");
10
+ const zlib = require("zlib");
10
11
 
11
- const VERSION = "0.3.5";
12
+ const VERSION = "0.3.7";
12
13
  const BASE_URL =
13
14
  "https://dedjlsvrwafhyznaazbm.supabase.co/storage/v1/object/public/releases";
14
15
 
@@ -38,7 +39,6 @@ function download(url) {
38
39
  return new Promise((resolve, reject) => {
39
40
  const get = url.startsWith("https") ? https.get : http.get;
40
41
  get(url, (res) => {
41
- // Follow redirects
42
42
  if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
43
43
  return download(res.headers.location).then(resolve).catch(reject);
44
44
  }
@@ -53,6 +53,52 @@ function download(url) {
53
53
  });
54
54
  }
55
55
 
56
+ /**
57
+ * Extract a zip file using pure Node.js (no PowerShell dependency).
58
+ * Handles the zip local file header format directly.
59
+ */
60
+ function extractZip(zipBuffer, destDir) {
61
+ let offset = 0;
62
+ while (offset < zipBuffer.length - 4) {
63
+ const sig = zipBuffer.readUInt32LE(offset);
64
+ // Local file header signature = 0x04034b50
65
+ if (sig !== 0x04034b50) break;
66
+
67
+ const compressionMethod = zipBuffer.readUInt16LE(offset + 8);
68
+ const compressedSize = zipBuffer.readUInt32LE(offset + 18);
69
+ const uncompressedSize = zipBuffer.readUInt32LE(offset + 22);
70
+ const nameLen = zipBuffer.readUInt16LE(offset + 26);
71
+ const extraLen = zipBuffer.readUInt16LE(offset + 28);
72
+ const nameStart = offset + 30;
73
+ const fileName = zipBuffer.toString("utf8", nameStart, nameStart + nameLen);
74
+ const dataStart = nameStart + nameLen + extraLen;
75
+
76
+ const destPath = path.join(destDir, fileName);
77
+
78
+ if (fileName.endsWith("/")) {
79
+ // Directory entry
80
+ fs.mkdirSync(destPath, { recursive: true });
81
+ } else {
82
+ // File entry
83
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
84
+ const rawData = zipBuffer.slice(dataStart, dataStart + compressedSize);
85
+
86
+ if (compressionMethod === 0) {
87
+ // Stored (no compression)
88
+ fs.writeFileSync(destPath, rawData);
89
+ } else if (compressionMethod === 8) {
90
+ // Deflated
91
+ const inflated = zlib.inflateRawSync(rawData);
92
+ fs.writeFileSync(destPath, inflated);
93
+ } else {
94
+ console.warn(`[OpenOwl] Skipping ${fileName} (unsupported compression: ${compressionMethod})`);
95
+ }
96
+ }
97
+
98
+ offset = dataStart + compressedSize;
99
+ }
100
+ }
101
+
56
102
  async function install() {
57
103
  const platformKey = getPlatformKey();
58
104
  const info = PLATFORMS[platformKey];
@@ -63,7 +109,6 @@ async function install() {
63
109
  process.exit(1);
64
110
  }
65
111
 
66
- const binDir = path.join(__dirname, "bin");
67
112
  const installDir = path.join(__dirname, ".owl");
68
113
 
69
114
  // Skip if already installed
@@ -76,35 +121,34 @@ async function install() {
76
121
  console.log(`[OpenOwl] Downloading for ${platformKey}...`);
77
122
 
78
123
  try {
79
- const tarball = await download(info.url);
80
-
81
- // Write archive to temp file
82
- const ext = info.isZip ? "zip" : "tar.gz";
83
- const tmpFile = path.join(os.tmpdir(), `owl-${VERSION}.${ext}`);
84
- fs.writeFileSync(tmpFile, tarball);
124
+ const archive = await download(info.url);
85
125
 
86
- // Extract
87
126
  fs.mkdirSync(installDir, { recursive: true });
127
+
88
128
  if (info.isZip) {
89
- // Windows: use PowerShell to extract zip
90
- execSync(
91
- `powershell -Command "Expand-Archive -Force -Path '${tmpFile}' -DestinationPath '${installDir}'"`,
92
- { stdio: "pipe" }
93
- );
129
+ // Pure Node.js zip extraction no PowerShell needed
130
+ extractZip(archive, installDir);
94
131
  } else {
132
+ // macOS/Linux: use tar
133
+ const tmpFile = path.join(os.tmpdir(), `owl-${VERSION}.tar.gz`);
134
+ fs.writeFileSync(tmpFile, archive);
95
135
  execSync(`tar -xzf "${tmpFile}" -C "${installDir}"`, { stdio: "pipe" });
136
+ fs.unlinkSync(tmpFile);
96
137
  }
97
- fs.unlinkSync(tmpFile);
98
138
 
99
- // Make binary executable
100
- if (fs.existsSync(binaryPath)) {
139
+ // Make binary executable (no-op on Windows)
140
+ if (fs.existsSync(binaryPath) && os.platform() !== "win32") {
101
141
  fs.chmodSync(binaryPath, 0o755);
102
142
  }
103
143
 
104
- console.log(`[OpenOwl] Installed successfully (${(tarball.length / 1024 / 1024).toFixed(1)} MB)`);
144
+ console.log(`[OpenOwl] Installed successfully (${(archive.length / 1024 / 1024).toFixed(1)} MB)`);
105
145
  } catch (err) {
106
146
  console.error(`[OpenOwl] Installation failed: ${err.message}`);
107
- console.error("[OpenOwl] Try: brew install mihir-kanzariya/owl/owl");
147
+ if (os.platform() === "win32") {
148
+ console.error("[OpenOwl] Try downloading manually from: https://openowl.dev/quick-setup");
149
+ } else {
150
+ console.error("[OpenOwl] Try: brew install mihir-kanzariya/owl/owl");
151
+ }
108
152
  process.exit(1);
109
153
  }
110
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openowl",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "AI desktop automation MCP server — give your AI eyes and hands",
5
5
  "homepage": "https://openowl.dev",
6
6
  "repository": {