nstantpage-agent 0.5.6 → 0.5.8

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/dist/cli.js CHANGED
@@ -25,7 +25,7 @@ const program = new Command();
25
25
  program
26
26
  .name('nstantpage')
27
27
  .description('Local development agent for nstantpage.com — run projects on your machine, preview in the cloud')
28
- .version('0.5.4');
28
+ .version('0.5.8');
29
29
  program
30
30
  .command('login')
31
31
  .description('Authenticate with nstantpage.com')
@@ -24,7 +24,7 @@ import { getConfig, getProjectConfig, setProjectConfig, clearProjectConfig, getD
24
24
  import { TunnelClient } from '../tunnel.js';
25
25
  import { LocalServer } from '../localServer.js';
26
26
  import { PackageInstaller } from '../packageInstaller.js';
27
- const VERSION = '0.5.6';
27
+ const VERSION = '0.5.8';
28
28
  /**
29
29
  * Resolve the backend API base URL.
30
30
  * - If --backend is passed, use it
@@ -82,16 +82,29 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
82
82
  console.log(chalk.gray(` Files up-to-date (version ${data.version})`));
83
83
  return { fileCount: data.files.length, isNew: false };
84
84
  }
85
- // Write all files to disk
86
- let written = 0;
85
+ // Write all files to disk in parallel (batch I/O for speed)
86
+ // First, collect unique directories to create
87
+ const dirsToCreate = new Set();
87
88
  for (const file of data.files) {
88
89
  const filePath = path.join(projectDir, file.path);
89
- const dir = path.dirname(filePath);
90
+ dirsToCreate.add(path.dirname(filePath));
91
+ }
92
+ // Create all directories first (sync is fine, there are few unique dirs)
93
+ for (const dir of dirsToCreate) {
90
94
  if (!fs.existsSync(dir)) {
91
95
  fs.mkdirSync(dir, { recursive: true });
92
96
  }
93
- fs.writeFileSync(filePath, file.content, 'utf-8');
94
- written++;
97
+ }
98
+ // Write files in parallel batches of 50
99
+ const BATCH_SIZE = 50;
100
+ let written = 0;
101
+ for (let i = 0; i < data.files.length; i += BATCH_SIZE) {
102
+ const batch = data.files.slice(i, i + BATCH_SIZE);
103
+ await Promise.all(batch.map(async (file) => {
104
+ const filePath = path.join(projectDir, file.path);
105
+ await fs.promises.writeFile(filePath, file.content, 'utf-8');
106
+ }));
107
+ written += batch.length;
95
108
  }
96
109
  // Write version marker
97
110
  fs.writeFileSync(versionFile, String(data.versionId), 'utf-8');
@@ -215,8 +228,8 @@ export async function startCommand(directory, options) {
215
228
  conf.set('projectId', projectId);
216
229
  // Kill any leftover agent for THIS PROJECT only (not other projects)
217
230
  cleanupPreviousAgent(projectId, apiPort, devPort);
218
- // Small delay to let ports release
219
- await new Promise(r => setTimeout(r, 300));
231
+ // Brief pause for OS to release ports (50ms is sufficient on macOS/Linux)
232
+ await new Promise(r => setTimeout(r, 50));
220
233
  console.log(chalk.blue(`\nšŸš€ nstantpage agent v${VERSION}\n`));
221
234
  console.log(chalk.gray(` Project ID: ${projectId}`));
222
235
  console.log(chalk.gray(` Device ID: ${deviceId.slice(0, 12)}...`));
@@ -558,57 +571,97 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
558
571
  */
559
572
  async function startAdditionalProject(projectId, opts) {
560
573
  const progress = opts.onProgress || (() => { });
574
+ const timings = {};
575
+ const t0 = Date.now();
561
576
  console.log(chalk.blue(`\n šŸ“¦ Starting project ${projectId}...`));
562
- progress('fetching-files', 'Fetching project files...');
563
577
  try {
564
578
  const allocated = allocatePortsForProject(projectId);
565
579
  const projectDir = resolveProjectDir('.', projectId);
566
580
  if (!fs.existsSync(projectDir))
567
581
  fs.mkdirSync(projectDir, { recursive: true });
568
- // Fetch project files
582
+ // Ensure ports are clear for this project before starting
583
+ cleanupPreviousAgent(projectId, allocated.apiPort, allocated.devPort);
584
+ await new Promise(r => setTimeout(r, 50));
585
+ // ── Phase 1: Fetch files + start API server in parallel ──────────
586
+ progress('fetching-files', 'Fetching project files...');
587
+ const localServer = new LocalServer({
588
+ projectDir, projectId,
589
+ apiPort: allocated.apiPort, devPort: allocated.devPort,
590
+ });
591
+ // Start API server immediately (doesn't need project files)
592
+ const apiServerPromise = localServer.start().then(() => {
593
+ timings['api-server'] = Date.now() - t0;
594
+ console.log(chalk.green(` āœ“ API server on port ${allocated.apiPort} (${timings['api-server']}ms)`));
595
+ });
596
+ // Fetch project files concurrently with API server start
597
+ const fileStart = Date.now();
569
598
  try {
570
599
  await fetchProjectFiles(opts.backendUrl, projectId, projectDir, opts.token);
571
- progress('fetching-files', 'Project files downloaded');
600
+ timings['fetch-files'] = Date.now() - fileStart;
601
+ progress('fetching-files', `Files downloaded (${timings['fetch-files']}ms)`);
572
602
  }
573
603
  catch (err) {
574
604
  console.log(chalk.yellow(` ⚠ Could not fetch files: ${err.message}`));
575
605
  progress('fetching-files', `Warning: ${err.message}`);
576
606
  }
577
- // Install dependencies (must complete before dev server can start)
607
+ // Wait for API server before proceeding
608
+ await apiServerPromise;
609
+ progress('starting-server', `API server ready`);
610
+ // ── Phase 2: Install deps (if needed) ────────────────────────────
578
611
  const installer = new PackageInstaller({ projectDir });
579
- if (!installer.areDependenciesInstalled() && fs.existsSync(path.join(projectDir, 'package.json'))) {
612
+ const needsInstall = !installer.areDependenciesInstalled() && fs.existsSync(path.join(projectDir, 'package.json'));
613
+ if (needsInstall) {
614
+ const installStart = Date.now();
580
615
  console.log(chalk.gray(` Installing dependencies...`));
581
616
  progress('installing-deps', 'Installing npm dependencies...');
582
617
  try {
583
618
  await installer.ensureDependencies();
584
- console.log(chalk.green(` āœ“ Dependencies installed`));
585
- progress('installing-deps', 'Dependencies installed');
619
+ timings['install'] = Date.now() - installStart;
620
+ console.log(chalk.green(` āœ“ Dependencies installed (${timings['install']}ms)`));
621
+ progress('installing-deps', `Dependencies installed (${timings['install']}ms)`);
586
622
  }
587
623
  catch (err) {
624
+ timings['install'] = Date.now() - installStart;
588
625
  console.log(chalk.red(` āœ— Install failed: ${err.message}`));
589
626
  console.log(chalk.yellow(` ⚠ Dev server may fail — retrying install on first request`));
590
627
  progress('installing-deps', `Install failed: ${err.message}`);
591
628
  }
592
629
  }
593
630
  else {
594
- progress('installing-deps', 'Dependencies already installed');
631
+ progress('installing-deps', 'Dependencies already installed (cached)');
595
632
  }
596
- // Start local server
597
- progress('starting-server', 'Starting API server...');
598
- const localServer = new LocalServer({
599
- projectDir, projectId,
600
- apiPort: allocated.apiPort, devPort: allocated.devPort,
633
+ // ── Phase 3: Start dev server + connect tunnel in parallel ───────
634
+ const tunnel = new TunnelClient({
635
+ gatewayUrl: opts.gatewayUrl,
636
+ token: opts.token,
637
+ projectId,
638
+ apiPort: allocated.apiPort,
639
+ devPort: allocated.devPort,
601
640
  });
602
- await localServer.start();
603
- console.log(chalk.green(` āœ“ API server on port ${allocated.apiPort}`));
604
- progress('starting-server', `API server on port ${allocated.apiPort}`);
605
- // Start dev server (only if dependencies are installed)
641
+ // Connect tunnel immediately (don't wait for dev server — tunnel is needed for status updates)
642
+ const tunnelPromise = (async () => {
643
+ progress('connecting', 'Connecting tunnel to gateway...');
644
+ try {
645
+ await tunnel.connect();
646
+ timings['tunnel'] = Date.now() - t0;
647
+ console.log(chalk.green(` āœ“ Tunnel connected for project ${projectId} (${timings['tunnel']}ms)`));
648
+ progress('connecting', 'Tunnel connected');
649
+ }
650
+ catch (err) {
651
+ console.log(chalk.yellow(` ⚠ Tunnel: ${err.message}`));
652
+ tunnel.startBackgroundReconnect();
653
+ progress('connecting', `Warning: ${err.message} — reconnecting`);
654
+ }
655
+ })();
656
+ // Start dev server in parallel with tunnel connection
606
657
  if (!opts.noDev) {
607
658
  if (installer.areDependenciesInstalled()) {
608
659
  progress('starting-dev', 'Starting dev server...');
609
660
  try {
661
+ const devStart = Date.now();
610
662
  await localServer.getDevServer().start();
611
- console.log(chalk.green(` āœ“ Dev server on port ${allocated.devPort}`));
663
+ timings['dev-server'] = Date.now() - devStart;
664
+ console.log(chalk.green(` āœ“ Dev server on port ${allocated.devPort} (${timings['dev-server']}ms)`));
612
665
  progress('starting-dev', `Dev server on port ${allocated.devPort}`);
613
666
  }
614
667
  catch (err) {
@@ -622,40 +675,22 @@ async function startAdditionalProject(projectId, opts) {
622
675
  progress('starting-dev', 'Skipped — dependencies not installed');
623
676
  }
624
677
  }
625
- // Connect project tunnel
626
- progress('connecting', 'Connecting tunnel to gateway...');
627
- const tunnel = new TunnelClient({
628
- gatewayUrl: opts.gatewayUrl,
629
- token: opts.token,
630
- projectId,
631
- apiPort: allocated.apiPort,
632
- devPort: allocated.devPort,
633
- });
634
- try {
635
- await tunnel.connect();
636
- console.log(chalk.green(` āœ“ Tunnel connected for project ${projectId}`));
637
- progress('connecting', 'Tunnel connected');
638
- }
639
- catch (err) {
640
- console.log(chalk.yellow(` ⚠ Tunnel: ${err.message}`));
641
- tunnel.startBackgroundReconnect();
642
- progress('connecting', `Warning: ${err.message} — reconnecting`);
643
- }
644
- // Register project with backend
645
- try {
646
- await fetch(`${opts.backendUrl}/api/agent/register`, {
647
- method: 'POST',
648
- headers: { 'Authorization': `Bearer ${opts.token}`, 'Content-Type': 'application/json' },
649
- body: JSON.stringify({
650
- deviceId: opts.deviceId, name: os.hostname(), hostname: os.hostname(),
651
- platform: `${os.platform()} ${os.arch()}`, agentVersion: VERSION,
652
- projectId, capabilities: ['file-sync', 'type-check', 'install', 'terminal', 'dev-server'],
653
- }),
654
- });
655
- }
656
- catch { }
657
- console.log(chalk.green(` āœ“ Project ${projectId} is live!\n`));
658
- progress('ready', 'Project is live!');
678
+ // Wait for tunnel to be connected
679
+ await tunnelPromise;
680
+ // Register project with backend (non-blocking)
681
+ fetch(`${opts.backendUrl}/api/agent/register`, {
682
+ method: 'POST',
683
+ headers: { 'Authorization': `Bearer ${opts.token}`, 'Content-Type': 'application/json' },
684
+ body: JSON.stringify({
685
+ deviceId: opts.deviceId, name: os.hostname(), hostname: os.hostname(),
686
+ platform: `${os.platform()} ${os.arch()}`, agentVersion: VERSION,
687
+ projectId, capabilities: ['file-sync', 'type-check', 'install', 'terminal', 'dev-server'],
688
+ }),
689
+ }).catch(() => { });
690
+ const totalTime = Date.now() - t0;
691
+ console.log(chalk.green(` āœ“ Project ${projectId} is live! (total: ${totalTime}ms)\n`));
692
+ console.log(chalk.gray(` Timings: ${JSON.stringify(timings)}`));
693
+ progress('ready', `Project is live! (${totalTime}ms)`);
659
694
  return { localServer, tunnel };
660
695
  }
661
696
  catch (err) {
package/dist/devServer.js CHANGED
@@ -294,14 +294,15 @@ export class DevServer {
294
294
  resolve();
295
295
  });
296
296
  req.on('error', () => {
297
- setTimeout(check, 500);
297
+ setTimeout(check, 300);
298
298
  });
299
299
  req.setTimeout(2000, () => {
300
300
  req.destroy();
301
- setTimeout(check, 500);
301
+ setTimeout(check, 300);
302
302
  });
303
303
  };
304
- setTimeout(check, 1000);
304
+ // Start checking after a short delay (Vite can be ready in <500ms)
305
+ setTimeout(check, 300);
305
306
  });
306
307
  }
307
308
  }
@@ -13,6 +13,7 @@
13
13
  * Requests arrive through the tunnel from the gateway.
14
14
  */
15
15
  import http from 'http';
16
+ import fs from 'fs';
16
17
  import os from 'os';
17
18
  import { createRequire } from 'module';
18
19
  import { spawn } from 'child_process';
@@ -202,7 +203,8 @@ export class LocalServer {
202
203
  '/live/normalize': this.handleNormalize,
203
204
  '/live/normalize-batch': this.handleNormalizeBatch,
204
205
  '/live/invalidate': this.handleInvalidate,
205
- '/live/refetch': this.handleRefetch,
206
+ '/live/refetch': this.handleRefetch, // Legacy — no-op in agent mode
207
+ '/live/reset': this.handleRefetch, // New push-based reset — also no-op in agent mode
206
208
  '/live/grace-period': this.handleGracePeriod,
207
209
  '/live/stats': this.handleStats,
208
210
  '/live/usage': this.handleUsage,
@@ -405,6 +407,8 @@ export class LocalServer {
405
407
  const label = parsed.label || `Terminal ${sessionCounter}`;
406
408
  let shell = null;
407
409
  let ptyProcess = null;
410
+ // Ensure project directory exists (posix_spawnp fails if cwd is missing)
411
+ const spawnCwd = fs.existsSync(this.options.projectDir) ? this.options.projectDir : process.cwd();
408
412
  // Prefer node-pty for real PTY (interactive shell, echo, prompt, resize)
409
413
  if (ptyModule) {
410
414
  try {
@@ -412,39 +416,61 @@ export class LocalServer {
412
416
  name: 'xterm-256color',
413
417
  cols,
414
418
  rows,
415
- cwd: this.options.projectDir,
419
+ cwd: spawnCwd,
416
420
  env: shellEnv,
417
421
  });
418
422
  }
419
423
  catch (ptyErr) {
420
424
  console.warn(` [Terminal] node-pty spawn failed: ${ptyErr.message} — falling back to script`);
421
425
  ptyProcess = null;
422
- // Fall through to script/spawn fallbacks below
423
426
  }
424
427
  }
425
- if (!ptyProcess && !shell && process.platform === 'darwin') {
426
- // macOS fallback: use 'script' to allocate a PTY
427
- shell = spawn('script', ['-q', '/dev/null', shellCmd], {
428
- cwd: this.options.projectDir,
429
- env: shellEnv,
430
- stdio: ['pipe', 'pipe', 'pipe'],
431
- });
432
- }
433
- else if (!ptyProcess && !shell && process.platform === 'linux') {
434
- // Linux fallback: 'script' with -c flag
435
- shell = spawn('script', ['-qc', shellCmd, '/dev/null'], {
436
- cwd: this.options.projectDir,
437
- env: shellEnv,
438
- stdio: ['pipe', 'pipe', 'pipe'],
439
- });
428
+ if (!ptyProcess && !shell) {
429
+ try {
430
+ if (process.platform === 'darwin') {
431
+ // macOS fallback: use 'script' to allocate a PTY
432
+ shell = spawn('script', ['-q', '/dev/null', shellCmd], {
433
+ cwd: spawnCwd,
434
+ env: shellEnv,
435
+ stdio: ['pipe', 'pipe', 'pipe'],
436
+ });
437
+ }
438
+ else if (process.platform === 'linux') {
439
+ // Linux fallback: 'script' with -c flag
440
+ shell = spawn('script', ['-qc', shellCmd, '/dev/null'], {
441
+ cwd: spawnCwd,
442
+ env: shellEnv,
443
+ stdio: ['pipe', 'pipe', 'pipe'],
444
+ });
445
+ }
446
+ else {
447
+ // Windows / other: raw spawn (limited interactivity)
448
+ shell = spawn(shellCmd, [], {
449
+ cwd: spawnCwd,
450
+ env: shellEnv,
451
+ stdio: ['pipe', 'pipe', 'pipe'],
452
+ });
453
+ }
454
+ }
455
+ catch (scriptErr) {
456
+ console.warn(` [Terminal] script fallback failed: ${scriptErr.message} — trying raw spawn`);
457
+ }
440
458
  }
441
- else if (!ptyProcess && !shell) {
442
- // Windows / other: raw spawn (limited interactivity)
443
- shell = spawn(shellCmd, [], {
444
- cwd: this.options.projectDir,
445
- env: shellEnv,
446
- stdio: ['pipe', 'pipe', 'pipe'],
447
- });
459
+ // Last resort: raw spawn with no PTY
460
+ if (!ptyProcess && !shell) {
461
+ try {
462
+ shell = spawn(shellCmd, [], {
463
+ cwd: spawnCwd,
464
+ env: shellEnv,
465
+ stdio: ['pipe', 'pipe', 'pipe'],
466
+ });
467
+ }
468
+ catch (rawErr) {
469
+ console.error(` [Terminal] All spawn methods failed: ${rawErr.message}`);
470
+ res.statusCode = 500;
471
+ this.json(res, { success: false, error: `Failed to spawn terminal: ${rawErr.message}` });
472
+ return;
473
+ }
448
474
  }
449
475
  const session = {
450
476
  id: sessionId,
@@ -566,7 +592,7 @@ export class LocalServer {
566
592
  connected: true,
567
593
  projectId: this.options.projectId,
568
594
  agent: {
569
- version: '0.5.4',
595
+ version: '0.5.8',
570
596
  hostname: os.hostname(),
571
597
  platform: `${os.platform()} ${os.arch()}`,
572
598
  },
@@ -21,8 +21,23 @@ export declare class PackageInstaller {
21
21
  /**
22
22
  * Ensure all project dependencies are installed.
23
23
  * Uses a lock to prevent concurrent installs.
24
+ * Skips install entirely if package.json + lockfile haven't changed (hash cache).
24
25
  */
25
26
  ensureDependencies(): Promise<void>;
27
+ /**
28
+ * Build the fastest possible install command:
29
+ * - npm ci (clean install from lockfile) if package-lock.json exists
30
+ * - npm install --prefer-offline otherwise
31
+ * - pnpm install --frozen-lockfile if pnpm
32
+ */
33
+ private buildFastInstallArgs;
34
+ /**
35
+ * Compute a hash of package.json + lockfile contents.
36
+ * Used to skip npm install when nothing has changed.
37
+ */
38
+ private computeDepsHash;
39
+ private isDepsHashMatch;
40
+ private writeDepsHash;
26
41
  /**
27
42
  * Check if dependencies are actually installed (not just that node_modules/ exists).
28
43
  * Verifies that at least one key dependency from package.json is present.
@@ -5,6 +5,7 @@
5
5
  import { spawn } from 'child_process';
6
6
  import path from 'path';
7
7
  import fs, { existsSync } from 'fs';
8
+ import crypto from 'crypto';
8
9
  export class PackageInstaller {
9
10
  projectDir;
10
11
  /** Serializes concurrent install calls */
@@ -39,26 +40,100 @@ export class PackageInstaller {
39
40
  /**
40
41
  * Ensure all project dependencies are installed.
41
42
  * Uses a lock to prevent concurrent installs.
43
+ * Skips install entirely if package.json + lockfile haven't changed (hash cache).
42
44
  */
43
45
  async ensureDependencies() {
44
46
  // Serialize with any in-flight install
45
47
  await this.installLock;
46
- if (this.areDependenciesInstalled())
48
+ // Fast path: check if deps are cached by hash
49
+ if (this.isDepsHashMatch()) {
50
+ console.log(` [Installer] Dependencies up-to-date (hash match) — skipping install`);
47
51
  return;
52
+ }
53
+ if (this.areDependenciesInstalled()) {
54
+ // node_modules exists and looks valid — write hash and skip
55
+ this.writeDepsHash();
56
+ return;
57
+ }
48
58
  // Acquire lock for this install
49
59
  let releaseLock;
50
60
  this.installLock = new Promise(resolve => { releaseLock = resolve; });
51
61
  try {
52
62
  console.log(` [Installer] Installing project dependencies...`);
53
63
  const pm = this.detectPackageManager();
54
- const args = pm === 'pnpm' ? ['install'] : ['install'];
64
+ const args = this.buildFastInstallArgs(pm);
55
65
  await this.runCommand(pm, args, 300_000);
66
+ this.writeDepsHash();
56
67
  console.log(` [Installer] Dependencies installed`);
57
68
  }
58
69
  finally {
59
70
  releaseLock();
60
71
  }
61
72
  }
73
+ /**
74
+ * Build the fastest possible install command:
75
+ * - npm ci (clean install from lockfile) if package-lock.json exists
76
+ * - npm install --prefer-offline otherwise
77
+ * - pnpm install --frozen-lockfile if pnpm
78
+ */
79
+ buildFastInstallArgs(pm) {
80
+ switch (pm) {
81
+ case 'pnpm': {
82
+ const hasLock = existsSync(path.join(this.projectDir, 'pnpm-lock.yaml'));
83
+ return hasLock ? ['install', '--frozen-lockfile', '--prefer-offline'] : ['install'];
84
+ }
85
+ case 'yarn': {
86
+ const hasLock = existsSync(path.join(this.projectDir, 'yarn.lock'));
87
+ return hasLock ? ['install', '--frozen-lockfile', '--prefer-offline'] : ['install'];
88
+ }
89
+ default: {
90
+ // npm: prefer ci (much faster) if lockfile exists
91
+ const hasLock = existsSync(path.join(this.projectDir, 'package-lock.json'));
92
+ return hasLock ? ['ci', '--prefer-offline'] : ['install', '--prefer-offline'];
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Compute a hash of package.json + lockfile contents.
98
+ * Used to skip npm install when nothing has changed.
99
+ */
100
+ computeDepsHash() {
101
+ const hash = crypto.createHash('sha256');
102
+ const pkgPath = path.join(this.projectDir, 'package.json');
103
+ if (existsSync(pkgPath))
104
+ hash.update(fs.readFileSync(pkgPath));
105
+ // Include lockfile if present
106
+ for (const lockFile of ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock']) {
107
+ const lockPath = path.join(this.projectDir, lockFile);
108
+ if (existsSync(lockPath)) {
109
+ hash.update(fs.readFileSync(lockPath));
110
+ break;
111
+ }
112
+ }
113
+ return hash.digest('hex').slice(0, 16);
114
+ }
115
+ isDepsHashMatch() {
116
+ const hashFile = path.join(this.projectDir, 'node_modules', '.nstantpage-deps-hash');
117
+ if (!existsSync(hashFile))
118
+ return false;
119
+ try {
120
+ const stored = fs.readFileSync(hashFile, 'utf-8').trim();
121
+ return stored === this.computeDepsHash();
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ writeDepsHash() {
128
+ const hashFile = path.join(this.projectDir, 'node_modules', '.nstantpage-deps-hash');
129
+ try {
130
+ const dir = path.dirname(hashFile);
131
+ if (!existsSync(dir))
132
+ fs.mkdirSync(dir, { recursive: true });
133
+ fs.writeFileSync(hashFile, this.computeDepsHash(), 'utf-8');
134
+ }
135
+ catch { }
136
+ }
62
137
  /**
63
138
  * Check if dependencies are actually installed (not just that node_modules/ exists).
64
139
  * Verifies that at least one key dependency from package.json is present.
package/dist/tunnel.js CHANGED
@@ -63,7 +63,7 @@ export class TunnelClient {
63
63
  // Send enhanced agent info with capabilities and deviceId
64
64
  this.send({
65
65
  type: 'agent-info',
66
- version: '0.5.4',
66
+ version: '0.5.8',
67
67
  hostname: os.hostname(),
68
68
  platform: `${os.platform()} ${os.arch()}`,
69
69
  deviceId: getDeviceId(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Local development agent for nstantpage.com — run your projects locally, preview in the cloud. Replaces cloud containers for faster builds.",
5
5
  "type": "module",
6
6
  "bin": {