nstantpage-agent 0.8.0 → 0.8.2

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
@@ -22,6 +22,7 @@ import { startCommand } from './commands/start.js';
22
22
  import { statusCommand } from './commands/status.js';
23
23
  import { serviceInstallCommand, serviceUninstallCommand, serviceStatusCommand, serviceStartCommand, serviceStopCommand } from './commands/service.js';
24
24
  import { updateCommand } from './commands/update.js';
25
+ import { runCommand } from './commands/run.js';
25
26
  import { syncCommand } from './commands/sync.js';
26
27
  import { getPackageVersion } from './version.js';
27
28
  const program = new Command();
@@ -32,6 +33,7 @@ program
32
33
  program
33
34
  .command('login')
34
35
  .description('Authenticate with nstantpage.com')
36
+ .option('--local [port]', 'Authenticate with local backend (default: 5001)')
35
37
  .option('--gateway <url>', 'Gateway URL (auto-detects local vs production)')
36
38
  .option('--force', 'Re-authenticate even if already logged in')
37
39
  .action(loginCommand);
@@ -45,6 +47,7 @@ program
45
47
  .argument('[directory]', 'Project directory (defaults to ~/.nstantpage/projects/<id>)', '.')
46
48
  .option('-p, --port <port>', 'Local dev server port', '3000')
47
49
  .option('-a, --api-port <port>', 'Local API server port (internal)', '18924')
50
+ .option('--local [port]', 'Connect to local backend (default: 5001)')
48
51
  .option('--project-id <id>', 'Link to a specific project ID')
49
52
  .option('--gateway <url>', 'Gateway URL (default: from login)')
50
53
  .option('--backend <url>', 'Backend API URL (auto-detected from gateway)')
@@ -52,17 +55,19 @@ program
52
55
  .option('--dir <path>', 'Project directory override')
53
56
  .option('--no-dev', 'Skip starting the dev server (start manually later)')
54
57
  .action(startCommand);
58
+ program
59
+ .command('run')
60
+ .description('Install background service and start the agent')
61
+ .option('--local [port]', 'Connect to local backend (default: 5001)')
62
+ .action(runCommand);
55
63
  program
56
64
  .command('sync')
57
- .description('Sync local directory to nstantpage and start agent')
65
+ .description('Sync local directory files to nstantpage database')
58
66
  .argument('[directory]', 'Project directory to sync (defaults to current directory)', '.')
59
- .option('-p, --port <port>', 'Local dev server port', '3000')
60
- .option('-a, --api-port <port>', 'Local API server port', '18924')
61
67
  .option('--local [port]', 'Sync to local backend (default: localhost:5001)')
62
68
  .option('--gateway <url>', 'Gateway URL (default: from login)')
63
69
  .option('--backend <url>', 'Backend API URL (auto-detected from gateway)')
64
70
  .option('--token <token>', 'Auth token (skip login flow)')
65
- .option('--no-start', 'Only sync files, do not start the agent')
66
71
  .action(syncCommand);
67
72
  program
68
73
  .command('stop')
@@ -121,5 +126,14 @@ program
121
126
  .command('update')
122
127
  .description('Update CLI to the latest version')
123
128
  .action(updateCommand);
129
+ program
130
+ .command('logs')
131
+ .description('Show agent log output')
132
+ .option('-f, --follow', 'Follow log output (like tail -f)')
133
+ .option('-n, --lines <count>', 'Number of lines to show', '50')
134
+ .action(async (options) => {
135
+ const { logsCommand } = await import('./commands/logs.js');
136
+ await logsCommand(options);
137
+ });
124
138
  program.parse();
125
139
  //# sourceMappingURL=cli.js.map
@@ -2,6 +2,7 @@
2
2
  * Login command — authenticate with nstantpage.com
3
3
  */
4
4
  interface LoginOptions {
5
+ local?: string | boolean;
5
6
  gateway?: string;
6
7
  force?: boolean;
7
8
  }
@@ -46,6 +46,13 @@ function getEmailFromToken(token) {
46
46
  }
47
47
  export async function loginCommand(options = {}) {
48
48
  const conf = getConfig();
49
+ // Handle --local flag: set gateway to point at local server
50
+ if (options.local !== undefined && options.local !== false) {
51
+ const port = (typeof options.local === 'string') ? options.local : '5001';
52
+ options.gateway = `ws://localhost:4000`;
53
+ // Also store the backend URL for other commands
54
+ conf.set('localBackendUrl', `http://localhost:${port}`);
55
+ }
49
56
  // Check if already logged in (unless --force)
50
57
  const existingToken = conf.get('token');
51
58
  if (existingToken && !options.force) {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Logs command — show agent log output.
3
+ *
4
+ * Usage:
5
+ * nstantpage logs — Show last 50 lines
6
+ * nstantpage logs -f — Follow log output (tail -f)
7
+ * nstantpage logs -n 100 — Show last 100 lines
8
+ */
9
+ interface LogsOptions {
10
+ follow?: boolean;
11
+ lines: string;
12
+ }
13
+ export declare function logsCommand(options: LogsOptions): Promise<void>;
14
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Logs command — show agent log output.
3
+ *
4
+ * Usage:
5
+ * nstantpage logs — Show last 50 lines
6
+ * nstantpage logs -f — Follow log output (tail -f)
7
+ * nstantpage logs -n 100 — Show last 100 lines
8
+ */
9
+ import chalk from 'chalk';
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import os from 'os';
13
+ import { execSync } from 'child_process';
14
+ export async function logsCommand(options) {
15
+ const logPath = path.join(os.homedir(), '.nstantpage', 'agent.log');
16
+ if (!fs.existsSync(logPath)) {
17
+ console.log(chalk.yellow(' No log file found.'));
18
+ console.log(chalk.gray(` Expected: ${logPath}`));
19
+ console.log(chalk.gray(' Run "nstantpage run" to start the agent service first.'));
20
+ return;
21
+ }
22
+ const lines = parseInt(options.lines, 10) || 50;
23
+ if (options.follow) {
24
+ console.log(chalk.gray(` Following ${logPath} (Ctrl+C to stop)\n`));
25
+ try {
26
+ execSync(`tail -n ${lines} -f "${logPath}"`, { stdio: 'inherit' });
27
+ }
28
+ catch {
29
+ // User pressed Ctrl+C
30
+ }
31
+ }
32
+ else {
33
+ try {
34
+ const output = execSync(`tail -n ${lines} "${logPath}"`, { encoding: 'utf-8' });
35
+ console.log(output);
36
+ }
37
+ catch {
38
+ console.log(chalk.red(' Failed to read log file.'));
39
+ }
40
+ }
41
+ }
42
+ //# sourceMappingURL=logs.js.map
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Run command — open the nstantpage desktop app.
2
+ * Run command — install the background service so the agent starts on boot.
3
3
  *
4
4
  * Usage:
5
- * nstantpage run — Open desktop app (loads nstantpage.com)
6
- * nstantpage run --local — Open desktop app pointing at localhost:5001
7
- * nstantpage run --local 3000 — Open desktop app pointing at localhost:3000
5
+ * nstantpage run — Install service (connects to nstantpage.com)
6
+ * nstantpage run --local — Install service targeting localhost:5001
7
+ * nstantpage run --local 3000 — Install service targeting localhost:3000
8
8
  */
9
9
  interface RunOptions {
10
10
  local?: string | boolean;
@@ -1,82 +1,44 @@
1
1
  /**
2
- * Run command — open the nstantpage desktop app.
2
+ * Run command — install the background service so the agent starts on boot.
3
3
  *
4
4
  * Usage:
5
- * nstantpage run — Open desktop app (loads nstantpage.com)
6
- * nstantpage run --local — Open desktop app pointing at localhost:5001
7
- * nstantpage run --local 3000 — Open desktop app pointing at localhost:3000
5
+ * nstantpage run — Install service (connects to nstantpage.com)
6
+ * nstantpage run --local — Install service targeting localhost:5001
7
+ * nstantpage run --local 3000 — Install service targeting localhost:3000
8
8
  */
9
9
  import chalk from 'chalk';
10
- import fs from 'fs';
11
- import path from 'path';
12
- import os from 'os';
13
- import { execSync } from 'child_process';
14
- /**
15
- * Find the Electron desktop app on disk.
16
- * Same logic as service.ts findElectronApp() — check postinstall location first.
17
- */
18
- function findElectronApp() {
19
- const platform = os.platform();
20
- if (platform === 'darwin') {
21
- const candidates = [
22
- path.join(os.homedir(), '.nstantpage', 'desktop', 'nstantpage.app'),
23
- '/Applications/nstantpage.app',
24
- path.join(os.homedir(), 'Applications', 'nstantpage.app'),
25
- ];
26
- for (const p of candidates) {
27
- if (fs.existsSync(p))
28
- return p;
29
- }
30
- }
31
- else if (platform === 'win32') {
32
- const candidates = [
33
- path.join(os.homedir(), '.nstantpage', 'desktop', 'nstantpage.exe'),
34
- path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'nstantpage', 'nstantpage.exe'),
35
- path.join('C:\\Program Files', 'nstantpage', 'nstantpage.exe'),
36
- ];
37
- for (const p of candidates) {
38
- if (fs.existsSync(p))
39
- return p;
40
- }
41
- }
42
- return null;
43
- }
10
+ import { getConfig } from '../config.js';
11
+ import { serviceInstallCommand } from './service.js';
44
12
  export async function runCommand(options = {}) {
45
- const appPath = findElectronApp();
46
- if (!appPath) {
47
- console.log(chalk.red(' ✗ Desktop app not found.'));
48
- console.log(chalk.gray(' Run "nstantpage update --desktop" to download it.'));
49
- process.exit(1);
50
- }
51
- const platform = os.platform();
52
- // Build args to pass to the Electron app
53
- const extraArgs = [];
13
+ const conf = getConfig();
14
+ // Resolve gateway based on --local flag
15
+ let gateway;
54
16
  if (options.local !== undefined && options.local !== false) {
55
17
  const port = (typeof options.local === 'string') ? options.local : '5001';
56
- extraArgs.push(`--local-url=http://localhost:${port}`);
18
+ gateway = `ws://localhost:4000`;
19
+ conf.set('localBackendUrl', `http://localhost:${port}`);
57
20
  }
58
- console.log(chalk.blue(`\n Opening nstantpage desktop app...`));
59
- if (extraArgs.length) {
60
- console.log(chalk.gray(` Args: ${extraArgs.join(' ')}`));
21
+ else {
22
+ gateway = conf.get('gatewayUrl') || 'wss://webprev.live';
23
+ }
24
+ const token = conf.get('token');
25
+ const isLocal = /^wss?:\/\/(localhost|127\.0\.0\.1)/.test(gateway);
26
+ if (!token && !isLocal) {
27
+ console.log(chalk.red(' ✗ Not authenticated. Run "nstantpage login" first.'));
28
+ process.exit(1);
61
29
  }
30
+ console.log(chalk.blue(`\n 🚀 nstantpage run\n`));
31
+ console.log(chalk.gray(` Server: ${isLocal ? 'localhost (dev)' : 'nstantpage.com'}`));
32
+ // Install background service (auto-start on boot + starts immediately)
62
33
  try {
63
- if (platform === 'darwin') {
64
- const argsStr = extraArgs.length ? ` --args ${extraArgs.join(' ')}` : '';
65
- execSync(`open -a "${appPath}"${argsStr}`, { stdio: 'inherit' });
66
- }
67
- else if (platform === 'win32') {
68
- const argsStr = extraArgs.join(' ');
69
- execSync(`"${appPath}" ${argsStr}`, { stdio: 'inherit' });
70
- }
71
- else {
72
- console.log(chalk.yellow(' ⚠ Desktop app not supported on this platform yet.'));
73
- process.exit(1);
74
- }
75
- console.log(chalk.green(' ✓ App launched\n'));
34
+ await serviceInstallCommand({ gateway });
76
35
  }
77
36
  catch (err) {
78
- console.log(chalk.red(` ✗ Failed to launch: ${err.message}`));
37
+ console.log(chalk.red(` ✗ Service install failed: ${err.message}`));
79
38
  process.exit(1);
80
39
  }
40
+ console.log(chalk.green('\n ✓ Agent is running as a background service.'));
41
+ console.log(chalk.gray(' Use "nstantpage logs" to view agent output.'));
42
+ console.log(chalk.gray(' Use "nstantpage service stop" to stop.\n'));
81
43
  }
82
44
  //# sourceMappingURL=run.js.map
@@ -18,6 +18,7 @@
18
18
  interface StartOptions {
19
19
  port: string;
20
20
  apiPort: string;
21
+ local?: string | boolean;
21
22
  projectId?: string;
22
23
  gateway: string;
23
24
  backend?: string;
@@ -182,6 +182,12 @@ function cleanupPreviousAgent(projectId, apiPort, devPort) {
182
182
  }
183
183
  export async function startCommand(directory, options) {
184
184
  const conf = getConfig();
185
+ // Handle --local flag: override backend & gateway to point at localhost
186
+ if (options.local !== undefined && options.local !== false) {
187
+ const localPort = (typeof options.local === 'string') ? options.local : '5001';
188
+ options.backend = `http://localhost:${localPort}`;
189
+ options.gateway = `ws://localhost:4000`;
190
+ }
185
191
  // If --token was passed, persist it
186
192
  if (options.token) {
187
193
  conf.set('token', options.token);
@@ -12,13 +12,10 @@
12
12
  * 4. Starts the agent (equivalent to `nstantpage start`)
13
13
  */
14
14
  interface SyncOptions {
15
- port: string;
16
- apiPort: string;
17
15
  local?: boolean | string;
18
16
  gateway?: string;
19
17
  backend?: string;
20
18
  token?: string;
21
- noStart?: boolean;
22
19
  }
23
20
  export declare function syncCommand(directory: string, options: SyncOptions): Promise<void>;
24
21
  export {};
@@ -15,7 +15,6 @@ import chalk from 'chalk';
15
15
  import path from 'path';
16
16
  import fs from 'fs';
17
17
  import { getConfig, getDeviceId } from '../config.js';
18
- import { startCommand } from './start.js';
19
18
  const SKIP_DIRS = new Set([
20
19
  'node_modules', 'dist', '.git', '.vite-cache', '.next',
21
20
  '__pycache__', '.turbo', '.cache', 'build', 'out',
@@ -136,7 +135,10 @@ export async function syncCommand(directory, options) {
136
135
  const parts = token.split('.');
137
136
  if (parts.length === 3) {
138
137
  const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf-8'));
139
- userId = payload.sub;
138
+ // .NET uses full claim type URIs; also check standard 'sub' claim
139
+ userId = payload['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier']
140
+ || payload['sub']
141
+ || payload['nameid'];
140
142
  }
141
143
  }
142
144
  catch { }
@@ -211,21 +213,8 @@ export async function syncCommand(directory, options) {
211
213
  if (files.length > BATCH_SIZE)
212
214
  process.stdout.write('\n');
213
215
  console.log(chalk.green(` ✓ ${totalPushed} files synced to database`));
214
- // 5. Start the agent unless --no-start
215
- if (options.noStart) {
216
- console.log(chalk.blue(`\n Sync complete! Project ID: ${projectId}\n`));
217
- console.log(chalk.gray(` To start the agent: nstantpage start --project-id ${projectId} --dir "${projectDir}"`));
218
- return;
219
- }
220
- console.log(chalk.gray('\n Starting agent...\n'));
221
- await startCommand(projectDir, {
222
- port: options.port,
223
- apiPort: options.apiPort,
224
- projectId,
225
- gateway,
226
- backend: options.backend,
227
- token,
228
- dir: projectDir,
229
- });
216
+ console.log(chalk.blue(`\n ✓ Sync complete! Project ID: ${projectId}`));
217
+ console.log(chalk.gray(`\n View on web: https://nstantpage.com/project/${projectId}`));
218
+ console.log(chalk.gray(` Start agent: nstantpage start --project-id ${projectId} --dir "${projectDir}"\n`));
230
219
  }
231
220
  //# sourceMappingURL=sync.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nstantpage-agent",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
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": {