tingly-box 0.2601.51400 → 0.2601.71440-preview

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 (2) hide show
  1. package/bin.js +91 -49
  2. package/package.json +3 -2
package/bin.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { execFileSync } from "child_process";
4
- import { chmodSync, createWriteStream, existsSync, fsyncSync, mkdirSync } from "fs";
5
- import { tmpdir } from "os";
4
+ import { chmodSync, createWriteStream, existsSync, fsyncSync, mkdirSync, statSync } from "fs";
6
5
  import { join } from "path";
7
6
  import { Readable } from "stream";
8
7
  import { ProxyAgent } from "undici";
8
+ import unzipper from "unzipper";
9
9
 
10
10
  // Configuration for binary downloads
11
11
  const BASE_URL = "https://github.com/tingly-dev/tingly-box/releases/download/";
@@ -15,7 +15,7 @@ const LATEST_RELEASE_API_URL = "https://github.com/tingly-dev/tingly-box/release
15
15
 
16
16
  // Default branch to use when not specified via transport version
17
17
  // This will be replaced during the NPX build process
18
- const BINARY_RELEASE_BRANCH = 'v0.2601.051400';
18
+ const BINARY_RELEASE_BRANCH = 'v0.2601.071440-preview';
19
19
 
20
20
  // Create proxy agent from environment variables (HTTP_PROXY, HTTPS_PROXY)
21
21
  // Only create ProxyAgent if proxy is configured, otherwise use undefined (direct connection)
@@ -73,6 +73,13 @@ function validateTransportVersion(version) {
73
73
 
74
74
  const { version: VERSION, remainingArgs } = parseTransportVersion();
75
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
+ ];
82
+
76
83
  async function getPlatformArchAndBinary() {
77
84
  const platform = process.platform;
78
85
  const arch = process.arch;
@@ -192,62 +199,94 @@ async function downloadAndExtractZip(url, extractDir, binaryName) {
192
199
  process.exit(1);
193
200
  }
194
201
 
195
- // Create a temporary file for the ZIP
196
- const zipPath = join(tmpdir(), `tingly-box-${Date.now()}.zip`);
197
- const fileStream = createWriteStream(zipPath, { flags: "w" });
198
-
199
202
  const contentLength = res.headers.get("content-length");
200
203
  const totalSize = contentLength ? parseInt(contentLength, 10) : null;
201
204
  let downloadedSize = 0;
202
205
 
203
- await new Promise((resolve, reject) => {
204
- try {
205
- const nodeStream = Readable.fromWeb(res.body);
206
+ // Convert the fetch response body to a Node.js readable stream
207
+ const nodeStream = Readable.fromWeb(res.body);
208
+
209
+ // Collect the entire ZIP into a buffer
210
+ const chunks = [];
211
+ for await (const chunk of nodeStream) {
212
+ chunks.push(chunk);
213
+ downloadedSize += chunk.length;
214
+ if (totalSize) {
215
+ const progress = ((downloadedSize / totalSize) * 100).toFixed(1);
216
+ process.stdout.write(`\r⏱️ Downloading: ${progress}% (${formatBytes(downloadedSize)}/${formatBytes(totalSize)})`);
217
+ } else {
218
+ process.stdout.write(`\r⏱️ Downloaded: ${formatBytes(downloadedSize)}`);
219
+ }
220
+ }
221
+ const zipBuffer = Buffer.concat(chunks);
206
222
 
207
- nodeStream.on("data", (chunk) => {
208
- downloadedSize += chunk.length;
209
- if (totalSize) {
210
- const progress = ((downloadedSize / totalSize) * 100).toFixed(1);
211
- process.stdout.write(`\r⏱️ Downloading ZIP: ${progress}% (${formatBytes(downloadedSize)}/${formatBytes(totalSize)})`);
212
- } else {
213
- process.stdout.write(`\r⏱️ Downloaded: ${formatBytes(downloadedSize)}`);
214
- }
215
- });
223
+ // Extract ZIP from buffer using unzipper
224
+ try {
225
+ console.log(`\n📦 Extracting ZIP to ${extractDir}...`);
216
226
 
217
- nodeStream.pipe(fileStream);
218
- fileStream.on("finish", () => {
219
- process.stdout.write("\n");
220
- resolve();
221
- });
222
- fileStream.on("error", reject);
223
- nodeStream.on("error", reject);
224
- } catch (error) {
225
- reject(error);
227
+ const directory = await unzipper.Open.buffer(zipBuffer);
228
+
229
+ // Debug: List all entries in the ZIP
230
+ console.log(`📋 ZIP contents (${directory.files.length} entries):`);
231
+ for (const file of directory.files) {
232
+ console.log(` ${file.type}: ${file.path} (permissions: ${file.unixPermissions?.toString(8)})`);
226
233
  }
227
- });
228
234
 
229
- // Extract the ZIP file using system unzip command
230
- try {
231
- console.log(`📦 Extracting ZIP...`);
232
- execFileSync("unzip", ["-q", "-o", zipPath, "-d", extractDir]);
233
- console.log(`✅ Extracted ZIP to ${extractDir}`);
234
- } catch (error) {
235
- console.error(`❌ Failed to extract ZIP: ${error.message}`);
236
- // Fallback: try using Python to extract
237
- try {
238
- execFileSync("python3", ["-m", "zipfile", "-e", zipPath, extractDir]);
239
- console.log(`✅ Extracted ZIP using Python`);
240
- } catch (pythonError) {
241
- console.error(`❌ Failed to extract ZIP with Python too: ${pythonError.message}`);
242
- process.exit(1);
235
+ // Extract all files to the target directory
236
+ for (const file of directory.files) {
237
+ // Skip directory entries and __MACOSX metadata
238
+ if (file.type === 'Directory' || file.path.startsWith('__MACOSX/') || file.path.includes('.DS_Store')) {
239
+ console.log(`⏭️ Skipping: ${file.path} (type: ${file.type})`);
240
+ continue;
241
+ }
242
+
243
+ const filePath = join(extractDir, file.path);
244
+ // Get parent directory of the file in the ZIP
245
+ const pathParts = file.path.split('/');
246
+ pathParts.pop(); // Remove the filename
247
+ const fileDir = pathParts.length > 0 ? join(extractDir, ...pathParts) : extractDir;
248
+
249
+ console.log(`📄 Extracting: ${file.path} -> ${filePath}`);
250
+
251
+ // Ensure parent directory exists
252
+ if (fileDir !== extractDir && !existsSync(fileDir)) {
253
+ mkdirSync(fileDir, { recursive: true });
254
+ }
255
+
256
+ // Remove existing directory if it exists (this was created incorrectly before)
257
+ if (existsSync(filePath) && statSync(filePath).isDirectory()) {
258
+ console.log(`🧹 Removing incorrect directory: ${filePath}`);
259
+ // Can't easily remove a directory in Node without fs.rm (Node 14.14+)
260
+ // Skip and let user clean up manually
261
+ console.log(`⚠️ Please manually remove: rm -rf "${filePath}"`);
262
+ continue;
263
+ }
264
+
265
+ // Extract file
266
+ const content = await file.buffer();
267
+ const fileStream = createWriteStream(filePath);
268
+ await new Promise((resolve, reject) => {
269
+ fileStream.write(content, (err) => {
270
+ if (err) reject(err);
271
+ else {
272
+ fileStream.end();
273
+ resolve();
274
+ }
275
+ });
276
+ });
277
+ // Set file permissions after writing
278
+ if (process.platform !== "win32") {
279
+ // Use ZIP permissions if available, otherwise default to 0o755 (executable)
280
+ const permissions = file.unixPermissions && file.unixPermissions > 0 ? file.unixPermissions : 0o755;
281
+ chmodSync(filePath, permissions);
282
+ }
243
283
  }
244
- }
245
284
 
246
- // Clean up the ZIP file
247
- try {
248
- execFileSync("rm", ["-f", zipPath]);
285
+ console.log(`✅ Extracted ZIP to ${extractDir}`);
249
286
  } catch (error) {
250
- // Ignore cleanup errors
287
+ console.error(`\n❌ Failed to extract ZIP: ${error.message}`);
288
+ console.error(`Stack: ${error.stack}`);
289
+ process.exit(1);
251
290
  }
252
291
  }
253
292
 
@@ -341,7 +380,10 @@ function formatBytes(bytes) {
341
380
  console.log(`🔍 Executing binary: ${binaryPath}`);
342
381
 
343
382
  try {
344
- execFileSync(binaryPath, remainingArgs, {
383
+ // Use default args if no arguments provided
384
+ const argsToUse = remainingArgs.length > 0 ? remainingArgs : DEFAULT_ARGS;
385
+
386
+ execFileSync(binaryPath, argsToUse, {
345
387
  stdio: "inherit",
346
388
  encoding: 'utf8'
347
389
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tingly-box",
3
- "version": "0.2601.51400",
3
+ "version": "0.2601.71440-preview",
4
4
  "description": "High-performance AI gateway CLI - connect to multiple AI providers through a single API",
5
5
  "keywords": [
6
6
  "ai",
@@ -29,6 +29,7 @@
29
29
  },
30
30
  "type": "module",
31
31
  "dependencies": {
32
- "undici": "^7.0.0"
32
+ "undici": "^7.0.0",
33
+ "unzipper": "^0.12.3"
33
34
  }
34
35
  }