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 +17 -2
- package/bin/owl.cmd +2 -0
- package/install.js +64 -20
- package/package.json +1 -1
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
|
-
|
|
37
|
-
|
|
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
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.
|
|
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
|
|
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
|
-
//
|
|
90
|
-
|
|
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 (${(
|
|
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
|
-
|
|
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
|
}
|