nstantpage-agent 0.3.3 → 0.3.4

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.
@@ -19,6 +19,7 @@ import chalk from 'chalk';
19
19
  import path from 'path';
20
20
  import fs from 'fs';
21
21
  import os from 'os';
22
+ import { execSync } from 'child_process';
22
23
  import { getConfig } from '../config.js';
23
24
  import { TunnelClient } from '../tunnel.js';
24
25
  import { LocalServer } from '../localServer.js';
@@ -97,6 +98,54 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
97
98
  console.log(chalk.green(` ✓ ${written} files downloaded (version ${data.version})`));
98
99
  return { fileCount: written, isNew: true };
99
100
  }
101
+ /**
102
+ * Kill any process listening on the given port.
103
+ */
104
+ function killPort(port) {
105
+ try {
106
+ // Works on macOS and Linux
107
+ const pids = execSync(`lsof -ti :${port} 2>/dev/null`, { encoding: 'utf-8' }).trim();
108
+ if (pids) {
109
+ for (const pid of pids.split('\n')) {
110
+ const p = parseInt(pid.trim(), 10);
111
+ if (p && p !== process.pid) {
112
+ try {
113
+ process.kill(p, 'SIGTERM');
114
+ }
115
+ catch { }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ catch {
121
+ // lsof not available or no process found — that's fine
122
+ try {
123
+ // Fallback for systems without lsof
124
+ execSync(`fuser -k ${port}/tcp 2>/dev/null`, { encoding: 'utf-8' });
125
+ }
126
+ catch { }
127
+ }
128
+ }
129
+ /**
130
+ * Clean up any previous agent instance (kill old PID + free ports).
131
+ */
132
+ function cleanupPreviousAgent(conf, apiPort, devPort) {
133
+ // 1. Try to kill the previously stored agent PID
134
+ const oldPid = conf.get('agentPid');
135
+ if (oldPid && oldPid !== process.pid) {
136
+ try {
137
+ process.kill(oldPid, 'SIGTERM');
138
+ console.log(chalk.gray(` Stopped previous agent (PID ${oldPid})`));
139
+ }
140
+ catch {
141
+ // Already dead
142
+ }
143
+ conf.delete('agentPid');
144
+ }
145
+ // 2. Free the ports in case orphaned processes are still holding them
146
+ killPort(apiPort);
147
+ killPort(devPort);
148
+ }
100
149
  export async function startCommand(directory, options) {
101
150
  const conf = getConfig();
102
151
  // If --token was passed, persist it
@@ -134,6 +183,10 @@ export async function startCommand(directory, options) {
134
183
  // Save project ID
135
184
  conf.set('projectId', projectId);
136
185
  const backendUrl = resolveBackendUrl(options);
186
+ // Kill any leftover agent / free ports from a previous run
187
+ cleanupPreviousAgent(conf, apiPort, devPort);
188
+ // Small delay to let ports release
189
+ await new Promise(r => setTimeout(r, 300));
137
190
  console.log(chalk.blue(`\n🚀 nstantpage agent v${VERSION}\n`));
138
191
  console.log(chalk.gray(` Project ID: ${projectId}`));
139
192
  console.log(chalk.gray(` Directory: ${projectDir}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
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": {