tingly-box-nightly 0.20260119.702-nightly
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/bin.js +463 -0
- package/package.json +35 -0
package/bin.js
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync } from "child_process";
|
|
4
|
+
import { chmodSync, createWriteStream, existsSync, fsyncSync, mkdirSync, statSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { Readable } from "stream";
|
|
7
|
+
import { ProxyAgent } from "undici";
|
|
8
|
+
import unzipper from "unzipper";
|
|
9
|
+
|
|
10
|
+
// Configuration for binary downloads
|
|
11
|
+
const BASE_URL = "https://github.com/tingly-dev/tingly-box/releases/download/";
|
|
12
|
+
|
|
13
|
+
// GitHub API endpoint for getting latest release info
|
|
14
|
+
const LATEST_RELEASE_API_URL = "https://github.com/tingly-dev/tingly-box/releases/download/";
|
|
15
|
+
|
|
16
|
+
// Default branch to use when not specified via transport version
|
|
17
|
+
// This will be replaced during the NPX build process
|
|
18
|
+
const BINARY_RELEASE_BRANCH = '0.20260119.0702-nightly+6f0bf9ae';
|
|
19
|
+
|
|
20
|
+
// Create proxy agent from environment variables (HTTP_PROXY, HTTPS_PROXY)
|
|
21
|
+
// Only create ProxyAgent if proxy is configured, otherwise use undefined (direct connection)
|
|
22
|
+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
23
|
+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
24
|
+
const proxyUri = httpsProxy || httpProxy;
|
|
25
|
+
const dispatcher = proxyUri ? new ProxyAgent(proxyUri) : undefined;
|
|
26
|
+
|
|
27
|
+
// Parse transport version from command line arguments
|
|
28
|
+
function parseTransportVersion() {
|
|
29
|
+
const args = process.argv.slice(2);
|
|
30
|
+
let transportVersion = "latest"; // Default to latest
|
|
31
|
+
|
|
32
|
+
// Find --transport-version argument
|
|
33
|
+
const versionArgIndex = args.findIndex((arg) => arg.startsWith("--transport-version"));
|
|
34
|
+
|
|
35
|
+
if (versionArgIndex !== -1) {
|
|
36
|
+
const versionArg = args[versionArgIndex];
|
|
37
|
+
|
|
38
|
+
if (versionArg.includes("=")) {
|
|
39
|
+
// Format: --transport-version=v1.2.3
|
|
40
|
+
transportVersion = versionArg.split("=")[1];
|
|
41
|
+
} else if (versionArgIndex + 1 < args.length) {
|
|
42
|
+
// Format: --transport-version v1.2.3
|
|
43
|
+
transportVersion = args[versionArgIndex + 1];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Remove the transport-version arguments from args array so they don't get passed to the binary
|
|
47
|
+
if (versionArg.includes("=")) {
|
|
48
|
+
args.splice(versionArgIndex, 1);
|
|
49
|
+
} else {
|
|
50
|
+
args.splice(versionArgIndex, 2);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { version: validateTransportVersion(transportVersion), remainingArgs: args };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Validate transport version format
|
|
58
|
+
function validateTransportVersion(version) {
|
|
59
|
+
if (version === "latest") {
|
|
60
|
+
return version;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check if version matches v{x.x.x} format
|
|
64
|
+
const versionRegex = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
65
|
+
if (versionRegex.test(version)) {
|
|
66
|
+
return version;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.error(`Invalid transport version format: ${version}`);
|
|
70
|
+
console.error(`Transport version must be either "latest", "v1.2.3", or "v1.2.3-prerelease1"`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { version: VERSION, remainingArgs } = parseTransportVersion();
|
|
75
|
+
|
|
76
|
+
// Default parameters to use when no arguments are provided
|
|
77
|
+
const DEFAULT_ARGS = [
|
|
78
|
+
// Add your default parameters here, e.g.:
|
|
79
|
+
"start",
|
|
80
|
+
"--daemon",
|
|
81
|
+
"--prompt-restart",
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
async function getPlatformArchAndBinary() {
|
|
85
|
+
const platform = process.platform;
|
|
86
|
+
const arch = process.arch;
|
|
87
|
+
|
|
88
|
+
let platformDir;
|
|
89
|
+
let archDir;
|
|
90
|
+
let binaryName;
|
|
91
|
+
binaryName = "tingly-box";
|
|
92
|
+
let suffix = ""
|
|
93
|
+
|
|
94
|
+
if (platform === "darwin") {
|
|
95
|
+
platformDir = "macos";
|
|
96
|
+
if (arch === "arm64") archDir = "arm64";
|
|
97
|
+
else archDir = "amd64";
|
|
98
|
+
} else if (platform === "linux") {
|
|
99
|
+
platformDir = "linux";
|
|
100
|
+
if (arch === "x64") archDir = "amd64";
|
|
101
|
+
else if (arch === "ia32") archDir = "386";
|
|
102
|
+
else archDir = arch; // fallback
|
|
103
|
+
} else if (platform === "win32") {
|
|
104
|
+
platformDir = "windows";
|
|
105
|
+
if (arch === "x64") archDir = "amd64";
|
|
106
|
+
else if (arch === "ia32") archDir = "386";
|
|
107
|
+
else archDir = arch; // fallback
|
|
108
|
+
suffix = ".exe";
|
|
109
|
+
} else {
|
|
110
|
+
console.error(`Unsupported platform/arch: ${platform}/${arch}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { platformDir, archDir, binaryName, suffix };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function downloadBinary(url, dest) {
|
|
118
|
+
// console.log(`š Downloading binary from ${url}...`);
|
|
119
|
+
|
|
120
|
+
// Fetch with redirect following and optional proxy support
|
|
121
|
+
const fetchOptions = {
|
|
122
|
+
redirect: 'follow', // Automatically follow redirects
|
|
123
|
+
headers: {
|
|
124
|
+
'User-Agent': 'tingly-box-npx'
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
if (dispatcher) {
|
|
128
|
+
fetchOptions.dispatcher = dispatcher;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const res = await fetch(url, fetchOptions);
|
|
132
|
+
|
|
133
|
+
if (!res.ok) {
|
|
134
|
+
console.error(`ā Download failed: ${res.status} ${res.statusText}`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const contentLength = res.headers.get("content-length");
|
|
139
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
140
|
+
let downloadedSize = 0;
|
|
141
|
+
|
|
142
|
+
const fileStream = createWriteStream(dest, { flags: "w" });
|
|
143
|
+
await new Promise((resolve, reject) => {
|
|
144
|
+
try {
|
|
145
|
+
// Convert the fetch response body to a Node.js readable stream
|
|
146
|
+
const nodeStream = Readable.fromWeb(res.body);
|
|
147
|
+
|
|
148
|
+
// Add progress tracking
|
|
149
|
+
nodeStream.on("data", (chunk) => {
|
|
150
|
+
downloadedSize += chunk.length;
|
|
151
|
+
if (totalSize) {
|
|
152
|
+
const progress = ((downloadedSize / totalSize) * 100).toFixed(1);
|
|
153
|
+
process.stdout.write(`\rā±ļø Downloading Binary: ${progress}% (${formatBytes(downloadedSize)}/${formatBytes(totalSize)})`);
|
|
154
|
+
} else {
|
|
155
|
+
process.stdout.write(`\rā±ļø Downloaded: ${formatBytes(downloadedSize)}`);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
nodeStream.pipe(fileStream);
|
|
160
|
+
fileStream.on("finish", () => {
|
|
161
|
+
process.stdout.write("\n");
|
|
162
|
+
|
|
163
|
+
// Ensure file is fully written to disk
|
|
164
|
+
try {
|
|
165
|
+
fsyncSync(fileStream.fd);
|
|
166
|
+
} catch (syncError) {
|
|
167
|
+
// fsync might fail on some systems, ignore
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
resolve();
|
|
171
|
+
});
|
|
172
|
+
fileStream.on("error", reject);
|
|
173
|
+
nodeStream.on("error", reject);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
reject(error);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
chmodSync(dest, 0o755);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function downloadAndExtractZip(url, extractDir, binaryName) {
|
|
183
|
+
console.log(`š Downloading ZIP from ${url}...`);
|
|
184
|
+
|
|
185
|
+
// Fetch with redirect following and optional proxy support
|
|
186
|
+
const fetchOptions = {
|
|
187
|
+
redirect: 'follow',
|
|
188
|
+
headers: {
|
|
189
|
+
'User-Agent': 'tingly-box-npx'
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
if (dispatcher) {
|
|
193
|
+
fetchOptions.dispatcher = dispatcher;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const res = await fetch(url, fetchOptions);
|
|
197
|
+
|
|
198
|
+
if (!res.ok) {
|
|
199
|
+
console.error(`ā Download failed: ${res.status} ${res.statusText}`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const contentLength = res.headers.get("content-length");
|
|
204
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
205
|
+
let downloadedSize = 0;
|
|
206
|
+
|
|
207
|
+
// Convert the fetch response body to a Node.js readable stream
|
|
208
|
+
const nodeStream = Readable.fromWeb(res.body);
|
|
209
|
+
|
|
210
|
+
// Collect the entire ZIP into a buffer
|
|
211
|
+
const chunks = [];
|
|
212
|
+
for await (const chunk of nodeStream) {
|
|
213
|
+
chunks.push(chunk);
|
|
214
|
+
downloadedSize += chunk.length;
|
|
215
|
+
if (totalSize) {
|
|
216
|
+
const progress = ((downloadedSize / totalSize) * 100).toFixed(1);
|
|
217
|
+
process.stdout.write(`\rā±ļø Downloading: ${progress}% (${formatBytes(downloadedSize)}/${formatBytes(totalSize)})`);
|
|
218
|
+
} else {
|
|
219
|
+
process.stdout.write(`\rā±ļø Downloaded: ${formatBytes(downloadedSize)}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const zipBuffer = Buffer.concat(chunks);
|
|
223
|
+
|
|
224
|
+
// Extract ZIP from buffer using unzipper
|
|
225
|
+
try {
|
|
226
|
+
console.log(`\nš¦ Extracting ZIP to ${extractDir}...`);
|
|
227
|
+
|
|
228
|
+
const directory = await unzipper.Open.buffer(zipBuffer);
|
|
229
|
+
|
|
230
|
+
// Debug: List all entries in the ZIP
|
|
231
|
+
console.log(`š ZIP contents (${directory.files.length} entries):`);
|
|
232
|
+
for (const file of directory.files) {
|
|
233
|
+
console.log(` ${file.type}: ${file.path} (permissions: ${file.unixPermissions?.toString(8)})`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Extract all files to the target directory
|
|
237
|
+
for (const file of directory.files) {
|
|
238
|
+
// Skip directory entries and __MACOSX metadata
|
|
239
|
+
if (file.type === 'Directory' || file.path.startsWith('__MACOSX/') || file.path.includes('.DS_Store')) {
|
|
240
|
+
console.log(`āļø Skipping: ${file.path} (type: ${file.type})`);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const filePath = join(extractDir, file.path);
|
|
245
|
+
// Get parent directory of the file in the ZIP
|
|
246
|
+
const pathParts = file.path.split('/');
|
|
247
|
+
pathParts.pop(); // Remove the filename
|
|
248
|
+
const fileDir = pathParts.length > 0 ? join(extractDir, ...pathParts) : extractDir;
|
|
249
|
+
|
|
250
|
+
console.log(`š Extracting: ${file.path} -> ${filePath}`);
|
|
251
|
+
|
|
252
|
+
// Ensure parent directory exists
|
|
253
|
+
if (fileDir !== extractDir && !existsSync(fileDir)) {
|
|
254
|
+
mkdirSync(fileDir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Remove existing directory if it exists (this was created incorrectly before)
|
|
258
|
+
if (existsSync(filePath) && statSync(filePath).isDirectory()) {
|
|
259
|
+
console.log(`š§¹ Removing incorrect directory: ${filePath}`);
|
|
260
|
+
// Can't easily remove a directory in Node without fs.rm (Node 14.14+)
|
|
261
|
+
// Skip and let user clean up manually
|
|
262
|
+
console.log(`ā ļø Please manually remove: rm -rf "${filePath}"`);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Extract file
|
|
267
|
+
const content = await file.buffer();
|
|
268
|
+
const fileStream = createWriteStream(filePath);
|
|
269
|
+
await new Promise((resolve, reject) => {
|
|
270
|
+
fileStream.write(content, (err) => {
|
|
271
|
+
if (err) reject(err);
|
|
272
|
+
else {
|
|
273
|
+
fileStream.end();
|
|
274
|
+
resolve();
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
// Set file permissions after writing
|
|
279
|
+
if (process.platform !== "win32") {
|
|
280
|
+
// Use ZIP permissions if available, otherwise default to 0o755 (executable)
|
|
281
|
+
const permissions = file.unixPermissions && file.unixPermissions > 0 ? file.unixPermissions : 0o755;
|
|
282
|
+
chmodSync(filePath, permissions);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log(`ā
Extracted ZIP to ${extractDir}`);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error(`\nā Failed to extract ZIP: ${error.message}`);
|
|
289
|
+
console.error(`Stack: ${error.stack}`);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Returns the os cache directory path for storing binaries
|
|
295
|
+
// Linux: $XDG_CACHE_HOME or ~/.cache
|
|
296
|
+
// macOS: ~/Library/Caches
|
|
297
|
+
// Windows: %LOCALAPPDATA% or %USERPROFILE%\AppData\Local
|
|
298
|
+
function cacheDir() {
|
|
299
|
+
if (process.platform === "linux") {
|
|
300
|
+
return process.env.XDG_CACHE_HOME || join(process.env.HOME || "", ".cache");
|
|
301
|
+
}
|
|
302
|
+
if (process.platform === "darwin") {
|
|
303
|
+
return join(process.env.HOME || "", "Library", "Caches");
|
|
304
|
+
}
|
|
305
|
+
if (process.platform === "win32") {
|
|
306
|
+
return process.env.LOCALAPPDATA || join(process.env.USERPROFILE || "", "AppData", "Local");
|
|
307
|
+
}
|
|
308
|
+
console.error(`Unsupported platform/arch: ${process.platform}/${process.arch}`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// gets the latest version number for transport
|
|
313
|
+
async function getLatestVersion() {
|
|
314
|
+
const releaseUrl = LATEST_RELEASE_API_URL;
|
|
315
|
+
const fetchOptions = {};
|
|
316
|
+
if (dispatcher) {
|
|
317
|
+
fetchOptions.dispatcher = dispatcher;
|
|
318
|
+
}
|
|
319
|
+
const res = await fetch(releaseUrl, fetchOptions);
|
|
320
|
+
if (!res.ok) {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const data = await res.json();
|
|
324
|
+
return data.name;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function formatBytes(bytes) {
|
|
328
|
+
if (bytes === 0) return "0 B";
|
|
329
|
+
const k = 1024;
|
|
330
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
331
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
332
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
(async () => {
|
|
336
|
+
const platformInfo = await getPlatformArchAndBinary();
|
|
337
|
+
const { platformDir, archDir, binaryName, suffix } = platformInfo;
|
|
338
|
+
|
|
339
|
+
const namedVersion = VERSION === "latest" ? BINARY_RELEASE_BRANCH : VERSION;
|
|
340
|
+
|
|
341
|
+
// For the NPX package, we always use the configured branch or the specified version
|
|
342
|
+
const branchName = VERSION === "latest" ? BINARY_RELEASE_BRANCH : VERSION;
|
|
343
|
+
|
|
344
|
+
// Build ZIP download URL
|
|
345
|
+
const zipFileName = `${binaryName}-${platformDir}-${archDir}.zip`;
|
|
346
|
+
const downloadUrl = `${BASE_URL}/${branchName}/${zipFileName}`;
|
|
347
|
+
|
|
348
|
+
let lastError = null;
|
|
349
|
+
let binaryWorking = false;
|
|
350
|
+
|
|
351
|
+
// Use branch name for caching
|
|
352
|
+
const tinglyBinDir = join(cacheDir(), "tingly-box", branchName, "bin");
|
|
353
|
+
|
|
354
|
+
// Create the binary directory
|
|
355
|
+
try {
|
|
356
|
+
if (!existsSync(tinglyBinDir)) {
|
|
357
|
+
mkdirSync(tinglyBinDir, { recursive: true });
|
|
358
|
+
}
|
|
359
|
+
} catch (mkdirError) {
|
|
360
|
+
console.error(`ā Failed to create directory ${tinglyBinDir}:`, mkdirError.message);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// The extracted binary path
|
|
365
|
+
const binaryPath = join(tinglyBinDir, `${binaryName}-${platformDir}-${archDir}${suffix}`);
|
|
366
|
+
|
|
367
|
+
// If binary doesn't exist, download and extract ZIP
|
|
368
|
+
if (!existsSync(binaryPath)) {
|
|
369
|
+
await downloadAndExtractZip(downloadUrl, tinglyBinDir, binaryName);
|
|
370
|
+
|
|
371
|
+
// Make sure the binary is executable
|
|
372
|
+
if (process.platform !== "win32") {
|
|
373
|
+
chmodSync(binaryPath, 0o755);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
console.log(`ā
Downloaded and extracted to ${binaryPath}`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Test if the binary can execute
|
|
380
|
+
// Debug: Show binary location
|
|
381
|
+
console.log(`š Executing binary: ${binaryPath}`);
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
// Use default args if no arguments provided
|
|
385
|
+
const argsToUse = remainingArgs.length > 0 ? remainingArgs : DEFAULT_ARGS;
|
|
386
|
+
|
|
387
|
+
execFileSync(binaryPath, argsToUse, {
|
|
388
|
+
stdio: "inherit",
|
|
389
|
+
encoding: 'utf8'
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// If we reach here, the binary executed successfully
|
|
393
|
+
binaryWorking = true;
|
|
394
|
+
|
|
395
|
+
// If execFileSync completes without throwing, the binary exited with code 0
|
|
396
|
+
// No need to explicitly exit here, let the script continue
|
|
397
|
+
} catch (execError) {
|
|
398
|
+
lastError = execError;
|
|
399
|
+
binaryWorking = false;
|
|
400
|
+
|
|
401
|
+
// Extract detailed error information
|
|
402
|
+
const errorCode = execError.code;
|
|
403
|
+
const errorSignal = execError.signal;
|
|
404
|
+
const errorMessage = execError.message;
|
|
405
|
+
const errorStatus = execError.status;
|
|
406
|
+
|
|
407
|
+
// Create comprehensive error output
|
|
408
|
+
console.error(`\nā Tingly-Box execution failed`);
|
|
409
|
+
console.error(`āā Error Details:`);
|
|
410
|
+
console.error(`ā Message: ${errorMessage}`);
|
|
411
|
+
|
|
412
|
+
if (errorCode) {
|
|
413
|
+
console.error(`ā Code: ${errorCode}`);
|
|
414
|
+
// Provide specific guidance for common error codes
|
|
415
|
+
switch (errorCode) {
|
|
416
|
+
case 'ENOENT':
|
|
417
|
+
console.error(`ā āā Binary not found at: ${binaryPath}`);
|
|
418
|
+
console.error(`ā Try removing the cached binary: rm -rf "${join(cacheDir(), 'tingly-box')}"`);
|
|
419
|
+
break;
|
|
420
|
+
case 'EACCES':
|
|
421
|
+
console.error(`ā āā Permission denied. Check binary permissions.`);
|
|
422
|
+
break;
|
|
423
|
+
case 'ETXTBSY':
|
|
424
|
+
console.error(`ā āā Binary file is busy or being modified.`);
|
|
425
|
+
break;
|
|
426
|
+
default:
|
|
427
|
+
console.error(`ā āā System error occurred.`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (errorStatus !== null && errorStatus !== undefined) {
|
|
432
|
+
console.error(`ā Exit Code: ${errorStatus}`);
|
|
433
|
+
console.error(`ā āā The binary exited with non-zero status code.`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (errorSignal) {
|
|
437
|
+
console.error(`ā Signal: ${errorSignal}`);
|
|
438
|
+
console.error(`ā āā The binary was terminated by a signal.`);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
console.error(`āā Binary Path: ${binaryPath}`);
|
|
442
|
+
console.error(` Platform: ${process.platform} (${process.arch})`);
|
|
443
|
+
|
|
444
|
+
// Provide additional help for common scenarios
|
|
445
|
+
if (process.platform === "linux") {
|
|
446
|
+
console.error(`\nš” Linux Troubleshooting:`);
|
|
447
|
+
console.error(` ⢠Check if required libraries are installed:`);
|
|
448
|
+
console.error(` - For glibc issues: try on a different Linux distribution`);
|
|
449
|
+
console.error(` - For missing dependencies: install required system packages`);
|
|
450
|
+
console.error(` ⢠Try running with strace: strace -o trace.log "${binaryPath}"`);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Suggest retry
|
|
454
|
+
console.error(`\nš To retry, run: npx tingly-box ${remainingArgs.join(' ')}`);
|
|
455
|
+
console.error(` Or clear cache first: rm -rf "${join(cacheDir(), 'tingly-box')}"`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (!binaryWorking) {
|
|
459
|
+
// Exit with the binary's exit code if available, otherwise default to 1
|
|
460
|
+
const exitCode = lastError.status !== undefined ? lastError.status : 1;
|
|
461
|
+
process.exit(exitCode);
|
|
462
|
+
}
|
|
463
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tingly-box-nightly",
|
|
3
|
+
"version": "0.20260119.702-nightly",
|
|
4
|
+
"description": "High-performance AI gateway CLI - connect to multiple AI providers through a single API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"gateway",
|
|
8
|
+
"openai",
|
|
9
|
+
"anthropic",
|
|
10
|
+
"claude",
|
|
11
|
+
"cli",
|
|
12
|
+
"tingly"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/tingly-dev/tingly-box-nightly",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/tingly-dev/tingly-box-nightly.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MPL-2.0",
|
|
20
|
+
"author": "Tingly Dev",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"bin": {
|
|
28
|
+
"tingly-box-nightly": "bin.js"
|
|
29
|
+
},
|
|
30
|
+
"type": "module",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"undici": "^7.0.0",
|
|
33
|
+
"unzipper": "^0.12.3"
|
|
34
|
+
}
|
|
35
|
+
}
|