nstantpage-agent 0.5.4 → 0.5.6
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/commands/start.js +29 -1
- package/dist/localServer.js +17 -10
- package/dist/tunnel.d.ts +7 -0
- package/dist/tunnel.js +11 -0
- package/package.json +1 -1
package/dist/commands/start.js
CHANGED
|
@@ -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.
|
|
27
|
+
const VERSION = '0.5.6';
|
|
28
28
|
/**
|
|
29
29
|
* Resolve the backend API base URL.
|
|
30
30
|
* - If --backend is passed, use it
|
|
@@ -278,6 +278,10 @@ export async function startCommand(directory, options) {
|
|
|
278
278
|
onStartProject: async (pid) => {
|
|
279
279
|
await startAdditionalProject(pid, {
|
|
280
280
|
token, backendUrl, gatewayUrl: options.gateway, deviceId, noDev: options.noDev,
|
|
281
|
+
onProgress: (phase, message) => {
|
|
282
|
+
// Send progress through the primary tunnel for multi-project starts
|
|
283
|
+
tunnel.sendSetupProgress(pid, phase, message);
|
|
284
|
+
},
|
|
281
285
|
});
|
|
282
286
|
},
|
|
283
287
|
});
|
|
@@ -466,6 +470,9 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
466
470
|
}
|
|
467
471
|
const result = await startAdditionalProject(pid, {
|
|
468
472
|
token, backendUrl, gatewayUrl: options.gateway, deviceId, noDev: options.noDev,
|
|
473
|
+
onProgress: (phase, message) => {
|
|
474
|
+
standbyTunnel.sendSetupProgress(pid, phase, message);
|
|
475
|
+
},
|
|
469
476
|
});
|
|
470
477
|
if (result)
|
|
471
478
|
activeProjects.set(pid, result);
|
|
@@ -550,7 +557,9 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
550
557
|
* sends a start-project command.
|
|
551
558
|
*/
|
|
552
559
|
async function startAdditionalProject(projectId, opts) {
|
|
560
|
+
const progress = opts.onProgress || (() => { });
|
|
553
561
|
console.log(chalk.blue(`\n 📦 Starting project ${projectId}...`));
|
|
562
|
+
progress('fetching-files', 'Fetching project files...');
|
|
554
563
|
try {
|
|
555
564
|
const allocated = allocatePortsForProject(projectId);
|
|
556
565
|
const projectDir = resolveProjectDir('.', projectId);
|
|
@@ -559,47 +568,62 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
559
568
|
// Fetch project files
|
|
560
569
|
try {
|
|
561
570
|
await fetchProjectFiles(opts.backendUrl, projectId, projectDir, opts.token);
|
|
571
|
+
progress('fetching-files', 'Project files downloaded');
|
|
562
572
|
}
|
|
563
573
|
catch (err) {
|
|
564
574
|
console.log(chalk.yellow(` ⚠ Could not fetch files: ${err.message}`));
|
|
575
|
+
progress('fetching-files', `Warning: ${err.message}`);
|
|
565
576
|
}
|
|
566
577
|
// Install dependencies (must complete before dev server can start)
|
|
567
578
|
const installer = new PackageInstaller({ projectDir });
|
|
568
579
|
if (!installer.areDependenciesInstalled() && fs.existsSync(path.join(projectDir, 'package.json'))) {
|
|
569
580
|
console.log(chalk.gray(` Installing dependencies...`));
|
|
581
|
+
progress('installing-deps', 'Installing npm dependencies...');
|
|
570
582
|
try {
|
|
571
583
|
await installer.ensureDependencies();
|
|
572
584
|
console.log(chalk.green(` ✓ Dependencies installed`));
|
|
585
|
+
progress('installing-deps', 'Dependencies installed');
|
|
573
586
|
}
|
|
574
587
|
catch (err) {
|
|
575
588
|
console.log(chalk.red(` ✗ Install failed: ${err.message}`));
|
|
576
589
|
console.log(chalk.yellow(` ⚠ Dev server may fail — retrying install on first request`));
|
|
590
|
+
progress('installing-deps', `Install failed: ${err.message}`);
|
|
577
591
|
}
|
|
578
592
|
}
|
|
593
|
+
else {
|
|
594
|
+
progress('installing-deps', 'Dependencies already installed');
|
|
595
|
+
}
|
|
579
596
|
// Start local server
|
|
597
|
+
progress('starting-server', 'Starting API server...');
|
|
580
598
|
const localServer = new LocalServer({
|
|
581
599
|
projectDir, projectId,
|
|
582
600
|
apiPort: allocated.apiPort, devPort: allocated.devPort,
|
|
583
601
|
});
|
|
584
602
|
await localServer.start();
|
|
585
603
|
console.log(chalk.green(` ✓ API server on port ${allocated.apiPort}`));
|
|
604
|
+
progress('starting-server', `API server on port ${allocated.apiPort}`);
|
|
586
605
|
// Start dev server (only if dependencies are installed)
|
|
587
606
|
if (!opts.noDev) {
|
|
588
607
|
if (installer.areDependenciesInstalled()) {
|
|
608
|
+
progress('starting-dev', 'Starting dev server...');
|
|
589
609
|
try {
|
|
590
610
|
await localServer.getDevServer().start();
|
|
591
611
|
console.log(chalk.green(` ✓ Dev server on port ${allocated.devPort}`));
|
|
612
|
+
progress('starting-dev', `Dev server on port ${allocated.devPort}`);
|
|
592
613
|
}
|
|
593
614
|
catch (err) {
|
|
594
615
|
console.log(chalk.yellow(` ⚠ Dev server: ${err.message}`));
|
|
616
|
+
progress('starting-dev', `Warning: ${err.message}`);
|
|
595
617
|
}
|
|
596
618
|
}
|
|
597
619
|
else {
|
|
598
620
|
console.log(chalk.yellow(` ⚠ Skipping dev server — dependencies not installed`));
|
|
599
621
|
console.log(chalk.gray(` Dev server will start when browser opens the project`));
|
|
622
|
+
progress('starting-dev', 'Skipped — dependencies not installed');
|
|
600
623
|
}
|
|
601
624
|
}
|
|
602
625
|
// Connect project tunnel
|
|
626
|
+
progress('connecting', 'Connecting tunnel to gateway...');
|
|
603
627
|
const tunnel = new TunnelClient({
|
|
604
628
|
gatewayUrl: opts.gatewayUrl,
|
|
605
629
|
token: opts.token,
|
|
@@ -610,10 +634,12 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
610
634
|
try {
|
|
611
635
|
await tunnel.connect();
|
|
612
636
|
console.log(chalk.green(` ✓ Tunnel connected for project ${projectId}`));
|
|
637
|
+
progress('connecting', 'Tunnel connected');
|
|
613
638
|
}
|
|
614
639
|
catch (err) {
|
|
615
640
|
console.log(chalk.yellow(` ⚠ Tunnel: ${err.message}`));
|
|
616
641
|
tunnel.startBackgroundReconnect();
|
|
642
|
+
progress('connecting', `Warning: ${err.message} — reconnecting`);
|
|
617
643
|
}
|
|
618
644
|
// Register project with backend
|
|
619
645
|
try {
|
|
@@ -629,10 +655,12 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
629
655
|
}
|
|
630
656
|
catch { }
|
|
631
657
|
console.log(chalk.green(` ✓ Project ${projectId} is live!\n`));
|
|
658
|
+
progress('ready', 'Project is live!');
|
|
632
659
|
return { localServer, tunnel };
|
|
633
660
|
}
|
|
634
661
|
catch (err) {
|
|
635
662
|
console.error(chalk.red(` ✗ Failed to start project ${projectId}: ${err.message}`));
|
|
663
|
+
progress('error', err.message);
|
|
636
664
|
return null;
|
|
637
665
|
}
|
|
638
666
|
}
|
package/dist/localServer.js
CHANGED
|
@@ -407,15 +407,22 @@ export class LocalServer {
|
|
|
407
407
|
let ptyProcess = null;
|
|
408
408
|
// Prefer node-pty for real PTY (interactive shell, echo, prompt, resize)
|
|
409
409
|
if (ptyModule) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
410
|
+
try {
|
|
411
|
+
ptyProcess = ptyModule.spawn(shellCmd, [], {
|
|
412
|
+
name: 'xterm-256color',
|
|
413
|
+
cols,
|
|
414
|
+
rows,
|
|
415
|
+
cwd: this.options.projectDir,
|
|
416
|
+
env: shellEnv,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
catch (ptyErr) {
|
|
420
|
+
console.warn(` [Terminal] node-pty spawn failed: ${ptyErr.message} — falling back to script`);
|
|
421
|
+
ptyProcess = null;
|
|
422
|
+
// Fall through to script/spawn fallbacks below
|
|
423
|
+
}
|
|
417
424
|
}
|
|
418
|
-
|
|
425
|
+
if (!ptyProcess && !shell && process.platform === 'darwin') {
|
|
419
426
|
// macOS fallback: use 'script' to allocate a PTY
|
|
420
427
|
shell = spawn('script', ['-q', '/dev/null', shellCmd], {
|
|
421
428
|
cwd: this.options.projectDir,
|
|
@@ -423,7 +430,7 @@ export class LocalServer {
|
|
|
423
430
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
424
431
|
});
|
|
425
432
|
}
|
|
426
|
-
else if (process.platform === 'linux') {
|
|
433
|
+
else if (!ptyProcess && !shell && process.platform === 'linux') {
|
|
427
434
|
// Linux fallback: 'script' with -c flag
|
|
428
435
|
shell = spawn('script', ['-qc', shellCmd, '/dev/null'], {
|
|
429
436
|
cwd: this.options.projectDir,
|
|
@@ -431,7 +438,7 @@ export class LocalServer {
|
|
|
431
438
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
432
439
|
});
|
|
433
440
|
}
|
|
434
|
-
else {
|
|
441
|
+
else if (!ptyProcess && !shell) {
|
|
435
442
|
// Windows / other: raw spawn (limited interactivity)
|
|
436
443
|
shell = spawn(shellCmd, [], {
|
|
437
444
|
cwd: this.options.projectDir,
|
package/dist/tunnel.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ interface TunnelClientOptions {
|
|
|
25
25
|
devPort: number;
|
|
26
26
|
/** Callback when gateway requests starting a new project on this device */
|
|
27
27
|
onStartProject?: (projectId: string) => Promise<void>;
|
|
28
|
+
/** Callback for setup progress — lets the standby tunnel relay phases to gateway */
|
|
29
|
+
onSetupProgress?: (projectId: string, phase: string, message: string) => void;
|
|
28
30
|
}
|
|
29
31
|
export declare class TunnelClient {
|
|
30
32
|
private ws;
|
|
@@ -82,6 +84,11 @@ export declare class TunnelClient {
|
|
|
82
84
|
* Called when user clicks "Connect" in the web editor's Cloud panel.
|
|
83
85
|
*/
|
|
84
86
|
private handleStartProject;
|
|
87
|
+
/**
|
|
88
|
+
* Send setup progress for a project through this tunnel.
|
|
89
|
+
* Used by the standby tunnel to relay progress from startAdditionalProject to the gateway.
|
|
90
|
+
*/
|
|
91
|
+
sendSetupProgress(projectId: string, phase: string, message: string): void;
|
|
85
92
|
private send;
|
|
86
93
|
private handleMessage;
|
|
87
94
|
/**
|
package/dist/tunnel.js
CHANGED
|
@@ -253,11 +253,15 @@ export class TunnelClient {
|
|
|
253
253
|
}
|
|
254
254
|
if (this.options.onStartProject) {
|
|
255
255
|
try {
|
|
256
|
+
// Send initial progress
|
|
257
|
+
this.sendSetupProgress(projectId, 'starting', 'Starting project setup...');
|
|
256
258
|
await this.options.onStartProject(projectId);
|
|
259
|
+
this.sendSetupProgress(projectId, 'ready', 'Project is live!');
|
|
257
260
|
this.send({ type: 'start-project-result', projectId, success: true });
|
|
258
261
|
}
|
|
259
262
|
catch (err) {
|
|
260
263
|
console.error(` [Tunnel] Failed to start project ${projectId}:`, err.message);
|
|
264
|
+
this.sendSetupProgress(projectId, 'error', err.message);
|
|
261
265
|
this.send({ type: 'start-project-result', projectId, success: false, error: err.message });
|
|
262
266
|
}
|
|
263
267
|
}
|
|
@@ -265,6 +269,13 @@ export class TunnelClient {
|
|
|
265
269
|
this.send({ type: 'start-project-result', success: false, error: 'Agent does not support remote project start' });
|
|
266
270
|
}
|
|
267
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Send setup progress for a project through this tunnel.
|
|
274
|
+
* Used by the standby tunnel to relay progress from startAdditionalProject to the gateway.
|
|
275
|
+
*/
|
|
276
|
+
sendSetupProgress(projectId, phase, message) {
|
|
277
|
+
this.send({ type: 'setup-progress', projectId, phase, message, timestamp: Date.now() });
|
|
278
|
+
}
|
|
268
279
|
send(msg) {
|
|
269
280
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
270
281
|
this.ws.send(JSON.stringify(msg));
|
package/package.json
CHANGED