tova 0.4.1 → 0.4.3

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/tova.js CHANGED
@@ -4408,6 +4408,55 @@ function compareSemver(a, b) {
4408
4408
  return 0;
4409
4409
  }
4410
4410
 
4411
+ function formatBytes(bytes) {
4412
+ if (bytes < 1024) return bytes + ' B';
4413
+ if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
4414
+ return (bytes / 1048576).toFixed(1) + ' MB';
4415
+ }
4416
+
4417
+ async function downloadWithProgress(url, destPath) {
4418
+ const res = await fetch(url);
4419
+ if (!res.ok) return null;
4420
+
4421
+ const contentLength = parseInt(res.headers.get('content-length'), 10) || 0;
4422
+ const reader = res.body.getReader();
4423
+ const chunks = [];
4424
+ let received = 0;
4425
+
4426
+ const barWidth = 20;
4427
+
4428
+ while (true) {
4429
+ const { done, value } = await reader.read();
4430
+ if (done) break;
4431
+ chunks.push(value);
4432
+ received += value.length;
4433
+
4434
+ if (isTTY) {
4435
+ if (contentLength > 0) {
4436
+ const pct = Math.min(100, Math.round((received / contentLength) * 100));
4437
+ const filled = Math.round((pct / 100) * barWidth);
4438
+ const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(barWidth - filled);
4439
+ process.stdout.write(`\r Downloading... [${bar}] ${pct}% (${formatBytes(received)} / ${formatBytes(contentLength)})`);
4440
+ } else {
4441
+ process.stdout.write(`\r Downloading... ${formatBytes(received)}`);
4442
+ }
4443
+ }
4444
+ }
4445
+
4446
+ if (isTTY) process.stdout.write('\n');
4447
+
4448
+ // Combine chunks into a single Uint8Array
4449
+ const result = new Uint8Array(received);
4450
+ let offset = 0;
4451
+ for (const chunk of chunks) {
4452
+ result.set(chunk, offset);
4453
+ offset += chunk.length;
4454
+ }
4455
+
4456
+ writeFileSync(destPath, result);
4457
+ return { compressed: url.endsWith('.gz'), size: received };
4458
+ }
4459
+
4411
4460
  async function upgradeCommand() {
4412
4461
  console.log(`\n Current version: ${color.bold('Tova v' + VERSION)}\n`);
4413
4462
  console.log(' Checking for updates...');
@@ -4446,9 +4495,9 @@ async function upgradeCommand() {
4446
4495
  }
4447
4496
 
4448
4497
  if (!ghTag) {
4449
- // No newer binary release available fall back to npm install
4450
- console.log(` ${color.dim('No binary release for v' + latestVersion + ' yet. Falling back to npm...')}\n`);
4451
- await npmUpgrade(latestVersion);
4498
+ // No newer binary release — install from npm tarball directly
4499
+ console.log(` ${color.dim('No binary release for v' + latestVersion + ' yet. Installing from npm...')}`);
4500
+ await npmTarballUpgrade(latestVersion);
4452
4501
  return;
4453
4502
  }
4454
4503
 
@@ -4465,20 +4514,22 @@ async function upgradeCommand() {
4465
4514
  // Ensure install directory exists
4466
4515
  mkdirSync(installDir, { recursive: true });
4467
4516
 
4468
- // Download compressed binary
4469
- const dlRes = await fetch(downloadUrl);
4470
- if (!dlRes.ok) {
4517
+ // Download compressed binary with progress
4518
+ let dlResult = await downloadWithProgress(downloadUrl, tmpPath);
4519
+ if (!dlResult) {
4471
4520
  // Fall back to uncompressed
4472
- const dlRes2 = await fetch(downloadUrl.replace('.gz', ''));
4473
- if (!dlRes2.ok) {
4521
+ dlResult = await downloadWithProgress(downloadUrl.replace('.gz', ''), tmpPath);
4522
+ if (!dlResult) {
4474
4523
  console.log(` ${color.dim('Binary download failed. Falling back to npm...')}\n`);
4475
4524
  await npmUpgrade(latestVersion);
4476
4525
  return;
4477
4526
  }
4478
- writeFileSync(tmpPath, new Uint8Array(await dlRes2.arrayBuffer()));
4479
- } else {
4527
+ }
4528
+
4529
+ if (dlResult.compressed) {
4480
4530
  // Decompress gzip
4481
- const compressed = new Uint8Array(await dlRes.arrayBuffer());
4531
+ console.log(' Decompressing...');
4532
+ const compressed = readFileSync(tmpPath);
4482
4533
  const { gunzipSync } = await import('zlib');
4483
4534
  const decompressed = gunzipSync(compressed);
4484
4535
  writeFileSync(tmpPath, decompressed);
@@ -4488,6 +4539,7 @@ async function upgradeCommand() {
4488
4539
  chmodSync(tmpPath, 0o755);
4489
4540
 
4490
4541
  // Verify the new binary works
4542
+ console.log(' Verifying binary...');
4491
4543
  const { spawnSync } = await import('child_process');
4492
4544
  const verifyProc = spawnSync(tmpPath, ['--version'], { timeout: 10000 });
4493
4545
  if (verifyProc.status !== 0) {
@@ -4535,6 +4587,52 @@ async function npmUpgrade(latestVersion) {
4535
4587
  }
4536
4588
  }
4537
4589
 
4590
+ async function npmTarballUpgrade(latestVersion) {
4591
+ const installDir = join(process.env.HOME || '', '.tova');
4592
+ const binDir = join(installDir, 'bin');
4593
+ const libDir = join(installDir, 'lib');
4594
+ mkdirSync(libDir, { recursive: true });
4595
+
4596
+ // Download npm tarball
4597
+ const tarballUrl = `https://registry.npmjs.org/tova/-/tova-${latestVersion}.tgz`;
4598
+ const tarballPath = join(installDir, 'tova.tgz');
4599
+
4600
+ const dlResult = await downloadWithProgress(tarballUrl, tarballPath);
4601
+ if (!dlResult) {
4602
+ console.error(color.red(' Failed to download npm package. Try manually: bun add -g tova@latest'));
4603
+ process.exit(1);
4604
+ }
4605
+
4606
+ // Extract tarball into lib dir
4607
+ console.log(' Extracting...');
4608
+ const { spawnSync: spawnTar } = await import('child_process');
4609
+ rmSync(libDir, { recursive: true, force: true });
4610
+ mkdirSync(libDir, { recursive: true });
4611
+ const tarResult = spawnTar('tar', ['-xzf', tarballPath, '-C', libDir, '--strip-components=1'], { stdio: 'pipe' });
4612
+ rmSync(tarballPath, { force: true });
4613
+ if (tarResult.status !== 0) {
4614
+ console.error(color.red(' Failed to extract package. Try manually: bun add -g tova@latest'));
4615
+ process.exit(1);
4616
+ }
4617
+
4618
+ // Create wrapper script at ~/.tova/bin/tova
4619
+ const libBin = join(libDir, 'bin', 'tova.js');
4620
+ const wrapperScript = `#!/bin/sh\nexec bun "${libBin}" "$@"\n`;
4621
+ const binPath = join(binDir, 'tova');
4622
+ writeFileSync(binPath, wrapperScript);
4623
+ chmodSync(binPath, 0o755);
4624
+
4625
+ // Verify
4626
+ console.log(' Verifying...');
4627
+ const verifyProc = spawnTar(binPath, ['--version'], { timeout: 10000 });
4628
+ if (verifyProc.status !== 0) {
4629
+ console.error(color.red(' Verification failed. Try manually: bun add -g tova@latest'));
4630
+ process.exit(1);
4631
+ }
4632
+
4633
+ console.log(`\n ${color.green('✓')} Upgraded: v${VERSION} -> ${color.bold('v' + latestVersion)}\n`);
4634
+ }
4635
+
4538
4636
  function detectPackageManager() {
4539
4637
  if (typeof Bun !== 'undefined') return 'bun';
4540
4638
  const ua = process.env.npm_config_user_agent || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tova",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Tova — a modern programming language that transpiles to JavaScript, unifying frontend and backend",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by scripts/embed-runtime.js — do not edit
2
- export const VERSION = "0.4.1";
2
+ export const VERSION = "0.4.3";