cawide 0.4.4

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 (3) hide show
  1. package/README.md +66 -0
  2. package/bin/cawide.js +201 -0
  3. package/package.json +19 -0
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Cawide
2
+
3
+ The official npm launcher for the Cawide desktop companion daemon. It runs a local development build when used from the Cawide repository; otherwise it downloads the matching Cawide release binary and caches it for later runs.
4
+
5
+ ## Quick start
6
+
7
+ Run Cawide without installing it globally:
8
+
9
+ ```sh
10
+ npx cawide start
11
+ ```
12
+
13
+ Or install the command globally:
14
+
15
+ ```sh
16
+ npm install -g cawide
17
+ cawide start
18
+ ```
19
+
20
+ All arguments are forwarded to the native Cawide CLI. Common commands include:
21
+
22
+ ```sh
23
+ cawide --help
24
+ cawide start --help
25
+ cawide status
26
+ cawide qr
27
+ cawide logs
28
+ cawide stop
29
+ ```
30
+
31
+ Use `cawide <command> --help` for the options supported by a particular command.
32
+
33
+ ## Supported platforms
34
+
35
+ - macOS on Apple Silicon and Intel
36
+ - Linux on x64 and ARM64
37
+ - Windows on x64 and ARM64
38
+
39
+ On first use, the launcher downloads the binary for the current platform from the matching [GitHub release](https://github.com/longd2k3/cawide/releases). The binary is cached at:
40
+
41
+ - macOS and Linux: `~/.cache/cawide/bin/v0.4.4/cawide`
42
+ - Windows: `%LOCALAPPDATA%\cawide\bin\v0.4.4\cawide.exe`
43
+
44
+ ## Troubleshooting
45
+
46
+ ### The download fails
47
+
48
+ Check that GitHub Releases is reachable from your network and that release `v0.4.4` contains an artifact for your platform. A proxy or firewall may block redirected downloads from GitHub's asset host.
49
+
50
+ ### The cached binary is damaged
51
+
52
+ Remove the versioned cache directory shown above and run the command again. Cawide will download a fresh copy.
53
+
54
+ ### Permission denied on macOS or Linux
55
+
56
+ The launcher makes the downloaded binary executable automatically. If the cache was copied from another machine, remove it and rerun Cawide so it can be recreated with the correct permissions.
57
+
58
+ ### macOS blocks the binary
59
+
60
+ Open **System Settings → Privacy & Security** and allow Cawide if macOS reports that it blocked the downloaded application. Only use binaries from the official Cawide GitHub release.
61
+
62
+ ### Show available commands
63
+
64
+ ```sh
65
+ cawide --help
66
+ ```
package/bin/cawide.js ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const os = require("node:os");
6
+ const https = require("node:https");
7
+ const childProcess = require("node:child_process");
8
+ const zlib = require("node:zlib");
9
+
10
+ const VERSION = "0.4.4";
11
+ const RELEASE_BASE = `https://github.com/longd2k3/cawide/releases/download/v${VERSION}`;
12
+ const TARGETS = {
13
+ "darwin-arm64": ["aarch64-apple-darwin"],
14
+ "darwin-x64": ["x86_64-apple-darwin", "aarch64-apple-darwin"],
15
+ "linux-x64": ["x86_64-unknown-linux-gnu"],
16
+ "linux-arm64": ["aarch64-unknown-linux-gnu"],
17
+ "win32-x64": ["x86_64-pc-windows-msvc"],
18
+ "win32-arm64": ["aarch64-pc-windows-msvc"],
19
+ };
20
+ const SIGNAL_EXIT_CODES = { SIGINT: 130, SIGTERM: 143 };
21
+
22
+ function executableName() {
23
+ return process.platform === "win32" ? "cawide.exe" : "cawide";
24
+ }
25
+
26
+ function localBinary() {
27
+ const repositoryRoot = path.resolve(__dirname, "../../..");
28
+ if (!fs.existsSync(path.join(repositoryRoot, "Cargo.toml"))) return null;
29
+
30
+ for (const profile of ["release", "debug"]) {
31
+ const candidate = path.join(repositoryRoot, "target", profile, executableName());
32
+ if (fs.existsSync(candidate)) return candidate;
33
+ }
34
+ return null;
35
+ }
36
+
37
+ function cacheBinary() {
38
+ const cacheRoot =
39
+ process.platform === "win32"
40
+ ? process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local")
41
+ : path.join(os.homedir(), ".cache");
42
+ return path.join(cacheRoot, "cawide", "bin", `v${VERSION}`, executableName());
43
+ }
44
+
45
+ function platformTargets() {
46
+ const targets = TARGETS[`${process.platform}-${process.arch}`];
47
+ if (!targets) {
48
+ throw new Error(
49
+ `Cawide does not provide a binary for ${process.platform}/${process.arch}. Supported platforms: macOS (arm64, x64), Linux (arm64, x64), and Windows (arm64, x64).`
50
+ );
51
+ }
52
+ return targets;
53
+ }
54
+
55
+ function download(url, redirectsLeft = 5) {
56
+ return new Promise((resolve, reject) => {
57
+ const request = https.get(
58
+ url,
59
+ { headers: { "User-Agent": `cawide-npm/${VERSION}` } },
60
+ (response) => {
61
+ const status = response.statusCode || 0;
62
+ if (status >= 300 && status < 400 && response.headers.location) {
63
+ response.resume();
64
+ if (redirectsLeft === 0) {
65
+ reject(new Error(`Too many redirects while downloading ${url}`));
66
+ return;
67
+ }
68
+ resolve(download(new URL(response.headers.location, url).toString(), redirectsLeft - 1));
69
+ return;
70
+ }
71
+ if (status !== 200) {
72
+ response.resume();
73
+ const error = new Error(`Download failed with HTTP ${status}: ${url}`);
74
+ error.statusCode = status;
75
+ reject(error);
76
+ return;
77
+ }
78
+
79
+ const chunks = [];
80
+ response.on("data", (chunk) => chunks.push(chunk));
81
+ response.on("end", () => resolve(Buffer.concat(chunks)));
82
+ response.on("error", reject);
83
+ }
84
+ );
85
+ request.on("error", reject);
86
+ });
87
+ }
88
+
89
+ function tarBinary(archive) {
90
+ const tar = zlib.gunzipSync(archive);
91
+ let offset = 0;
92
+ while (offset + 512 <= tar.length) {
93
+ const header = tar.subarray(offset, offset + 512);
94
+ if (header.every((byte) => byte === 0)) break;
95
+ const name = header.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
96
+ const sizeText = header.subarray(124, 136).toString("ascii").replace(/\0.*$/, "").trim();
97
+ const size = Number.parseInt(sizeText || "0", 8);
98
+ const dataStart = offset + 512;
99
+ if (!Number.isFinite(size) || dataStart + size > tar.length) {
100
+ throw new Error("Downloaded tar archive is corrupt");
101
+ }
102
+ if (path.posix.basename(name) === "cawide") return tar.subarray(dataStart, dataStart + size);
103
+ offset = dataStart + Math.ceil(size / 512) * 512;
104
+ }
105
+ throw new Error("Downloaded archive does not contain the cawide binary");
106
+ }
107
+
108
+ function zipBinary(archive) {
109
+ const endSignature = 0x06054b50;
110
+ const centralSignature = 0x02014b50;
111
+ const localSignature = 0x04034b50;
112
+ const searchStart = Math.max(0, archive.length - 65557);
113
+ let endOffset = -1;
114
+ for (let offset = archive.length - 22; offset >= searchStart; offset -= 1) {
115
+ if (archive.readUInt32LE(offset) === endSignature) {
116
+ endOffset = offset;
117
+ break;
118
+ }
119
+ }
120
+ if (endOffset < 0) throw new Error("Downloaded zip archive is corrupt");
121
+
122
+ const entryCount = archive.readUInt16LE(endOffset + 10);
123
+ let offset = archive.readUInt32LE(endOffset + 16);
124
+ for (let index = 0; index < entryCount; index += 1) {
125
+ if (archive.readUInt32LE(offset) !== centralSignature) {
126
+ throw new Error("Downloaded zip archive has an invalid directory");
127
+ }
128
+ const method = archive.readUInt16LE(offset + 10);
129
+ const compressedSize = archive.readUInt32LE(offset + 20);
130
+ const fileNameLength = archive.readUInt16LE(offset + 28);
131
+ const extraLength = archive.readUInt16LE(offset + 30);
132
+ const commentLength = archive.readUInt16LE(offset + 32);
133
+ const localOffset = archive.readUInt32LE(offset + 42);
134
+ const name = archive.subarray(offset + 46, offset + 46 + fileNameLength).toString("utf8");
135
+
136
+ if (path.posix.basename(name.replace(/\\/g, "/")) === "cawide.exe") {
137
+ if (archive.readUInt32LE(localOffset) !== localSignature) {
138
+ throw new Error("Downloaded zip archive has an invalid entry");
139
+ }
140
+ const localNameLength = archive.readUInt16LE(localOffset + 26);
141
+ const localExtraLength = archive.readUInt16LE(localOffset + 28);
142
+ const dataStart = localOffset + 30 + localNameLength + localExtraLength;
143
+ const compressed = archive.subarray(dataStart, dataStart + compressedSize);
144
+ if (method === 0) return compressed;
145
+ if (method === 8) return zlib.inflateRawSync(compressed);
146
+ throw new Error(`Downloaded zip uses unsupported compression method ${method}`);
147
+ }
148
+ offset += 46 + fileNameLength + extraLength + commentLength;
149
+ }
150
+ throw new Error("Downloaded archive does not contain cawide.exe");
151
+ }
152
+
153
+ async function installBinary(destination) {
154
+ const extension = process.platform === "win32" ? "zip" : "tar.gz";
155
+ let lastError;
156
+ for (const target of platformTargets()) {
157
+ const asset = `cawide-${target}.${extension}`;
158
+ const url = `${RELEASE_BASE}/${asset}`;
159
+ try {
160
+ process.stderr.write(`Downloading Cawide v${VERSION} for ${target}...\n`);
161
+ const archive = await download(url);
162
+ const binary = extension === "zip" ? zipBinary(archive) : tarBinary(archive);
163
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
164
+ const temporary = `${destination}.${process.pid}.tmp`;
165
+ try {
166
+ fs.writeFileSync(temporary, binary, { mode: 0o755 });
167
+ fs.chmodSync(temporary, 0o755);
168
+ fs.renameSync(temporary, destination);
169
+ } finally {
170
+ if (fs.existsSync(temporary)) fs.unlinkSync(temporary);
171
+ }
172
+ return;
173
+ } catch (error) {
174
+ lastError = error;
175
+ if (error.statusCode !== 404) break;
176
+ }
177
+ }
178
+ throw lastError;
179
+ }
180
+
181
+ function run(binaryPath) {
182
+ const result = childProcess.spawnSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
183
+ if (result.error) throw result.error;
184
+ if (result.signal && SIGNAL_EXIT_CODES[result.signal])
185
+ process.exit(SIGNAL_EXIT_CODES[result.signal]);
186
+ process.exit(result.status ?? 0);
187
+ }
188
+
189
+ async function main() {
190
+ const local = localBinary();
191
+ if (local) run(local);
192
+
193
+ const cached = cacheBinary();
194
+ if (!fs.existsSync(cached)) await installBinary(cached);
195
+ run(cached);
196
+ }
197
+
198
+ main().catch((error) => {
199
+ process.stderr.write(`cawide: ${error.message}\n`);
200
+ process.exit(1);
201
+ });
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "cawide",
3
+ "version": "0.4.4",
4
+ "description": "Desktop companion daemon for Cawide remote coding terminal",
5
+ "bin": {
6
+ "cawide": "./bin/cawide.js"
7
+ },
8
+ "files": ["bin/", "README.md"],
9
+ "engines": {
10
+ "node": ">=16.0.0"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/longd2k3/cawide.git"
15
+ },
16
+ "keywords": ["cawide", "terminal", "ai-agent", "remote-editor", "gpui"],
17
+ "author": "Cawide Team",
18
+ "license": "MIT"
19
+ }