@cloneisyou/cli 0.1.2 → 0.1.3-darwin-x64

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/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@cloneisyou/cli",
3
- "version": "0.1.2",
4
- "description": "Native launcher for the Clone CLI",
3
+ "version": "0.1.3-darwin-x64",
4
+ "description": "Native Clone CLI binary for darwin-x64",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
- "private": false,
7
6
  "author": "Clone Labs, Inc.",
8
7
  "homepage": "https://clone.is",
9
8
  "repository": {
@@ -11,44 +10,17 @@
11
10
  "url": "git+https://github.com/cloneisyou/clone.git",
12
11
  "directory": "apps/cli/npm"
13
12
  },
14
- "bugs": {
15
- "url": "https://github.com/cloneisyou/clone/issues"
16
- },
17
- "keywords": [
18
- "clone",
19
- "cli",
20
- "agent",
21
- "automation",
22
- "capture",
23
- "memory",
24
- "terminal"
25
- ],
26
- "publishConfig": {
27
- "access": "public"
28
- },
13
+ "os": ["darwin"],
14
+ "cpu": ["x64"],
29
15
  "bin": {
30
- "clone": "bin/clone.js"
31
- },
32
- "optionalDependencies": {
33
- "@cloneisyou/cli-darwin-arm64": "npm:@cloneisyou/cli@0.1.2-darwin-arm64",
34
- "@cloneisyou/cli-darwin-x64": "npm:@cloneisyou/cli@0.1.2-darwin-x64",
35
- "@cloneisyou/cli-linux-x64": "npm:@cloneisyou/cli@0.1.2-linux-x64",
36
- "@cloneisyou/cli-win32-x64": "npm:@cloneisyou/cli@0.1.2-win32-x64"
16
+ "clone": "vendor/darwin-x64/clone/clone"
37
17
  },
38
18
  "files": [
39
- "bin",
40
- "scripts",
19
+ "vendor",
41
20
  "README.md",
42
21
  "LICENSE.md"
43
22
  ],
44
- "scripts": {
45
- "prepack": "node scripts/sync-platform-deps.js",
46
- "postinstall": "node scripts/install-native.js",
47
- "sync-platform-deps": "node scripts/sync-platform-deps.js",
48
- "test": "node --test tests/*.test.js",
49
- "smoke": "node -e \"const native=require('./scripts/native'); console.log(native.resolvePlatformKey())\" && npm pack --dry-run"
50
- },
51
- "engines": {
52
- "node": ">=18"
23
+ "publishConfig": {
24
+ "access": "public"
53
25
  }
54
26
  }
Binary file
package/bin/clone.js DELETED
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
-
4
- const { spawnSync } = require("node:child_process");
5
- const { ensureNative } = require("../scripts/native");
6
- const { checkForUpdate } = require("../scripts/update-check");
7
-
8
- main().catch((error) => {
9
- process.stderr.write(`\nClone npm wrapper error:\n${error.message}\n`);
10
- process.exit(1);
11
- });
12
-
13
- async function main() {
14
- await checkForUpdate();
15
-
16
- const executable = await ensureNative({ allowDownload: true });
17
- const result = spawnSync(executable, process.argv.slice(2), {
18
- stdio: "inherit",
19
- env: process.env,
20
- });
21
-
22
- if (result.error) {
23
- throw new Error(`failed to run Clone CLI: ${result.error.message}`);
24
- }
25
- if (result.signal) {
26
- process.kill(process.pid, result.signal);
27
- }
28
- process.exit(result.status ?? 1);
29
- }
@@ -1,13 +0,0 @@
1
- "use strict";
2
-
3
- const { ensureNative } = require("./native");
4
-
5
- ensureNative({ allowDownload: true, optional: true })
6
- .then((executable) => {
7
- if (executable) {
8
- process.stderr.write(`▮ CLONE native binary ready: ${executable}\n`);
9
- }
10
- })
11
- .catch((error) => {
12
- process.stderr.write(`▮ CLONE native install skipped: ${error.message}\n`);
13
- });
package/scripts/native.js DELETED
@@ -1,244 +0,0 @@
1
- "use strict";
2
-
3
- const crypto = require("node:crypto");
4
- const fs = require("node:fs");
5
- const https = require("node:https");
6
- const os = require("node:os");
7
- const path = require("node:path");
8
- const { pipeline } = require("node:stream/promises");
9
-
10
- const packageRoot = path.resolve(__dirname, "..");
11
- const packageJson = require(path.join(packageRoot, "package.json"));
12
- const runtimeRoot = path.resolve(
13
- process.env.CLONE_NPM_RUNTIME ||
14
- path.join(os.homedir(), ".clone", "npm-runtime", packageJson.version),
15
- );
16
-
17
- async function ensureNative({ allowDownload = true, optional = false } = {}) {
18
- const existing = findNative();
19
- if (existing) {
20
- return existing;
21
- }
22
-
23
- if (process.env.CLONE_SKIP_NATIVE_INSTALL === "1" || !allowDownload) {
24
- return failOrNull(missingNativeMessage(), optional);
25
- }
26
-
27
- if (!releaseBaseUrl()) {
28
- return failOrNull(missingNativeMessage(), optional);
29
- }
30
-
31
- try {
32
- return await downloadNative();
33
- } catch (error) {
34
- return failOrNull(`${missingNativeMessage()}\n\nDownload failed: ${error.message}`, optional);
35
- }
36
- }
37
-
38
- function findNative() {
39
- const explicit = process.env.CLONE_NATIVE_BINARY;
40
- if (explicit && isExecutableFile(explicit)) {
41
- return path.resolve(explicit);
42
- }
43
-
44
- const optionalPackageBinary = findOptionalPackageBinary();
45
- if (optionalPackageBinary) {
46
- return optionalPackageBinary;
47
- }
48
-
49
- const cached = cachedBinaryPath();
50
- if (isExecutableFile(cached)) {
51
- return cached;
52
- }
53
-
54
- return null;
55
- }
56
-
57
- function findOptionalPackageBinary() {
58
- const packageName = `@cloneisyou/cli-${resolvePlatformKey()}`;
59
- try {
60
- const manifestPath = require.resolve(`${packageName}/package.json`, {
61
- paths: [packageRoot],
62
- });
63
- const manifest = require(manifestPath);
64
- const binField = typeof manifest.bin === "string" ? manifest.bin : manifest.bin?.clone;
65
- if (!binField) {
66
- return null;
67
- }
68
- const candidate = path.resolve(path.dirname(manifestPath), binField);
69
- return isExecutableFile(candidate) ? candidate : null;
70
- } catch {
71
- return null;
72
- }
73
- }
74
-
75
- async function downloadNative() {
76
- const platform = resolvePlatformKey();
77
- const manifest = await fetchManifest().catch(() => null);
78
- const entry = manifest?.platforms?.[platform];
79
- const downloadUrl = entry?.url || buildDefaultBinaryUrl(platform);
80
- const expectedSha256 = entry?.sha256 || entry?.checksum || null;
81
- const destination = cachedBinaryPath();
82
- const temp = `${destination}.tmp-${process.pid}`;
83
-
84
- fs.mkdirSync(path.dirname(destination), { recursive: true });
85
- log(`installing native Clone CLI for ${platform}`);
86
- await downloadFile(downloadUrl, temp);
87
-
88
- if (expectedSha256) {
89
- const actual = sha256File(temp);
90
- if (actual.toLowerCase() !== expectedSha256.toLowerCase()) {
91
- safeUnlink(temp);
92
- throw new Error(`checksum mismatch for ${downloadUrl}`);
93
- }
94
- }
95
-
96
- fs.renameSync(temp, destination);
97
- if (process.platform !== "win32") {
98
- fs.chmodSync(destination, 0o755);
99
- }
100
- return destination;
101
- }
102
-
103
- async function fetchManifest() {
104
- const baseUrl = releaseBaseUrl();
105
- const manifestUrl = `${baseUrl.replace(/\/$/, "")}/manifest.json`;
106
- const text = await readUrl(manifestUrl);
107
- return JSON.parse(text);
108
- }
109
-
110
- function buildDefaultBinaryUrl(platform) {
111
- const baseUrl = releaseBaseUrl().replace(/\/$/, "");
112
- const extension = process.platform === "win32" ? ".exe" : "";
113
- return `${baseUrl}/clone-${platform}${extension}`;
114
- }
115
-
116
- function releaseBaseUrl() {
117
- return process.env.CLONE_DOWNLOAD_BASE_URL || null;
118
- }
119
-
120
- function cachedBinaryPath() {
121
- return path.join(runtimeRoot, "native", resolvePlatformKey(), binaryName());
122
- }
123
-
124
- function binaryName() {
125
- return process.platform === "win32" ? "clone.exe" : "clone";
126
- }
127
-
128
- function resolvePlatformKey() {
129
- const platform = process.platform;
130
- const arch = process.arch;
131
- const supported = new Set([
132
- "darwin-arm64",
133
- "darwin-x64",
134
- "linux-x64",
135
- "win32-x64",
136
- ]);
137
- const key = `${platform}-${arch}`;
138
- if (!supported.has(key)) {
139
- throw new Error(`unsupported platform: ${key}`);
140
- }
141
- return key;
142
- }
143
-
144
- function isExecutableFile(filePath) {
145
- try {
146
- return fs.statSync(filePath).isFile();
147
- } catch {
148
- return false;
149
- }
150
- }
151
-
152
- async function readUrl(url) {
153
- return new Promise((resolve, reject) => {
154
- https
155
- .get(url, (response) => {
156
- if (isRedirect(response.statusCode)) {
157
- readUrl(response.headers.location).then(resolve, reject);
158
- return;
159
- }
160
- if (response.statusCode !== 200) {
161
- reject(new Error(`${url} returned HTTP ${response.statusCode}`));
162
- response.resume();
163
- return;
164
- }
165
- response.setEncoding("utf8");
166
- let body = "";
167
- response.on("data", (chunk) => {
168
- body += chunk;
169
- });
170
- response.on("end", () => resolve(body));
171
- })
172
- .on("error", reject);
173
- });
174
- }
175
-
176
- async function downloadFile(url, destination) {
177
- await new Promise((resolve, reject) => {
178
- https
179
- .get(url, (response) => {
180
- if (isRedirect(response.statusCode)) {
181
- downloadFile(response.headers.location, destination).then(resolve, reject);
182
- response.resume();
183
- return;
184
- }
185
- if (response.statusCode !== 200) {
186
- reject(new Error(`${url} returned HTTP ${response.statusCode}`));
187
- response.resume();
188
- return;
189
- }
190
- pipeline(response, fs.createWriteStream(destination)).then(resolve, reject);
191
- })
192
- .on("error", reject);
193
- });
194
- }
195
-
196
- function isRedirect(statusCode) {
197
- return [301, 302, 303, 307, 308].includes(statusCode);
198
- }
199
-
200
- function sha256File(filePath) {
201
- const hash = crypto.createHash("sha256");
202
- hash.update(fs.readFileSync(filePath));
203
- return hash.digest("hex");
204
- }
205
-
206
- function safeUnlink(filePath) {
207
- try {
208
- fs.unlinkSync(filePath);
209
- } catch {
210
- // Best-effort cleanup only.
211
- }
212
- }
213
-
214
- function failOrNull(message, optional) {
215
- if (optional) {
216
- log(message);
217
- return null;
218
- }
219
- throw new Error(message);
220
- }
221
-
222
- function missingNativeMessage() {
223
- return [
224
- "Clone native binary is not installed.",
225
- "",
226
- "This npm package intentionally does not include Clone's proprietary Python source.",
227
- "Install options:",
228
- " 1. Reinstall @cloneisyou/cli without --omit=optional so npm can install the matching platform package.",
229
- " 2. For internal development, set CLONE_NATIVE_BINARY to an existing clone executable.",
230
- " 3. For private artifact testing, set CLONE_DOWNLOAD_BASE_URL explicitly.",
231
- ].join("\n");
232
- }
233
-
234
- function log(message) {
235
- process.stderr.write(`▮ CLONE ${message}\n`);
236
- }
237
-
238
- module.exports = {
239
- ensureNative,
240
- findNative,
241
- resolvePlatformKey,
242
- cachedBinaryPath,
243
- releaseBaseUrl,
244
- };
@@ -1,18 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require("node:fs");
4
- const path = require("node:path");
5
-
6
- const packagePath = path.resolve(__dirname, "..", "package.json");
7
- const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
8
- const platforms = ["darwin-arm64", "darwin-x64", "linux-x64", "win32-x64"];
9
-
10
- packageJson.optionalDependencies = Object.fromEntries(
11
- platforms.map((platform) => [
12
- `@cloneisyou/cli-${platform}`,
13
- `npm:@cloneisyou/cli@${packageJson.version}-${platform}`,
14
- ]),
15
- );
16
-
17
- fs.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
18
- console.error(`synced optional platform dependencies for ${packageJson.version}`);
@@ -1,132 +0,0 @@
1
- "use strict";
2
-
3
- const https = require("node:https");
4
-
5
- const packageJson = require("../package.json");
6
- const packageName = packageJson.name;
7
- const defaultTimeoutMs = 750;
8
-
9
- async function checkForUpdate({
10
- currentVersion = packageJson.version,
11
- env = process.env,
12
- stderr = process.stderr,
13
- fetchLatestVersion = defaultFetchLatestVersion,
14
- timeoutMs = defaultTimeoutMs,
15
- } = {}) {
16
- if (env.CLONE_SKIP_UPDATE_CHECK === "1") {
17
- return;
18
- }
19
-
20
- try {
21
- const latestVersion = await withTimeout(fetchLatestVersion(), timeoutMs);
22
- if (compareVersions(latestVersion, currentVersion) <= 0) {
23
- return;
24
- }
25
- stderr.write(updateMessage(currentVersion, latestVersion));
26
- } catch {
27
- // Update checks should never block normal CLI execution.
28
- }
29
- }
30
-
31
- function updateMessage(currentVersion, latestVersion) {
32
- return [
33
- `[CLONE] update available: ${packageName} ${currentVersion} -> ${latestVersion}`,
34
- `[CLONE] run: npm install -g ${packageName}@latest`,
35
- "",
36
- ].join("\n");
37
- }
38
-
39
- function defaultFetchLatestVersion() {
40
- const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
41
- return readJson(url).then((body) => body.version);
42
- }
43
-
44
- function readJson(url) {
45
- return new Promise((resolve, reject) => {
46
- const request = https
47
- .get(url, (response) => {
48
- if (isRedirect(response.statusCode)) {
49
- response.resume();
50
- readJson(response.headers.location).then(resolve, reject);
51
- return;
52
- }
53
- if (response.statusCode !== 200) {
54
- response.resume();
55
- reject(new Error(`${url} returned HTTP ${response.statusCode}`));
56
- return;
57
- }
58
-
59
- response.setEncoding("utf8");
60
- let body = "";
61
- response.on("data", (chunk) => {
62
- body += chunk;
63
- });
64
- response.on("end", () => {
65
- try {
66
- resolve(JSON.parse(body));
67
- } catch (error) {
68
- reject(error);
69
- }
70
- });
71
- })
72
- .on("error", reject);
73
-
74
- request.setTimeout(defaultTimeoutMs, () => {
75
- request.destroy(new Error("update check timed out"));
76
- });
77
- });
78
- }
79
-
80
- function withTimeout(promise, timeoutMs) {
81
- return new Promise((resolve, reject) => {
82
- const timer = setTimeout(() => {
83
- reject(new Error("update check timed out"));
84
- }, timeoutMs);
85
-
86
- Promise.resolve(promise).then(
87
- (value) => {
88
- clearTimeout(timer);
89
- resolve(value);
90
- },
91
- (error) => {
92
- clearTimeout(timer);
93
- reject(error);
94
- },
95
- );
96
- });
97
- }
98
-
99
- function compareVersions(left, right) {
100
- const leftParts = parseStableVersion(left);
101
- const rightParts = parseStableVersion(right);
102
- if (!leftParts || !rightParts) {
103
- return 0;
104
- }
105
-
106
- for (let index = 0; index < 3; index += 1) {
107
- if (leftParts[index] > rightParts[index]) {
108
- return 1;
109
- }
110
- if (leftParts[index] < rightParts[index]) {
111
- return -1;
112
- }
113
- }
114
- return 0;
115
- }
116
-
117
- function parseStableVersion(version) {
118
- const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version));
119
- if (!match) {
120
- return null;
121
- }
122
- return match.slice(1).map((part) => Number.parseInt(part, 10));
123
- }
124
-
125
- function isRedirect(statusCode) {
126
- return [301, 302, 303, 307, 308].includes(statusCode);
127
- }
128
-
129
- module.exports = {
130
- checkForUpdate,
131
- compareVersions,
132
- };